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

Cole-Greer pushed a commit to branch 3.7-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/3.7-dev by this push:
     new 75429ec525 Fix gremlin-go PartitionStrategy panic and gremlin-python 
ProductiveByStrategy (#3531)
75429ec525 is described below

commit 75429ec525d1d6cc09118e839bd06487709bc1c9
Author: Guian Gumpac <[email protected]>
AuthorDate: Wed Jul 22 16:26:48 2026 -0700

    Fix gremlin-go PartitionStrategy panic and gremlin-python 
ProductiveByStrategy (#3531)
    
    Assisted-by: Kiro: Claude Opus 4.8
---
 CHANGELOG.asciidoc                                 |  2 ++
 gremlin-go/driver/strategies.go                    |  2 +-
 gremlin-go/driver/strategies_test.go               | 31 ++++++++++++++++++++++
 .../python/gremlin_python/process/strategies.py    |  2 ++
 .../python/tests/unit/process/test_strategies.py   | 12 +++++++++
 5 files changed, 48 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 67c31cc865..e7bb8dd607 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -35,6 +35,8 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 * Expanded `gremlin-python` CI matrix to test against Python 3.9, 3.10, 3.11, 
3.12, and 3.13.
 * Add Node 26 support for `gremlin-javascript` and `gremlint`.
 * Corrected numerous inaccuracies in the reference documentation, including 
wrong default values (connection pool sizes, buffer sizes, ports, timeouts), 
stale serializer class names, removed options documented as available, and 
broken code examples across the JVM, Python, `.NET`, Go, and JavaScript drivers.
+* Fixed a panic in `gremlin-go` `PartitionStrategy` when `ReadPartitions` was 
left unset.
+* Fixed `gremlin-python` `ProductiveByStrategy` to pass through the 
`productiveKeys` argument, which was previously accepted but never serialized 
to the server.
 
 [[release-3-7-6]]
 === TinkerPop 3.7.6 (Release Date: April 1, 2026)
diff --git a/gremlin-go/driver/strategies.go b/gremlin-go/driver/strategies.go
index b839a07276..5998747d62 100644
--- a/gremlin-go/driver/strategies.go
+++ b/gremlin-go/driver/strategies.go
@@ -86,7 +86,7 @@ func PartitionStrategy(config PartitionStrategyConfig) 
TraversalStrategy {
        if config.WritePartition != "" {
                configMap["writePartition"] = config.WritePartition
        }
-       if len(config.ReadPartitions.ToSlice()) != 0 {
+       if config.ReadPartitions != nil && len(config.ReadPartitions.ToSlice()) 
!= 0 {
                configMap["readPartitions"] = config.ReadPartitions
        }
        return &traversalStrategy{name: decorationNamespace + 
"PartitionStrategy", configuration: configMap}
diff --git a/gremlin-go/driver/strategies_test.go 
b/gremlin-go/driver/strategies_test.go
index 36095586f2..395b50fd71 100644
--- a/gremlin-go/driver/strategies_test.go
+++ b/gremlin-go/driver/strategies_test.go
@@ -414,3 +414,34 @@ func TestStrategy(t *testing.T) {
                assert.Equal(t, int32(6), val)
        })
 }
+
+func Test_StrategyConfig_partitionNilReadPartitions(t *testing.T) {
+       t.Run("Test PartitionStrategy with nil ReadPartitions does not panic", 
func(t *testing.T) {
+               config := PartitionStrategyConfig{
+                       PartitionKey:   "partition",
+                       WritePartition: "write",
+                       // ReadPartitions intentionally left unset (nil 
interface).
+               }
+               var strategy TraversalStrategy
+               assert.NotPanics(t, func() {
+                       strategy = PartitionStrategy(config)
+               })
+               assert.NotNil(t, strategy)
+               configMap := strategy.(*traversalStrategy).configuration
+               _, ok := configMap["readPartitions"]
+               assert.False(t, ok)
+       })
+
+       t.Run("Test PartitionStrategy with non-empty ReadPartitions sets 
readPartitions", func(t *testing.T) {
+               config := PartitionStrategyConfig{
+                       PartitionKey:   "partition",
+                       WritePartition: "write",
+                       ReadPartitions: NewSimpleSet("read"),
+               }
+               strategy := PartitionStrategy(config)
+               assert.NotNil(t, strategy)
+               configMap := strategy.(*traversalStrategy).configuration
+               _, ok := configMap["readPartitions"]
+               assert.True(t, ok)
+       })
+}
diff --git 
a/gremlin-python/src/main/python/gremlin_python/process/strategies.py 
b/gremlin-python/src/main/python/gremlin_python/process/strategies.py
index f4df2f2df8..10deb6bb26 100644
--- a/gremlin-python/src/main/python/gremlin_python/process/strategies.py
+++ b/gremlin-python/src/main/python/gremlin_python/process/strategies.py
@@ -188,6 +188,8 @@ class PathRetractionStrategy(TraversalStrategy):
 class ProductiveByStrategy(TraversalStrategy):
     def __init__(self, productiveKeys=None):
         TraversalStrategy.__init__(self, fqcn=optimization_namespace + 
'ProductiveByStrategy')
+        if productiveKeys is not None:
+            self.configuration["productiveKeys"] = productiveKeys
 
 
 class CountStrategy(TraversalStrategy):
diff --git 
a/gremlin-python/src/main/python/tests/unit/process/test_strategies.py 
b/gremlin-python/src/main/python/tests/unit/process/test_strategies.py
index faf5b95a78..1f8846e833 100644
--- a/gremlin-python/src/main/python/tests/unit/process/test_strategies.py
+++ b/gremlin-python/src/main/python/tests/unit/process/test_strategies.py
@@ -110,6 +110,18 @@ class TestTraversalStrategies(object):
         assert 1 == len(strategy.configuration)
         assert __.has("name","marko") == strategy.configuration["vertices"]
         ###
+        bytecode = 
g.withStrategies(ProductiveByStrategy(productiveKeys=["name", "age"])).bytecode
+        assert 1 == len(bytecode.source_instructions)
+        assert 2 == len(bytecode.source_instructions[0])
+        assert "withStrategies" == bytecode.source_instructions[0][0]
+        assert ProductiveByStrategy() == bytecode.source_instructions[0][1]
+        strategy = bytecode.source_instructions[0][1]
+        assert 1 == len(strategy.configuration)
+        assert ["name", "age"] == strategy.configuration["productiveKeys"]
+        ###
+        bytecode = g.withStrategies(ProductiveByStrategy()).bytecode
+        assert 0 == len(bytecode.source_instructions[0][1].configuration)
+        ###
         bytecode = g.withStrategies(OptionsStrategy(options={"x": "test", "y": 
True})).bytecode
         assert 1 == len(bytecode.source_instructions)
         assert 2 == len(bytecode.source_instructions[0])

Reply via email to