This is an automated email from the ASF dual-hosted git repository. spmallette pushed a commit to branch TINKERPOP-2279 in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 45afe8d281ce15a841519007eca949e6742e0fb9 Author: Stephen Mallette <[email protected]> AuthorDate: Mon Jul 22 09:35:05 2019 -0400 Initial setup for GraphBinary in Python --- .../gremlin_python/structure/io/graphbinaryV1.py | 151 +++++++++++++++++++++ .../tests/structure/io/test_graphbinaryV1.py | 49 +++++++ 2 files changed, 200 insertions(+) diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphbinaryV1.py b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphbinaryV1.py new file mode 100644 index 0000000..4eff156 --- /dev/null +++ b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphbinaryV1.py @@ -0,0 +1,151 @@ +""" +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 datetime +import struct +import time +import uuid +import math +import base64 +import numbers +from collections import OrderedDict +from decimal import * +import logging +from datetime import timedelta + +import six +from aenum import Enum +from isodate import parse_duration, duration_isoformat + +from gremlin_python import statics +from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, DictType, ListType, SetType, SingleByte, ByteBufferType, SingleChar +from gremlin_python.process.traversal import Binding, Bytecode, P, TextP, Traversal, Traverser, TraversalStrategy, T +from gremlin_python.structure.graph import 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): + string = 0x03 + + +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): + try: + return self.serializers[type(obj)].dictify(obj, self) + except KeyError: + for key, serializer in self.serializers.items(): + if isinstance(obj, key): + return serializer.dictify(obj, self) + + if isinstance(obj, dict): + return dict((self.toDict(k), self.toDict(v)) for k, v in obj.items()) + elif isinstance(obj, set): + return set([self.toDict(o) for o in obj]) + elif isinstance(obj, list): + return [self.toDict(o) 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): + return self.toObject(b) + + def toObject(self, obj): + binary_type, rest = DataType(obj[0]), obj[1:] + return self.deserializers[binary_type].objectify(rest, self) + + [email protected]_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"} + + @classmethod + def as_bytes(cls, graphbin_type, *args): + ba = bytearray([graphbin_type.value]) + for arg in args: + if isinstance(arg, str): + ba.extend(arg.encode("utf-8")) + elif isinstance(arg, numbers.Number): + ba.extend(bytes([arg])) + elif isinstance(arg, (bytes, bytearray)): + ba.extend(arg) + return ba + + @classmethod + def unmangleKeyword(cls, symbol): + return cls.symbolMap.get(symbol, symbol) + + def dictify(self, obj, writer): + raise NotImplementedError() + + def objectify(self, d, reader): + raise NotImplementedError() + + +class StringIO(_GraphBinaryTypeIO): + + python_type = str + graphbinary_type = DataType.string + + @classmethod + def dictify(cls, n, writer): + return cls.as_bytes(cls.graphbinary_type, len(n), n) + + @classmethod + def objectify(cls, b, reader): + len_block, rest = b[0:4], b[4:] + size = struct.unpack("<L", len_block)[0] + string_block, b = rest[0:size], rest[size:] + return string_block diff --git a/gremlin-python/src/main/jython/tests/structure/io/test_graphbinaryV1.py b/gremlin-python/src/main/jython/tests/structure/io/test_graphbinaryV1.py new file mode 100644 index 0000000..9eb82cf --- /dev/null +++ b/gremlin-python/src/main/jython/tests/structure/io/test_graphbinaryV1.py @@ -0,0 +1,49 @@ +""" +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 datetime +import time +import uuid +import math +from decimal import * + +from mock import Mock + +import six + +from gremlin_python.statics import * +from gremlin_python.structure.graph import Vertex, Edge, Property, VertexProperty, Graph, Path +from gremlin_python.structure.io.graphbinaryV1 import GraphBinaryWriter, GraphBinaryReader, DataType +from gremlin_python.process.traversal import P +from gremlin_python.process.strategies import SubgraphStrategy +from gremlin_python.process.graph_traversal import __ + + +class TestGraphBinaryReader(object): + graphbinary_reader = GraphBinaryReader() + + +class TestGraphSONWriter(object): + graphbinary_writer = GraphBinaryWriter() + graphbinary_reader = GraphBinaryReader() + + def test_string(self): + x = "serialize this!" + output = self.graphbinary_reader.readObject(self.graphbinary_writer.writeObject(x)) + assert x == output
