From f80a5ab503fdde56f04e80ff03184f9970bc0c99 Mon Sep 17 00:00:00 2001
From: davebshow <davebshow@gmail.com>
Date: Sun, 10 Jul 2016 21:02:12 -0400
Subject: [PATCH] simple async remote graph interface

---
 goblin/driver/connection.py                   |  4 ++
 goblin/driver/graph.py                        | 45 +++++++++++++++++++
 goblin/gremlin_python/__init__.py             |  2 +-
 goblin/gremlin_python/driver/__init__.py      |  4 +-
 .../driver/rest_remote_connection.py          |  4 +-
 goblin/gremlin_python/process/__init__.py     | 34 +++++++-------
 .../gremlin_python/process/graph_traversal.py | 24 +++++-----
 .../process/groovy_translator.py              | 10 ++---
 .../process/jython_translator.py              | 18 ++++----
 goblin/gremlin_python/process/traversal.py    |  2 +-
 goblin/gremlin_python/structure/__init__.py   |  4 +-
 goblin/gremlin_python/structure/graph.py      |  4 +-
 .../gremlin_python/structure/remote_graph.py  |  6 +--
 goblin/query.py                               |  6 +--
 setup.py                                      |  3 +-
 tests/test_driver.py                          | 16 +++++++
 16 files changed, 126 insertions(+), 60 deletions(-)
 create mode 100644 goblin/driver/graph.py

diff --git a/goblin/driver/connection.py b/goblin/driver/connection.py
index 3fbb2ac..468dda6 100644
--- a/goblin/driver/connection.py
+++ b/goblin/driver/connection.py
@@ -77,6 +77,10 @@ class Connection(AbstractConnection):
     def force_close(self):
         return self._force_close
 
+    @property
+    def url(self):
+        return self._url
+
     async def submit(self,
                     gremlin,
                     *,
diff --git a/goblin/driver/graph.py b/goblin/driver/graph.py
new file mode 100644
index 0000000..7d6c70e
--- /dev/null
+++ b/goblin/driver/graph.py
@@ -0,0 +1,45 @@
+from goblin.gremlin_python.process.graph_traversal import GraphTraversalSource, GraphTraversal
+from goblin.gremlin_python.process.traversal import TraversalStrategy, TraversalStrategies
+
+
+class AsyncGraphTraversal(GraphTraversal):
+    def __init__(self, graph, traversal_strategies, bytecode):
+        GraphTraversal.__init__(self, graph, traversal_strategies, bytecode)
+
+    def __repr__(self):
+        return self.graph.translator.translate(self.bytecode)
+
+    def toList(self):
+        raise NotImplementedError
+
+    def toSet(self):
+        raise NotImplementedError
+
+    async def next(self):
+        resp = await self.traversal_strategies.apply(self)
+        return resp
+
+
+class AsyncRemoteStrategy(TraversalStrategy):
+    async def apply(self, traversal):
+        result = await traversal.graph.remote_connection.submit(
+            traversal.graph.translator.translate(traversal.bytecode),
+            bindings=traversal.bindings,
+            lang=traversal.graph.translator.target_language)
+        return result
+
+
+class AsyncGraph(object):
+    def traversal(self):
+        return GraphTraversalSource(self, self.traversal_strategy,
+                                    graph_traversal=AsyncGraphTraversal)
+
+
+class AsyncRemoteGraph(AsyncGraph):
+    def __init__(self, translator, remote_connection):
+        self.traversal_strategy = AsyncRemoteStrategy()  # A single traversal strategy
+        self.translator = translator
+        self.remote_connection = remote_connection
+
+    def __repr__(self):
+        return "remotegraph[" + self.remote_connection.url + "]"
diff --git a/goblin/gremlin_python/__init__.py b/goblin/gremlin_python/__init__.py
index cd21e56..518d8e0 100644
--- a/goblin/gremlin_python/__init__.py
+++ b/goblin/gremlin_python/__init__.py
@@ -16,6 +16,6 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 '''
-import statics
+from . import statics
 
 __author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
diff --git a/goblin/gremlin_python/driver/__init__.py b/goblin/gremlin_python/driver/__init__.py
index bb4e612..7e1c0f1 100644
--- a/goblin/gremlin_python/driver/__init__.py
+++ b/goblin/gremlin_python/driver/__init__.py
@@ -16,7 +16,7 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 '''
-from remote_connection import RemoteConnection
-from rest_remote_connection import RESTRemoteConnection
+from .remote_connection import RemoteConnection
+from .rest_remote_connection import RESTRemoteConnection
 
 __author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
diff --git a/goblin/gremlin_python/driver/rest_remote_connection.py b/goblin/gremlin_python/driver/rest_remote_connection.py
index b827d0d..b2034fd 100644
--- a/goblin/gremlin_python/driver/rest_remote_connection.py
+++ b/goblin/gremlin_python/driver/rest_remote_connection.py
@@ -19,8 +19,8 @@ under the License.
 import json
 import requests
 
-from gremlin_python.process.traversal import Traverser
-from remote_connection import RemoteConnection
+from goblin.gremlin_python.process.traversal import Traverser
+from .remote_connection import RemoteConnection
 
 __author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
 
diff --git a/goblin/gremlin_python/process/__init__.py b/goblin/gremlin_python/process/__init__.py
index d84b097..e93356e 100644
--- a/goblin/gremlin_python/process/__init__.py
+++ b/goblin/gremlin_python/process/__init__.py
@@ -17,22 +17,22 @@ specific language governing permissions and limitations
 under the License.
 '''
 
-from graph_traversal import GraphTraversal
-from graph_traversal import GraphTraversalSource
-from graph_traversal import __
-from groovy_translator import GroovyTranslator
-from jython_translator import JythonTranslator
-from traversal import Barrier
-from traversal import Bytecode
-from traversal import Cardinality
-from traversal import Column
-from traversal import Direction
-from traversal import Operator
-from traversal import Order
-from traversal import P
-from traversal import Pop
-from traversal import Scope
-from traversal import T
-from traversal import Traversal
+from .graph_traversal import GraphTraversal
+from .graph_traversal import GraphTraversalSource
+from .graph_traversal import __
+from .groovy_translator import GroovyTranslator
+from .jython_translator import JythonTranslator
+from .traversal import Barrier
+from .traversal import Bytecode
+from .traversal import Cardinality
+from .traversal import Column
+from .traversal import Direction
+from .traversal import Operator
+from .traversal import Order
+from .traversal import P
+from .traversal import Pop
+from .traversal import Scope
+from .traversal import T
+from .traversal import Traversal
 
 __author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
diff --git a/goblin/gremlin_python/process/graph_traversal.py b/goblin/gremlin_python/process/graph_traversal.py
index 2261e83..b5d6a17 100644
--- a/goblin/gremlin_python/process/graph_traversal.py
+++ b/goblin/gremlin_python/process/graph_traversal.py
@@ -16,20 +16,23 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 '''
-from traversal import RawExpression
-from traversal import Traversal
-from traversal import Bytecode
-from gremlin_python import statics
+from .traversal import RawExpression
+from .traversal import Traversal
+from .traversal import Bytecode
+from goblin.gremlin_python import statics
 
 class GraphTraversalSource(object):
-  def __init__(self, graph, traversal_strategies, bytecode=Bytecode()):
+  def __init__(self, graph, traversal_strategies, graph_traversal=None, bytecode=Bytecode()):
     self.graph = graph
     self.traversal_strategies = traversal_strategies
+    if graph_traversal is None:
+        graph_traversal = GraphTraversal
+    self.graph_traversal = graph_traversal
     self.bytecode = bytecode
   def __repr__(self):
     return "graphtraversalsource[" + str(self.graph) + "]"
   def E(self, *args):
-    traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
+    traversal = self.graph_traversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
     traversal.bytecode.add_step("E", *args)
     for arg in args:
       if isinstance(arg, tuple) and 2 == len(arg) and isinstance(arg[0], str):
@@ -38,7 +41,7 @@ class GraphTraversalSource(object):
         self.bindings.update(arg.bindings)
     return traversal
   def V(self, *args):
-    traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
+    traversal = self.graph_traversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
     traversal.bytecode.add_step("V", *args)
     for arg in args:
       if isinstance(arg, tuple) and 2 == len(arg) and isinstance(arg[0], str):
@@ -47,7 +50,7 @@ class GraphTraversalSource(object):
         self.bindings.update(arg.bindings)
     return traversal
   def addV(self, *args):
-    traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
+    traversal = self.graph_traversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
     traversal.bytecode.add_step("addV", *args)
     for arg in args:
       if isinstance(arg, tuple) and 2 == len(arg) and isinstance(arg[0], str):
@@ -56,7 +59,7 @@ class GraphTraversalSource(object):
         self.bindings.update(arg.bindings)
     return traversal
   def inject(self, *args):
-    traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
+    traversal = self.graph_traversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode))
     traversal.bytecode.add_step("inject", *args)
     for arg in args:
       if isinstance(arg, tuple) and 2 == len(arg) and isinstance(arg[0], str):
@@ -1684,6 +1687,3 @@ def where(*args):
       return __.where(*args)
 
 statics.add_static('where', where)
-
-
-
diff --git a/goblin/gremlin_python/process/groovy_translator.py b/goblin/gremlin_python/process/groovy_translator.py
index a05885d..2c2d79a 100644
--- a/goblin/gremlin_python/process/groovy_translator.py
+++ b/goblin/gremlin_python/process/groovy_translator.py
@@ -20,11 +20,11 @@ under the License.
 import sys
 from aenum import Enum
 
-from traversal import Bytecode
-from traversal import P
-from traversal import RawExpression
-from traversal import SymbolHelper
-from traversal import Translator
+from .traversal import Bytecode
+from .traversal import P
+from .traversal import RawExpression
+from .traversal import SymbolHelper
+from .traversal import Translator
 
 if sys.version_info.major > 2:
     long = int
diff --git a/goblin/gremlin_python/process/jython_translator.py b/goblin/gremlin_python/process/jython_translator.py
index 0ffcaab..c3169f0 100644
--- a/goblin/gremlin_python/process/jython_translator.py
+++ b/goblin/gremlin_python/process/jython_translator.py
@@ -21,14 +21,14 @@ import inspect
 import sys
 from aenum import Enum
 
-from traversal import Barrier
-from traversal import Bytecode
-from traversal import Cardinality
-from traversal import Column
-from traversal import P
-from traversal import RawExpression
-from traversal import SymbolHelper
-from traversal import Translator
+from .traversal import Barrier
+from .traversal import Bytecode
+from .traversal import Cardinality
+from .traversal import Column
+from .traversal import P
+from .traversal import RawExpression
+from .traversal import SymbolHelper
+from .traversal import Translator
 
 if sys.version_info.major > 2:
     long = int
@@ -57,7 +57,7 @@ class JythonTranslator(Translator):
         if isinstance(arg, str):
             return "\"" + arg + "\""
         elif isinstance(arg, long):
-            return str(arg) + "L" if arg > 9223372036854775807L else "Long(" + str(arg) + ")"
+            return str(arg)
         elif isinstance(arg, Barrier):
             return "Barrier" + "." + SymbolHelper.toJava(str(arg.name))
         elif isinstance(arg, Column):
diff --git a/goblin/gremlin_python/process/traversal.py b/goblin/gremlin_python/process/traversal.py
index 7558151..c37c440 100644
--- a/goblin/gremlin_python/process/traversal.py
+++ b/goblin/gremlin_python/process/traversal.py
@@ -18,7 +18,7 @@ under the License.
 '''
 from abc import abstractmethod
 from aenum import Enum
-from gremlin_python import statics
+from goblin.gremlin_python import statics
 
 class Traversal(object):
     def __init__(self, graph, traversal_strategies, bytecode):
diff --git a/goblin/gremlin_python/structure/__init__.py b/goblin/gremlin_python/structure/__init__.py
index fe9ad17..1c69b5c 100644
--- a/goblin/gremlin_python/structure/__init__.py
+++ b/goblin/gremlin_python/structure/__init__.py
@@ -16,7 +16,7 @@ KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 '''
-from graph import Graph
-from remote_graph import RemoteGraph
+from .graph import Graph
+from .remote_graph import RemoteGraph
 
 __author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
diff --git a/goblin/gremlin_python/structure/graph.py b/goblin/gremlin_python/structure/graph.py
index 60b2211..82909f1 100644
--- a/goblin/gremlin_python/structure/graph.py
+++ b/goblin/gremlin_python/structure/graph.py
@@ -19,8 +19,8 @@ under the License.
 
 __author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
 
-from gremlin_python.process.graph_traversal import GraphTraversalSource
-from gremlin_python.process.traversal import TraversalStrategies
+from goblin.gremlin_python.process.graph_traversal import GraphTraversalSource
+from goblin.gremlin_python.process.traversal import TraversalStrategies
 
 
 class Graph(object):
diff --git a/goblin/gremlin_python/structure/remote_graph.py b/goblin/gremlin_python/structure/remote_graph.py
index bc2a11a..19125ea 100644
--- a/goblin/gremlin_python/structure/remote_graph.py
+++ b/goblin/gremlin_python/structure/remote_graph.py
@@ -19,9 +19,9 @@ under the License.
 
 __author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
 
-from graph import Graph
-from gremlin_python.process.traversal import TraversalStrategies
-from gremlin_python.process.traversal import TraversalStrategy
+from .graph import Graph
+from goblin.gremlin_python.process.traversal import TraversalStrategies
+from goblin.gremlin_python.process.traversal import TraversalStrategy
 
 
 class RemoteGraph(Graph):
diff --git a/goblin/query.py b/goblin/query.py
index 69b05f8..41ce449 100644
--- a/goblin/query.py
+++ b/goblin/query.py
@@ -2,7 +2,7 @@
 import asyncio
 import logging
 
-from goblin import gremlin_python
+from goblin.gremlin_python import process
 from goblin import mapper
 
 
@@ -35,7 +35,7 @@ class QueryResponse:
             raise StopAsyncIteration
 
 
-class GoblinTraversal(gremlin_python.PythonGraphTraversal):
+class GoblinTraversal(process.GraphTraversal):
 
     def __init__(self, translator, query, element_class):
         super().__init__(translator, remote_connection=None)
@@ -57,7 +57,7 @@ class Query:
     def __init__(self, session, translator, loop):
         self._session = session
         self._translator = translator
-        self._traversal_source = gremlin_python.PythonGraphTraversalSource(
+        self._traversal_source = process.PythonGraphTraversalSource(
             self._translator)
         self._loop = loop
         self._binding = 0
diff --git a/setup.py b/setup.py
index e5d6396..dc6daf4 100644
--- a/setup.py
+++ b/setup.py
@@ -9,7 +9,8 @@ setup(
     author="davebshow",
     author_email="davebshow@gmail.com",
     description="Python driver for TP3 Gremlin Server",
-    packages=["goblin", "goblin.gremlin_python",
+    packages=["goblin", "goblin.gremlin_python", "goblin.gremlin_python.process",
+              "goblin.gremlin_python.driver", "goblin.gremlin_python.structure",
               "goblin.driver", "tests"],
     install_requires=[
         "aenum==1.4.5",
diff --git a/tests/test_driver.py b/tests/test_driver.py
index 041733c..0b486a8 100644
--- a/tests/test_driver.py
+++ b/tests/test_driver.py
@@ -2,6 +2,8 @@ import asyncio
 import unittest
 
 from goblin import driver
+from goblin.driver import graph
+from goblin.gremlin_python import process
 
 
 class TestDriver(unittest.TestCase):
@@ -42,3 +44,17 @@ class TestDriver(unittest.TestCase):
             await connection.close()
 
         self.loop.run_until_complete(go())
+
+    def test_async_graph(self):
+
+        async def go():
+            translator = process.GroovyTranslator('g')
+            connection = await driver.GremlinServer.open(
+                "http://localhost:8182/", self.loop)
+            g = graph.AsyncRemoteGraph(translator, connection)
+            traversal = g.traversal()
+            resp = await traversal.V().next()
+            async for msg in resp:
+                print(msg)
+            await connection.close()
+        self.loop.run_until_complete(go())
-- 
GitLab