From 7b2580e520f11b300e0987b5cd39e2fca552c1ce Mon Sep 17 00:00:00 2001 From: Yang Xia <55853655+xiazcy@users.noreply.github.com> Date: Thu, 14 Dec 2023 08:48:39 -0800 Subject: [PATCH] Add missing int16 serialization type to graphson in python (#2396) --- CHANGELOG.asciidoc | 1 + .../structure/io/graphsonV2d0.py | 26 ++++++++++++++++- .../structure/io/graphsonV3d0.py | 28 ++++++++++++++++++- .../main/python/tests/driver/test_client.py | 9 ++++++ .../tests/structure/io/test_graphsonV2d0.py | 8 ++++++ .../tests/structure/io/test_graphsonV3d0.py | 8 ++++++ 6 files changed, 78 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index fa3f2608fa7..59cd8b99403 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -24,6 +24,7 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima === TinkerPop 3.6.7 (NOT OFFICIALLY RELEASED YET) * Improved error message from `JavaTranslator` by including exception source. +* Added missing `short` serialization (`gx:Int16`) to GraphSONV2 and GraphSONV3 in `gremlin-python` * Added tests for error handling for GLV's if tx.commit() is called remotely for graphs without transactions support. * Introduced multi-architecture AMD64/ARM64 docker images for gremlin-console. * Fixed bug in `JavaTranslator` where `has(String, null)` could call `has(String, Traversal)` to generate an error. diff --git a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py index 1b05989ade3..d75dbb8ca02 100644 --- a/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py +++ b/gremlin-python/src/main/python/gremlin_python/structure/io/graphsonV2d0.py @@ -30,7 +30,7 @@ from isodate import parse_duration, duration_isoformat from gremlin_python import statics -from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, SingleByte, ByteBufferType, SingleChar +from gremlin_python.statics import FloatType, FunctionType, ShortType, IntType, LongType, TypeType, SingleByte, ByteBufferType, SingleChar from gremlin_python.process.traversal import Binding, Bytecode, P, TextP, Traversal, Traverser, TraversalStrategy from gremlin_python.structure.graph import Edge, Property, Vertex, VertexProperty, Path from gremlin_python.structure.io.util import SymbolUtil @@ -498,6 +498,30 @@ def dictify(cls, n, writer): return GraphSONUtil.typed_value(cls.graphson_base_type, n) +class Int16IO(Int64IO): + python_type = ShortType + graphson_type = "gx:Int16" + graphson_base_type = "Int16" + + @classmethod + def dictify(cls, n, writer): + # if we exceed Java int range then we need a long + if isinstance(n, bool): + return n + elif n < -9223372036854775808 or n > 9223372036854775807: + return GraphSONUtil.typed_value("BigInteger", str(n), "gx") + elif n < -2147483648 or n > 2147483647: + return GraphSONUtil.typed_value("Int64", n) + elif n < -32768 or n > 32767: + return GraphSONUtil.typed_value("Int32", n) + else: + return GraphSONUtil.typed_value(cls.graphson_base_type, n, "gx") + + @classmethod + def objectify(cls, v, _): + return int.__new__(ShortType, v) + + class ByteIO(_NumberIO): python_type = SingleByte graphson_type = "gx:Byte" 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 b7a165a5cde..e80bdbd45fc 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 @@ -14,6 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. + import calendar import datetime import json @@ -28,7 +29,7 @@ from isodate import parse_duration, duration_isoformat from gremlin_python import statics -from gremlin_python.statics import FloatType, FunctionType, IntType, LongType, TypeType, DictType, ListType, SetType, SingleByte, ByteBufferType, SingleChar +from gremlin_python.statics import FloatType, FunctionType, ShortType, IntType, LongType, TypeType, DictType, ListType, SetType, SingleByte, ByteBufferType, SingleChar from gremlin_python.process.traversal import Binding, Bytecode, Direction, P, TextP, Traversal, Traverser, TraversalStrategy, T from gremlin_python.structure.graph import Edge, Property, Vertex, VertexProperty, Path from gremlin_python.structure.io.util import HashableDict, SymbolUtil @@ -596,6 +597,31 @@ def dictify(cls, n, writer): else: return GraphSONUtil.typed_value(cls.graphson_base_type, n) + +class Int16IO(Int64IO): + python_type = ShortType + graphson_type = "gx:Int16" + graphson_base_type = "Int16" + + @classmethod + def dictify(cls, n, writer): + # if we exceed Java int range then we need a long + if isinstance(n, bool): + return n + elif n < -9223372036854775808 or n > 9223372036854775807: + return GraphSONUtil.typed_value("BigInteger", str(n), "gx") + elif n < -2147483648 or n > 2147483647: + return GraphSONUtil.typed_value("Int64", n) + elif n < -32768 or n > 32767: + return GraphSONUtil.typed_value("Int32", n) + else: + return GraphSONUtil.typed_value(cls.graphson_base_type, n, "gx") + + @classmethod + def objectify(cls, v, _): + return int.__new__(ShortType, v) + + class ByteIO(_NumberIO): python_type = SingleByte graphson_type = "gx:Byte" diff --git a/gremlin-python/src/main/python/tests/driver/test_client.py b/gremlin-python/src/main/python/tests/driver/test_client.py index a8de2fdd21c..221b825ea6d 100644 --- a/gremlin-python/src/main/python/tests/driver/test_client.py +++ b/gremlin-python/src/main/python/tests/driver/test_client.py @@ -278,6 +278,15 @@ def thread_run(tr, result_list): assert len(results[2][0]) == 6 assert results[3][0][0].object == 6 +def test_client_bytecode_with_short(client): + g = Graph().traversal() + t = g.V().has('age', short(16)).count() + message = RequestMessage('traversal', 'bytecode', {'gremlin': t.bytecode, 'aliases': {'g': 'gmodern'}}) + result_set = client.submit(message) + results = [] + for result in result_set: + results += result + assert len(results) == 1 def test_client_bytecode_with_long(client): g = Graph().traversal() diff --git a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py index 34aa44e37e5..a08ed95697e 100644 --- a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py +++ b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV2d0.py @@ -47,6 +47,12 @@ def test_number_input(self): })) assert isinstance(x, SingleByte) assert 1 == x + x = self.graphson_reader.read_object(json.dumps({ + "@type": "gx:Int16", + "@value": 16 + })) + assert isinstance(x, short) + assert 16 == x x = self.graphson_reader.read_object(json.dumps({ "@type": "g:Int32", "@value": 31 @@ -297,6 +303,8 @@ class TestGraphSONWriter(object): def test_numbers(self): assert {"@type": "gx:Byte", "@value": 1} == json.loads(self.graphson_writer.write_object(int.__new__(SingleByte, 1))) + assert {"@type": "gx:Int16", "@value": 16} == json.loads(self.graphson_writer.write_object(short(16))) + assert {"@type": "gx:Int16", "@value": -16} == json.loads(self.graphson_writer.write_object(short(-16))) assert {"@type": "g:Int64", "@value": 2} == json.loads(self.graphson_writer.write_object(long(2))) assert {"@type": "g:Int64", "@value": 851401972585122} == json.loads(self.graphson_writer.write_object(long(851401972585122))) assert {"@type": "g:Int64", "@value": -2} == json.loads(self.graphson_writer.write_object(long(-2))) diff --git a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py index 250c70a0e1b..6b852fbf68f 100644 --- a/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py +++ b/gremlin-python/src/main/python/tests/structure/io/test_graphsonV3d0.py @@ -93,6 +93,12 @@ def test_number_input(self): })) assert isinstance(x, SingleByte) assert 1 == x + x = self.graphson_reader.read_object(json.dumps({ + "@type": "gx:Int16", + "@value": 16 + })) + assert isinstance(x, short) + assert 16 == x x = self.graphson_reader.read_object(json.dumps({ "@type": "g:Int32", "@value": 31 @@ -357,6 +363,8 @@ def test_collections(self): def test_numbers(self): assert {"@type": "gx:Byte", "@value": 1} == json.loads(self.graphson_writer.write_object(int.__new__(SingleByte, 1))) + assert {"@type": "gx:Int16", "@value": 16} == json.loads(self.graphson_writer.write_object(short(16))) + assert {"@type": "gx:Int16", "@value": -16} == json.loads(self.graphson_writer.write_object(short(-16))) assert {"@type": "g:Int64", "@value": 2} == json.loads(self.graphson_writer.write_object(long(2))) assert {"@type": "g:Int64", "@value": 851401972585122} == json.loads(self.graphson_writer.write_object(long(851401972585122))) assert {"@type": "g:Int64", "@value": -2} == json.loads(self.graphson_writer.write_object(long(-2)))