added basic pattern for gremlin-python dsl development
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/e0dc97d0 Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/e0dc97d0 Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/e0dc97d0 Branch: refs/heads/tp32-glv Commit: e0dc97d0d8337f8808807b1dbf218202e2b0cced Parents: 2d574fb Author: davebshow <[email protected]> Authored: Mon May 8 17:47:37 2017 -0400 Committer: Stephen Mallette <[email protected]> Committed: Tue May 16 11:01:50 2017 -0400 ---------------------------------------------------------------------- .../python/GraphTraversalSourceGenerator.groovy | 13 +++-- .../gremlin_python/process/graph_traversal.py | 29 ++++++----- .../jython/gremlin_python/structure/graph.py | 6 ++- .../src/main/jython/tests/process/test_dsl.py | 54 ++++++++++++++++++++ 4 files changed, 84 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e0dc97d0/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/GraphTraversalSourceGenerator.groovy ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/GraphTraversalSourceGenerator.groovy b/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/GraphTraversalSourceGenerator.groovy index 1c66c35..c2e733f 100644 --- a/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/GraphTraversalSourceGenerator.groovy +++ b/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/GraphTraversalSourceGenerator.groovy @@ -75,8 +75,13 @@ under the License. if bytecode is None: bytecode = Bytecode() self.bytecode = bytecode + self.graph_traversal = GraphTraversal def __repr__(self): return "graphtraversalsource[" + str(self.graph) + "]" + def get_graph_traversal_source(self): + return self.__class__(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) + def get_graph_traversal(self): + return self.graph_traversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode)) """) GraphTraversalSource.getMethods(). // SOURCE STEPS findAll { GraphTraversalSource.class.equals(it.returnType) }. @@ -92,14 +97,14 @@ under the License. forEach { method -> pythonClass.append( """ def ${method}(self, *args): - source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) + source = self.get_graph_traversal_source() source.bytecode.add_source("${SymbolHelper.toJava(method)}", *args) return source """) } pythonClass.append( """ def withRemote(self, remote_connection): - source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) + source = self.get_graph_traversal_source() source.traversal_strategies.add_strategies([RemoteStrategy(remote_connection)]) return source def withComputer(self,graph_computer=None, workers=None, result=None, persist=None, vertices=None, edges=None, configuration=None): @@ -113,7 +118,7 @@ under the License. forEach { method -> pythonClass.append( """ def ${method}(self, *args): - traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode)) + traversal = self.get_graph_traversal() traversal.bytecode.add_step("${SymbolHelper.toJava(method)}", *args) return traversal """) @@ -126,7 +131,7 @@ under the License. pythonClass.append( """class GraphTraversal(Traversal): def __init__(self, graph, traversal_strategies, bytecode): - Traversal.__init__(self, graph, traversal_strategies, bytecode) + super(GraphTraversal, self).__init__(graph, traversal_strategies, bytecode) def __getitem__(self, index): if isinstance(index, int): return self.range(long(index), long(index + 1)) http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e0dc97d0/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py b/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py index e722215..ef49443 100644 --- a/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py +++ b/gremlin-python/src/main/jython/gremlin_python/process/graph_traversal.py @@ -32,59 +32,64 @@ class GraphTraversalSource(object): if bytecode is None: bytecode = Bytecode() self.bytecode = bytecode + self.graph_traversal = GraphTraversal def __repr__(self): return "graphtraversalsource[" + str(self.graph) + "]" + def get_graph_traversal_source(self): + return self.__class__(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) + def get_graph_traversal(self): + return self.graph_traversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode)) def withBulk(self, *args): - source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) + source = self.get_graph_traversal_source() source.bytecode.add_source("withBulk", *args) return source def withPath(self, *args): - source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) + source = self.get_graph_traversal_source() source.bytecode.add_source("withPath", *args) return source def withSack(self, *args): - source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) + source = self.get_graph_traversal_source() source.bytecode.add_source("withSack", *args) return source def withSideEffect(self, *args): - source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) + source = self.get_graph_traversal_source() source.bytecode.add_source("withSideEffect", *args) return source def withStrategies(self, *args): - source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) + source = self.get_graph_traversal_source() source.bytecode.add_source("withStrategies", *args) return source def withoutStrategies(self, *args): - source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) + source = self.get_graph_traversal_source() source.bytecode.add_source("withoutStrategies", *args) return source def withRemote(self, remote_connection): - source = GraphTraversalSource(self.graph, TraversalStrategies(self.traversal_strategies), Bytecode(self.bytecode)) + source = self.get_graph_traversal_source() source.traversal_strategies.add_strategies([RemoteStrategy(remote_connection)]) return source def withComputer(self,graph_computer=None, workers=None, result=None, persist=None, vertices=None, edges=None, configuration=None): return self.withStrategies(VertexProgramStrategy(graph_computer,workers,result,persist,vertices,edges,configuration)) def E(self, *args): - traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode)) + traversal = self.get_graph_traversal() traversal.bytecode.add_step("E", *args) return traversal def V(self, *args): - traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode)) + traversal = self.get_graph_traversal() traversal.bytecode.add_step("V", *args) return traversal def addV(self, *args): - traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode)) + traversal = self.get_graph_traversal() traversal.bytecode.add_step("addV", *args) return traversal def inject(self, *args): - traversal = GraphTraversal(self.graph, self.traversal_strategies, Bytecode(self.bytecode)) + traversal = self.get_graph_traversal() traversal.bytecode.add_step("inject", *args) return traversal class GraphTraversal(Traversal): def __init__(self, graph, traversal_strategies, bytecode): - Traversal.__init__(self, graph, traversal_strategies, bytecode) + super(GraphTraversal, self).__init__(graph, traversal_strategies, bytecode) def __getitem__(self, index): if isinstance(index, int): return self.range(long(index), long(index + 1)) http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e0dc97d0/gremlin-python/src/main/jython/gremlin_python/structure/graph.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/gremlin_python/structure/graph.py b/gremlin-python/src/main/jython/gremlin_python/structure/graph.py index d77cde1..7089dad 100644 --- a/gremlin-python/src/main/jython/gremlin_python/structure/graph.py +++ b/gremlin-python/src/main/jython/gremlin_python/structure/graph.py @@ -28,8 +28,10 @@ class Graph(object): if self.__class__ not in TraversalStrategies.global_cache: TraversalStrategies.global_cache[self.__class__] = TraversalStrategies() - def traversal(self): - return GraphTraversalSource(self, TraversalStrategies.global_cache[self.__class__]) + def traversal(self, traversal_source_class=None): + if not traversal_source_class: + traversal_source_class = GraphTraversalSource + return traversal_source_class(self, TraversalStrategies.global_cache[self.__class__]) def __repr__(self): return "graph[empty]" http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/e0dc97d0/gremlin-python/src/main/jython/tests/process/test_dsl.py ---------------------------------------------------------------------- diff --git a/gremlin-python/src/main/jython/tests/process/test_dsl.py b/gremlin-python/src/main/jython/tests/process/test_dsl.py new file mode 100644 index 0000000..ece81dc --- /dev/null +++ b/gremlin-python/src/main/jython/tests/process/test_dsl.py @@ -0,0 +1,54 @@ +''' +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 pytest + +from gremlin_python.process.graph_traversal import ( + GraphTraversalSource, GraphTraversal) +from gremlin_python.structure.graph import Graph + +__author__ = 'David M. Brown ([email protected])' + + +class SocialTraversalDsl(GraphTraversal): + + def knows(self, person_name): + return self.out("knows").hasLabel("person").has("name", person_name) + + def youngestFriendsAge(self): + return self.out("knows").hasLabel("person").values("age").min() + + +class SocialTraversalSourceDsl(GraphTraversalSource): + + def __init__(self, *args, **kwargs): + super(SocialTraversalSourceDsl, self).__init__(*args, **kwargs) + self.graph_traversal = SocialTraversalDsl + + def persons(self): + traversal = self.get_graph_traversal() + traversal.bytecode.add_step("V") + traversal.bytecode.add_step("hasLabel", "person") + return traversal + + +def test_dsl(remote_connection): + social = Graph().traversal(SocialTraversalSourceDsl).withRemote(remote_connection) + assert social.V().has("name", "marko").knows("josh").next() + assert social.V().has("name", "marko").youngestFriendsAge().next() == 27 + assert social.persons().count().next() == 4
