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

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

commit 163e1d03bbb49565f2082a572fddd0d3b89e50d8
Author: Yang Xia <[email protected]>
AuthorDate: Wed Mar 25 16:07:44 2026 -0700

    coerce set into list when it contains non-hashable elements
---
 .../gremlin_python/structure/io/graphbinaryV1.py   |  4 +-
 .../gremlin_python/structure/io/graphsonV3d0.py    |  6 ++-
 .../driver/test_driver_remote_connection.py        |  5 ++-
 .../python/tests/unit/io/test_graphbinaryV1.py     | 44 +++++++---------------
 .../main/python/tests/unit/io/test_graphsonV3d0.py | 21 +++++------
 5 files changed, 33 insertions(+), 47 deletions(-)

diff --git 
a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py 
b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py
index b9b3338d82..39a0c3a678 100644
--- 
a/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py
+++ 
b/gremlin-python/src/main/python/gremlin_python/structure/io/graphbinaryV1.py
@@ -524,7 +524,9 @@ class SetDeserializer(ListIO):
         try:
             return set(the_list)
         except TypeError:
-            return set(HashableDict.of(e) for e in the_list)
+            log.warning("Coercing Set to list as it contains unhashable 
elements (e.g. dict, list). "
+                        "See TINKERPOP-3232 for more details.")
+            return the_list
 
 
 class MapIO(_GraphBinaryTypeIO):
diff --git 
a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py 
b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py
index 4d25816abd..c032e2fd88 100644
--- a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py
+++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV3d0.py
@@ -440,14 +440,16 @@ class SetIO(_GraphSONTypeIO):
         See comments of TINKERPOP-1844 for more details
 
         In case the set contains non-hashable elements (e.g. dict, list),
-        use HashableDict.of() to make them hashable.
+        coerce and return a list.
         See TINKERPOP-3232 for more details
         """
         new_list = [reader.to_object(obj) for obj in s]
         try:
             new_set = set(new_list)
         except TypeError:
-            new_set = set(HashableDict.of(e) for e in new_list)
+            log.warning("Coercing g:Set to list as it contains unhashable 
elements (e.g. dict, list). "
+                        "See TINKERPOP-3232 for more details.")
+            return new_list
         if len(new_list) != len(new_set):
             log.warning("Coercing g:Set to list due to java numeric values. "
                         "See TINKERPOP-1844 for more details.")
diff --git 
a/gremlin-python/src/main/python/tests/integration/driver/test_driver_remote_connection.py
 
b/gremlin-python/src/main/python/tests/integration/driver/test_driver_remote_connection.py
index 72f45b8aa9..77e5516614 100644
--- 
a/gremlin-python/src/main/python/tests/integration/driver/test_driver_remote_connection.py
+++ 
b/gremlin-python/src/main/python/tests/integration/driver/test_driver_remote_connection.py
@@ -152,11 +152,12 @@ class TestDriverRemoteConnection(object):
             return
         g = traversal().withRemote(remote_connection)
         # g.V().valueMap().dedup(Scope.local) returns a Set of Map results 
which previously
-        # threw TypeError because Python sets cannot contain unhashable dict 
elements
+        # threw TypeError because Python sets cannot contain unhashable dict 
elements.
+        # The Set is now coerced to a list when it contains unhashable 
elements.
         results = g.V().valueMap().dedup(Scope.local).toList()
         assert len(results) > 0
         for r in results:
-            assert isinstance(r, set)
+            assert isinstance(r, list)
 
     def test_lambda_traversals(self, remote_connection):
         statics.load_statics(globals())
diff --git a/gremlin-python/src/main/python/tests/unit/io/test_graphbinaryV1.py 
b/gremlin-python/src/main/python/tests/unit/io/test_graphbinaryV1.py
index 30105c6659..b1234369c1 100644
--- a/gremlin-python/src/main/python/tests/unit/io/test_graphbinaryV1.py
+++ b/gremlin-python/src/main/python/tests/unit/io/test_graphbinaryV1.py
@@ -24,7 +24,6 @@ import math
 from gremlin_python.statics import timestamp, long, bigint, BigDecimal, 
SingleByte, SingleChar, ByteBufferType
 from gremlin_python.structure.graph import Vertex, Edge, Property, 
VertexProperty, Path
 from gremlin_python.structure.io.graphbinaryV1 import GraphBinaryWriter, 
GraphBinaryReader
-from gremlin_python.structure.io.util import HashableDict
 from gremlin_python.process.traversal import Barrier, Binding, Bytecode, 
Merge, Direction
 
 
@@ -124,62 +123,45 @@ class TestGraphSONWriter(object):
         assert x == output
 
     def test_set_with_unhashable_dict_elements(self):
-        # test that sets containing dicts can be deserialized - see 
TINKERPOP-3232
+        # test that sets containing dicts are coerced to list - see 
TINKERPOP-3232
         x = [{"name": "marko", "age": 29}, {"name": "josh", "age": 32}]
-        output = 
self.graphbinary_reader.read_object(self.graphbinary_writer.write_object(set(
-            HashableDict.of(e) for e in x)))
-        assert isinstance(output, set)
+        list_payload = self.graphbinary_writer.write_object(x)
+        # patch outer type from list (0x09) to set (0x0b)
+        set_payload = bytearray(list_payload)
+        set_payload[0] = 0x0b
+        output = self.graphbinary_reader.read_object(set_payload)
+        assert isinstance(output, list)
         assert len(output) == 2
 
     def test_set_with_unhashable_list_elements(self):
-        # test that sets containing lists can be deserialized - see 
TINKERPOP-3232
-        # build a set payload manually: write as list-of-lists, then patch the 
type byte to set
+        # test that sets containing lists are coerced to list - see 
TINKERPOP-3232
         list_payload = self.graphbinary_writer.write_object([["marko", 
"josh"], ["vadas", "peter"]])
         # the first byte is the DataType for list (0x09), change it to set 
(0x0b)
         set_payload = bytearray(list_payload)
         set_payload[0] = 0x0b
         output = self.graphbinary_reader.read_object(set_payload)
-        assert isinstance(output, set)
-        assert len(output) == 2
-
-    def test_set_with_unhashable_set_elements(self):
-        # test that sets containing sets can be deserialized - see 
TINKERPOP-3232
-        # build a set-of-sets payload: write as list-of-lists, patch outer and 
inner type bytes
-        inner1 = self.graphbinary_writer.write_object(["a", "b"])
-        inner2 = self.graphbinary_writer.write_object(["c", "d"])
-        # patch inner payloads from list (0x09) to set (0x0b)
-        inner1 = bytearray(inner1)
-        inner1[0] = 0x0b
-        inner2 = bytearray(inner2)
-        inner2[0] = 0x0b
-        # build outer set: type byte (set=0x0b) + nullable (0x00) + count (2) 
+ inner payloads
-        import struct
-        outer = bytearray([0x0b, 0x00]) + struct.pack('>i', 2) + inner1 + 
inner2
-        output = self.graphbinary_reader.read_object(outer)
-        assert isinstance(output, set)
+        assert isinstance(output, list)
         assert len(output) == 2
 
     def test_set_with_mixed_hashable_and_unhashable_elements(self):
-        # test that sets containing a mix of hashable and unhashable elements 
work - see TINKERPOP-3232
-        # build payload: write a list of [string, dict, int], then patch type 
to set
+        # test that sets containing a mix of hashable and unhashable elements 
are coerced to list - see TINKERPOP-3232
         x = ["marko", {"name": "josh"}, 42]
         list_payload = self.graphbinary_writer.write_object(x)
         set_payload = bytearray(list_payload)
         set_payload[0] = 0x0b
         output = self.graphbinary_reader.read_object(set_payload)
-        assert isinstance(output, set)
+        assert isinstance(output, list)
         assert len(output) == 3
 
     def test_set_with_nested_unhashable_elements(self):
-        # test that sets containing dicts with list values can be deserialized 
- see TINKERPOP-3232
-        # build payload manually since HashableDict.of() converts lists to 
tuples which can't be serialized
+        # test that sets containing dicts with list values are coerced to list 
- see TINKERPOP-3232
         x = [{"name": "marko", "langs": ["java", "python"]}, {"name": "josh", 
"langs": ["gremlin"]}]
         list_payload = self.graphbinary_writer.write_object(x)
         # patch outer type from list (0x09) to set (0x0b)
         set_payload = bytearray(list_payload)
         set_payload[0] = 0x0b
         output = self.graphbinary_reader.read_object(set_payload)
-        assert isinstance(output, set)
+        assert isinstance(output, list)
         assert len(output) == 2
 
     def test_dict(self):
diff --git a/gremlin-python/src/main/python/tests/unit/io/test_graphsonV3d0.py 
b/gremlin-python/src/main/python/tests/unit/io/test_graphsonV3d0.py
index 027fb3a4bd..3a03fff7cd 100644
--- a/gremlin-python/src/main/python/tests/unit/io/test_graphsonV3d0.py
+++ b/gremlin-python/src/main/python/tests/unit/io/test_graphsonV3d0.py
@@ -32,7 +32,6 @@ from gremlin_python.statics import *
 from gremlin_python.structure.graph import Vertex, Edge, Property, 
VertexProperty, Path
 from gremlin_python.structure.io.graphsonV3d0 import GraphSONWriter, 
GraphSONReader, GraphSONUtil
 import gremlin_python.structure.io.graphsonV3d0
-from gremlin_python.structure.io.util import HashableDict
 from gremlin_python.process.traversal import P, Merge, Barrier, Order, 
Operator, Direction
 from gremlin_python.process.strategies import SubgraphStrategy
 from gremlin_python.process.graph_traversal import __
@@ -88,48 +87,48 @@ class TestGraphSONReader:
         assert x.count("josh") == 3
 
     def test_set_with_unhashable_dict_elements(self):
-        # test that sets containing dicts can be deserialized - see 
TINKERPOP-3232
+        # test that sets containing dicts are coerced to list - see 
TINKERPOP-3232
         x = self.graphson_reader.read_object(
             json.dumps({"@type": "g:Set", "@value": [
                 {"@type": "g:Map", "@value": ["name", "marko", "age", 
{"@type": "g:Int32", "@value": 29}]},
                 {"@type": "g:Map", "@value": ["name", "josh", "age", {"@type": 
"g:Int32", "@value": 32}]}
             ]}))
-        assert isinstance(x, set)
+        assert isinstance(x, list)
         assert len(x) == 2
 
     def test_set_with_unhashable_list_elements(self):
-        # test that sets containing lists can be deserialized - see 
TINKERPOP-3232
+        # test that sets containing lists are coerced to list - see 
TINKERPOP-3232
         x = self.graphson_reader.read_object(
             json.dumps({"@type": "g:Set", "@value": [
                 {"@type": "g:List", "@value": ["marko", "josh"]},
                 {"@type": "g:List", "@value": ["vadas", "peter"]}
             ]}))
-        assert isinstance(x, set)
+        assert isinstance(x, list)
         assert len(x) == 2
 
     def test_set_with_unhashable_set_elements(self):
-        # test that sets containing sets can be deserialized - see 
TINKERPOP-3232
+        # test that sets containing sets are coerced to list - see 
TINKERPOP-3232
         x = self.graphson_reader.read_object(
             json.dumps({"@type": "g:Set", "@value": [
                 {"@type": "g:Set", "@value": ["a", "b"]},
                 {"@type": "g:Set", "@value": ["c", "d"]}
             ]}))
-        assert isinstance(x, set)
+        assert isinstance(x, list)
         assert len(x) == 2
 
     def test_set_with_mixed_hashable_and_unhashable_elements(self):
-        # test that sets containing a mix of hashable and unhashable elements 
work - see TINKERPOP-3232
+        # test that sets containing a mix of hashable and unhashable elements 
are coerced to list - see TINKERPOP-3232
         x = self.graphson_reader.read_object(
             json.dumps({"@type": "g:Set", "@value": [
                 "marko",
                 {"@type": "g:Map", "@value": ["name", "josh"]},
                 {"@type": "g:Int32", "@value": 42}
             ]}))
-        assert isinstance(x, set)
+        assert isinstance(x, list)
         assert len(x) == 3
 
     def test_set_with_nested_unhashable_elements(self):
-        # test that sets containing dicts with list values can be deserialized 
- see TINKERPOP-3232
+        # test that sets containing dicts with list values are coerced to list 
- see TINKERPOP-3232
         x = self.graphson_reader.read_object(
             json.dumps({"@type": "g:Set", "@value": [
                 {"@type": "g:Map", "@value": [
@@ -141,7 +140,7 @@ class TestGraphSONReader:
                     "langs", {"@type": "g:List", "@value": ["gremlin"]}
                 ]}
             ]}))
-        assert isinstance(x, set)
+        assert isinstance(x, list)
         assert len(x) == 2
 
     def test_number_input(self):

Reply via email to