You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2020/09/14 20:42:23 UTC

[tinkerpop] 01/01: TINKERPOP-2296 support per-request options in python

This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch TINKERPOP-2296
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 4bc4d85a02a45871e33b73da3e784265df54b299
Author: Stephen Mallette <st...@amazon.com>
AuthorDate: Mon Sep 14 16:41:44 2020 -0400

    TINKERPOP-2296 support per-request options in python
---
 CHANGELOG.asciidoc                                 |  1 +
 docs/src/reference/gremlin-variants.asciidoc       | 32 +++++++++++-
 gremlin-python/glv/GraphTraversalSource.template   | 14 ++++-
 gremlin-python/glv/generate.groovy                 |  1 +
 .../main/jython/gremlin_python/driver/client.py    |  8 +--
 .../driver/driver_remote_connection.py             | 16 +++++-
 .../gremlin_python/process/graph_traversal.py      | 17 ++++--
 .../jython/gremlin_python/process/strategies.py    | 60 ++++++++++++----------
 .../tests/driver/test_driver_remote_connection.py  |  8 ++-
 .../main/jython/tests/process/test_strategies.py   | 11 ++++
 10 files changed, 128 insertions(+), 40 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index a1d822d..f441616 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -29,6 +29,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Removed `Connection` from `Connection Pool` when server closes a connection with no pending requests in Java Driver.
 * Improved initialization time of Java Driver if the default serializer is replaced.
 * Deprecated `withGraph()` in favor of `withEmbedded()` on `AnonymousTraversalSource`.
+* Added support for per-request level configurations, like timeouts, in Python.
 * Fixed bug in Javascript `Translator` that wasn't handling child traversals well.
 * Implemented `AutoCloseable` on `MultiIterator`.
 * Fixed an iterator leak in `HasContainer`.
diff --git a/docs/src/reference/gremlin-variants.asciidoc b/docs/src/reference/gremlin-variants.asciidoc
index 934e4ae..abf6952 100644
--- a/docs/src/reference/gremlin-variants.asciidoc
+++ b/docs/src/reference/gremlin-variants.asciidoc
@@ -215,6 +215,10 @@ GraphTraversalSource g = traversal().withRemote(conf);
 List<Vertex> vertices = g.with(Tokens.ARGS_EVAL_TIMEOUT, 500L).V().out("knows").toList()
 ----
 
+The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
+`evaluationTimeout` (formerly 'scriptEvaluationTimeout' which is also supported but now deprecated). Use of `Tokens`
+to reference these options is preferred.
+
 anchor:java-imports[]
 [[gremlin-java-imports]]
 === Common Imports
@@ -421,7 +425,7 @@ which will boost performance and reduce resources required on the server.
 
 There are a number of overloads to `Client.submit()` that accept a `RequestOptions` object. The `RequestOptions`
 provide a way to include options that are specific to the request made with the call to `submit()`. A good use-case for
-this feature is to set a per-request override to the `scriptEvaluationTimeout` so that it only applies to the current
+this feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current
 request.
 
 [source,java]
@@ -675,6 +679,17 @@ traversals to complete is acceptable, it might be helpful to set `pool_size` and
 See the <<python-configuration,Configuration>> section just below.  Examples where this could apply are serverless cloud functions or WSGI
 worker processes.
 
+Some connection options can also be set on individual requests made through the using `with()` step on the
+`TraversalSource`. For instance to set request timeout to 500 milliseconds:
+
+[source,python]
+----
+vertices = g.with_("evaluationTimeout", 500L).V().out("knows").toList()
+----
+
+The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
+`evaluationTimeout` (formerly 'scriptEvaluationTimeout' which is also supported but now deprecated).
+
 anchor:python-imports[]
 [[gremlin-python-imports]]
 === Common Imports
@@ -937,6 +952,21 @@ returns a `concurrent.futures.Future` that resolves to a list when it is complet
 <9> Verify that the all results have been read and stream is closed.
 <10> Close client and underlying pool connections.
 
+==== Per Request Settings
+
+The `client.submit()` functions accept a `request_options` which expects a dictionary. The `request_options`
+provide a way to include options that are specific to the request made with the call to `submit()`. A good use-case for
+this feature is to set a per-request override to the `evaluationTimeout` so that it only applies to the current
+request.
+
+[source,java]
+----
+result_set = client.submit("[1,2,3,4]", result_options={'evaluationTimeout': 5000})
+----
+
+The following options are allowed on a per-request basis in this fashion: `batchSize`, `requestId`, `userAgent` and
+`evaluationTimeout` (formerly 'scriptEvaluationTimeout' which is also supported but now deprecated).
+
 [[gremlin-python-dsl]]
 === Domain Specific Languages
 
diff --git a/gremlin-python/glv/GraphTraversalSource.template b/gremlin-python/glv/GraphTraversalSource.template
index 27d9e15..b8a4912 100644
--- a/gremlin-python/glv/GraphTraversalSource.template
+++ b/gremlin-python/glv/GraphTraversalSource.template
@@ -21,7 +21,7 @@ import sys
 import copy
 from .traversal import Traversal
 from .traversal import TraversalStrategies
-from .strategies import VertexProgramStrategy
+from .strategies import VertexProgramStrategy, OptionsStrategy
 from .traversal import Bytecode
 from ..driver.remote_connection import RemoteStrategy
 from .. import statics
@@ -51,6 +51,18 @@ class GraphTraversalSource(object):
         source.bytecode.add_source("<%= toJava.call(method) %>", *args)
         return source
 <% } %>
+    def with_(self, *args):
+        source = self.get_graph_traversal_source()
+        options_strategy = next((x for x in source.bytecode.source_instructions
+                                if x[0] == "withStrategies" and type(x[1]) is OptionsStrategy), None)
+        if options_strategy is None:
+            options_strategy = OptionsStrategy({args[0]: args[1]})
+            source = self.withStrategies(options_strategy)
+        else:
+            options_strategy[1].configuration[args[0]] = args[1]
+
+        return source
+
     def withRemote(self, remote_connection):
         source = self.get_graph_traversal_source()
         source.traversal_strategies.add_strategies([RemoteStrategy(remote_connection)])
diff --git a/gremlin-python/glv/generate.groovy b/gremlin-python/glv/generate.groovy
index 5011a40..214eb2f 100644
--- a/gremlin-python/glv/generate.groovy
+++ b/gremlin-python/glv/generate.groovy
@@ -90,6 +90,7 @@ def binding = ["enums": CoreImports.getClassImports()
                        findAll { GraphTraversalSource.class.equals(it.returnType) }.
                        findAll {
                            !it.name.equals("clone") &&
+                                   !it.name.equals(TraversalSource.Symbols.with) &&
                                    !it.name.equals(TraversalSource.Symbols.withRemote) &&
                                    !it.name.equals(TraversalSource.Symbols.withComputer)
                        }.
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/client.py b/gremlin-python/src/main/jython/gremlin_python/driver/client.py
index f43a054..2885e32 100644
--- a/gremlin-python/src/main/jython/gremlin_python/driver/client.py
+++ b/gremlin-python/src/main/jython/gremlin_python/driver/client.py
@@ -123,10 +123,10 @@ class Client:
             self._transport_factory, self._executor, self._pool,
             headers=self._headers)
 
-    def submit(self, message, bindings=None):
-        return self.submitAsync(message, bindings=bindings).result()
+    def submit(self, message, bindings=None, request_options=None):
+        return self.submitAsync(message, bindings=bindings, request_options=request_options).result()
 
-    def submitAsync(self, message, bindings=None):
+    def submitAsync(self, message, bindings=None, request_options=None):
         if isinstance(message, traversal.Bytecode):
             message = request.RequestMessage(
                 processor='traversal', op='bytecode',
@@ -143,4 +143,6 @@ class Client:
                 message = message._replace(processor='session')
                 message.args.update({'session': self._session})
         conn = self._pool.get(True)
+        if request_options:
+            message.args.update(request_options)
         return conn.write(message)
diff --git a/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py b/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
index 3b6a760..067f65b 100644
--- a/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
+++ b/gremlin-python/src/main/jython/gremlin_python/driver/driver_remote_connection.py
@@ -21,6 +21,7 @@ from concurrent.futures import Future
 from gremlin_python.driver import client, serializer
 from gremlin_python.driver.remote_connection import (
     RemoteConnection, RemoteTraversal, RemoteTraversalSideEffects)
+from gremlin_python.process.strategies import OptionsStrategy
 
 __author__ = 'David M. Brown (davebshow@gmail.com)'
 
@@ -52,7 +53,7 @@ class DriverRemoteConnection(RemoteConnection):
         self._client.close()
 
     def submit(self, bytecode):
-        result_set = self._client.submit(bytecode)
+        result_set = self._client.submit(bytecode, request_options=self._extract_request_options(bytecode))
         results = result_set.all().result()
         side_effects = RemoteTraversalSideEffects(result_set.request_id, self._client,
                                                   result_set.status_attributes)
@@ -60,7 +61,7 @@ class DriverRemoteConnection(RemoteConnection):
 
     def submitAsync(self, bytecode):
         future = Future()
-        future_result_set = self._client.submitAsync(bytecode)
+        future_result_set = self._client.submitAsync(bytecode, request_options=self._extract_request_options(bytecode))
 
         def cb(f):
             try:
@@ -74,3 +75,14 @@ class DriverRemoteConnection(RemoteConnection):
 
         future_result_set.add_done_callback(cb)
         return future
+
+    @staticmethod
+    def _extract_request_options(bytecode):
+        options_strategy = next((x for x in bytecode.source_instructions
+                                 if x[0] == "withStrategies" and type(x[1]) is OptionsStrategy), None)
+        request_options = None
+        if options_strategy:
+            allowed_keys = ['evaluationTimeout', 'scriptEvaluationTimeout', 'batchSize', 'requestId', 'userAgent']
+            request_options = {allowed: options_strategy[1].configuration[allowed] for allowed in allowed_keys
+                               if allowed in options_strategy[1].configuration}
+        return request_options
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 d47301b..edb10ac 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
@@ -21,7 +21,7 @@ import sys
 import copy
 from .traversal import Traversal
 from .traversal import TraversalStrategies
-from .strategies import VertexProgramStrategy
+from .strategies import VertexProgramStrategy, OptionsStrategy
 from .traversal import Bytecode
 from ..driver.remote_connection import RemoteStrategy
 from .. import statics
@@ -71,14 +71,21 @@ class GraphTraversalSource(object):
         source.bytecode.add_source("withStrategies", *args)
         return source
 
-    def with_(self, *args):
+    def withoutStrategies(self, *args):
         source = self.get_graph_traversal_source()
-        source.bytecode.add_source("with", *args)
+        source.bytecode.add_source("withoutStrategies", *args)
         return source
 
-    def withoutStrategies(self, *args):
+    def with_(self, *args):
         source = self.get_graph_traversal_source()
-        source.bytecode.add_source("withoutStrategies", *args)
+        options_strategy = next((x for x in source.bytecode.source_instructions
+                                if x[0] == "withStrategies" and type(x[1]) is OptionsStrategy), None)
+        if options_strategy is None:
+            options_strategy = OptionsStrategy({args[0]: args[1]})
+            source = self.withStrategies(options_strategy)
+        else:
+            options_strategy[1].configuration[args[0]] = args[1]
+
         return source
 
     def withRemote(self, remote_connection):
diff --git a/gremlin-python/src/main/jython/gremlin_python/process/strategies.py b/gremlin-python/src/main/jython/gremlin_python/process/strategies.py
index 8988b79..6d97b27 100644
--- a/gremlin-python/src/main/jython/gremlin_python/process/strategies.py
+++ b/gremlin-python/src/main/jython/gremlin_python/process/strategies.py
@@ -21,38 +21,45 @@ __author__ = 'Marko A. Rodriguez (http://markorodriguez.com)'
 
 from gremlin_python.process.traversal import TraversalStrategy
 
+base_namespace = 'org.apache.tinkerpop.gremlin.process.traversal.strategy.'
+decoration_namespace = base_namespace + 'decoration.'
+finalization_namespace = base_namespace + 'finalization.'
+optimization_namespace = base_namespace + 'optimization.'
+verification_namespace = base_namespace + 'verification.'
+computer_decoration_namespace = 'org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.'
 
 #########################
 # DECORATION STRATEGIES #
 #########################
 
+
 class ConnectiveStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ConnectiveStrategy")
+        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'ConnectiveStrategy')
 
 
 class ElementIdStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ElementIdStrategy")
+        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'ElementIdStrategy')
 
 
 # EventStrategy doesn't make sense outside JVM traversal machine
 
 class HaltedTraverserStrategy(TraversalStrategy):
     def __init__(self, halted_traverser_factory=None):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.HaltedTraverserStrategy")
+        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'HaltedTraverserStrategy')
         if halted_traverser_factory is not None:
             self.configuration["haltedTraverserFactory"] = halted_traverser_factory
 
 
 class OptionsStrategy(TraversalStrategy):
     def __init__(self, options=None):
-        TraversalStrategy.__init__(self, configuration=options, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy")
+        TraversalStrategy.__init__(self, configuration=options, fqcn=decoration_namespace + 'OptionsStrategy')
 
 
 class PartitionStrategy(TraversalStrategy):
     def __init__(self, partition_key=None, write_partition=None, read_partitions=None, include_meta_properties=None):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.PartitionStrategy")
+        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'PartitionStrategy')
         if partition_key is not None:
             self.configuration["partitionKey"] = partition_key
         if write_partition is not None:
@@ -66,7 +73,7 @@ class PartitionStrategy(TraversalStrategy):
 class SubgraphStrategy(TraversalStrategy):
 
     def __init__(self, vertices=None, edges=None, vertex_properties=None):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy")
+        TraversalStrategy.__init__(self, fqcn=decoration_namespace + 'SubgraphStrategy')
         if vertices is not None:
             self.configuration["vertices"] = vertices
         if edges is not None:
@@ -78,7 +85,7 @@ class SubgraphStrategy(TraversalStrategy):
 class VertexProgramStrategy(TraversalStrategy):
     def __init__(self, graph_computer=None, workers=None, persist=None, result=None, vertices=None, edges=None,
                  configuration=None):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.decoration.VertexProgramStrategy")
+        TraversalStrategy.__init__(self, fqcn=computer_decoration_namespace + 'VertexProgramStrategy')
         if graph_computer is not None:
             self.configuration["graphComputer"] = graph_computer
         if workers is not None:
@@ -101,7 +108,7 @@ class VertexProgramStrategy(TraversalStrategy):
 
 class MatchAlgorithmStrategy(TraversalStrategy):
     def __init__(self, match_algorithm=None):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization.MatchAlgorithmStrategy")
+        TraversalStrategy.__init__(self, fqcn=finalization_namespace + 'MatchAlgorithmStrategy')
         if match_algorithm is not None:
             self.configuration["matchAlgorithm"] = match_algorithm
 
@@ -112,73 +119,73 @@ class MatchAlgorithmStrategy(TraversalStrategy):
 
 class AdjacentToIncidentStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.AdjacentToIncidentStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'AdjacentToIncidentStrategy')
 
 
 class FilterRankingStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.FilterRankingStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'FilterRankingStrategy')
 
 
 class IdentityRemovalStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IdentityRemovalStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'IdentityRemovalStrategy')
 
 
 class IncidentToAdjacentStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.IncidentToAdjacentStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'IncidentToAdjacentStrategy')
 
 
 class InlineFilterStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.InlineFilterStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'InlineFilterStrategy')
 
 
 class LazyBarrierStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.LazyBarrierStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'LazyBarrierStrategy')
 
 
 class MatchPredicateStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.MatchPredicateStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'MatchPredicateStrategy')
 
 
 class OrderLimitStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.OrderLimitStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'OrderLimitStrategy')
 
 
 class PathProcessorStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.PathProcessorStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'PathProcessorStrategy')
 
 
 class PathRetractionStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.PathRetractionStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'PathRetractionStrategy')
 
 
 class CountStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.CountStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'CountStrategy')
 
 
 class RepeatUnrollStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.RepeatUnrollStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'RepeatUnrollStrategy')
 
 
 class GraphFilterStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.computer.traversal.strategy.optimization.GraphFilterStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'GraphFilterStrategy')
 
 
 
 class EarlyLimitStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.optimization.EarlyLimitStrategy")
+        TraversalStrategy.__init__(self, fqcn=optimization_namespace + 'EarlyLimitStrategy')
 
 ###########################
 # VERIFICATION STRATEGIES #
@@ -187,24 +194,23 @@ class EarlyLimitStrategy(TraversalStrategy):
 
 class LambdaRestrictionStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.LambdaRestrictionStrategy")
-
+        TraversalStrategy.__init__(self, fqcn=verification_namespace + 'LambdaRestrictionStrategy')
 
 class ReadOnlyStrategy(TraversalStrategy):
     def __init__(self):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReadOnlyStrategy")
+        TraversalStrategy.__init__(self, fqcn=verification_namespace + 'ReadOnlyStrategy')
 
 
 class EdgeLabelVerificationStrategy(TraversalStrategy):
     def __init__(self, log_warning=False, throw_exception=False):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.EdgeLabelVerificationStrategy")
+        TraversalStrategy.__init__(self, fqcn=verification_namespace + 'EdgeLabelVerificationStrategy')
         self.configuration["logWarning"] = log_warning
         self.configuration["throwException"] = throw_exception
 
 
 class ReservedKeysVerificationStrategy(TraversalStrategy):
     def __init__(self, log_warning=False, throw_exception=False, keys=["id", "label"]):
-        TraversalStrategy.__init__(self, fqcn="org.apache.tinkerpop.gremlin.process.traversal.strategy.verification.ReservedKeysVerificationStrategy")
+        TraversalStrategy.__init__(self, fqcn=verification_namespace + 'ReservedKeysVerificationStrategy')
         self.configuration["logWarning"] = log_warning
         self.configuration["throwException"] = throw_exception
         self.configuration["keys"] = keys
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 44d8dea..bc1d405 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
@@ -100,7 +100,6 @@ class TestDriverRemoteConnection(object):
         results = g.V().has('person', 'age', Bindings.of('x', lt(30))).count().next()
         assert 2 == results
 
-
     def test_lambda_traversals(self, remote_connection):
         statics.load_statics(globals())
         assert "remoteconnection[ws://localhost:45940/gremlin,gmodern]" == str(remote_connection)
@@ -194,6 +193,13 @@ class TestDriverRemoteConnection(object):
             assert False
         except GremlinServerError as gse:
             assert gse.status_code == 500
+        #
+        g = traversal().withRemote(remote_connection).with_("x", True).with_('evaluationTimeout', 10)
+        try:
+            g.inject(1).sideEffect(lambda: ("Thread.sleep(5000)", "gremlin-groovy")).iterate()
+            assert False
+        except GremlinServerError as gse:
+            assert gse.status_code == 598
 
     def test_side_effects(self, remote_connection):
         statics.load_statics(globals())
diff --git a/gremlin-python/src/main/jython/tests/process/test_strategies.py b/gremlin-python/src/main/jython/tests/process/test_strategies.py
index 4b03f8a..27394cc 100644
--- a/gremlin-python/src/main/jython/tests/process/test_strategies.py
+++ b/gremlin-python/src/main/jython/tests/process/test_strategies.py
@@ -77,6 +77,17 @@ class TestTraversalStrategies(object):
         assert LazyBarrierStrategy() == bytecode.source_instructions[1][2]
         assert 1 == len(bytecode.step_instructions)
         assert "V" == bytecode.step_instructions[0][0]
+        ###
+        g = Graph().traversal()
+        bytecode = g.with_("x", "test").with_("y", True).bytecode
+        assert 1 == len(bytecode.source_instructions)
+        assert 2 == len(bytecode.source_instructions[0])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert OptionsStrategy() == bytecode.source_instructions[0][1]
+        strategy = bytecode.source_instructions[0][1]
+        assert 2 == len(strategy.configuration)
+        assert "test" == strategy.configuration["x"]
+        assert strategy.configuration["y"]
 
     def test_configurable(self):
         g = Graph().traversal()