You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by rd...@apache.org on 2018/10/05 11:38:01 UTC
[39/48] tinkerpop git commit: Merge branch 'tp32' into tp33
Merge branch 'tp32' into tp33
Conflicts:
gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperEmbeddedTypeTest.java
gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/28bf3046
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/28bf3046
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/28bf3046
Branch: refs/heads/TINKERPOP-2037
Commit: 28bf30468cca9bbd5c95b3814619801348cfad96
Parents: 650d1e8 80fa89b
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Oct 4 14:10:54 2018 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Oct 4 14:10:54 2018 -0400
----------------------------------------------------------------------
CHANGELOG.asciidoc | 1 +
docs/src/dev/io/graphson.asciidoc | 2 +
.../io/graphson/GraphSONSerializersV2d0.java | 19 ++++++--
.../GraphSONMapperEmbeddedTypeTest.java | 14 ++++++
.../IO/GraphSON/GraphSONReaderTests.cs | 49 +++++++++++++++++---
.../IO/GraphSON/GraphSONWriterTests.cs | 32 ++++++++++++-
.../lib/structure/io/type-serializers.js | 30 +++++++++++-
.../test/unit/graphson-test.js | 39 ++++++++++++++++
.../gremlin_python/structure/io/graphsonV2d0.py | 26 +++++++++++
.../tests/structure/io/test_graphsonV2d0.py | 25 ++++++++++
10 files changed, 224 insertions(+), 13 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/28bf3046/CHANGELOG.asciidoc
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/28bf3046/docs/src/dev/io/graphson.asciidoc
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/28bf3046/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2d0.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/28bf3046/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperEmbeddedTypeTest.java
----------------------------------------------------------------------
diff --cc gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperEmbeddedTypeTest.java
index a375e3b,e5f2693..c9400cd
--- a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperEmbeddedTypeTest.java
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONMapperEmbeddedTypeTest.java
@@@ -44,16 -44,8 +44,17 @@@ import java.time.ZoneOffset
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import static org.hamcrest.CoreMatchers.any;
+import static org.hamcrest.Matchers.either;
++import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.StringStartsWith.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeThat;
@@@ -85,58 -74,21 +86,71 @@@ public class GraphSONMapperEmbeddedType
public String version;
@Test
+ public void shouldHandleNumberConstants() throws Exception {
- assumeThat(version, startsWith("v2"));
++ assumeThat(version, not(startsWith("v1")));
+
+ final List<Object> o = new ArrayList<>();
+ o.add(123.321d);
+ o.add(Double.NaN);
+ o.add(Double.NEGATIVE_INFINITY);
+ o.add(Double.POSITIVE_INFINITY);
+
+ assertEquals(o, serializeDeserialize(mapper, o, List.class));
+ }
+
+ @Test
+ public void shouldHandleMap() throws Exception {
+ assumeThat(version, startsWith("v3"));
+
+ final Map<Object,Object> o = new LinkedHashMap<>();
+ o.put("string key", "string value");
+ o.put(1, 1);
+ o.put(1L, 1L);
+
+ final List<Object> l = Arrays.asList("test", 1, 5L);
+ o.put(l, "crazy");
+
+ assertEquals(o, serializeDeserialize(mapper, o, Map.class));
+ }
+
+ @Test
+ public void shouldHandleList() throws Exception {
+ assumeThat(version, startsWith("v3"));
+
+ final List<Object> o = new ArrayList<>();
+ o.add("test");
+ o.add(1);
+ o.add(1);
+ o.add(1L);
+ o.add(1L);
+
+ final List<Object> l = Arrays.asList("test", 1, 5L);
+ o.add(l);
+
+ assertEquals(o, serializeDeserialize(mapper, o, List.class));
+ }
+
+ @Test
+ public void shouldHandleSet() throws Exception {
+ assumeThat(version, startsWith("v3"));
+
+ final Set<Object> o = new LinkedHashSet<>();
+ o.add("test");
+ o.add(1);
+ o.add(1);
+ o.add(1L);
+ o.add(1L);
+
+ final List<Object> l = Arrays.asList("test", 1, 5L);
+ o.add(l);
+
+ assertEquals(o, serializeDeserialize(mapper, o, Set.class));
+
+ }
+
+ @Test
public void shouldHandleBiFunctionLambda() throws Exception {
- assumeThat(version, startsWith("v2"));
+ assumeThat(version, either(startsWith("v2")).or(startsWith("v3")));
final Lambda o = (Lambda) Lambda.biFunction("x,y -> 'test'");
assertEquals(o, serializeDeserialize(mapper, o, Lambda.class));
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/28bf3046/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
----------------------------------------------------------------------
diff --cc gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
index 00cf853,08a91ae..15e5b05
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONReaderTests.cs
@@@ -35,30 -34,9 +34,30 @@@ namespace Gremlin.Net.UnitTest.Structur
{
public class GraphSONReaderTests
{
- private GraphSONReader CreateStandardGraphSONReader()
+ /// <summary>
+ /// Parameters for each test supporting multiple versions of GraphSON
+ /// </summary>
+ public static IEnumerable<object[]> Versions => new []
{
- return new GraphSONReader();
+ new object[] { 2 },
+ new object[] { 3 }
+ };
-
++
+ /// <summary>
+ /// Parameters for each collections test supporting multiple versions of GraphSON
+ /// </summary>
+ public static IEnumerable<object[]> VersionsSupportingCollections => new []
+ {
+ new object[] { 3 }
+ };
-
++
+ private GraphSONReader CreateStandardGraphSONReader(int version)
+ {
+ if (version == 3)
+ {
+ return new GraphSON3Reader();
+ }
+ return new GraphSON2Reader();
}
//During CI, we encountered a case where Newtonsoft.Json version 9.0.0
@@@ -197,11 -175,47 +196,47 @@@
Assert.Equal(31.2, deserializedValue);
}
- [Fact]
- public void ShouldDeserializeNaN()
+ [Theory, MemberData(nameof(Versions))]
++ public void ShouldDeserializeNaN(int version)
+ {
+ var serializedValue = "{\"@type\":\"g:Double\",\"@value\":'NaN'}";
+ var reader = CreateStandardGraphSONReader();
+
+ var jObject = JObject.Parse(serializedValue);
+ var deserializedValue = reader.ToObject(jObject);
+
+ Assert.Equal(Double.NaN, deserializedValue);
+ }
+
- [Fact]
- public void ShouldDeserializePositiveInfinity()
++ [Theory, MemberData(nameof(Versions))]
++ public void ShouldDeserializePositiveInfinity(int version)
+ {
+ var serializedValue = "{\"@type\":\"g:Double\",\"@value\":'Infinity'}";
+ var reader = CreateStandardGraphSONReader();
+
+ var jObject = JObject.Parse(serializedValue);
+ var deserializedValue = reader.ToObject(jObject);
+
+ Assert.Equal(Double.PositiveInfinity, deserializedValue);
+ }
+
- [Fact]
- public void ShouldDeserializeNegativeInfinity()
++ [Theory, MemberData(nameof(Versions))]
++ public void ShouldDeserializeNegativeInfinity(int version)
+ {
+ var serializedValue = "{\"@type\":\"g:Double\",\"@value\":'-Infinity'}";
+ var reader = CreateStandardGraphSONReader();
+
+ var jObject = JObject.Parse(serializedValue);
+ var deserializedValue = reader.ToObject(jObject);
+
+ Assert.Equal(Double.NegativeInfinity, deserializedValue);
+ }
+
- [Fact]
- public void ShouldDeserializeDecimal()
++ [Theory, MemberData(nameof(Versions))]
+ public void ShouldDeserializeDecimal(int version)
{
var serializedValue = "{\"@type\":\"gx:BigDecimal\",\"@value\":-8.201}";
- var reader = CreateStandardGraphSONReader();
+ var reader = CreateStandardGraphSONReader(version);
var jObject = JObject.Parse(serializedValue);
decimal deserializedValue = reader.ToObject(jObject);
@@@ -220,12 -234,12 +255,12 @@@
Assert.Equal(7.5M, deserializedValue);
}
-
+
- [Fact]
- public void ShouldDeserializeList()
+ [Theory, MemberData(nameof(Versions))]
+ public void ShouldDeserializeList(int version)
{
var serializedValue = "[{\"@type\":\"g:Int32\",\"@value\":5},{\"@type\":\"g:Int32\",\"@value\":6}]";
- var reader = CreateStandardGraphSONReader();
+ var reader = CreateStandardGraphSONReader(version);
var jObject = JArray.Parse(serializedValue);
var deserializedValue = reader.ToObject(jObject);
@@@ -373,53 -360,6 +408,53 @@@
Assert.Equal(typeof(int), readVertex.Id.GetType());
}
+ [Theory, MemberData(nameof(VersionsSupportingCollections))]
+ public void ShouldDeserializeEmptyGList(int version)
+ {
+ var graphSon =
+ "{\"@type\":\"g:List\", \"@value\": []}";
+ var reader = CreateStandardGraphSONReader(version);
+
+ var deserializedValue = reader.ToObject(JObject.Parse(graphSon));
+ Assert.Equal(new object[0], deserializedValue);
+ }
+
+ [Theory, MemberData(nameof(VersionsSupportingCollections))]
+ public void ShouldDeserializeGList(int version)
+ {
+ const string json = "{\"@type\":\"g:List\", \"@value\": [{\"@type\": \"g:Int32\", \"@value\": 1}," +
+ "{\"@type\": \"g:Int32\", \"@value\": 2}, {\"@type\": \"g:Int32\", \"@value\": 3}]}";
+ var reader = CreateStandardGraphSONReader(version);
+
+ var deserializedValue = reader.ToObject(JObject.Parse(json));
-
++
+ Assert.Equal((IList<object>)new object[] { 1, 2, 3}, deserializedValue);
+ }
+
+ [Theory, MemberData(nameof(VersionsSupportingCollections))]
+ public void ShouldDeserializeGSet(int version)
+ {
+ const string json = "{\"@type\":\"g:Set\", \"@value\": [{\"@type\": \"g:Int32\", \"@value\": 1}," +
+ "{\"@type\": \"g:Int32\", \"@value\": 2}, {\"@type\": \"g:Int32\", \"@value\": 3}]}";
+ var reader = CreateStandardGraphSONReader(version);
+
+ var deserializedValue = reader.ToObject(JObject.Parse(json));
-
++
+ Assert.Equal((ISet<object>)new HashSet<object>{ 1, 2, 3}, deserializedValue);
+ }
+
+ [Theory, MemberData(nameof(VersionsSupportingCollections))]
+ public void ShouldDeserializeGMap(int version)
+ {
+ const string json = "{\"@type\":\"g:Map\", \"@value\": [\"a\",{\"@type\": \"g:Int32\", \"@value\": 1}, " +
+ "\"b\", {\"@type\": \"g:Int32\", \"@value\": 2}]}";
+ var reader = CreateStandardGraphSONReader(version);
+
+ var deserializedValue = reader.ToObject(JObject.Parse(json));
-
++
+ Assert.Equal(new Dictionary<object, object>{ { "a", 1 }, { "b", 2 }}, deserializedValue);
+ }
+
[Fact]
public void ShouldDeserializeTraverser()
{
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/28bf3046/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
----------------------------------------------------------------------
diff --cc gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
index 2d30fa1,13fbddc..07f00a9
--- a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphSON/GraphSONWriterTests.cs
@@@ -35,36 -35,15 +35,36 @@@ namespace Gremlin.Net.UnitTest.Structur
{
public class GraphSONWriterTests
{
- private GraphSONWriter CreateStandardGraphSONWriter()
+ /// <summary>
+ /// Parameters for each test supporting multiple versions of GraphSON
+ /// </summary>
+ public static IEnumerable<object[]> Versions => new []
{
- return new GraphSONWriter();
+ new object[] { 2 },
+ new object[] { 3 }
+ };
-
++
+ /// <summary>
+ /// Parameters for each collections test supporting multiple versions of GraphSON
+ /// </summary>
+ public static IEnumerable<object[]> VersionsSupportingCollections => new []
+ {
+ new object[] { 3 }
+ };
+
+ private GraphSONWriter CreateGraphSONWriter(int version)
+ {
+ if (version == 3)
+ {
+ return new GraphSON3Writer();
+ }
+ return new GraphSON2Writer();
}
- [Fact]
- public void ShouldSerializeInt()
+ [Theory, MemberData(nameof(Versions))]
+ public void ShouldSerializeInt(int version)
{
- var writer = CreateStandardGraphSONWriter();
+ var writer = CreateGraphSONWriter(version);
var graphSon = writer.WriteObject(1);
@@@ -101,10 -80,40 +101,40 @@@
Assert.Equal("{\"@type\":\"g:Double\",\"@value\":3.2}", graphSon);
}
- [Fact]
- public void ShouldSerializeNaN()
+ [Theory, MemberData(nameof(Versions))]
++ public void ShouldSerializeNaN(int version)
+ {
- var writer = CreateStandardGraphSONWriter();
++ var writer = CreateGraphSONWriter(version);
+
+ var graphSon = writer.WriteObject(Double.NaN);
+
+ Assert.Equal("{\"@type\":\"g:Double\",\"@value\":\"NaN\"}", graphSon);
+ }
+
- [Fact]
- public void ShouldSerializePositiveInfinity()
++ [Theory, MemberData(nameof(Versions))]
++ public void ShouldSerializePositiveInfinity(int version)
+ {
- var writer = CreateStandardGraphSONWriter();
++ var writer = CreateGraphSONWriter(version);
+
+ var graphSon = writer.WriteObject(Double.PositiveInfinity);
+
+ Assert.Equal("{\"@type\":\"g:Double\",\"@value\":\"Infinity\"}", graphSon);
+ }
+
- [Fact]
- public void ShouldSerializeNegativeInfinity()
++ [Theory, MemberData(nameof(Versions))]
++ public void ShouldSerializeNegativeInfinity(int version)
+ {
- var writer = CreateStandardGraphSONWriter();
++ var writer = CreateGraphSONWriter();
+
+ var graphSon = writer.WriteObject(Double.NegativeInfinity);
+
+ Assert.Equal("{\"@type\":\"g:Double\",\"@value\":\"-Infinity\"}", graphSon);
+ }
+
- [Fact]
- public void ShouldSerializeDecimal()
++ [Theory, MemberData(nameof(Versions))]
+ public void ShouldSerializeDecimal(int version)
{
- var writer = CreateStandardGraphSONWriter();
+ var writer = CreateGraphSONWriter(version);
var graphSon = writer.WriteObject(6.5M);
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/28bf3046/gremlin-javascript/src/main/javascript/gremlin-javascript/lib/structure/io/type-serializers.js
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/28bf3046/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV2d0.py
----------------------------------------------------------------------
diff --cc gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV2d0.py
index d53a080,0000000..18598b7
mode 100644,000000..100644
--- a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV2d0.py
+++ b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphsonV2d0.py
@@@ -1,469 -1,0 +1,495 @@@
+'''
+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 json
+import time
+import uuid
++import math
+from collections import OrderedDict
+
+import six
+from aenum import Enum
+
+from gremlin_python import statics
+from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType
+from gremlin_python.process.traversal import Binding, Bytecode, P, Traversal, Traverser, TraversalStrategy
+from gremlin_python.structure.graph import Edge, Property, Vertex, VertexProperty, Path
+
+# 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 GraphSONTypeType(type):
+ def __new__(mcs, name, bases, dct):
+ cls = super(GraphSONTypeType, mcs).__new__(mcs, name, bases, dct)
+ if not name.startswith('_'):
+ if cls.python_type:
+ _serializers[cls.python_type] = cls
+ if cls.graphson_type:
+ _deserializers[cls.graphson_type] = cls
+ return cls
+
+
+class GraphSONUtil(object):
+ TYPE_KEY = "@type"
+ VALUE_KEY = "@value"
+
+ @classmethod
+ def typedValue(cls, type_name, value, prefix="g"):
+ out = {cls.TYPE_KEY: cls.formatType(prefix, type_name)}
+ if value is not None:
+ out[cls.VALUE_KEY] = value
+ return out
+
+ @classmethod
+ def formatType(cls, prefix, type_name):
+ return "%s:%s" % (prefix, type_name)
+
+
+# Read/Write classes split to follow precedence of the Java API
+class GraphSONWriter(object):
+ def __init__(self, serializer_map=None):
+ """
+ :param serializer_map: map from Python type to serializer instance implementing `dictify`
+ """
+ self.serializers = _serializers.copy()
+ if serializer_map:
+ self.serializers.update(serializer_map)
+
+ def writeObject(self, objectData):
+ # to JSON
+ return json.dumps(self.toDict(objectData), separators=(',', ':'))
+
+ def toDict(self, obj):
+ """
+ Encodes python objects in GraphSON type-tagged dict values
+ """
+ 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)
+
+ # list and map are treated as normal json objs (could be isolated serializers)
+ if isinstance(obj, (list, set)):
+ return [self.toDict(o) for o in obj]
+ elif isinstance(obj, dict):
+ return dict((self.toDict(k), self.toDict(v)) for k, v in obj.items())
+ else:
+ return obj
+
+
+class GraphSONReader(object):
+ def __init__(self, deserializer_map=None):
+ """
+ :param deserializer_map: map from GraphSON type tag to deserializer instance implementing `objectify`
+ """
+ self.deserializers = _deserializers.copy()
+ if deserializer_map:
+ self.deserializers.update(deserializer_map)
+
+ def readObject(self, jsonData):
+ # from JSON
+ return self.toObject(json.loads(jsonData))
+
+ def toObject(self, obj):
+ """
+ Unpacks GraphSON type-tagged dict values into objects mapped in self.deserializers
+ """
+ if isinstance(obj, dict):
+ try:
+ return self.deserializers[obj[GraphSONUtil.TYPE_KEY]].objectify(obj[GraphSONUtil.VALUE_KEY], self)
+ except KeyError:
+ pass
+ # list and map are treated as normal json objs (could be isolated deserializers)
+ return dict((self.toObject(k), self.toObject(v)) for k, v in obj.items())
+ elif isinstance(obj, list):
+ return [self.toObject(o) for o in obj]
+ else:
+ return obj
+
+
+@six.add_metaclass(GraphSONTypeType)
+class _GraphSONTypeIO(object):
+ python_type = None
+ graphson_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"}
+
+ @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 _BytecodeSerializer(_GraphSONTypeIO):
+ @classmethod
+ def _dictify_instructions(cls, instructions, writer):
+ out = []
+ for instruction in instructions:
+ inst = [instruction[0]]
+ inst.extend(writer.toDict(arg) for arg in instruction[1:])
+ out.append(inst)
+ return out
+
+ @classmethod
+ def dictify(cls, bytecode, writer):
+ if isinstance(bytecode, Traversal):
+ bytecode = bytecode.bytecode
+ out = {}
+ if bytecode.source_instructions:
+ out["source"] = cls._dictify_instructions(bytecode.source_instructions, writer)
+ if bytecode.step_instructions:
+ out["step"] = cls._dictify_instructions(bytecode.step_instructions, writer)
+ return GraphSONUtil.typedValue("Bytecode", out)
+
+class TraversalSerializer(_BytecodeSerializer):
+ python_type = Traversal
+
+
+class BytecodeSerializer(_BytecodeSerializer):
+ python_type = Bytecode
+
+
+class VertexSerializer(_GraphSONTypeIO):
+ python_type = Vertex
+ graphson_type = "g:Vertex"
+
+ @classmethod
+ def dictify(cls, vertex, writer):
+ return GraphSONUtil.typedValue("Vertex", {"id": writer.toDict(vertex.id),
+ "label": writer.toDict(vertex.label)})
+
+
+class EdgeSerializer(_GraphSONTypeIO):
+ python_type = Edge
+ graphson_type = "g:Edge"
+
+ @classmethod
+ def dictify(cls, edge, writer):
+ return GraphSONUtil.typedValue("Edge", {"id": writer.toDict(edge.id),
+ "outV": writer.toDict(edge.outV.id),
+ "outVLabel": writer.toDict(edge.outV.label),
+ "label": writer.toDict(edge.label),
+ "inV": writer.toDict(edge.inV.id),
+ "inVLabel": writer.toDict(edge.inV.label)})
+
+
+class VertexPropertySerializer(_GraphSONTypeIO):
+ python_type = VertexProperty
+ graphson_type = "g:VertexProperty"
+
+ @classmethod
+ def dictify(cls, vertex_property, writer):
+ return GraphSONUtil.typedValue("VertexProperty", {"id": writer.toDict(vertex_property.id),
+ "label": writer.toDict(vertex_property.label),
+ "value": writer.toDict(vertex_property.value),
+ "vertex": writer.toDict(vertex_property.vertex.id)})
+
+
+class PropertySerializer(_GraphSONTypeIO):
+ python_type = Property
+ graphson_type = "g:Property"
+
+ @classmethod
+ def dictify(cls, property, writer):
+ elementDict = writer.toDict(property.element)
+ if elementDict is not None:
+ valueDict = elementDict["@value"]
+ if "outVLabel" in valueDict:
+ del valueDict["outVLabel"]
+ if "inVLabel" in valueDict:
+ del valueDict["inVLabel"]
+ if "properties" in valueDict:
+ del valueDict["properties"]
+ if "value" in valueDict:
+ del valueDict["value"]
+ return GraphSONUtil.typedValue("Property", {"key": writer.toDict(property.key),
+ "value": writer.toDict(property.value),
+ "element": elementDict})
+
+
+class TraversalStrategySerializer(_GraphSONTypeIO):
+ python_type = TraversalStrategy
+
+ @classmethod
+ def dictify(cls, strategy, writer):
+ return GraphSONUtil.typedValue(strategy.strategy_name, writer.toDict(strategy.configuration))
+
+
+class TraverserIO(_GraphSONTypeIO):
+ python_type = Traverser
+ graphson_type = "g:Traverser"
+
+ @classmethod
+ def dictify(cls, traverser, writer):
+ return GraphSONUtil.typedValue("Traverser", {"value": writer.toDict(traverser.object),
+ "bulk": writer.toDict(traverser.bulk)})
+
+ @classmethod
+ def objectify(cls, d, reader):
+ return Traverser(reader.toObject(d["value"]),
+ reader.toObject(d["bulk"]))
+
+
+class EnumSerializer(_GraphSONTypeIO):
+ python_type = Enum
+
+ @classmethod
+ def dictify(cls, enum, _):
+ return GraphSONUtil.typedValue(cls.unmangleKeyword(type(enum).__name__),
+ cls.unmangleKeyword(str(enum.name)))
+
+
+class PSerializer(_GraphSONTypeIO):
+ python_type = P
+
+ @classmethod
+ def dictify(cls, p, writer):
+ out = {"predicate": p.operator,
+ "value": [writer.toDict(p.value), writer.toDict(p.other)] if p.other is not None else
+ writer.toDict(p.value)}
+ return GraphSONUtil.typedValue("P", out)
+
+
+class BindingSerializer(_GraphSONTypeIO):
+ python_type = Binding
+
+ @classmethod
+ def dictify(cls, binding, writer):
+ out = {"key": binding.key,
+ "value": writer.toDict(binding.value)}
+ return GraphSONUtil.typedValue("Binding", out)
+
+
+class LambdaSerializer(_GraphSONTypeIO):
+ python_type = FunctionType
+
+ @classmethod
+ def dictify(cls, lambda_object, writer):
+ lambda_result = lambda_object()
+ 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]
+ out = {"script": script,
+ "language": language}
+ if language == "gremlin-jython" or language == "gremlin-python":
+ if not script.strip().startswith("lambda"):
+ script = "lambda " + script
+ out["script"] = script
+ out["arguments"] = six.get_function_code(eval(out["script"])).co_argcount
+ else:
+ out["arguments"] = -1
+ return GraphSONUtil.typedValue("Lambda", out)
+
+
+class TypeSerializer(_GraphSONTypeIO):
+ python_type = TypeType
+
+ @classmethod
+ def dictify(cls, typ, writer):
+ return writer.toDict(typ())
+
+
+class UUIDIO(_GraphSONTypeIO):
+ python_type = uuid.UUID
+ graphson_type = "g:UUID"
+ graphson_base_type = "UUID"
+
+ @classmethod
+ def dictify(cls, obj, writer):
+ return GraphSONUtil.typedValue(cls.graphson_base_type, str(obj))
+
+ @classmethod
+ def objectify(cls, d, reader):
+ return cls.python_type(d)
+
+
+class DateIO(_GraphSONTypeIO):
+ python_type = datetime.datetime
+ graphson_type = "g:Date"
+ graphson_base_type = "Date"
+
+ @classmethod
+ def dictify(cls, obj, writer):
+ # Java timestamp expects miliseconds
+ if six.PY3:
+ pts = obj.timestamp()
+ else:
+ # Hack for legacy Python
+ # timestamp() in Python 3.3
+ pts = time.mktime((obj.year, obj.month, obj.day,
+ obj.hour, obj.minute, obj.second,
+ -1, -1, -1)) + obj.microsecond / 1e6
+
+ # Have to use int because of legacy Python
+ ts = int(round(pts * 1000))
+ return GraphSONUtil.typedValue(cls.graphson_base_type, ts)
+
+ @classmethod
+ def objectify(cls, ts, reader):
+ # Python timestamp expects seconds
+ return datetime.datetime.fromtimestamp(ts / 1000.0)
+
+
+# Based on current implementation, this class must always be declared before FloatIO.
+# Seems pretty fragile for future maintainers. Maybe look into this.
+class TimestampIO(_GraphSONTypeIO):
+ """A timestamp in Python is type float"""
+ python_type = statics.timestamp
+ graphson_type = "g:Timestamp"
+ graphson_base_type = "Timestamp"
+
+ @classmethod
+ def dictify(cls, obj, writer):
+ # Java timestamp expects milliseconds integer
+ # Have to use int because of legacy Python
+ ts = int(round(obj * 1000))
+ return GraphSONUtil.typedValue(cls.graphson_base_type, ts)
+
+ @classmethod
+ def objectify(cls, ts, reader):
+ # Python timestamp expects seconds
+ return cls.python_type(ts / 1000.0)
+
+
+class _NumberIO(_GraphSONTypeIO):
+ @classmethod
+ def dictify(cls, n, writer):
+ if isinstance(n, bool): # because isinstance(False, int) and isinstance(True, int)
+ return n
+ return GraphSONUtil.typedValue(cls.graphson_base_type, n)
+
+ @classmethod
+ def objectify(cls, v, _):
+ return cls.python_type(v)
+
+
+class FloatIO(_NumberIO):
+ python_type = FloatType
+ graphson_type = "g:Float"
+ graphson_base_type = "Float"
+
++ @classmethod
++ def dictify(cls, n, writer):
++ if isinstance(n, bool): # because isinstance(False, int) and isinstance(True, int)
++ return n
++ elif math.isnan(n):
++ return GraphSONUtil.typedValue(cls.graphson_base_type, "NaN")
++ elif math.isinf(n) and n > 0:
++ return GraphSONUtil.typedValue(cls.graphson_base_type, "Infinity")
++ elif math.isinf(n) and n < 0:
++ return GraphSONUtil.typedValue(cls.graphson_base_type, "-Infinity")
++ else:
++ return GraphSONUtil.typedValue(cls.graphson_base_type, n)
++
++ @classmethod
++ def objectify(cls, v, _):
++ if isinstance(v, str):
++ if v == 'NaN':
++ return float('nan')
++ elif v == "Infinity":
++ return float('inf')
++ elif v == "-Infinity":
++ return float('-inf')
++
++ return cls.python_type(v)
++
+
+class DoubleIO(FloatIO):
+ graphson_type = "g:Double"
+ graphson_base_type = "Double"
+
+
+class Int64IO(_NumberIO):
+ python_type = LongType
+ graphson_type = "g:Int64"
+ graphson_base_type = "Int64"
+
+
+class Int32IO(_NumberIO):
+ python_type = IntType
+ graphson_type = "g:Int32"
+ graphson_base_type = "Int32"
+
+ @classmethod
+ def dictify(cls, n, writer):
+ if isinstance(n, bool):
+ return n
+ return GraphSONUtil.typedValue(cls.graphson_base_type, n)
+
+
+class VertexDeserializer(_GraphSONTypeIO):
+ graphson_type = "g:Vertex"
+
+ @classmethod
+ def objectify(cls, d, reader):
+ return Vertex(reader.toObject(d["id"]), d.get("label", "vertex"))
+
+
+class EdgeDeserializer(_GraphSONTypeIO):
+ graphson_type = "g:Edge"
+
+ @classmethod
+ def objectify(cls, d, reader):
+ return Edge(reader.toObject(d["id"]),
+ Vertex(reader.toObject(d["outV"]), d.get("outVLabel", "vertex")),
+ d.get("label", "edge"),
+ Vertex(reader.toObject(d["inV"]), d.get("inVLabel", "vertex")))
+
+
+class VertexPropertyDeserializer(_GraphSONTypeIO):
+ graphson_type = "g:VertexProperty"
+
+ @classmethod
+ def objectify(cls, d, reader):
+ vertex = Vertex(reader.toObject(d.get("vertex"))) if "vertex" in d else None
+ return VertexProperty(reader.toObject(d["id"]),
+ d["label"],
+ reader.toObject(d["value"]),
+ vertex)
+
+
+class PropertyDeserializer(_GraphSONTypeIO):
+ graphson_type = "g:Property"
+
+ @classmethod
+ def objectify(cls, d, reader):
+ element = reader.toObject(d["element"]) if "element" in d else None
+ return Property(d["key"], reader.toObject(d["value"]), element)
+
+
+class PathDeserializer(_GraphSONTypeIO):
+ graphson_type = "g:Path"
+
+ @classmethod
+ def objectify(cls, d, reader):
+ labels = [set(label) for label in d["labels"]]
+ objects = [reader.toObject(o) for o in d["objects"]]
+ return Path(labels, objects)
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/28bf3046/gremlin-python/src/main/jython/tests/structure/io/test_graphsonV2d0.py
----------------------------------------------------------------------
diff --cc gremlin-python/src/main/jython/tests/structure/io/test_graphsonV2d0.py
index 416a9a4,0000000..e6ea550
mode 100644,000000..100644
--- a/gremlin-python/src/main/jython/tests/structure/io/test_graphsonV2d0.py
+++ b/gremlin-python/src/main/jython/tests/structure/io/test_graphsonV2d0.py
@@@ -1,377 -1,0 +1,402 @@@
+"""
+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.
+"""
+
+__author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
+
+import datetime
+import time
+import json
+import uuid
++import math
+
+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.graphsonV2d0 import GraphSONWriter, GraphSONReader, GraphSONUtil
+import gremlin_python.structure.io.graphsonV2d0
+from gremlin_python.process.traversal import P
+from gremlin_python.process.strategies import SubgraphStrategy
+from gremlin_python.process.graph_traversal import __
+
+
+class TestGraphSONReader(object):
+ graphson_reader = GraphSONReader()
+
+ def test_number_input(self):
+ x = self.graphson_reader.readObject(json.dumps({
+ "@type": "g:Int32",
+ "@value": 31
+ }))
+ assert isinstance(x, int)
+ assert 31 == x
+ ##
+ x = self.graphson_reader.readObject(json.dumps({
+ "@type": "g:Int64",
+ "@value": 31
+ }))
+ assert isinstance(x, long)
+ assert long(31) == x
+ ##
+ x = self.graphson_reader.readObject(json.dumps({
+ "@type": "g:Float",
+ "@value": 31.3
+ }))
+ assert isinstance(x, float)
+ assert 31.3 == x
+ ##
+ x = self.graphson_reader.readObject(json.dumps({
+ "@type": "g:Double",
+ "@value": 31.2
+ }))
+ assert isinstance(x, float)
+ assert 31.2 == x
++ ##
++ x = self.graphson_reader.readObject(json.dumps({
++ "@type": "g:Double",
++ "@value": "NaN"
++ }))
++ assert isinstance(x, float)
++ assert math.isnan(x)
++ ##
++ x = self.graphson_reader.readObject(json.dumps({
++ "@type": "g:Double",
++ "@value": "Infinity"
++ }))
++ assert isinstance(x, float)
++ assert math.isinf(x) and x > 0
++ ##
++ x = self.graphson_reader.readObject(json.dumps({
++ "@type": "g:Double",
++ "@value": "-Infinity"
++ }))
++ assert isinstance(x, float)
++ assert math.isinf(x) and x < 0
+
+ def test_graph(self):
+ vertex = self.graphson_reader.readObject("""
+ {"@type":"g:Vertex", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","outE":{"created":[{"id":{"@type":"g:Int32","@value":9},"inV":{"@type":"g:Int32","@value":3},"properties":{"weight":{"@type":"g:Double","@value":0.4}}}],"knows":[{"id":{"@type":"g:Int32","@value":7},"inV":{"@type":"g:Int32","@value":2},"properties":{"weight":{"@type":"g:Double","@value":0.5}}},{"id":{"@type":"g:Int32","@value":8},"inV":{"@type":"g:Int32","@value":4},"properties":{"weight":{"@type":"g:Double","@value":1.0}}}]},"properties":{"name":[{"id":{"@type":"g:Int64","@value":0},"value":"marko"}],"age":[{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29}}]}}}""")
+ assert isinstance(vertex, Vertex)
+ assert "person" == vertex.label
+ assert 1 == vertex.id
+ assert isinstance(vertex.id, int)
+ assert vertex == Vertex(1)
+ ##
+ vertex = self.graphson_reader.readObject("""
+ {"@type":"g:Vertex", "@value":{"id":{"@type":"g:Float","@value":45.23}}}""")
+ assert isinstance(vertex, Vertex)
+ assert 45.23 == vertex.id
+ assert isinstance(vertex.id, FloatType)
+ assert "vertex" == vertex.label
+ assert vertex == Vertex(45.23)
+ ##
+ vertex_property = self.graphson_reader.readObject("""
+ {"@type":"g:VertexProperty", "@value":{"id":"anId","label":"aKey","value":true,"vertex":{"@type":"g:Int32","@value":9}}}""")
+ assert isinstance(vertex_property, VertexProperty)
+ assert "anId" == vertex_property.id
+ assert "aKey" == vertex_property.label
+ assert vertex_property.value
+ assert vertex_property.vertex == Vertex(9)
+ ##
+ vertex_property = self.graphson_reader.readObject("""
+ {"@type":"g:VertexProperty", "@value":{"id":{"@type":"g:Int32","@value":1},"label":"name","value":"marko"}}""")
+ assert isinstance(vertex_property, VertexProperty)
+ assert 1 == vertex_property.id
+ assert "name" == vertex_property.label
+ assert "marko" == vertex_property.value
+ assert vertex_property.vertex is None
+ ##
+ edge = self.graphson_reader.readObject("""
+ {"@type":"g:Edge", "@value":{"id":{"@type":"g:Int64","@value":17},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab","properties":{"aKey":"aValue","bKey":true}}}""")
+ # print edge
+ assert isinstance(edge, Edge)
+ assert 17 == edge.id
+ assert "knows" == edge.label
+ assert edge.inV == Vertex("x", "xLabel")
+ assert edge.outV == Vertex("y", "vertex")
+ ##
+ property = self.graphson_reader.readObject("""
+ {"@type":"g:Property", "@value":{"key":"aKey","value":{"@type":"g:Int64","@value":17},"element":{"@type":"g:Edge","@value":{"id":{"@type":"g:Int64","@value":122},"label":"knows","inV":"x","outV":"y","inVLabel":"xLab"}}}}""")
+ # print property
+ assert isinstance(property, Property)
+ assert "aKey" == property.key
+ assert 17 == property.value
+ assert Edge(122, Vertex("x"), "knows", Vertex("y")) == property.element
+
+ def test_path(self):
+ path = self.graphson_reader.readObject(
+ """{"@type":"g:Path","@value":{"labels":[["a"],["b","c"],[]],"objects":[{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":1},"label":"person","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":0},"value":"marko","label":"name"}}],"age":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":1},"value":{"@type":"g:Int32","@value":29},"label":"age"}}]}}},{"@type":"g:Vertex","@value":{"id":{"@type":"g:Int32","@value":3},"label":"software","properties":{"name":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":4},"value":"lop","label":"name"}}],"lang":[{"@type":"g:VertexProperty","@value":{"id":{"@type":"g:Int64","@value":5},"value":"java","label":"lang"}}]}}},"lop"]}}"""
+ )
+ assert isinstance(path, Path)
+ if six.PY3:
+ assert "[v[1], v[3], 'lop']" == str(path)
+ else:
+ assert "[v[1], v[3], u'lop']" == str(path)
+ assert Vertex(1) == path[0]
+ assert Vertex(1) == path["a"]
+ assert "lop" == path[2]
+ assert 3 == len(path)
+
+ def test_custom_mapping(self):
+
+ # extended mapping
+ class X(object):
+ pass
+
+ type_string = "test:Xtype"
+ override_string = "g:Int64"
+ serdes = Mock()
+
+ reader = GraphSONReader(deserializer_map={type_string: serdes})
+ assert type_string in reader.deserializers
+
+ # base dicts are not modified
+ assert type_string not in gremlin_python.structure.io.graphsonV2d0._deserializers
+
+ x = X()
+ o = reader.toObject({GraphSONUtil.TYPE_KEY: type_string, GraphSONUtil.VALUE_KEY: x})
+ serdes.objectify.assert_called_once_with(x, reader)
+ assert o is serdes.objectify()
+
+ # overridden mapping
+ type_string = "g:Int64"
+ serdes = Mock()
+ reader = GraphSONReader(deserializer_map={type_string: serdes, override_string: serdes})
+ assert gremlin_python.structure.io.graphsonV2d0._deserializers[type_string] is not reader.deserializers[type_string]
+
+ value = 3
+ o = reader.toObject({GraphSONUtil.TYPE_KEY: type_string, GraphSONUtil.VALUE_KEY: value})
+ serdes.objectify.assert_called_once_with(value, reader)
+ assert o is serdes.objectify()
+
+ def test_datetime(self):
+ expected = datetime.datetime(2016, 12, 14, 16, 14, 36, 295000)
+ pts = time.mktime((expected.year, expected.month, expected.day,
+ expected.hour, expected.minute, expected.second,
+ -1, -1, -1)) + expected.microsecond / 1e6
+ timestamp = int(round(pts * 1000))
+ dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Date", "@value": timestamp}))
+ assert isinstance(dt, datetime.datetime)
+ # TINKERPOP-1848
+ assert dt == expected
+
+ def test_timestamp(self):
+ dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}))
+ assert isinstance(dt, timestamp)
+ assert float(dt) == 1481750076.295
+
+ def test_uuid(self):
+ prop = self.graphson_reader.readObject(
+ json.dumps({'@type': 'g:UUID', '@value': "41d2e28a-20a4-4ab0-b379-d810dede3786"}))
+ assert isinstance(prop, uuid.UUID)
+ assert str(prop) == '41d2e28a-20a4-4ab0-b379-d810dede3786'
+
+
+class TestGraphSONWriter(object):
+ graphson_writer = GraphSONWriter()
+ graphson_reader = GraphSONReader()
+
+ def test_number_output(self):
+ assert {"@type": "g:Int64", "@value": 2} == json.loads(self.graphson_writer.writeObject(long(2)))
+ assert {"@type": "g:Int32", "@value": 1} == json.loads(self.graphson_writer.writeObject(1))
+ assert {"@type": "g:Double", "@value": 3.2} == json.loads(self.graphson_writer.writeObject(3.2))
+ assert """true""" == self.graphson_writer.writeObject(True)
+
+ def test_numbers(self):
+ assert {"@type": "g:Int64", "@value": 2} == json.loads(self.graphson_writer.writeObject(long(2)))
+ assert {"@type": "g:Int32", "@value": 1} == json.loads(self.graphson_writer.writeObject(1))
+ assert {"@type": "g:Double", "@value": 3.2} == json.loads(self.graphson_writer.writeObject(3.2))
++ assert {"@type": "g:Double", "@value": "NaN"} == json.loads(self.graphson_writer.writeObject(float('nan')))
++ assert {"@type": "g:Double", "@value": "Infinity"} == json.loads(self.graphson_writer.writeObject(float('inf')))
++ assert {"@type": "g:Double", "@value": "-Infinity"} == json.loads(self.graphson_writer.writeObject(float('-inf')))
+ assert """true""" == self.graphson_writer.writeObject(True)
+
+ def test_P(self):
+ result = {'@type': 'g:P',
+ '@value': {
+ 'predicate': 'and',
+ 'value': [{
+ '@type': 'g:P',
+ '@value': {
+ 'predicate': 'or',
+ 'value': [{
+ '@type': 'g:P',
+ '@value': {'predicate': 'lt', 'value': 'b'}
+ },
+ {'@type': 'g:P', '@value': {'predicate': 'gt', 'value': 'c'}}
+ ]
+ }
+ },
+ {'@type': 'g:P', '@value': {'predicate': 'neq', 'value': 'd'}}]}}
+
+ assert result == json.loads(
+ self.graphson_writer.writeObject(P.lt("b").or_(P.gt("c")).and_(P.neq("d"))))
+
+ result = {'@type': 'g:P', '@value': {'predicate':'within','value': [{"@type": "g:Int32", "@value": 1},{"@type": "g:Int32", "@value": 2}]}}
+ assert result == json.loads(self.graphson_writer.writeObject(P.within([1,2])))
+
+ def test_strategies(self):
+ # we have a proxy model for now given that we don't want to have to have g:XXX all registered on the Gremlin traversal machine (yet)
+ assert {"@type": "g:SubgraphStrategy", "@value": {}} == json.loads(
+ self.graphson_writer.writeObject(SubgraphStrategy))
+ assert {"@type": "g:SubgraphStrategy", "@value": {
+ "vertices": {"@type": "g:Bytecode", "@value": {"step": [["has", "name", "marko"]]}}}} == json.loads(
+ self.graphson_writer.writeObject(SubgraphStrategy(vertices=__.has("name", "marko"))))
+
+ def test_graph(self):
+ # TODO: this assert is not compatible with python 3 and now that we test with both 2 and 3 it fails
+ assert {"@type": "g:Vertex", "@value": {"id": {"@type": "g:Int64", "@value": 12}, "label": "person"}} == json.loads(self.graphson_writer.writeObject(Vertex(long(12), "person")))
+
+ assert {"@type": "g:Edge", "@value": {"id": {"@type": "g:Int32", "@value": 7},
+ "outV": {"@type": "g:Int32", "@value": 0},
+ "outVLabel": "person",
+ "label": "knows",
+ "inV": {"@type": "g:Int32", "@value": 1},
+ "inVLabel": "dog"}} == json.loads(
+ self.graphson_writer.writeObject(Edge(7, Vertex(0, "person"), "knows", Vertex(1, "dog"))))
+ assert {"@type": "g:VertexProperty", "@value": {"id": "blah", "label": "keyA", "value": True,
+ "vertex": "stephen"}} == json.loads(
+ self.graphson_writer.writeObject(VertexProperty("blah", "keyA", True, Vertex("stephen"))))
+
+ assert {"@type": "g:Property",
+ "@value": {"key": "name", "value": "marko", "element": {"@type": "g:VertexProperty",
+ "@value": {
+ "vertex": "vertexId",
+ "id": {"@type": "g:Int32", "@value": 1234},
+ "label": "aKey"}}}} == json.loads(
+ self.graphson_writer.writeObject(
+ Property("name", "marko", VertexProperty(1234, "aKey", 21345, Vertex("vertexId")))))
+
+ vertex = self.graphson_reader.readObject(self.graphson_writer.writeObject(Vertex(1, "person")))
+ assert 1 == vertex.id
+ assert "person" == vertex.label
+
+ edge = self.graphson_reader.readObject(
+ self.graphson_writer.writeObject(Edge(3, Vertex(1, "person"), "knows", Vertex(2, "dog"))))
+ assert "knows" == edge.label
+ assert 3 == edge.id
+ assert 1 == edge.outV.id
+ assert 2 == edge.inV.id
+
+ vertex_property = self.graphson_reader.readObject(
+ self.graphson_writer.writeObject(VertexProperty(1, "age", 32, Vertex(1))))
+ assert 1 == vertex_property.id
+ assert "age" == vertex_property.key
+ assert 32 == vertex_property.value
+
+ property = self.graphson_reader.readObject(self.graphson_writer.writeObject(Property("age", 32.2, Edge(1,Vertex(2),"knows",Vertex(3)))))
+ assert "age" == property.key
+ assert 32.2 == property.value
+
+ def test_custom_mapping(self):
+ # extended mapping
+ class X(object):
+ pass
+
+ serdes = Mock()
+ writer = GraphSONWriter(serializer_map={X: serdes})
+ assert X in writer.serializers
+
+ # base dicts are not modified
+ assert X not in gremlin_python.structure.io.graphsonV2d0._serializers
+
+ obj = X()
+ d = writer.toDict(obj)
+ serdes.dictify.assert_called_once_with(obj, writer)
+ assert d is serdes.dictify()
+
+ # overridden mapping
+ serdes = Mock()
+ writer = GraphSONWriter(serializer_map={int: serdes})
+ assert gremlin_python.structure.io.graphsonV2d0._serializers[int] is not writer.serializers[int]
+
+ value = 3
+ d = writer.toDict(value)
+ serdes.dictify.assert_called_once_with(value, writer)
+ assert d is serdes.dictify()
+
+ def test_write_long(self):
+ mapping = self.graphson_writer.toDict(1)
+ assert mapping['@type'] == 'g:Int32'
+ assert mapping['@value'] == 1
+
+ mapping = self.graphson_writer.toDict(long(1))
+ assert mapping['@type'] == 'g:Int64'
+ assert mapping['@value'] == 1
+
+ def test_datetime(self):
+ expected = json.dumps({"@type": "g:Date", "@value": 1481750076295}, separators=(',', ':'))
+ dt = datetime.datetime.fromtimestamp(1481750076295 / 1000.0)
+ output = self.graphson_writer.writeObject(dt)
+ assert expected == output
+
+ def test_timestamp(self):
+ expected = json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}, separators=(',', ':'))
+ ts = timestamp(1481750076295 / 1000.0)
+ output = self.graphson_writer.writeObject(ts)
+ assert expected == output
+
+ def test_uuid(self):
+ expected = json.dumps({'@type': 'g:UUID', '@value': "41d2e28a-20a4-4ab0-b379-d810dede3786"}, separators=(',', ':'))
+ prop = uuid.UUID("41d2e28a-20a4-4ab0-b379-d810dede3786")
+ output = self.graphson_writer.writeObject(prop)
+ assert expected == output
+
+
+class TestFunctionalGraphSONIO(object):
+ """Functional IO tests"""
+
+ def test_timestamp(self, remote_connection_v2):
+ g = Graph().traversal().withRemote(remote_connection_v2)
+ ts = timestamp(1481750076295 / 1000)
+ resp = g.addV('test_vertex').property('ts', ts)
+ resp = resp.toList()
+ vid = resp[0].id
+ try:
+ ts_prop = g.V(vid).properties('ts').toList()[0]
+ assert isinstance(ts_prop.value, timestamp)
+ assert ts_prop.value == ts
+ finally:
+ g.V(vid).drop().iterate()
+
+ def test_datetime(self, remote_connection_v2):
+ g = Graph().traversal().withRemote(remote_connection_v2)
+ dt = datetime.datetime.fromtimestamp(1481750076295 / 1000)
+ resp = g.addV('test_vertex').property('dt', dt).toList()
+ vid = resp[0].id
+ try:
+ dt_prop = g.V(vid).properties('dt').toList()[0]
+ assert isinstance(dt_prop.value, datetime.datetime)
+ assert dt_prop.value == dt
+ finally:
+ g.V(vid).drop().iterate()
+
+ def test_uuid(self, remote_connection_v2):
+ g = Graph().traversal().withRemote(remote_connection_v2)
+ uid = uuid.UUID("41d2e28a-20a4-4ab0-b379-d810dede3786")
+ resp = g.addV('test_vertex').property('uuid', uid).toList()
+ vid = resp[0].id
+ try:
+ uid_prop = g.V(vid).properties('uuid').toList()[0]
+ assert isinstance(uid_prop.value, uuid.UUID)
+ assert uid_prop.value == uid
+ finally:
+ g.V(vid).drop().iterate()