You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by ok...@apache.org on 2016/10/07 16:12:00 UTC

tinkerpop git commit: added and removing strategies from a traversal source in Python is sooooooooo elegant. Mapped the strategies from Gremlin JVM, to Python. Add a good body of test cases.

Repository: tinkerpop
Updated Branches:
  refs/heads/TINKERPOP-1455-redux 027959811 -> f84b19637


added and removing strategies from a traversal source in Python is sooooooooo elegant. Mapped the strategies from Gremlin JVM, to Python. Add a good body of test cases.


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

Branch: refs/heads/TINKERPOP-1455-redux
Commit: f84b196372f89479472e9a39a0d885a866c9cdb4
Parents: 0279598
Author: Marko A. Rodriguez <ok...@gmail.com>
Authored: Fri Oct 7 10:11:52 2016 -0600
Committer: Marko A. Rodriguez <ok...@gmail.com>
Committed: Fri Oct 7 10:11:52 2016 -0600

----------------------------------------------------------------------
 docs/src/reference/gremlin-variants.asciidoc    |  12 +-
 .../process/traversal/TraversalSource.java      |   3 -
 .../python/TraversalSourceGenerator.groovy      |  22 ++-
 .../jython/gremlin_python/process/strategies.py | 149 +++++++++++++++++++
 .../jython/gremlin_python/process/traversal.py  |  22 ++-
 .../src/main/jython/gremlin_python/statics.py   |   3 +-
 .../gremlin_python/structure/io/graphson.py     |  17 ++-
 .../driver/test_driver_remote_connection.py     |  11 +-
 .../jython/tests/process/test_strategies.py     | 106 +++++++++++++
 .../jython/tests/structure/io/test_graphson.py  |  17 ++-
 10 files changed, 340 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f84b1963/docs/src/reference/gremlin-variants.asciidoc
----------------------------------------------------------------------
diff --git a/docs/src/reference/gremlin-variants.asciidoc b/docs/src/reference/gremlin-variants.asciidoc
index 0001ba4..51e2d2b 100644
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@ -229,20 +229,22 @@ Traversal Strategies
 ~~~~~~~~~~~~~~~~~~~~
 
 In order to add and remove <<traversalstrategy,traversal strategies>> from a traversal source, Gremlin-Python has a
-`TraversalStrategy` class that can be used.
+`TraversalStrategy` class along with numerous subclasses that mirror the standard, distributed strategies.
 
 [gremlin-python,modern]
 ----
-g = g.withStrategies(TraversalStrategy('SubgraphStrategy',{'vertices': hasLabel('person'),'edges': has('weight',gt(0.5))}))
+g = g.withStrategies(SubgraphStrategy(vertices=hasLabel('person'),edges=has('weight',gt(0.5))))
 g.V().name.toList()
 g.V().outE().valueMap(True).toList()
-g = g.withoutStrategies(TraversalStrategy('SubgraphStrategy'))
+g = g.withoutStrategies(SubgraphStrategy)
 g.V().name.toList()
 g.V().outE().valueMap(True).toList()
 ----
 
-IMPORTANT: Future work will include extending the Gremlin-Python `TraversalStrategy` class with mirrors of the Java-based
-Gremlin traversal machine strategies so the two variants have the same look-and-feel.
+NOTE: Many of the `TraversalStrategy` classes in Gremlin-Python are proxies to the respective strategy on the
+Apache TinkerPop's JVM-based Gremlin traversal machine. As such, their `apply(Traversal)` method does nothing. However,
+the strategy is encoded in the Gremlin-Python bytecode and transmittable to the Gremlin traversal machine for
+re-construction machine-side.
 
 The Lambda Solution
 ~~~~~~~~~~~~~~~~~~~

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f84b1963/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java
index de77ea5..fa697f6 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/TraversalSource.java
@@ -33,9 +33,6 @@ import org.apache.tinkerpop.gremlin.util.function.ConstantSupplier;
 
 import java.io.Serializable;
 import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.function.BinaryOperator;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f84b1963/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy b/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy
index 9534a0c..a12fe05 100644
--- a/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy
+++ b/gremlin-python/src/main/groovy/org/apache/tinkerpop/gremlin/python/TraversalSourceGenerator.groovy
@@ -70,6 +70,11 @@ class Traversal(object):
         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):
@@ -220,14 +225,22 @@ class TraversalStrategies(object):
     def apply_strategies(self, traversal):
         for traversal_strategy in self.traversal_strategies:
             traversal_strategy.apply(traversal)
+    def __repr__(self):
+        return str(self.traversal_strategies)
 
 
 class TraversalStrategy(object):
-    def __init__(self, strategy_name, configuration=None):
-        self.strategy_name = strategy_name
+    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 __eq__(self, other):
+        return isinstance(other, self.__class__)
+    def __hash__(self):
+        return hash(self.strategy_name)
+    def __repr__(self):
+        return self.strategy_name
 
 '''
 BYTECODE
@@ -251,6 +264,11 @@ class Bytecode(object):
         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)

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f84b1963/gremlin-python/src/main/jython/gremlin_python/process/strategies.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/gremlin_python/process/strategies.py b/gremlin-python/src/main/jython/gremlin_python/process/strategies.py
new file mode 100644
index 0000000..db9e094
--- /dev/null
+++ b/gremlin-python/src/main/jython/gremlin_python/process/strategies.py
@@ -0,0 +1,149 @@
+'''
+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)'
+
+from gremlin_python.process.traversal import TraversalStrategy
+
+
+#########################
+# DECORATION STRATEGIES #
+#########################
+
+class ConnectiveStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class ElementIdStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class HaltedTraverserStrategy(TraversalStrategy):
+    def __init__(self, haltedTraverserFactory="detached"):
+        TraversalStrategy.__init__(self, configuration={"haltedTraverserFactory": haltedTraverserFactory})
+
+
+class PartitionStrategy(TraversalStrategy):
+    def __init__(self, partitionKey, writePartition=None, readPartitions=None, includeMetaProperties=False):
+        TraversalStrategy.__init__(self, configuration={"partitionKey": partitionKey,
+                                                        "includeMetaProperties": includeMetaProperties})
+        if writePartition is not None:
+            self.configuration["writePartition"] = writePartition
+        if writePartition is not None:
+            self.configuration["readPartitions"] = readPartitions
+
+
+class SubgraphStrategy(TraversalStrategy):
+    def __init__(self, vertices=None, edges=None, vertexProperties=None):
+        TraversalStrategy.__init__(self)
+        if vertices is not None:
+            self.configuration["vertices"] = vertices
+        if edges is not None:
+            self.configuration["edges"] = edges
+        if vertexProperties is not None:
+            self.configuration["vertexProperties"] = vertexProperties
+
+
+###########################
+# FINALIZATION STRATEGIES #
+###########################
+
+class MatchAlgorithmStrategy(TraversalStrategy):
+    def __init__(self, matchAlgorithm="count"):
+        TraversalStrategy.__init__(self, configuration={"matchAlgorithm": matchAlgorithm})
+
+
+###########################
+# OPTIMIZATION STRATEGIES #
+###########################
+
+class AdjacentToIncidentStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class FilterRankingStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class IdentityRemoveStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class IncidentToAdjacentStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class InlineFilterStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class LazyBarrierStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class MatchPredicateStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class OrderLimitStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class PathProcessorStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class PathRetractionStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class RangeByIsCountStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class RepeatUnrollStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+###########################
+# VERIFICATION STRATEGIES #
+###########################
+
+class LambdaRestrictionStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)
+
+
+class ReadOnlyStrategy(TraversalStrategy):
+    def __init__(self):
+        TraversalStrategy.__init__(self)

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f84b1963/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 6ca763e..4611541 100644
--- a/gremlin-python/src/main/jython/gremlin_python/process/traversal.py
+++ b/gremlin-python/src/main/jython/gremlin_python/process/traversal.py
@@ -33,6 +33,11 @@ class Traversal(object):
         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):
@@ -279,14 +284,22 @@ class TraversalStrategies(object):
     def apply_strategies(self, traversal):
         for traversal_strategy in self.traversal_strategies:
             traversal_strategy.apply(traversal)
+    def __repr__(self):
+        return str(self.traversal_strategies)
 
 
 class TraversalStrategy(object):
-    def __init__(self, strategy_name, configuration=None):
-        self.strategy_name = strategy_name
+    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 __eq__(self, other):
+        return isinstance(other, self.__class__)
+    def __hash__(self):
+        return hash(self.strategy_name)
+    def __repr__(self):
+        return self.strategy_name
 
 '''
 BYTECODE
@@ -310,6 +323,11 @@ class Bytecode(object):
         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)

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f84b1963/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 c827020..a1abf8e 100644
--- a/gremlin-python/src/main/jython/gremlin_python/statics.py
+++ b/gremlin-python/src/main/jython/gremlin_python/statics.py
@@ -28,12 +28,13 @@ if six.PY3:
     FloatType = float
     IntType = int
     LongType = long
+    TypeType = type
 else:
     long = long
     from types import FloatType
     from types import IntType
     from types import LongType
-
+    from types import TypeType
 
 staticMethods = {}
 staticEnums = {}

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f84b1963/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 63ea463..248d319 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
@@ -27,7 +27,7 @@ import six
 
 from gremlin_python import statics
 from gremlin_python.statics import (
-    FloatType, FunctionType, IntType, LongType, long)
+    FloatType, FunctionType, IntType, LongType, long, TypeType)
 from gremlin_python.process.traversal import Binding
 from gremlin_python.process.traversal import Bytecode
 from gremlin_python.process.traversal import P
@@ -183,6 +183,11 @@ class LambdaSerializer(GraphSONSerializer):
         return _SymbolHelper.objectify("Lambda", dict)
 
 
+class TypeSerializer(GraphSONSerializer):
+    def _dictify(self, clazz):
+        return GraphSONWriter._dictify(clazz())
+
+
 class NumberSerializer(GraphSONSerializer):
     def _dictify(self, number):
         if isinstance(number, bool):  # python thinks that 0/1 integers are booleans
@@ -280,8 +285,11 @@ class _SymbolHelper(object):
         return _SymbolHelper.symbolMap[symbol] if symbol in _SymbolHelper.symbolMap else symbol
 
     @staticmethod
-    def objectify(type, value, prefix="g"):
-        return {_SymbolHelper._TYPE: prefix + ":" + type, _SymbolHelper._VALUE: value}
+    def objectify(type, value=None, prefix="g"):
+        object = {_SymbolHelper._TYPE: prefix + ":" + type}
+        if value is not None:
+            object[_SymbolHelper._VALUE] = value
+        return object
 
 
 serializers = {
@@ -295,7 +303,8 @@ serializers = {
     LongType: NumberSerializer(),
     IntType: NumberSerializer(),
     FloatType: NumberSerializer(),
-    TraversalStrategy: TraversalStrategySerializer()
+    TypeType: TypeSerializer(),
+    TraversalStrategy: TraversalStrategySerializer(),
 }
 
 deserializers = {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f84b1963/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 847d14d..0de045a 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
@@ -31,6 +31,7 @@ from gremlin_python.process.graph_traversal import __
 from gremlin_python.structure.graph import Graph
 from gremlin_python.structure.graph import Vertex
 from gremlin_python.structure.io.graphson import GraphSONWriter
+from gremlin_python.process.strategies import SubgraphStrategy
 
 
 class TestDriverRemoteConnection(TestCase):
@@ -75,7 +76,15 @@ class TestDriverRemoteConnection(TestCase):
         assert 1 == g.V().label().dedup().count().next()
         assert "person" == g.V().label().dedup().next()
         #
-        g = g.withoutStrategies(TraversalStrategy("SubgraphStrategy")). \
+        g = Graph().traversal().withRemote(connection). \
+            withStrategies(SubgraphStrategy(vertices=__.hasLabel("person"), edges=__.hasLabel("created")))
+        print GraphSONWriter.writeObject(g.bytecode)
+        assert 4 == g.V().count().next()
+        assert 0 == g.E().count().next()
+        assert 1 == g.V().label().dedup().count().next()
+        assert "person" == g.V().label().dedup().next()
+        #
+        g = g.withoutStrategies(SubgraphStrategy). \
             withComputer({"workers": 4, "vertices": __.has("name", "marko"), "edges": __.limit(0)})
         assert 1 == g.V().count().next()
         assert 0 == g.E().count().next()

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f84b1963/gremlin-python/src/main/jython/tests/process/test_strategies.py
----------------------------------------------------------------------
diff --git a/gremlin-python/src/main/jython/tests/process/test_strategies.py b/gremlin-python/src/main/jython/tests/process/test_strategies.py
new file mode 100644
index 0000000..6d1d2c3
--- /dev/null
+++ b/gremlin-python/src/main/jython/tests/process/test_strategies.py
@@ -0,0 +1,106 @@
+'''
+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 unittest
+from unittest import TestCase
+
+from gremlin_python.structure.graph import Graph
+from gremlin_python.process.strategies import *
+from gremlin_python.process.graph_traversal import __
+
+
+class TestTraversalStrategies(TestCase):
+    def test_singletons(self):
+        g = Graph().traversal()
+        bytecode = g.withStrategies(ReadOnlyStrategy()).bytecode
+        assert 1 == len(bytecode.source_instructions)
+        assert 2 == len(bytecode.source_instructions[0])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[0][1]
+        assert "ReadOnlyStrategy" == str(bytecode.source_instructions[0][1])
+        assert hash(ReadOnlyStrategy()) == hash(bytecode.source_instructions[0][1])
+        assert 0 == len(g.traversal_strategies.traversal_strategies)  # these strategies are proxies
+        ##
+        g = g.withStrategies(ReadOnlyStrategy(), IncidentToAdjacentStrategy())
+        bytecode = g.bytecode
+        assert 1 == len(bytecode.source_instructions)
+        assert 3 == len(bytecode.source_instructions[0])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[0][1]
+        assert IncidentToAdjacentStrategy() == bytecode.source_instructions[0][2]
+        ##
+        bytecode = g.V().bytecode
+        assert 1 == len(bytecode.source_instructions)
+        assert 3 == len(bytecode.source_instructions[0])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[0][1]
+        assert IncidentToAdjacentStrategy() == bytecode.source_instructions[0][2]
+        assert 1 == len(bytecode.step_instructions)
+        assert "V" == bytecode.step_instructions[0][0]
+        ##
+        bytecode = g.withoutStrategies(ReadOnlyStrategy()).V().bytecode
+        assert 2 == len(bytecode.source_instructions)
+        assert 3 == len(bytecode.source_instructions[0])
+        assert 2 == len(bytecode.source_instructions[1])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[0][1]
+        assert IncidentToAdjacentStrategy() == bytecode.source_instructions[0][2]
+        assert "withoutStrategies" == bytecode.source_instructions[1][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[1][1]
+        assert 1 == len(bytecode.step_instructions)
+        assert "V" == bytecode.step_instructions[0][0]
+        ##
+        bytecode = g.withoutStrategies(ReadOnlyStrategy(), LazyBarrierStrategy()).V().bytecode
+        assert 2 == len(bytecode.source_instructions)
+        assert 3 == len(bytecode.source_instructions[0])
+        assert 3 == len(bytecode.source_instructions[1])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[0][1]
+        assert IncidentToAdjacentStrategy() == bytecode.source_instructions[0][2]
+        assert "withoutStrategies" == bytecode.source_instructions[1][0]
+        assert ReadOnlyStrategy() == bytecode.source_instructions[1][1]
+        assert LazyBarrierStrategy() == bytecode.source_instructions[1][2]
+        assert 1 == len(bytecode.step_instructions)
+        assert "V" == bytecode.step_instructions[0][0]
+
+    def test_configurable(self):
+        g = Graph().traversal()
+        bytecode = g.withStrategies(MatchAlgorithmStrategy("greedy")).bytecode
+        assert 1 == len(bytecode.source_instructions)
+        assert 2 == len(bytecode.source_instructions[0])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert MatchAlgorithmStrategy() == bytecode.source_instructions[0][1]
+        assert "MatchAlgorithmStrategy" == str(bytecode.source_instructions[0][1])
+        assert hash(MatchAlgorithmStrategy()) == hash(
+            bytecode.source_instructions[0][1])  # even though different confs, same strategy
+        assert 0 == len(g.traversal_strategies.traversal_strategies)  # these strategies are proxies
+        ###
+        bytecode = g.withStrategies(SubgraphStrategy(vertices=__.has("name","marko"))).bytecode
+        assert 1 == len(bytecode.source_instructions)
+        assert 2 == len(bytecode.source_instructions[0])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert SubgraphStrategy() == bytecode.source_instructions[0][1]
+        strategy = bytecode.source_instructions[0][1]
+        assert 1 == len(strategy.configuration)
+        assert __.has("name","marko") == strategy.configuration["vertices"]
+
+if __name__ == '__main__':
+    unittest.main()

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/f84b1963/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 99c9a45..615a0e2 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
@@ -25,12 +25,14 @@ from unittest import TestCase
 
 import six
 
-from gremlin_python.statics import long
+from gremlin_python.statics import *
 from gremlin_python.structure.graph import Vertex
 from gremlin_python.structure.graph import Path
 from gremlin_python.structure.io.graphson import GraphSONReader
 from gremlin_python.structure.io.graphson import GraphSONWriter
 from gremlin_python.process.traversal import P
+from gremlin_python.process.strategies import SubgraphStrategy
+from gremlin_python.process.graph_traversal import __
 
 
 class TestGraphSONReader(TestCase):
@@ -89,15 +91,22 @@ class TestGraphSONReader(TestCase):
 
 class TestGraphSONWriter(TestCase):
     def test_numbers(self):
-        assert {"@type":"g:Int64","@value":2} == json.loads(GraphSONWriter.writeObject(long(2)))
-        assert {"@type":"g:Int32","@value":1} == json.loads(GraphSONWriter.writeObject(1))
-        assert {"@type":"g:Float","@value":3.2} == json.loads(GraphSONWriter.writeObject(3.2))
+        assert {"@type": "g:Int64", "@value": 2} == json.loads(GraphSONWriter.writeObject(long(2)))
+        assert {"@type": "g:Int32", "@value": 1} == json.loads(GraphSONWriter.writeObject(1))
+        assert {"@type": "g:Float", "@value": 3.2} == json.loads(GraphSONWriter.writeObject(3.2))
         assert """true""" == GraphSONWriter.writeObject(True)
 
     def test_P(self):
         assert """{"@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"}}]}}""" == GraphSONWriter.writeObject(
             P.lt("b").or_(P.gt("c")).and_(P.neq("d")))
 
+    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"} == json.loads(GraphSONWriter.writeObject(SubgraphStrategy))
+        assert {"@type": "g:SubgraphStrategy", "@value": {
+            "vertices": {"@type": "g:Bytecode", "@value": {"step": [["has", "name", "marko"]]}}}} == json.loads(
+            GraphSONWriter.writeObject(SubgraphStrategy(vertices=__.has("name", "marko"))))
+
 
 if __name__ == '__main__':
     unittest.main()