gremlinpython 4.0.0b2__py3-none-any.whl → 4.0.0.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gremlin_python/__init__.py +1 -1
- gremlin_python/driver/aiohttp/transport.py +257 -85
- gremlin_python/driver/auth.py +46 -21
- gremlin_python/driver/client.py +89 -61
- gremlin_python/driver/connection.py +123 -19
- gremlin_python/driver/driver_remote_connection.py +16 -39
- gremlin_python/driver/{transport.py → exceptions.py} +10 -24
- gremlin_python/driver/http_request.py +65 -0
- gremlin_python/driver/request.py +3 -2
- gremlin_python/driver/resultset.py +11 -5
- gremlin_python/driver/serializer.py +50 -130
- gremlin_python/driver/transaction.py +178 -0
- gremlin_python/driver/useragent.py +1 -1
- gremlin_python/process/graph_traversal.py +210 -93
- gremlin_python/process/traversal.py +114 -51
- gremlin_python/structure/graph.py +450 -5
- gremlin_python/structure/io/graphbinaryV4.py +177 -37
- {gremlinpython-4.0.0b2.dist-info → gremlinpython-4.0.0.dev1.dist-info}/METADATA +7 -5
- gremlinpython-4.0.0.dev1.dist-info/RECORD +33 -0
- {gremlinpython-4.0.0b2.dist-info → gremlinpython-4.0.0.dev1.dist-info}/WHEEL +1 -1
- gremlin_python/driver/protocol.py +0 -175
- gremlin_python/structure/io/graphsonV4.py +0 -599
- gremlinpython-4.0.0b2.dist-info/RECORD +0 -33
- {gremlinpython-4.0.0b2.dist-info → gremlinpython-4.0.0.dev1.dist-info}/licenses/LICENSE +0 -0
- {gremlinpython-4.0.0b2.dist-info → gremlinpython-4.0.0.dev1.dist-info}/licenses/NOTICE +0 -0
- {gremlinpython-4.0.0b2.dist-info → gremlinpython-4.0.0.dev1.dist-info}/top_level.txt +0 -0
|
@@ -19,16 +19,18 @@
|
|
|
19
19
|
|
|
20
20
|
import copy
|
|
21
21
|
import math
|
|
22
|
+
import re
|
|
22
23
|
import threading
|
|
23
24
|
import uuid
|
|
24
25
|
import warnings
|
|
25
26
|
|
|
26
27
|
from aenum import Enum
|
|
27
|
-
from gremlin_python.structure.graph import Vertex, Edge, Path, Property
|
|
28
|
+
from gremlin_python.structure.graph import Vertex, Edge, Path, Property, CompositePDT, PrimitivePDT
|
|
28
29
|
|
|
29
30
|
from .. import statics
|
|
30
|
-
from ..statics import long, SingleByte, short, bigint, BigDecimal
|
|
31
|
-
from datetime import datetime
|
|
31
|
+
from ..statics import long, SingleByte, SingleChar, short, bigint, BigDecimal
|
|
32
|
+
from datetime import datetime, timedelta
|
|
33
|
+
import base64
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
class Traversal(object):
|
|
@@ -358,6 +360,8 @@ class P(object):
|
|
|
358
360
|
return P("within", args[0])
|
|
359
361
|
elif len(args) == 1 and type(args[0]) == set:
|
|
360
362
|
return P("within", list(args[0]))
|
|
363
|
+
elif len(args) == 1 and isinstance(args[0], Traversal):
|
|
364
|
+
return P("within", args[0])
|
|
361
365
|
else:
|
|
362
366
|
return P("within", list(args))
|
|
363
367
|
|
|
@@ -367,6 +371,8 @@ class P(object):
|
|
|
367
371
|
return P("without", args[0])
|
|
368
372
|
elif len(args) == 1 and type(args[0]) == set:
|
|
369
373
|
return P("without", list(args[0]))
|
|
374
|
+
elif len(args) == 1 and isinstance(args[0], Traversal):
|
|
375
|
+
return P("without", args[0])
|
|
370
376
|
else:
|
|
371
377
|
return P("without", list(args))
|
|
372
378
|
|
|
@@ -813,13 +819,13 @@ class GremlinLang(object):
|
|
|
813
819
|
self.gremlin = []
|
|
814
820
|
self.parameters = {}
|
|
815
821
|
self.options_strategies = []
|
|
816
|
-
self.
|
|
822
|
+
self.pdt_registry = None
|
|
817
823
|
|
|
818
824
|
if gremlin_lang is not None:
|
|
819
825
|
self.gremlin = list(gremlin_lang.gremlin)
|
|
820
826
|
self.parameters = dict(gremlin_lang.parameters)
|
|
821
827
|
self.options_strategies = list(gremlin_lang.options_strategies)
|
|
822
|
-
self.
|
|
828
|
+
self.pdt_registry = gremlin_lang.pdt_registry
|
|
823
829
|
|
|
824
830
|
def _add_to_gremlin(self, string_name, *args):
|
|
825
831
|
|
|
@@ -844,6 +850,9 @@ class GremlinLang(object):
|
|
|
844
850
|
if arg is None:
|
|
845
851
|
return 'null'
|
|
846
852
|
|
|
853
|
+
if isinstance(arg, SingleChar):
|
|
854
|
+
return f'{arg!r}c'
|
|
855
|
+
|
|
847
856
|
if isinstance(arg, str):
|
|
848
857
|
return f'{arg!r}' # use repr() format for canonical string rep
|
|
849
858
|
# return f'"{arg}"'
|
|
@@ -879,6 +888,20 @@ class GremlinLang(object):
|
|
|
879
888
|
if isinstance(arg, uuid.UUID):
|
|
880
889
|
return f'UUID("{arg}")'
|
|
881
890
|
|
|
891
|
+
if isinstance(arg, timedelta):
|
|
892
|
+
is_negative = arg.total_seconds() < 0
|
|
893
|
+
abs_td = -arg if is_negative else arg
|
|
894
|
+
# Use integer components directly to avoid float precision loss
|
|
895
|
+
seconds = abs_td.days * 86400 + abs_td.seconds
|
|
896
|
+
nanos = abs_td.microseconds * 1000
|
|
897
|
+
if is_negative:
|
|
898
|
+
return f'Duration({seconds},{nanos},false)'
|
|
899
|
+
else:
|
|
900
|
+
return f'Duration({seconds},{nanos})'
|
|
901
|
+
|
|
902
|
+
if isinstance(arg, bytes):
|
|
903
|
+
return f'Binary("{base64.b64encode(arg).decode("ascii")}")'
|
|
904
|
+
|
|
882
905
|
if isinstance(arg, Enum):
|
|
883
906
|
tmp = str(arg)
|
|
884
907
|
if tmp.endswith('_'):
|
|
@@ -888,6 +911,12 @@ class GremlinLang(object):
|
|
|
888
911
|
else:
|
|
889
912
|
return tmp
|
|
890
913
|
|
|
914
|
+
if isinstance(arg, CompositePDT):
|
|
915
|
+
return f'PDT({self._arg_as_string(arg.name)},{self._process_dict(arg.fields)})'
|
|
916
|
+
|
|
917
|
+
if isinstance(arg, PrimitivePDT):
|
|
918
|
+
return f'PDT({self._arg_as_string(arg.name)},{self._arg_as_string(arg.value)})'
|
|
919
|
+
|
|
891
920
|
if isinstance(arg, Vertex):
|
|
892
921
|
return f'{self._arg_as_string(arg.id)}'
|
|
893
922
|
|
|
@@ -901,9 +930,8 @@ class GremlinLang(object):
|
|
|
901
930
|
|
|
902
931
|
if isinstance(arg, GValue):
|
|
903
932
|
key = arg.get_name()
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
raise Exception(f'invalid parameter name {key}.')
|
|
933
|
+
if not re.fullmatch(r'(?:[^\W\d]|\$)(?:\w|\$)*', key):
|
|
934
|
+
raise Exception(f'Invalid parameter name [{key}].')
|
|
907
935
|
|
|
908
936
|
if key in self.parameters:
|
|
909
937
|
if self.parameters[key] != arg.value:
|
|
@@ -921,18 +949,42 @@ class GremlinLang(object):
|
|
|
921
949
|
if isinstance(arg, list):
|
|
922
950
|
return self._process_list(arg)
|
|
923
951
|
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
952
|
+
# Strategy instances render as their name (e.g. "ReadOnlyStrategy") for withoutStrategies.
|
|
953
|
+
# Class objects render as their __name__ (e.g. strategy classes passed directly).
|
|
954
|
+
# These replace the old hasattr(arg, '__class__') check which was too broad since every
|
|
955
|
+
# Python object has __class__, making it a silent escape hatch for anything with __name__.
|
|
956
|
+
if isinstance(arg, TraversalStrategy):
|
|
957
|
+
return arg.strategy_name
|
|
958
|
+
|
|
959
|
+
if isinstance(arg, type):
|
|
960
|
+
return arg.__name__
|
|
961
|
+
|
|
962
|
+
# Registry-based dehydration — a registered adapter intentionally takes
|
|
963
|
+
# precedence over the @provider_defined decorator fallback below, allowing
|
|
964
|
+
# explicit adapters to override decorator-derived behavior.
|
|
965
|
+
if self.pdt_registry is not None:
|
|
966
|
+
primitive_adapter = self.pdt_registry.get_primitive_adapter_by_class(type(arg))
|
|
967
|
+
if primitive_adapter is not None and primitive_adapter['to_value'] is not None:
|
|
968
|
+
value = primitive_adapter['to_value'](arg)
|
|
969
|
+
return self._arg_as_string(PrimitivePDT(primitive_adapter['type_name'], value))
|
|
970
|
+
adapter = self.pdt_registry.get_composite_adapter_by_class(type(arg))
|
|
971
|
+
if adapter is not None and adapter['serialize'] is not None:
|
|
972
|
+
fields = adapter['serialize'](arg)
|
|
973
|
+
return self._arg_as_string(CompositePDT(adapter['type_name'], fields))
|
|
974
|
+
|
|
975
|
+
# Auto-dehydrate @provider_defined decorated objects
|
|
976
|
+
if hasattr(arg, '_pdt_name'):
|
|
977
|
+
included = getattr(arg, '_pdt_included_fields', None)
|
|
978
|
+
excluded = getattr(arg, '_pdt_excluded_fields', None)
|
|
979
|
+
fields = [f for f in vars(arg) if not f.startswith('_')]
|
|
980
|
+
if included:
|
|
981
|
+
fields = [f for f in fields if f in included]
|
|
982
|
+
elif excluded:
|
|
983
|
+
fields = [f for f in fields if f not in excluded]
|
|
984
|
+
pdt = CompositePDT(arg._pdt_name, {f: getattr(arg, f) for f in fields})
|
|
985
|
+
return self._arg_as_string(pdt)
|
|
986
|
+
|
|
987
|
+
raise TypeError(f'GremlinLang contains at least one type [{type(arg).__name__}] that cannot be represented as text.')
|
|
936
988
|
|
|
937
989
|
# Do special processing needed to format predicates that come in
|
|
938
990
|
# such as "gt(a)" correctly.
|
|
@@ -949,13 +1001,22 @@ class GremlinLang(object):
|
|
|
949
1001
|
c = 0
|
|
950
1002
|
res = [str(p).split('(')[0] + '(']
|
|
951
1003
|
if isinstance(p.value, list):
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
1004
|
+
# If all elements are Traversals, serialize as comma-separated args (no brackets)
|
|
1005
|
+
# This matches the server grammar: within(trav1, trav2) via genericArgumentVarargs
|
|
1006
|
+
if len(p.value) > 0 and all(isinstance(v, Traversal) for v in p.value):
|
|
1007
|
+
for v in p.value:
|
|
1008
|
+
if c > 0:
|
|
1009
|
+
res.append(',')
|
|
1010
|
+
res.append(self._arg_as_string(v))
|
|
1011
|
+
c += 1
|
|
1012
|
+
else:
|
|
1013
|
+
res.append('[')
|
|
1014
|
+
for v in p.value:
|
|
1015
|
+
if c > 0:
|
|
1016
|
+
res.append(',')
|
|
1017
|
+
res.append(self._arg_as_string(v))
|
|
1018
|
+
c += 1
|
|
1019
|
+
res.append(']')
|
|
959
1020
|
else:
|
|
960
1021
|
res.append(self._arg_as_string(p.value))
|
|
961
1022
|
if p.other is not None:
|
|
@@ -1011,11 +1072,23 @@ class GremlinLang(object):
|
|
|
1011
1072
|
def get_parameters(self):
|
|
1012
1073
|
return self.parameters
|
|
1013
1074
|
|
|
1014
|
-
def
|
|
1015
|
-
self.parameters
|
|
1075
|
+
def get_parameters_as_string(self):
|
|
1076
|
+
return GremlinLang.convert_parameters_to_string(self.parameters)
|
|
1016
1077
|
|
|
1017
|
-
|
|
1018
|
-
|
|
1078
|
+
@staticmethod
|
|
1079
|
+
def convert_parameters_to_string(params):
|
|
1080
|
+
"""Converts a parameter map to a gremlin-lang map literal string.
|
|
1081
|
+
|
|
1082
|
+
Raises TypeError if any value is an unsupported type.
|
|
1083
|
+
"""
|
|
1084
|
+
if params is None or len(params) == 0:
|
|
1085
|
+
return '[:]'
|
|
1086
|
+
|
|
1087
|
+
helper = GremlinLang()
|
|
1088
|
+
parts = []
|
|
1089
|
+
for k, v in params.items():
|
|
1090
|
+
parts.append(f'{helper._arg_as_string(k)}:{helper._arg_as_string(v)}')
|
|
1091
|
+
return '[' + ','.join(parts) + ']'
|
|
1019
1092
|
|
|
1020
1093
|
def add_source(self, source_name, *args):
|
|
1021
1094
|
|
|
@@ -1062,7 +1135,7 @@ class GremlinLang(object):
|
|
|
1062
1135
|
|
|
1063
1136
|
def __eq__(self, other):
|
|
1064
1137
|
if isinstance(other, self.__class__):
|
|
1065
|
-
return ''.join(self.gremlin) == ''.join(
|
|
1138
|
+
return ''.join(self.gremlin) == ''.join(other.gremlin) and self.parameters == other.parameters
|
|
1066
1139
|
else:
|
|
1067
1140
|
return False
|
|
1068
1141
|
|
|
@@ -1111,30 +1184,14 @@ class GremlinLang(object):
|
|
|
1111
1184
|
return (''.join(self.gremlin) if len(self.gremlin) > 0 else "") + \
|
|
1112
1185
|
(str(self.parameters) if len(self.parameters) > 0 else "")
|
|
1113
1186
|
|
|
1114
|
-
# TODO to be removed or updated once HTTP transaction is implemented
|
|
1115
|
-
# @staticmethod
|
|
1116
|
-
# def _create_graph_op(name, *values):
|
|
1117
|
-
# bc = Bytecode()
|
|
1118
|
-
# bc.add_source(name, *values)
|
|
1119
|
-
# return bc
|
|
1120
|
-
#
|
|
1121
|
-
# @staticmethod
|
|
1122
|
-
# class GraphOp:
|
|
1123
|
-
# @staticmethod
|
|
1124
|
-
# def commit():
|
|
1125
|
-
# return Bytecode._create_graph_op("tx", "commit")
|
|
1126
|
-
#
|
|
1127
|
-
# @staticmethod
|
|
1128
|
-
# def rollback():
|
|
1129
|
-
# return Bytecode._create_graph_op("tx", "rollback")
|
|
1130
1187
|
|
|
1131
1188
|
|
|
1132
1189
|
class GValue:
|
|
1133
1190
|
def __init__(self, name, value):
|
|
1191
|
+
if isinstance(value, GValue):
|
|
1192
|
+
raise Exception('GValues cannot be nested')
|
|
1134
1193
|
if name is None:
|
|
1135
|
-
raise Exception(
|
|
1136
|
-
if name.startswith('_'):
|
|
1137
|
-
raise Exception(f'invalid GValue name {name}. Should not start with _.')
|
|
1194
|
+
raise Exception('GValue name cannot be null.')
|
|
1138
1195
|
self.name = name
|
|
1139
1196
|
self.value = value
|
|
1140
1197
|
|
|
@@ -1147,6 +1204,12 @@ class GValue:
|
|
|
1147
1204
|
def get(self):
|
|
1148
1205
|
return self.value
|
|
1149
1206
|
|
|
1207
|
+
def __repr__(self):
|
|
1208
|
+
return f'{self.name}={self.value}'
|
|
1209
|
+
|
|
1210
|
+
def __str__(self):
|
|
1211
|
+
return f'{self.name}={self.value}'
|
|
1212
|
+
|
|
1150
1213
|
|
|
1151
1214
|
class CardinalityValue(GremlinLang):
|
|
1152
1215
|
def __init__(self, cardinality, val):
|