You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by da...@apache.org on 2017/11/27 17:52:58 UTC

[1/4] tinkerpop git commit: Implemented support for missing core GraphSON types in gremlin-python

Repository: tinkerpop
Updated Branches:
  refs/heads/tp32 072b08214 -> 3db47e016


Implemented support for missing core GraphSON types in gremlin-python


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/3b651ff5
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/3b651ff5
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/3b651ff5

Branch: refs/heads/tp32
Commit: 3b651ff58cdf210a63a0101d0a311c7076de2b0e
Parents: f2b4fb9
Author: davebshow <da...@gmail.com>
Authored: Wed Nov 1 16:31:10 2017 -0700
Committer: davebshow <da...@gmail.com>
Committed: Wed Nov 1 16:31:10 2017 -0700

----------------------------------------------------------------------
 .../src/main/jython/gremlin_python/statics.py   |  9 +++
 .../gremlin_python/structure/io/graphson.py     | 71 ++++++++++++++++-
 .../jython/tests/structure/io/test_graphson.py  | 81 +++++++++++++++++++-
 3 files changed, 156 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/3b651ff5/gremlin-python/src/main/jython/gremlin_python/statics.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/gremlin_python/statics.py b/gremlin-python/src/main/jython/gremlin_python/statics.py
index a1abf8e..f98347e 100644
--- a/gremlin-python/src/main/jython/gremlin_python/statics.py
+++ b/gremlin-python/src/main/jython/gremlin_python/statics.py
@@ -36,6 +36,15 @@ else:
     from types import LongType
     from types import TypeType
 
+
+class timestamp(float):
+    """
+    In Python a timestamp is simply a float. This dummy class (similar to long), allows users to wrap a float
+    in a GLV script to make sure the value is serialized as a GraphSON timestamp.
+    """
+    pass
+
+
 staticMethods = {}
 staticEnums = {}
 default_lambda_language = "gremlin-python"

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/3b651ff5/gremlin-python/src/main/jython/gremlin_python/structure/io/graphson.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphson.py b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphson.py
index 0daeffa..04085ee 100644
--- a/gremlin-python/src/main/jython/gremlin_python/structure/io/graphson.py
+++ b/gremlin-python/src/main/jython/gremlin_python/structure/io/graphson.py
@@ -16,11 +16,15 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 '''
-from aenum import Enum
+import datetime
 import json
-import six
+import time
+import uuid
 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
@@ -298,6 +302,69 @@ class TypeSerializer(_GraphSONTypeIO):
         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
+            # Taken from:
+            # https://github.com/jaraco/backports.datetime_timestamp/blob/master/backports/datetime_timestamp/__init__.py
+            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):

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/3b651ff5/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py b/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py
index d80d045..75e7136 100644
--- a/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py
+++ b/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py
@@ -18,16 +18,20 @@ under the License.
 '''
 
 __author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
-
+import datetime
 import json
+import uuid
+
 from mock import Mock
 
 import six
 
 from gremlin_python.statics import *
-from gremlin_python.structure.graph import Vertex, Edge, VertexProperty, Property
+from gremlin_python.structure.graph import (
+    Vertex, Edge, VertexProperty, Property, Graph)
 from gremlin_python.structure.graph import Path
-from gremlin_python.structure.io.graphson import GraphSONWriter, GraphSONReader, GraphSONUtil
+from gremlin_python.structure.io.graphson import (
+    GraphSONWriter, GraphSONReader, GraphSONUtil)
 import gremlin_python.structure.io.graphson
 from gremlin_python.process.traversal import P
 from gremlin_python.process.strategies import SubgraphStrategy
@@ -121,6 +125,19 @@ class TestGraphSONReader(object):
         serdes.objectify.assert_called_once_with(value, reader)
         assert o is serdes.objectify()
 
+    def test_datetime(self):
+        dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Date", "@value": 1481750076295}))
+        assert isinstance(dt, datetime.datetime)
+
+    def test_timestamp(self):
+        dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Timestamp", "@value": 1481750076295}))
+        assert isinstance(dt, timestamp)
+
+    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)
+
 
 class TestGraphSONWriter(object):
     graphson_writer = GraphSONWriter()
@@ -224,3 +241,61 @@ class TestGraphSONWriter(object):
         property = self.graphson_reader.readObject(self.graphson_writer.writeObject(Property("age", 32.2)))
         assert "age" == property.key
         assert 32.2 == property.value
+
+    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):
+        g = Graph().traversal().withRemote(remote_connection)
+        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):
+        g = Graph().traversal().withRemote(remote_connection)
+        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):
+        g = Graph().traversal().withRemote(remote_connection)
+        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()


[2/4] tinkerpop git commit: updated changelog and upgrade docs

Posted by da...@apache.org.
updated changelog and upgrade docs


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/46612842
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/46612842
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/46612842

Branch: refs/heads/tp32
Commit: 4661284292306fecb67fbcc46617af97b3b7762f
Parents: 3b651ff
Author: davebshow <da...@gmail.com>
Authored: Tue Nov 7 09:40:05 2017 -0800
Committer: davebshow <da...@gmail.com>
Committed: Tue Nov 7 09:40:05 2017 -0800

----------------------------------------------------------------------
 CHANGELOG.asciidoc                                 | 1 +
 docs/src/upgrade/release-3.2.x-incubating.asciidoc | 9 +++++++++
 2 files changed, 10 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/46612842/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index fcba906..acfa892 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -23,6 +23,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 [[release-3-2-7]]
 === TinkerPop 3.2.7 (Release Date: NOT OFFICIALLY RELEASED YET)
 
+* Added core GraphSON classes for Gremlin-Python: `UUID`, `Date`, and `Timestamp`.
 * `TraversalVertexProgram` ``profile()` now accounts for worker iteration in `GraphComputer` OLAP.
 * Added a test for self-edges and fixed `Neo4jVertex` to provided repeated self-edges on `BOTH`.
 * Better respected permissions on the `plugins.txt` file and prevented writing if marked as read-only.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/46612842/docs/src/upgrade/release-3.2.x-incubating.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/upgrade/release-3.2.x-incubating.asciidoc b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
index 60fd320..9be51f9 100644
--- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
@@ -29,6 +29,15 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 
 Please see the link:https://github.com/apache/tinkerpop/blob/3.2.7/CHANGELOG.asciidoc#release-3-2-7[changelog] for a complete list of all the modifications that are part of this release.
 
+==== Gremlin-Python Core Types
+With the addition of `UUID`, `Date`, and `Timestamp`, Gremlin-Python now implements serializers for all core GraphSON types. Users
+that were using other types to represent this data can now use the Python classes `datetime.datetime` and`uuid.UUID` in GLV traversals.
+Since Python does not support a native `Timestamp` object, Gremlin-Python now offers a dummy class `Timestamp`, which allows
+users to wrap a float and submit it to the Gremlin Server as a `Timestamp` GraphSON type. `Timestamp` can be found in
+`gremlin_python.statics`.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-1807[TINKERPOP-1807]
+
 ==== Embedded Remote Connection
 
 As Gremlin Language Variants (GLVs) expand their usage and use of `withRemote()` becomes more common, the need to mock


[3/4] tinkerpop git commit: added asserts to check values are deserialized as expected

Posted by da...@apache.org.
added asserts to check values are deserialized as expected


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/c0078cc1
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/c0078cc1
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/c0078cc1

Branch: refs/heads/tp32
Commit: c0078cc172e918f96460630da27ff04cb4e9478d
Parents: 4661284
Author: davebshow <da...@gmail.com>
Authored: Mon Nov 13 10:11:46 2017 -0800
Committer: davebshow <da...@gmail.com>
Committed: Mon Nov 13 10:11:46 2017 -0800

----------------------------------------------------------------------
 .../src/main/jython/tests/structure/io/test_graphson.py          | 4 ++++
 1 file changed, 4 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c0078cc1/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py b/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py
index 75e7136..68d14ca 100644
--- a/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py
+++ b/gremlin-python/src/main/jython/tests/structure/io/test_graphson.py
@@ -128,15 +128,18 @@ class TestGraphSONReader(object):
     def test_datetime(self):
         dt = self.graphson_reader.readObject(json.dumps({"@type": "g:Date", "@value": 1481750076295}))
         assert isinstance(dt, datetime.datetime)
+        assert dt == datetime.datetime(2016, 12, 14, 13, 14, 36, 295000)
 
     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):
@@ -260,6 +263,7 @@ class TestGraphSONWriter(object):
         output = self.graphson_writer.writeObject(prop)
         assert expected == output
 
+
 class TestFunctionalGraphSONIO(object):
     """Functional IO tests"""
 


[4/4] tinkerpop git commit: Merge branch 'TINKERPOP-1807' into tp32

Posted by da...@apache.org.
Merge branch 'TINKERPOP-1807' into tp32


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/3db47e01
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/3db47e01
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/3db47e01

Branch: refs/heads/tp32
Commit: 3db47e0162ef6330fe84e168591e9ab2f51b5725
Parents: 072b082 c0078cc
Author: davebshow <da...@gmail.com>
Authored: Mon Nov 27 09:45:41 2017 -0800
Committer: davebshow <da...@gmail.com>
Committed: Mon Nov 27 09:45:41 2017 -0800

----------------------------------------------------------------------
 CHANGELOG.asciidoc                              |  2 +
 .../upgrade/release-3.2.x-incubating.asciidoc   |  9 +++
 .../src/main/jython/gremlin_python/statics.py   |  9 +++
 .../gremlin_python/structure/io/graphson.py     | 71 +++++++++++++++-
 .../jython/tests/structure/io/test_graphson.py  | 85 +++++++++++++++++++-
 5 files changed, 171 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/3db47e01/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --cc CHANGELOG.asciidoc
index 02c87ca,acfa892..dd971de
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@@ -23,15 -23,8 +23,17 @@@ image::https://raw.githubusercontent.co
  [[release-3-2-7]]
  === TinkerPop 3.2.7 (Release Date: NOT OFFICIALLY RELEASED YET)
  
+ * Added core GraphSON classes for Gremlin-Python: `UUID`, `Date`, and `Timestamp`.
 +* Provided a method to configure detachment options with `EventStrategy`.
 +* Fixed a race condition in `TinkerIndex`.
 +* Fixed an `ArrayOutOfBoundsException` in `hasId()` for the rare situation when the provided collection is empty.
 +* Bump to Netty 4.0.52
 +* `TraversalVertexProgram` `profile()` now accounts for worker iteration in `GraphComputer` OLAP.
 +* Returned the `Builder` instance from the `DetachedEdge.Builder` methods of `setOutE` and `setOutV`.
 +* Added test framework for GLVs.
 +* Fixed bug in `TraversalHelper.replaceStep()` where the step being replaced needed to be removed prior to the new one being added.
 +* Added alias support in the .NET `DriverRemoteConnection`.
+ * `TraversalVertexProgram` ``profile()` now accounts for worker iteration in `GraphComputer` OLAP.
  * Added a test for self-edges and fixed `Neo4jVertex` to provided repeated self-edges on `BOTH`.
  * Better respected permissions on the `plugins.txt` file and prevented writing if marked as read-only.
  * Added getters for the lambdas held by `LambdaCollectingBarrierStep`, `LambdaFlatMapStep` and `LambdaSideEffectStep`.

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/3db47e01/docs/src/upgrade/release-3.2.x-incubating.asciidoc
----------------------------------------------------------------------
diff --cc docs/src/upgrade/release-3.2.x-incubating.asciidoc
index 1589069,9be51f9..a8b5ad6
--- a/docs/src/upgrade/release-3.2.x-incubating.asciidoc
+++ b/docs/src/upgrade/release-3.2.x-incubating.asciidoc
@@@ -29,16 -29,15 +29,25 @@@ image::https://raw.githubusercontent.co
  
  Please see the link:https://github.com/apache/tinkerpop/blob/3.2.7/CHANGELOG.asciidoc#release-3-2-7[changelog] for a complete list of all the modifications that are part of this release.
  
+ ==== Gremlin-Python Core Types
+ With the addition of `UUID`, `Date`, and `Timestamp`, Gremlin-Python now implements serializers for all core GraphSON types. Users
+ that were using other types to represent this data can now use the Python classes `datetime.datetime` and`uuid.UUID` in GLV traversals.
+ Since Python does not support a native `Timestamp` object, Gremlin-Python now offers a dummy class `Timestamp`, which allows
+ users to wrap a float and submit it to the Gremlin Server as a `Timestamp` GraphSON type. `Timestamp` can be found in
+ `gremlin_python.statics`.
+ 
+ See: link:https://issues.apache.org/jira/browse/TINKERPOP-1807[TINKERPOP-1807]
+ 
 +==== EventStrategy Detachment
 +
 +`EventStrategy` forced detachment of mutated elements prior to raising them in events. While this was a desired
 +outcome, it may not have always fit every use case. For example, a user may have wanted a reference element or the
 +actual element itself. As a result, `EventStrategy` has changed to allow it to be constructed with a `detach()`
 +option, where it is possible to specify any of the following: `null` for no detachment, `DetachedFactory` for the
 +original behavior, and `ReferenceFactory` for detachment that returns reference elements.
 +
 +See: link:https://issues.apache.org/jira/browse/TINKERPOP-1829[TINKERPOP-1829]
 +
  ==== Embedded Remote Connection
  
  As Gremlin Language Variants (GLVs) expand their usage and use of `withRemote()` becomes more common, the need to mock