blob: c06ee128e578f9bd4aefdac18d0d937ebf4e57ef [file] [log] [blame]
"""
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
"""
import six
import datetime
import calendar
import uuid
import math
import io
import struct
from collections import OrderedDict
import logging
from struct import pack, unpack
from aenum import Enum
from datetime import timedelta
from gremlin_python import statics
from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, DictType, ListType, SetType, \
SingleByte, ByteBufferType, GremlinType, SingleChar
from gremlin_python.process.traversal import Barrier, Binding, Bytecode, Cardinality, Column, Direction, Operator, \
Order, Pick, Pop, P, Scope, TextP, Traversal, Traverser, \
TraversalStrategy, T
from gremlin_python.process.graph_traversal import GraphTraversal
from gremlin_python.structure.graph import Graph, Edge, Property, Vertex, VertexProperty, Path
log = logging.getLogger(__name__)
# When we fall back to a superclass's serializer, we iterate over this map.
# We want that iteration order to be consistent, so we use an OrderedDict,
# not a dict.
_serializers = OrderedDict()
_deserializers = {}
class DataType(Enum):
null = 0xfe
int = 0x01
long = 0x02
string = 0x03
date = 0x04
timestamp = 0x05
clazz = 0x06
double = 0x07
float = 0x08
list = 0x09
map = 0x0a
set = 0x0b
uuid = 0x0c
edge = 0x0d
path = 0x0e
property = 0x0f
graph = 0x10 # not supported - no graph object in python yet
vertex = 0x11
vertexproperty = 0x12
barrier = 0x13
binding = 0x14
bytecode = 0x15
cardinality = 0x16
column = 0x17
direction = 0x18
operator = 0x19
order = 0x1a
pick = 0x1b
pop = 0x1c
lambda_ = 0x1d
p = 0x1e
scope = 0x1f
t = 0x20
traverser = 0x21
bigdecimal = 0x22 # todo
biginteger = 0x23 # todo
byte = 0x24
bytebuffer = 0x25
short = 0x26 # todo
boolean = 0x27
textp = 0x28
traversalstrategy = 0x29
bulkset = 0x2a
tree = 0x2b # not supported - no tree object in Python yet
metrics = 0x2c
traversalmetrics = 0x2d
char = 0x80
duration = 0x81
inetaddress = 0x82 # todo
instant = 0x83 # todo
localdate = 0x84 # todo
localdatetime = 0x85 # todo
localtime = 0x86 # todo
monthday = 0x87 # todo
offsetdatetime = 0x88 # todo
offsettime = 0x89 # todo
period = 0x8a # todo
year = 0x8b # todo
yearmonth = 0x8c # todo
zonedatetime = 0x8d # todo
zoneoffset = 0x8e # todo
custom = 0x00 # todo
NULL_BYTES = [DataType.null.value, 0x01]
def _make_packer(format_string):
packer = struct.Struct(format_string)
pack = packer.pack
unpack = lambda s: packer.unpack(s)[0]
return pack, unpack
int64_pack, int64_unpack = _make_packer('>q')
int32_pack, int32_unpack = _make_packer('>i')
int8_pack, int8_unpack = _make_packer('>b')
uint64_pack, uint64_unpack = _make_packer('>Q')
uint8_pack, uint8_unpack = _make_packer('>B')
float_pack, float_unpack = _make_packer('>f')
double_pack, double_unpack = _make_packer('>d')
class GraphBinaryTypeType(type):
def __new__(mcs, name, bases, dct):
cls = super(GraphBinaryTypeType, mcs).__new__(mcs, name, bases, dct)
if not name.startswith('_'):
if cls.python_type:
_serializers[cls.python_type] = cls
if cls.graphbinary_type:
_deserializers[cls.graphbinary_type] = cls
return cls
class GraphBinaryWriter(object):
def __init__(self, serializer_map=None):
self.serializers = _serializers.copy()
if serializer_map:
self.serializers.update(serializer_map)
def writeObject(self, objectData):
return self.toDict(objectData)
def toDict(self, obj, to_extend=None):
if to_extend is None:
to_extend = bytearray()
try:
t = type(obj)
# coerce unicode to str so the serializer will be found properly in the cache...better way?
if not six.PY3:
t = str if isinstance(obj, unicode) else t
return self.serializers[t].dictify(obj, self, to_extend)
except KeyError:
for key, serializer in self.serializers.items():
if isinstance(obj, key):
return serializer.dictify(obj, self, to_extend)
if isinstance(obj, dict):
return dict((self.toDict(k, to_extend), self.toDict(v, to_extend)) for k, v in obj.items())
elif isinstance(obj, set):
return set([self.toDict(o, to_extend) for o in obj])
elif isinstance(obj, list):
return [self.toDict(o, to_extend) for o in obj]
else:
return obj
class GraphBinaryReader(object):
def __init__(self, deserializer_map=None):
self.deserializers = _deserializers.copy()
if deserializer_map:
self.deserializers.update(deserializer_map)
def readObject(self, b):
if isinstance(b, bytearray):
return self.toObject(io.BytesIO(b))
elif isinstance(b, io.BufferedIOBase):
return self.toObject(b)
def toObject(self, buff, data_type=None, nullable=True):
if data_type is None:
bt = uint8_unpack(buff.read(1))
if bt == DataType.null.value:
if nullable:
buff.read(1)
return None
return self.deserializers[DataType(bt)].objectify(buff, self, nullable)
else:
return self.deserializers[data_type].objectify(buff, self, nullable)
@six.add_metaclass(GraphBinaryTypeType)
class _GraphBinaryTypeIO(object):
python_type = None
graphbinary_type = None
symbolMap = {"global_": "global", "as_": "as", "in_": "in", "and_": "and",
"or_": "or", "is_": "is", "not_": "not", "from_": "from",
"set_": "set", "list_": "list", "all_": "all", "with_": "with",
"filter_": "filter", "id_": "id", "max_": "max", "min_": "min", "sum_": "sum"}
@classmethod
def prefix_bytes(cls, graphbin_type, as_value=False, nullable=True, to_extend=None):
if to_extend is None:
to_extend = bytearray()
if not as_value:
to_extend += uint8_pack(graphbin_type.value)
if nullable:
to_extend += int8_pack(0)
return to_extend
@classmethod
def read_int(cls, buff):
return int32_unpack(buff.read(4))
@classmethod
def unmangle_keyword(cls, symbol):
return cls.symbolMap.get(symbol, symbol)
@classmethod
def is_null(cls, buff, reader, else_opt, nullable=True):
return None if nullable and buff.read(1)[0] == 0x01 else else_opt(buff, reader)
def dictify(self, obj, writer, to_extend, as_value=False, nullable=True):
raise NotImplementedError()
def objectify(self, d, reader, nullable=True):
raise NotImplementedError()
class LongIO(_GraphBinaryTypeIO):
python_type = LongType
graphbinary_type = DataType.long
byte_format_pack = int64_pack
byte_format_unpack = int64_unpack
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
if obj < -9223372036854775808 or obj > 9223372036854775807:
raise Exception("TODO: don't forget bigint")
else:
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(cls.byte_format_pack(obj))
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, lambda b, r: int64_unpack(buff.read(8)), nullable)
class IntIO(LongIO):
python_type = IntType
graphbinary_type = DataType.int
byte_format_pack = int32_pack
byte_format_unpack = int32_unpack
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, lambda b, r: cls.read_int(b), nullable)
class DateIO(_GraphBinaryTypeIO):
python_type = datetime.datetime
graphbinary_type = DataType.date
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
try:
timestamp_seconds = calendar.timegm(obj.utctimetuple())
pts = timestamp_seconds * 1e3 + getattr(obj, 'microsecond', 0) / 1e3
except AttributeError:
pts = calendar.timegm(obj.timetuple()) * 1e3
ts = int(round(pts))
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(int64_pack(ts))
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader,
lambda b, r: datetime.datetime.utcfromtimestamp(int64_unpack(b.read(8)) / 1000.0),
nullable)
# Based on current implementation, this class must always be declared before FloatIO.
# Seems pretty fragile for future maintainers. Maybe look into this.
class TimestampIO(_GraphBinaryTypeIO):
python_type = statics.timestamp
graphbinary_type = DataType.timestamp
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
# Java timestamp expects milliseconds integer - Have to use int because of legacy Python
ts = int(round(obj * 1000))
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(int64_pack(ts))
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
# Python timestamp expects seconds
return cls.is_null(buff, reader, lambda b, r: statics.timestamp(int64_unpack(b.read(8)) / 1000.0),
nullable)
def _long_bits_to_double(bits):
return unpack('d', pack('Q', bits))[0]
NAN = _long_bits_to_double(0x7ff8000000000000)
POSITIVE_INFINITY = _long_bits_to_double(0x7ff0000000000000)
NEGATIVE_INFINITY = _long_bits_to_double(0xFff0000000000000)
class FloatIO(LongIO):
python_type = FloatType
graphbinary_type = DataType.float
graphbinary_base_type = DataType.float
byte_format_pack = float_pack
byte_format_unpack = float_unpack
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
if math.isnan(obj):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(cls.byte_format_pack(NAN))
elif math.isinf(obj) and obj > 0:
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(cls.byte_format_pack(POSITIVE_INFINITY))
elif math.isinf(obj) and obj < 0:
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(cls.byte_format_pack(NEGATIVE_INFINITY))
else:
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(cls.byte_format_pack(obj))
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, lambda b, r: float_unpack(b.read(4)), nullable)
class DoubleIO(FloatIO):
"""
Floats basically just fall through to double serialization.
"""
graphbinary_type = DataType.double
graphbinary_base_type = DataType.double
byte_format_pack = double_pack
byte_format_unpack = double_unpack
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, lambda b, r: double_unpack(b.read(8)), nullable)
class CharIO(_GraphBinaryTypeIO):
python_type = SingleChar
graphbinary_type = DataType.char
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(obj.encode("utf-8"))
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_char, nullable)
@classmethod
def _read_char(cls, b, r):
max_bytes = 4
x = b.read(1)
while max_bytes > 0:
max_bytes = max_bytes - 1
try:
return x.decode("utf-8")
except UnicodeDecodeError:
x += b.read(1)
class StringIO(_GraphBinaryTypeIO):
python_type = str
graphbinary_type = DataType.string
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
str_bytes = obj.encode("utf-8")
to_extend += int32_pack(len(str_bytes))
to_extend += str_bytes
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, lambda b, r: b.read(cls.read_int(b)).decode("utf-8"), nullable)
class ListIO(_GraphBinaryTypeIO):
python_type = list
graphbinary_type = DataType.list
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(int32_pack(len(obj)))
for item in obj:
writer.toDict(item, to_extend)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_list, nullable)
@classmethod
def _read_list(cls, b, r):
size = cls.read_int(b)
the_list = []
while size > 0:
the_list.append(r.readObject(b))
size = size - 1
return the_list
class SetDeserializer(ListIO):
python_type = SetType
graphbinary_type = DataType.set
@classmethod
def objectify(cls, buff, reader, nullable=True):
return set(ListIO.objectify(buff, reader, nullable))
class MapIO(_GraphBinaryTypeIO):
python_type = DictType
graphbinary_type = DataType.map
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(int32_pack(len(obj)))
for k, v in obj.items():
writer.toDict(k, to_extend)
writer.toDict(v, to_extend)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_map, nullable)
@classmethod
def _read_map(cls, b, r):
size = cls.read_int(b)
the_dict = {}
while size > 0:
k = r.readObject(b)
v = r.readObject(b)
the_dict[k] = v
size = size - 1
return the_dict
class UuidIO(_GraphBinaryTypeIO):
python_type = uuid.UUID
graphbinary_type = DataType.uuid
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(obj.bytes)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, lambda b, r: uuid.UUID(bytes=b.read(16)), nullable)
class EdgeIO(_GraphBinaryTypeIO):
python_type = Edge
graphbinary_type = DataType.edge
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
writer.toDict(obj.id, to_extend)
StringIO.dictify(obj.label, writer, to_extend, True, False)
writer.toDict(obj.inV.id, to_extend)
StringIO.dictify(obj.inV.label, writer, to_extend, True, False)
writer.toDict(obj.outV.id, to_extend)
StringIO.dictify(obj.outV.label, writer, to_extend, True, False)
to_extend.extend(NULL_BYTES)
to_extend.extend(NULL_BYTES)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_edge, nullable)
@classmethod
def _read_edge(cls, b, r):
edgeid = r.readObject(b)
edgelbl = r.toObject(b, DataType.string, False)
inv = Vertex(r.readObject(b), r.toObject(b, DataType.string, False))
outv = Vertex(r.readObject(b), r.toObject(b, DataType.string, False))
edge = Edge(edgeid, outv, edgelbl, inv)
b.read(4)
return edge
class PathIO(_GraphBinaryTypeIO):
python_type = Path
graphbinary_type = DataType.path
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
writer.toDict(obj.labels, to_extend)
writer.toDict(obj.objects, to_extend)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, lambda b, r: Path(r.readObject(b), r.readObject(b)), nullable)
class PropertyIO(_GraphBinaryTypeIO):
python_type = Property
graphbinary_type = DataType.property
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
StringIO.dictify(obj.key, writer, to_extend, True, False)
writer.toDict(obj.value, to_extend)
to_extend.extend(NULL_BYTES)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_property, nullable)
@classmethod
def _read_property(cls, b, r):
p = Property(r.toObject(b, DataType.string, False), r.readObject(b), None)
b.read(2)
return p
class TinkerGraphIO(_GraphBinaryTypeIO):
python_type = Graph
graphbinary_type = DataType.graph
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
raise AttributeError("TinkerGraph serialization is not currently supported by gremlin-python")
@classmethod
def objectify(cls, b, reader, as_value=False):
raise AttributeError("TinkerGraph deserialization is not currently supported by gremlin-python")
class VertexIO(_GraphBinaryTypeIO):
python_type = Vertex
graphbinary_type = DataType.vertex
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
writer.toDict(obj.id, to_extend)
StringIO.dictify(obj.label, writer, to_extend, True, False)
to_extend.extend(NULL_BYTES)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_vertex, nullable)
@classmethod
def _read_vertex(cls, b, r):
vertex = Vertex(r.readObject(b), r.toObject(b, DataType.string, False))
b.read(2)
return vertex
class VertexPropertyIO(_GraphBinaryTypeIO):
python_type = VertexProperty
graphbinary_type = DataType.vertexproperty
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
writer.toDict(obj.id, to_extend)
StringIO.dictify(obj.label, writer, to_extend, True, False)
writer.toDict(obj.value, to_extend)
to_extend.extend(NULL_BYTES)
to_extend.extend(NULL_BYTES)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_vertexproperty, nullable)
@classmethod
def _read_vertexproperty(cls, b, r):
vp = VertexProperty(r.readObject(b), r.toObject(b, DataType.string, False), r.readObject(b), None)
b.read(4)
return vp
class _EnumIO(_GraphBinaryTypeIO):
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
StringIO.dictify(cls.unmangle_keyword(str(obj.name)), writer, to_extend)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_enumval, nullable)
@classmethod
def _read_enumval(cls, b, r):
enum_name = r.toObject(b)
return cls.python_type[enum_name]
class BarrierIO(_EnumIO):
graphbinary_type = DataType.barrier
python_type = Barrier
class CardinalityIO(_EnumIO):
graphbinary_type = DataType.cardinality
python_type = Cardinality
class ColumnIO(_EnumIO):
graphbinary_type = DataType.column
python_type = Column
class DirectionIO(_EnumIO):
graphbinary_type = DataType.direction
python_type = Direction
class OperatorIO(_EnumIO):
graphbinary_type = DataType.operator
python_type = Operator
class OrderIO(_EnumIO):
graphbinary_type = DataType.order
python_type = Order
class PickIO(_EnumIO):
graphbinary_type = DataType.pick
python_type = Pick
class PopIO(_EnumIO):
graphbinary_type = DataType.pop
python_type = Pop
class BindingIO(_GraphBinaryTypeIO):
python_type = Binding
graphbinary_type = DataType.binding
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
StringIO.dictify(obj.key, writer, to_extend, True, False)
writer.toDict(obj.value, to_extend)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, lambda b, r: Binding(r.toObject(b, DataType.string, False),
reader.readObject(b)), nullable)
class BytecodeIO(_GraphBinaryTypeIO):
python_type = Bytecode
graphbinary_type = DataType.bytecode
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
bc = obj.bytecode if isinstance(obj, Traversal) else obj
to_extend.extend(int32_pack(len(bc.step_instructions)))
for inst in bc.step_instructions:
inst_name, inst_args = inst[0], inst[1:] if len(inst) > 1 else []
StringIO.dictify(inst_name, writer, to_extend, True, False)
to_extend.extend(int32_pack(len(inst_args)))
for arg in inst_args:
writer.toDict(arg, to_extend)
to_extend.extend(int32_pack(len(bc.source_instructions)))
for inst in bc.source_instructions:
inst_name, inst_args = inst[0], inst[1:] if len(inst) > 1 else []
StringIO.dictify(inst_name, writer, to_extend, True, False)
to_extend.extend(int32_pack(len(inst_args)))
for arg in inst_args:
if isinstance(arg, TypeType):
writer.toDict(GremlinType(arg().fqcn), to_extend)
else:
writer.toDict(arg, to_extend)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_bytecode, nullable)
@classmethod
def _read_bytecode(cls, b, r):
bytecode = Bytecode()
step_count = cls.read_int(b)
ix = 0
while ix < step_count:
inst = [r.toObject(b, DataType.string, False)]
inst_ct = cls.read_int(b)
iy = 0
while iy < inst_ct:
inst.append(r.readObject(b))
iy += 1
bytecode.step_instructions.append(inst)
ix += 1
source_count = cls.read_int(b)
ix = 0
while ix < source_count:
inst = [r.toObject(b, DataType.string, False)]
inst_ct = cls.read_int(b)
iy = 0
while iy < inst_ct:
inst.append(r.readObject(b))
iy += 1
bytecode.source_instructions.append(inst)
ix += 1
return bytecode
class TraversalIO(BytecodeIO):
python_type = GraphTraversal
class LambdaSerializer(_GraphBinaryTypeIO):
python_type = FunctionType
graphbinary_type = DataType.lambda_
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
lambda_result = obj()
script = lambda_result if isinstance(lambda_result, str) else lambda_result[0]
language = statics.default_lambda_language if isinstance(lambda_result, str) else lambda_result[1]
StringIO.dictify(language, writer, to_extend, True, False)
script_cleaned = script
script_args = -1
if language == "gremlin-jython" or language == "gremlin-python":
if not script.strip().startswith("lambda"):
script_cleaned = "lambda " + script
script_args = six.get_function_code(eval(script_cleaned)).co_argcount
elif language == "gremlin-groovy" and "->" in script:
# if the user has explicitly added parameters to the groovy closure then we can easily detect one or two
# arg lambdas - if we can't detect 1 or 2 then we just go with "unknown"
args = script[0:script.find("->")]
script_args = 2 if "," in args else 1
StringIO.dictify(script_cleaned, writer, to_extend, True, False)
to_extend.extend(int32_pack(script_args))
return to_extend
class PSerializer(_GraphBinaryTypeIO):
graphbinary_type = DataType.p
python_type = P
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
StringIO.dictify(obj.operator, writer, to_extend, True, False)
args = []
if obj.other is None:
if isinstance(obj.value, ListType):
args = obj.value
else:
args.append(obj.value)
else:
args.append(obj.value)
args.append(obj.other)
to_extend.extend(int32_pack(len(args)))
for a in args:
writer.toDict(a, to_extend)
return to_extend
class ScopeIO(_EnumIO):
graphbinary_type = DataType.scope
python_type = Scope
class TIO(_EnumIO):
graphbinary_type = DataType.t
python_type = T
class TraverserIO(_GraphBinaryTypeIO):
graphbinary_type = DataType.traverser
python_type = Traverser
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(int64_pack(obj.bulk))
writer.toDict(obj.object, to_extend)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_traverser, nullable)
@classmethod
def _read_traverser(cls, b, r):
bulk = int64_unpack(b.read(8))
obj = r.readObject(b)
return Traverser(obj, bulk=bulk)
class ByteIO(_GraphBinaryTypeIO):
python_type = SingleByte
graphbinary_type = DataType.byte
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(int8_pack(obj))
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader,
lambda b, r: int.__new__(SingleByte, int8_unpack(b.read(1))),
nullable)
class ByteBufferIO(_GraphBinaryTypeIO):
python_type = ByteBufferType
graphbinary_type = DataType.bytebuffer
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(int32_pack(len(obj)))
to_extend.extend(obj)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_bytebuffer, nullable)
@classmethod
def _read_bytebuffer(cls, b, r):
size = cls.read_int(b)
return ByteBufferType(b.read(size))
class BooleanIO(_GraphBinaryTypeIO):
python_type = bool
graphbinary_type = DataType.boolean
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
to_extend.extend(int8_pack(0x01 if obj else 0x00))
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader,
lambda b, r: True if int8_unpack(b.read(1)) == 0x01 else False,
nullable)
class TextPSerializer(_GraphBinaryTypeIO):
graphbinary_type = DataType.textp
python_type = TextP
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
StringIO.dictify(obj.operator, writer, to_extend, True, False)
args = []
if obj.other is None:
if isinstance(obj.value, ListType):
args = obj.value
else:
args.append(obj.value)
else:
args.append(obj.value)
args.append(obj.other)
to_extend.extend(int32_pack(len(args)))
for a in args:
writer.toDict(a, to_extend)
return to_extend
class BulkSetDeserializer(_GraphBinaryTypeIO):
graphbinary_type = DataType.bulkset
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_bulkset, nullable)
@classmethod
def _read_bulkset(cls, b, r):
size = cls.read_int(b)
the_list = []
while size > 0:
itm = r.readObject(b)
bulk = int64_unpack(b.read(8))
for y in range(bulk):
the_list.append(itm)
size = size - 1
return the_list
class MetricsDeserializer(_GraphBinaryTypeIO):
graphbinary_type = DataType.metrics
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_metrics, nullable)
@classmethod
def _read_metrics(cls, b, r):
metricid = r.toObject(b, DataType.string, False)
name = r.toObject(b, DataType.string, False)
duration = r.toObject(b, DataType.long, nullable=False)
counts = r.toObject(b, DataType.map, nullable=False)
annotations = r.toObject(b, DataType.map, nullable=False)
metrics = r.toObject(b, DataType.list, nullable=False)
return {"id": metricid,
"name": name,
"dur": duration,
"counts": counts,
"annotations": annotations,
"metrics": metrics}
class TraversalMetricsDeserializer(_GraphBinaryTypeIO):
graphbinary_type = DataType.traversalmetrics
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_traversalmetrics, nullable)
@classmethod
def _read_traversalmetrics(cls, b, r):
duration = r.toObject(b, DataType.long, nullable=False)
metrics = r.toObject(b, DataType.list, nullable=False)
return {"dur": duration,
"metrics": metrics}
class ClassSerializer(_GraphBinaryTypeIO):
graphbinary_type = DataType.clazz
python_type = GremlinType
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
StringIO.dictify(obj.gremlin_type, writer, to_extend, True, False)
return to_extend
class TraversalStrategySerializer(_GraphBinaryTypeIO):
graphbinary_type = DataType.traversalstrategy
python_type = TraversalStrategy
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
ClassSerializer.dictify(GremlinType(obj.fqcn), writer, to_extend, True, False)
conf = {k: cls._convert(v) for k, v in obj.configuration.items()}
MapIO.dictify(conf, writer, to_extend, True, False)
return to_extend
@classmethod
def _convert(cls, v):
return v.bytecode if isinstance(v, Traversal) else v
class DurationIO(_GraphBinaryTypeIO):
python_type = timedelta
graphbinary_type = DataType.duration
@classmethod
def dictify(cls, obj, writer, to_extend, as_value=False, nullable=True):
cls.prefix_bytes(cls.graphbinary_type, as_value, nullable, to_extend)
LongIO.dictify(obj.seconds, writer, to_extend, True, False)
IntIO.dictify(obj.microseconds * 1000, writer, to_extend, True, False)
return to_extend
@classmethod
def objectify(cls, buff, reader, nullable=True):
return cls.is_null(buff, reader, cls._read_duration, nullable)
@classmethod
def _read_duration(cls, b, r):
seconds = r.toObject(b, DataType.long, False)
nanos = r.toObject(b, DataType.int, False)
return timedelta(seconds=seconds, microseconds=nanos / 1000)