diff --git a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV4.py b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV4.py index 41843a33eb7..23bb0ef083f 100644 --- a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV4.py +++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV4.py @@ -79,6 +79,9 @@ class DataType(Enum): NULL_BYTES = [DataType.null.value, 0x01] +# null type code as a plain int, so the per-read null check skips the aenum lookup +_NULL = DataType.null.value + def _make_packer(format_string): packer = struct.Struct(format_string) @@ -149,6 +152,9 @@ def __init__(self, deserializer_map=None, pdt_registry=None): if deserializer_map: self.deserializers.update(deserializer_map) self.pdt_registry = pdt_registry + # Mirror of self.deserializers keyed by int type code instead of DataType. + # Avoids the per-read DataType(bt) call, whose aenum construction negatively affects performance on large results. + self._deserializer_by_type_code = {dt.value: des.objectify for dt, des in self.deserializers.items()} def read_object(self, b): if b is None: @@ -160,11 +166,15 @@ def read_object(self, b): def to_object(self, buff, data_type=None, nullable=True): if data_type is None: bt = uint8_unpack(buff.read(1)) - if bt == DataType.null.value: + if bt == _NULL: if nullable: buff.read(1) return None - result = self.deserializers[DataType(bt)].objectify(buff, self, nullable) + try: + objectify = self._deserializer_by_type_code[bt] + except KeyError: + raise ValueError("%r is not a valid DataType" % bt) from None + result = objectify(buff, self, nullable) else: result = self.deserializers[data_type].objectify(buff, self, nullable) if self.pdt_registry is not None and isinstance(result, ProviderDefinedType):