Repository: tinkerpop Updated Branches: refs/heads/master 16ec3ccc2 -> f9668cc62
TINKERPOP-1921 Added hasNext() 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/9dbd2d28 Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/9dbd2d28 Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/9dbd2d28 Branch: refs/heads/master Commit: 9dbd2d28b624ae262b359a7320fdcb5d7b207476 Parents: c029eef Author: Stephen Mallette <sp...@genoprime.com> Authored: Fri Sep 7 13:23:36 2018 -0400 Committer: Stephen Mallette <sp...@genoprime.com> Committed: Fri Sep 7 13:23:36 2018 -0400 ---------------------------------------------------------------------- CHANGELOG.asciidoc | 1 + gremlin-python/glv/TraversalSource.template | 40 ++++++++++++++++++++ .../jython/gremlin_python/process/traversal.py | 40 ++++++++++++++++++++ .../driver/test_driver_remote_connection.py | 39 +++++++++++++++++++ 4 files changed, 120 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9dbd2d28/CHANGELOG.asciidoc ---------------------------------------------------------------------- diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 158cc7a..8f14b8e 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -33,6 +33,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima * Match numbers in `choose()` options using `NumberHelper` (match values, ignore data type). * Added support for GraphSON serialization of `Date` in Javascript. * Added better internal processing of `Column` in `by(Function)`. +* Added `hasNext()` support on `Traversal` for `gremlin-python`. * Added support for additional extended types in Gremlin.Net with `decimal`, `TimeSpan`, `BigInteger`, `byte`, `byte[]`, `char` and `short`. * Fixed bug in Java driver where an disorderly shutdown of the server would cause the client to hang. * Added a dotnet template project that should make it easier to get started with Gremlin.Net. http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9dbd2d28/gremlin-python/glv/TraversalSource.template ---------------------------------------------------------------------- diff --git a/gremlin-python/glv/TraversalSource.template b/gremlin-python/glv/TraversalSource.template index b6f5b9f..a6ab9ad 100644 --- a/gremlin-python/glv/TraversalSource.template +++ b/gremlin-python/glv/TraversalSource.template @@ -29,15 +29,19 @@ class Traversal(object): self.side_effects = TraversalSideEffects() self.traversers = None self.last_traverser = None + def __repr__(self): return str(self.bytecode) + def __eq__(self, other): if isinstance(other, self.__class__): return self.bytecode == other.bytecode else: return False + def __iter__(self): return self + def __next__(self): if self.traversers is None: self.traversal_strategies.apply_strategies(self) @@ -48,14 +52,18 @@ class Traversal(object): if self.last_traverser.bulk <= 0: self.last_traverser = None return object + def toList(self): return list(iter(self)) + def toSet(self): return set(iter(self)) + def iterate(self): while True: try: self.nextTraverser() except StopIteration: return self + def nextTraverser(self): if self.traversers is None: self.traversal_strategies.apply_strategies(self) @@ -65,6 +73,15 @@ class Traversal(object): temp = self.last_traverser self.last_traverser = None return temp + + def hasNext(self): + if self.traversers is None: + self.traversal_strategies.apply_strategies(self) + if self.last_traverser is None: + try: self.last_traverser = next(self.traversers) + except StopIteration: return False + return not(self.last_traverser is None) and self.last_traverser.bulk > 0 + def next(self, amount=None): if amount is None: return self.__next__() @@ -77,6 +94,7 @@ class Traversal(object): except StopIteration: return tempList tempList.append(temp) return tempList + def promise(self, cb=None): self.traversal_strategies.apply_async_strategies(self) future_traversal = self.remote_results @@ -144,8 +162,10 @@ class Traverser(object): bulk = long(1) self.object = object self.bulk = bulk + def __repr__(self): return str(self.object) + def __eq__(self, other): return isinstance(other, self.__class__) and self.object == other.object @@ -156,10 +176,13 @@ TRAVERSAL SIDE-EFFECTS class TraversalSideEffects(object): def keys(self): return set() + def get(self, key): raise KeyError(key) + def __getitem__(self, key): return self.get(key) + def __repr__(self): return "sideEffects[size:" + str(len(self.keys())) + "]" @@ -171,14 +194,18 @@ class TraversalStrategies(object): global_cache = {} def __init__(self, traversal_strategies=None): self.traversal_strategies = traversal_strategies.traversal_strategies if traversal_strategies is not None else [] + def add_strategies(self, traversal_strategies): self.traversal_strategies = self.traversal_strategies + traversal_strategies + def apply_strategies(self, traversal): for traversal_strategy in self.traversal_strategies: traversal_strategy.apply(traversal) + def apply_async_strategies(self, traversal): for traversal_strategy in self.traversal_strategies: traversal_strategy.apply_async(traversal) + def __repr__(self): return str(self.traversal_strategies) @@ -187,14 +214,19 @@ class TraversalStrategy(object): def __init__(self, strategy_name=None, configuration=None): self.strategy_name = type(self).__name__ if strategy_name is None else strategy_name self.configuration = {} if configuration is None else configuration + def apply(self, traversal): return + def apply_async(self, traversal): return + def __eq__(self, other): return isinstance(other, self.__class__) + def __hash__(self): return hash(self.strategy_name) + def __repr__(self): return self.strategy_name @@ -210,21 +242,25 @@ class Bytecode(object): if bytecode is not None: self.source_instructions = list(bytecode.source_instructions) self.step_instructions = list(bytecode.step_instructions) + def add_source(self, source_name, *args): instruction = [source_name] for arg in args: instruction.append(self.__convertArgument(arg)) self.source_instructions.append(instruction) + def add_step(self, step_name, *args): instruction = [step_name] for arg in args: instruction.append(self.__convertArgument(arg)) self.step_instructions.append(instruction) + def __eq__(self, other): if isinstance(other, self.__class__): return self.source_instructions == other.source_instructions and self.step_instructions == other.step_instructions else: return False + def __convertArgument(self,arg): if isinstance(arg, Traversal): self.bindings.update(arg.bytecode.bindings) @@ -249,6 +285,7 @@ class Bytecode(object): return Binding(arg[0],self.__convertArgument(arg[1])) else: return arg + def __repr__(self): return (str(self.source_instructions) if len(self.source_instructions) > 0 else "") + \\ (str(self.step_instructions) if len(self.step_instructions) > 0 else "") @@ -268,9 +305,12 @@ class Binding(object): def __init__(self,key,value): self.key = key self.value = value + def __eq__(self, other): return isinstance(other, self.__class__) and self.key == other.key and self.value == other.value + def __hash__(self): return hash(self.key) + hash(self.value) + def __repr__(self): return "binding[" + self.key + "=" + str(self.value) + "]" \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9dbd2d28/gremlin-python/src/main/jython/gremlin_python/process/traversal.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py index 747ed81..73f8962 100644 --- a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py +++ b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py @@ -29,15 +29,19 @@ class Traversal(object): self.side_effects = TraversalSideEffects() self.traversers = None self.last_traverser = None + def __repr__(self): return str(self.bytecode) + def __eq__(self, other): if isinstance(other, self.__class__): return self.bytecode == other.bytecode else: return False + def __iter__(self): return self + def __next__(self): if self.traversers is None: self.traversal_strategies.apply_strategies(self) @@ -48,14 +52,18 @@ class Traversal(object): if self.last_traverser.bulk <= 0: self.last_traverser = None return object + def toList(self): return list(iter(self)) + def toSet(self): return set(iter(self)) + def iterate(self): while True: try: self.nextTraverser() except StopIteration: return self + def nextTraverser(self): if self.traversers is None: self.traversal_strategies.apply_strategies(self) @@ -65,6 +73,15 @@ class Traversal(object): temp = self.last_traverser self.last_traverser = None return temp + + def hasNext(self): + if self.traversers is None: + self.traversal_strategies.apply_strategies(self) + if self.last_traverser is None: + try: self.last_traverser = next(self.traversers) + except StopIteration: return False + return not(self.last_traverser is None) and self.last_traverser.bulk > 0 + def next(self, amount=None): if amount is None: return self.__next__() @@ -77,6 +94,7 @@ class Traversal(object): except StopIteration: return tempList tempList.append(temp) return tempList + def promise(self, cb=None): self.traversal_strategies.apply_async_strategies(self) future_traversal = self.remote_results @@ -313,8 +331,10 @@ class Traverser(object): bulk = long(1) self.object = object self.bulk = bulk + def __repr__(self): return str(self.object) + def __eq__(self, other): return isinstance(other, self.__class__) and self.object == other.object @@ -325,10 +345,13 @@ TRAVERSAL SIDE-EFFECTS class TraversalSideEffects(object): def keys(self): return set() + def get(self, key): raise KeyError(key) + def __getitem__(self, key): return self.get(key) + def __repr__(self): return "sideEffects[size:" + str(len(self.keys())) + "]" @@ -340,14 +363,18 @@ class TraversalStrategies(object): global_cache = {} def __init__(self, traversal_strategies=None): self.traversal_strategies = traversal_strategies.traversal_strategies if traversal_strategies is not None else [] + def add_strategies(self, traversal_strategies): self.traversal_strategies = self.traversal_strategies + traversal_strategies + def apply_strategies(self, traversal): for traversal_strategy in self.traversal_strategies: traversal_strategy.apply(traversal) + def apply_async_strategies(self, traversal): for traversal_strategy in self.traversal_strategies: traversal_strategy.apply_async(traversal) + def __repr__(self): return str(self.traversal_strategies) @@ -356,14 +383,19 @@ class TraversalStrategy(object): def __init__(self, strategy_name=None, configuration=None): self.strategy_name = type(self).__name__ if strategy_name is None else strategy_name self.configuration = {} if configuration is None else configuration + def apply(self, traversal): return + def apply_async(self, traversal): return + def __eq__(self, other): return isinstance(other, self.__class__) + def __hash__(self): return hash(self.strategy_name) + def __repr__(self): return self.strategy_name @@ -379,21 +411,25 @@ class Bytecode(object): if bytecode is not None: self.source_instructions = list(bytecode.source_instructions) self.step_instructions = list(bytecode.step_instructions) + def add_source(self, source_name, *args): instruction = [source_name] for arg in args: instruction.append(self.__convertArgument(arg)) self.source_instructions.append(instruction) + def add_step(self, step_name, *args): instruction = [step_name] for arg in args: instruction.append(self.__convertArgument(arg)) self.step_instructions.append(instruction) + def __eq__(self, other): if isinstance(other, self.__class__): return self.source_instructions == other.source_instructions and self.step_instructions == other.step_instructions else: return False + def __convertArgument(self,arg): if isinstance(arg, Traversal): self.bindings.update(arg.bytecode.bindings) @@ -418,6 +454,7 @@ class Bytecode(object): return Binding(arg[0],self.__convertArgument(arg[1])) else: return arg + def __repr__(self): return (str(self.source_instructions) if len(self.source_instructions) > 0 else "") + \ (str(self.step_instructions) if len(self.step_instructions) > 0 else "") @@ -437,9 +474,12 @@ class Binding(object): def __init__(self,key,value): self.key = key self.value = value + def __eq__(self, other): return isinstance(other, self.__class__) and self.key == other.key and self.value == other.value + def __hash__(self): return hash(self.key) + hash(self.value) + def __repr__(self): return "binding[" + self.key + "=" + str(self.value) + "]" \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/9dbd2d28/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py b/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py index 4d2409e..627fbe4 100644 --- a/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py +++ b/gremlin-python/src/main/jython/tests/driver/test_driver_remote_connection.py @@ -26,6 +26,7 @@ from gremlin_python.driver.driver_remote_connection import ( DriverRemoteConnection) from gremlin_python.process.traversal import Traverser from gremlin_python.process.traversal import TraversalStrategy +from gremlin_python.process.traversal import P from gremlin_python.process.graph_traversal import __ from gremlin_python.structure.graph import Graph from gremlin_python.structure.graph import Vertex @@ -82,6 +83,44 @@ class TestDriverRemoteConnection(object): assert 'marko' in results assert 'vadas' in results + def test_iteration(self, remote_connection): + statics.load_statics(globals()) + assert "remoteconnection[ws://localhost:45940/gremlin,gmodern]" == str(remote_connection) + g = Graph().traversal().withRemote(remote_connection) + + t = g.V().count() + assert t.hasNext() + assert t.hasNext() + assert t.hasNext() + assert t.hasNext() + assert t.hasNext() + assert 6 == t.next() + assert not(t.hasNext()) + assert not(t.hasNext()) + assert not(t.hasNext()) + assert not(t.hasNext()) + assert not(t.hasNext()) + + t = g.V().has('name', P.within('marko', 'peter')).values('name').order() + assert "marko" == t.next() + assert t.hasNext() + assert t.hasNext() + assert t.hasNext() + assert t.hasNext() + assert t.hasNext() + assert "peter" == t.next() + assert not(t.hasNext()) + assert not(t.hasNext()) + assert not(t.hasNext()) + assert not(t.hasNext()) + assert not(t.hasNext()) + + try: + t.next() + assert False + except StopIteration: + assert True + def test_strategies(self, remote_connection): statics.load_statics(globals()) #