gremlinpython 3.6.5__py2.py3-none-any.whl → 3.6.6__py2.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.
@@ -16,5 +16,5 @@ KIND, either express or implied. See the License for the
16
16
  specific language governing permissions and limitations
17
17
  under the License.
18
18
  '''
19
- version = '3.6.5'
20
- timestamp = 1691177118
19
+ version = '3.6.6'
20
+ timestamp = 1701718721
@@ -138,3 +138,99 @@ class AiohttpTransport(AbstractBaseTransport):
138
138
  def closed(self):
139
139
  # Connection is closed if either the websocket or the client session is closed.
140
140
  return self._websocket.closed or self._client_session.closed
141
+
142
+
143
+ class AiohttpHTTPTransport(AbstractBaseTransport):
144
+ nest_asyncio_applied = False
145
+
146
+ def __init__(self, call_from_event_loop=None, read_timeout=None, write_timeout=None, **kwargs):
147
+ if call_from_event_loop is not None and call_from_event_loop and not AiohttpTransport.nest_asyncio_applied:
148
+ """
149
+ The AiohttpTransport implementation uses the asyncio event loop. Because of this, it cannot be called
150
+ within an event loop without nest_asyncio. If the code is ever refactored so that it can be called
151
+ within an event loop this import and call can be removed. Without this, applications which use the
152
+ event loop to call gremlin-python (such as Jupyter) will not work.
153
+ """
154
+ import nest_asyncio
155
+ nest_asyncio.apply()
156
+ AiohttpTransport.nest_asyncio_applied = True
157
+
158
+ # Start event loop and initialize client session and response to None
159
+ self._loop = asyncio.new_event_loop()
160
+ self._client_session = None
161
+ self._http_req_resp = None
162
+ self._enable_ssl = False
163
+
164
+ # Set all inner variables to parameters passed in.
165
+ self._aiohttp_kwargs = kwargs
166
+ self._write_timeout = write_timeout
167
+ self._read_timeout = read_timeout
168
+ if "ssl_options" in self._aiohttp_kwargs:
169
+ self._ssl_context = self._aiohttp_kwargs.pop("ssl_options")
170
+ self._enable_ssl = True
171
+
172
+ def __del__(self):
173
+ # Close will only actually close if things are left open, so this is safe to call.
174
+ # Clean up any connection resources and close the event loop.
175
+ self.close()
176
+
177
+ def connect(self, url, headers=None):
178
+ # Inner function to perform async connect.
179
+ async def async_connect():
180
+ # Start client session and use it to send all HTTP requests. Base url is the endpoint, headers are set here
181
+ # Base url can only parse basic url with no path, see https://github.com/aio-libs/aiohttp/issues/6647
182
+ if self._enable_ssl:
183
+ # ssl context is established through tcp connector
184
+ tcp_conn = aiohttp.TCPConnector(ssl_context=self._ssl_context)
185
+ self._client_session = aiohttp.ClientSession(connector=tcp_conn,
186
+ base_url=url, headers=headers, loop=self._loop)
187
+ else:
188
+ self._client_session = aiohttp.ClientSession(base_url=url, headers=headers, loop=self._loop)
189
+
190
+ # Execute the async connect synchronously.
191
+ self._loop.run_until_complete(async_connect())
192
+
193
+ def write(self, message):
194
+ # Inner function to perform async write.
195
+ async def async_write():
196
+ basic_auth = None
197
+ # basic password authentication for https connections
198
+ if message['auth']:
199
+ basic_auth = aiohttp.BasicAuth(message['auth']['username'], message['auth']['password'])
200
+ async with async_timeout.timeout(self._write_timeout):
201
+ self._http_req_resp = await self._client_session.post(url="/gremlin",
202
+ auth=basic_auth,
203
+ data=message['payload'],
204
+ headers=message['headers'],
205
+ **self._aiohttp_kwargs)
206
+
207
+ # Execute the async write synchronously.
208
+ self._loop.run_until_complete(async_write())
209
+
210
+ def read(self):
211
+ # Inner function to perform async read.
212
+ async def async_read():
213
+ async with async_timeout.timeout(self._read_timeout):
214
+ return await self._http_req_resp.read()
215
+
216
+ return self._loop.run_until_complete(async_read())
217
+
218
+ def close(self):
219
+ # Inner function to perform async close.
220
+ async def async_close():
221
+ if self._client_session is not None and not self._client_session.closed:
222
+ await self._client_session.close()
223
+ self._client_session = None
224
+
225
+ # If the loop is not closed (connection hasn't already been closed)
226
+ if not self._loop.is_closed():
227
+ # Execute the async close synchronously.
228
+ self._loop.run_until_complete(async_close())
229
+
230
+ # Close the event loop.
231
+ self._loop.close()
232
+
233
+ @property
234
+ def closed(self):
235
+ # Connection is closed when client session is closed.
236
+ return self._client_session.closed
@@ -19,6 +19,7 @@
19
19
  import logging
20
20
  import warnings
21
21
  import queue
22
+ import re
22
23
  from concurrent.futures import ThreadPoolExecutor
23
24
 
24
25
  from gremlin_python.driver import connection, protocol, request, serializer
@@ -45,12 +46,16 @@ class Client:
45
46
  kerberized_service="", headers=None, session=None,
46
47
  enable_user_agent_on_connect=True, **transport_kwargs):
47
48
  log.info("Creating Client with url '%s'", url)
49
+
50
+ # check via url that we are using http protocol
51
+ self._use_http = re.search('^http', url)
52
+
48
53
  self._closed = False
49
54
  self._url = url
50
55
  self._headers = headers
51
56
  self._enable_user_agent_on_connect = enable_user_agent_on_connect
52
57
  self._traversal_source = traversal_source
53
- if "max_content_length" not in transport_kwargs:
58
+ if not self._use_http and "max_content_length" not in transport_kwargs:
54
59
  transport_kwargs["max_content_length"] = 10 * 1024 * 1024
55
60
  if message_serializer is None:
56
61
  message_serializer = serializer.GraphBinarySerializersV1()
@@ -63,21 +68,31 @@ class Client:
63
68
  if transport_factory is None:
64
69
  try:
65
70
  from gremlin_python.driver.aiohttp.transport import (
66
- AiohttpTransport)
71
+ AiohttpTransport, AiohttpHTTPTransport)
67
72
  except ImportError:
68
73
  raise Exception("Please install AIOHTTP or pass "
69
74
  "custom transport factory")
70
75
  else:
71
76
  def transport_factory():
72
- return AiohttpTransport(**transport_kwargs)
77
+ if self._use_http:
78
+ return AiohttpHTTPTransport(**transport_kwargs)
79
+ else:
80
+ return AiohttpTransport(**transport_kwargs)
73
81
  self._transport_factory = transport_factory
74
82
  if protocol_factory is None:
75
- def protocol_factory(): return protocol.GremlinServerWSProtocol(
76
- self._message_serializer,
77
- username=self._username,
78
- password=self._password,
79
- kerberized_service=kerberized_service,
80
- max_content_length=transport_kwargs["max_content_length"])
83
+ def protocol_factory():
84
+ if self._use_http:
85
+ return protocol.GremlinServerHTTPProtocol(
86
+ self._message_serializer,
87
+ username=self._username,
88
+ password=self._password)
89
+ else:
90
+ return protocol.GremlinServerWSProtocol(
91
+ self._message_serializer,
92
+ username=self._username,
93
+ password=self._password,
94
+ kerberized_service=kerberized_service,
95
+ max_content_length=transport_kwargs["max_content_length"])
81
96
  self._protocol_factory = protocol_factory
82
97
  if self._session_enabled:
83
98
  if pool_size is None:
@@ -61,6 +61,7 @@ class Connection:
61
61
  request_id = str(uuid.uuid4())
62
62
  if request_message.args.get("requestId"):
63
63
  request_id = request_message.args.get("requestId")
64
+ uuid.UUID(request_id) # Checks for proper UUID or else server will return an error.
64
65
  result_set = resultset.ResultSet(queue.Queue(), request_id)
65
66
  self._results[request_id] = result_set
66
67
  # Create write task
@@ -16,6 +16,7 @@
16
16
  # specific language governing permissions and limitations
17
17
  # under the License.
18
18
  #
19
+ import json
19
20
  import logging
20
21
  import abc
21
22
  import base64
@@ -25,6 +26,8 @@ import struct
25
26
 
26
27
  from gremlin_python.driver import request
27
28
  from gremlin_python.driver.resultset import ResultSet
29
+ from gremlin_python.process.translator import Translator
30
+ from gremlin_python.process.traversal import Bytecode
28
31
 
29
32
  log = logging.getLogger("gremlinpython")
30
33
 
@@ -63,7 +66,6 @@ class AbstractBaseProtocol(metaclass=abc.ABCMeta):
63
66
 
64
67
 
65
68
  class GremlinServerWSProtocol(AbstractBaseProtocol):
66
-
67
69
  QOP_AUTH_BIT = 1
68
70
  _kerberos_context = None
69
71
  _max_content_length = 10 * 1024 * 1024
@@ -133,7 +135,7 @@ class GremlinServerWSProtocol(AbstractBaseProtocol):
133
135
  # This message is going to be huge and kind of hard to read, but in the event of an error,
134
136
  # it can provide invaluable info, so space it out appropriately.
135
137
  log.error("\r\nReceived error message '%s'\r\n\r\nWith results dictionary '%s'",
136
- str(message), str(results_dict))
138
+ str(message), str(results_dict))
137
139
  del results_dict[request_id]
138
140
  raise GremlinServerError(message['status'])
139
141
 
@@ -185,8 +187,71 @@ class GremlinServerWSProtocol(AbstractBaseProtocol):
185
187
  name_length = len(self._username)
186
188
  fmt = '!I' + str(name_length) + 's'
187
189
  word = self.QOP_AUTH_BIT << 24 | self._max_content_length
188
- out = struct.pack(fmt, word, self._username.encode("utf-8"),)
190
+ out = struct.pack(fmt, word, self._username.encode("utf-8"), )
189
191
  encoded = base64.b64encode(out).decode('ascii')
190
192
  kerberos.authGSSClientWrap(self._kerberos_context, encoded)
191
193
  auth = kerberos.authGSSClientResponse(self._kerberos_context)
192
194
  return request.RequestMessage('', 'authentication', {'sasl': auth})
195
+
196
+
197
+ class GremlinServerHTTPProtocol(AbstractBaseProtocol):
198
+
199
+ def __init__(self,
200
+ message_serializer,
201
+ username='', password=''):
202
+ self._message_serializer = message_serializer
203
+ self._username = username
204
+ self._password = password
205
+
206
+ def connection_made(self, transport):
207
+ super(GremlinServerHTTPProtocol, self).connection_made(transport)
208
+
209
+ def write(self, request_id, request_message):
210
+
211
+ basic_auth = {}
212
+ if self._username and self._password:
213
+ basic_auth['username'] = self._username
214
+ basic_auth['password'] = self._password
215
+
216
+ content_type = str(self._message_serializer.version, encoding='utf-8')
217
+ message = {
218
+ 'headers': {'CONTENT-TYPE': content_type,
219
+ 'ACCEPT': content_type},
220
+ 'payload': self._message_serializer.serialize_message(request_id, request_message),
221
+ 'auth': basic_auth
222
+ }
223
+
224
+ self._transport.write(message)
225
+
226
+ def data_received(self, message, results_dict):
227
+ # if Gremlin Server cuts off then we get a None for the message
228
+ if message is None:
229
+ log.error("Received empty message from server.")
230
+ raise GremlinServerError({'code': 500,
231
+ 'message': 'Server disconnected - please try to reconnect', 'attributes': {}})
232
+
233
+ message = self._message_serializer.deserialize_message(message)
234
+ request_id = message['requestId']
235
+ result_set = results_dict[request_id] if request_id in results_dict else ResultSet(None, None)
236
+ status_code = message['status']['code']
237
+ aggregate_to = message['result']['meta'].get('aggregateTo', 'list')
238
+ data = message['result']['data']
239
+ result_set.aggregate_to = aggregate_to
240
+
241
+ if status_code == 204:
242
+ result_set.stream.put_nowait([])
243
+ del results_dict[request_id]
244
+ return status_code
245
+ elif status_code in [200, 206]:
246
+ result_set.stream.put_nowait(data)
247
+ if status_code == 200:
248
+ result_set.status_attributes = message['status']['attributes']
249
+ del results_dict[request_id]
250
+ return status_code
251
+ else:
252
+ # This message is going to be huge and kind of hard to read, but in the event of an error,
253
+ # it can provide invaluable info, so space it out appropriately.
254
+ log.error("\r\nReceived error message '%s'\r\n\r\nWith results dictionary '%s'",
255
+ str(message), str(results_dict))
256
+ del results_dict[request_id]
257
+ raise GremlinServerError(message['status'])
@@ -17,6 +17,7 @@
17
17
  # under the License.
18
18
  #
19
19
 
20
+ import base64
20
21
  import logging
21
22
  import struct
22
23
  import uuid
@@ -156,7 +157,8 @@ class GraphSONMessageSerializer(object):
156
157
  return message
157
158
 
158
159
  def deserialize_message(self, message):
159
- msg = json.loads(message.decode('utf-8'))
160
+ # for parsing string message via HTTP connections
161
+ msg = json.loads(message if isinstance(message, str) else message.decode('utf-8'))
160
162
  return self._graphson_reader.to_object(msg)
161
163
 
162
164
 
@@ -268,7 +270,8 @@ class GraphBinarySerializersV1(object):
268
270
  return bytes(ba)
269
271
 
270
272
  def deserialize_message(self, message):
271
- b = io.BytesIO(message)
273
+ # for parsing string message via HTTP connections
274
+ b = io.BytesIO(base64.b64decode(message) if isinstance(message, str) else message)
272
275
 
273
276
  b.read(1) # version
274
277
 
@@ -18,7 +18,7 @@
18
18
  #
19
19
  import platform
20
20
 
21
- gremlin_version = "3.6.5" # DO NOT MODIFY - Configured automatically by Maven Replacer Plugin
21
+ gremlin_version = "3.6.6" # DO NOT MODIFY - Configured automatically by Maven Replacer Plugin
22
22
 
23
23
  def _generate_user_agent():
24
24
  application_name = "NotAvailable"
@@ -24,11 +24,13 @@ sent to any TinkerPop compliant HTTP endpoint.
24
24
  """
25
25
  __author__ = 'Kelvin R. Lawrence (gfxman)'
26
26
 
27
- from gremlin_python.process.graph_traversal import __
28
- from gremlin_python.process.anonymous_traversal import traversal
27
+ import math
28
+ import numbers
29
+ import re
30
+
29
31
  from gremlin_python.process.traversal import *
30
- from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
31
32
  from gremlin_python.process.strategies import *
33
+ from gremlin_python.structure.graph import Vertex, Edge, VertexProperty
32
34
  from datetime import datetime
33
35
 
34
36
 
@@ -39,18 +41,20 @@ class Translator:
39
41
 
40
42
  # Dictionary used to reverse-map token IDs to strings
41
43
  options = {
42
- WithOptions.tokens: 'tokens',
43
- WithOptions.none: 'none',
44
- WithOptions.ids: 'ids',
45
- WithOptions.labels: 'labels',
46
- WithOptions.keys: 'keys',
47
- WithOptions.values: 'values',
48
- WithOptions.all: 'all',
49
- WithOptions.indexer: 'indexer',
50
- WithOptions.list: 'list',
51
- WithOptions.map: 'map'
44
+ WithOptions.tokens: 'tokens',
45
+ WithOptions.none: 'none',
46
+ WithOptions.ids: 'ids',
47
+ WithOptions.labels: 'labels',
48
+ WithOptions.keys: 'keys',
49
+ WithOptions.values: 'values',
50
+ WithOptions.all: 'all',
51
+ WithOptions.indexer: 'indexer',
52
+ WithOptions.list: 'list',
53
+ WithOptions.map: 'map'
52
54
  }
53
55
 
56
+ conn_p = ['and', 'or']
57
+
54
58
  def __init__(self, traversal_source=None):
55
59
  self.traversal_source = traversal_source
56
60
 
@@ -60,20 +64,37 @@ class Translator:
60
64
  def get_target_language(self):
61
65
  return "gremlin-groovy"
62
66
 
63
- def of(self,traversal_source):
67
+ def of(self, traversal_source):
64
68
  self.traversal_source = traversal_source
65
69
  return self
66
70
 
67
71
  # Do any needed special processing for the representation
68
- # of strings and dates.
72
+ # of strings and dates and boolean.
69
73
  def fixup(self, v):
70
74
  if isinstance(v, str):
71
- return f'\'{v}\''
75
+ return f'{v!r}' # use repr() format for canonical string rep
72
76
  elif type(v) == datetime:
73
77
  return self.process_date(v)
78
+ elif type(v) == bool:
79
+ return 'true' if v else 'false'
80
+ elif isinstance(v, numbers.Number):
81
+ return self.process_number(v)
82
+ elif isinstance(v, set):
83
+ return f'[{str(v)[1:-1]}]'
84
+ elif isinstance(v, P):
85
+ return self.process_predicate(v)
86
+ elif type(v) == Vertex:
87
+ return self.process_vertex(v)
88
+ elif type(v) == Edge:
89
+ return self.process_edge(v)
90
+ elif type(v) in [Merge]: # on_create on_match out_v in_v
91
+ tmp = str(v)
92
+ return f'{tmp.split("_")[0]}{tmp.split("_")[1].capitalize()}' if tmp.find('_') else tmp
93
+ elif v is None:
94
+ return 'null'
74
95
  else:
75
96
  return str(v)
76
-
97
+
77
98
  # Turn a Python datetime into the equivalent new Date(...)
78
99
  def process_date(self, date):
79
100
  y = date.year - 1900
@@ -87,36 +108,113 @@ class Translator:
87
108
  # Do special processing needed to format predicates that come in
88
109
  # such as "gt(a)" correctly.
89
110
  def process_predicate(self, p):
90
- res = str(p).split('(')[0] + '('
111
+ res = ''
112
+ if p.operator in self.conn_p:
113
+ res += f'{self.process_predicate(p.value)}.{p.operator}({self.process_predicate(p.other)})'
114
+ else:
115
+ res += f'{self.process_p_value(p)}'
116
+ return res
91
117
 
118
+ # process the value of the predicates
119
+ def process_p_value(self, p):
120
+ res = str(p).split('(')[0] + '('
92
121
  if type(p.value) == list:
93
122
  res += '['
94
123
  for v in p.value:
95
124
  res += self.fixup(v) + ','
96
- res = res[0:-1] + ']'
125
+ res = (res[0:-1] + ']') if len(p.value) > 0 else (res + ']')
97
126
  else:
98
127
  res += self.fixup(p.value)
99
128
  if p.other is not None:
100
- res+= ',' + self.fixup(p.other)
129
+ res += f',{self.fixup(p.other)}'
101
130
  res += ')'
102
131
  return res
103
132
 
104
133
  # Special processing to handle strategies
105
134
  def process_strategy(self, s):
106
135
  c = 0
107
- res = f'new {str(s)}('
108
- for key in s.configuration:
109
- res += ',' if c > 0 else ''
110
- res += key + ':'
111
- val = s.configuration[key]
112
- if isinstance(val, Traversal):
113
- res += self.translate(val.bytecode, child=True)
136
+ res = ''
137
+ # if parameter is empty, only pass class name (referenced GroovyTranslator.java)
138
+ if not s.configuration:
139
+ res += s.strategy_name
140
+ else:
141
+ res = f'new {str(s)}('
142
+ for key in s.configuration:
143
+ res += ',' if c > 0 else ''
144
+ res += key + ':'
145
+ val = s.configuration[key]
146
+ if isinstance(val, Traversal):
147
+ res += self.translate(val.bytecode, child=True)
148
+ else:
149
+ res += self.fixup(val)
150
+ c += 1
151
+ res += ')'
152
+ return res
153
+ pass
154
+
155
+ # Special processing to handle vertices
156
+ def process_vertex(self, vertex):
157
+ return f'new ReferenceVertex({self.fixup(vertex.id)},\'{vertex.label}\')'
158
+
159
+ # Special processing to handle edges
160
+ def process_edge(self, edge):
161
+ return f'new ReferenceEdge({str(edge.id)},\'{edge.label}\',' \
162
+ f'new ReferenceVertex({str(edge.inV.id)},\'{edge.inV.label}\'),' \
163
+ f'new ReferenceVertex({str(edge.outV.id)},\'{edge.outV.label}\'))'
164
+
165
+ # Special processing to handle vertex property
166
+ def process_vertex_property(self, vp):
167
+ return f'new ReferenceVertexProperty({str(vp.id)},\'{vp.label}\',{self.fixup(vp.value)})'
168
+
169
+ # Special processing to handle lambda
170
+ def process_lambda(self, lam):
171
+ lambda_result = lam()
172
+ script = lambda_result if isinstance(lambda_result, str) else lambda_result[0]
173
+ return f'{script}' if re.match(r"^\{.*\}$", script, flags=re.DOTALL) else f'{{{script}}}'
174
+
175
+ def process_dict(self, d):
176
+ c = 0
177
+ res = '['
178
+ if len(d) == 0:
179
+ res += ':'
180
+ else:
181
+ for k, v in d.items():
182
+ wrap = not isinstance(k, str)
183
+ res += ',' if c > 0 else ''
184
+ res += '(' if wrap else ''
185
+ res += self.fixup(k)
186
+ res += ')' if wrap else ''
187
+ res += f':{self.fixup(v)}'
188
+ c += 1
189
+ res += ']'
190
+ return res
191
+
192
+ def process_number(self, n):
193
+ if isinstance(n, float):
194
+ # converting floats into doubles for script since python doesn't distinguish and java defaults to double
195
+ if math.isnan(n):
196
+ return "Double.NaN"
197
+ elif math.isinf(n) and n > 0:
198
+ return "Double.POSITIVE_INFINITY"
199
+ elif math.isinf(n) and n < 0:
200
+ return "Double.NEGATIVE_INFINITY"
114
201
  else:
115
- res += self.fixup(val)
202
+ return f'{n}d'
203
+ return f'{n}'
204
+
205
+ def process_list(self, l):
206
+ c = 0
207
+ res = '['
208
+ for i in l:
209
+ res += ',' if c > 0 else ''
210
+ res += self.fixup(i)
116
211
  c += 1
117
- res += ')'
212
+ res += ']'
118
213
  return res
119
- pass
214
+
215
+ # Special processing to handle bindings inside of traversals
216
+ def process_binding(self, binding):
217
+ return f'Bindings.instance().of(\'{binding.key}\', {str(binding.value)})'
120
218
 
121
219
  # Main driver of the translation. Different parts of
122
220
  # a Traversal are handled appropriately.
@@ -127,19 +225,29 @@ class Translator:
127
225
  if len(params) > 0:
128
226
  c = 0
129
227
  with_opts = False
228
+ is_merge_op = (step[0] == 'mergeV') or (step[0] == 'mergeE')
130
229
  for p in params:
131
230
  script += ',' if c > 0 else ''
132
231
  if with_opts:
133
- script += f'WithOptions.{self.options[p]}'
232
+ script += f'WithOptions.{self.options[p]}'
134
233
  elif type(p) == Bytecode:
135
234
  script += self.translate(p, True)
136
235
  elif isinstance(p, P):
137
236
  script += self.process_predicate(p)
138
- elif type(p) in [Cardinality, Pop, Operator]:
237
+ elif type(p) == Vertex:
238
+ script += self.process_vertex(p)
239
+ elif type(p) == Edge:
240
+ script += self.process_edge(p)
241
+ elif type(p) == VertexProperty:
242
+ script += self.process_vertex_property(p)
243
+ elif type(p) in [Cardinality, Pop, Operator, Scope, T]:
244
+ tmp = str(p)
245
+ script += tmp[0:-1] if tmp.endswith('_') else tmp
246
+ elif type(p) in [Merge]: # on_create on_match out_v in_v
247
+ is_merge_op = True
139
248
  tmp = str(p)
140
- script += tmp[0:-1] if tmp.endswith('_') else tmp
141
- elif type(p) in [ReadOnlyStrategy, SubgraphStrategy, VertexProgramStrategy,
142
- OptionsStrategy, PartitionStrategy]:
249
+ script += f'{tmp.split("_")[0]}{tmp.split("_")[1].capitalize()}' if tmp.find('_') else tmp
250
+ elif isinstance(p, TraversalStrategy): # this will capture all strategies
143
251
  script += self.process_strategy(p)
144
252
  elif type(p) == datetime:
145
253
  script += self.process_date(p)
@@ -147,11 +255,25 @@ class Translator:
147
255
  script += 'WithOptions.tokens'
148
256
  with_opts = True
149
257
  elif isinstance(p, str):
150
- script += f'\'{p}\''
258
+ script += f'{p!r}' # use repr() format for canonical string rep
151
259
  elif type(p) == bool:
152
260
  script += 'true' if p else 'false'
261
+ elif isinstance(p, type(lambda: None)) and p.__name__ == (lambda: None).__name__:
262
+ script += self.process_lambda(p)
263
+ elif type(p) == Binding:
264
+ script += self.process_binding(p)
153
265
  elif p is None:
154
- script += 'null'
266
+ script += '(Traversal) null' if is_merge_op else 'null'
267
+ elif isinstance(p, type):
268
+ script += p.__name__
269
+ elif isinstance(p, dict):
270
+ script += self.process_dict(p)
271
+ elif isinstance(p, numbers.Number):
272
+ script += self.process_number(p)
273
+ elif isinstance(p, set):
274
+ script += f'[{str(p)[1:-1]}] as Set' if len(p) > 0 else '[] as Set'
275
+ elif isinstance(p, list):
276
+ script += self.process_list(p)
155
277
  else:
156
278
  script += str(p)
157
279
  c += 1
@@ -165,11 +287,11 @@ class Translator:
165
287
  # anonymous traversal style syntax.
166
288
  def translate(self, bytecode, child=False):
167
289
  script = '__' if child else self.traversal_source
168
-
290
+
169
291
  for step in bytecode.source_instructions:
170
292
  script += self.do_translation(step)
171
293
 
172
294
  for step in bytecode.step_instructions:
173
295
  script += self.do_translation(step)
174
-
296
+
175
297
  return script
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gremlinpython
3
- Version: 3.6.5
3
+ Version: 3.6.6
4
4
  Summary: Gremlin-Python for Apache TinkerPop
5
5
  Home-page: http://tinkerpop.apache.org
6
6
  License: Apache 2
@@ -1,24 +1,24 @@
1
1
  gremlin_python/__init__.py,sha256=rbOOdo_19nz_mHTXVc5p8ZXLI5pUGMfXLKQiw7Olu7g,850
2
- gremlin_python/__version__.py,sha256=0ziu1yIjAcHDwuwTnKTPaUR9LVforR8SYbIrFTwGNjg,804
2
+ gremlin_python/__version__.py,sha256=y0xEAtZ4-6wJeqieWTyT_bc2McYCIlmtqGOAnUvysno,804
3
3
  gremlin_python/statics.py,sha256=BXnrfx25Todku_U0ddd-zB4eyQMf2paT5uuN9znK2fQ,2849
4
4
  gremlin_python/driver/__init__.py,sha256=rbOOdo_19nz_mHTXVc5p8ZXLI5pUGMfXLKQiw7Olu7g,850
5
- gremlin_python/driver/client.py,sha256=HJZmYGsxb4tzVmEfM3QQGuqK--kxmcd0Y255pBo6-Rc,7399
6
- gremlin_python/driver/connection.py,sha256=LKrslNCXf5Gu8um1b2pBiZ84zKZ_HsJ-dQh4DouDd-U,3395
5
+ gremlin_python/driver/client.py,sha256=D5JfgxOBvOkZZX10CZ_uVbA14Ez2SW_nWl7gRXrd7qw,8030
6
+ gremlin_python/driver/connection.py,sha256=m_wjluA1tv30s7X9LhDi4GgPMCB4nMcDHHXxMA58z2E,3491
7
7
  gremlin_python/driver/driver_remote_connection.py,sha256=YK4_se8Md57Dq-P6VwcLag0vH-AOoGqayQA9suG-_fM,8670
8
- gremlin_python/driver/protocol.py,sha256=LmzvTMjQEmRd2GRWN2CSishbtOKvD11376wZ2Todpe4,8746
8
+ gremlin_python/driver/protocol.py,sha256=s-TC8iRlcYmO7iNk6RQW0SttO9nIOfUBkj0h9mwqwPA,11549
9
9
  gremlin_python/driver/remote_connection.py,sha256=DtglObhiyLDIgLKIcv7enDuXd9KiCJVLXWAvreBQ4wA,3014
10
10
  gremlin_python/driver/request.py,sha256=IlqBmQlT2UU95xbY6z1ajlmNQeDZ4ePzT4uF8M0USFk,953
11
11
  gremlin_python/driver/resultset.py,sha256=_-13igfH1zQ72mgreDptPmUaXnadnprERVQTSZWeIl4,2669
12
- gremlin_python/driver/serializer.py,sha256=dMKXL9YYFK2DJKQfIQ2Y-R-_DoyqjRBSPTn4k5SID0M,10009
12
+ gremlin_python/driver/serializer.py,sha256=e__rrMw3p74RoGl4Hh1zsDw2XFyRihfuNu7GuTK_E4E,10239
13
13
  gremlin_python/driver/transport.py,sha256=aEXb9oS1SMI9oKWYINnWuYhYaosi6FdsOJ7oj6FzkkY,1246
14
- gremlin_python/driver/useragent.py,sha256=zBm9UgIIUtnZH0IzF8_40aWKa5ATii37_Q7wSkLciuc,1588
14
+ gremlin_python/driver/useragent.py,sha256=ynpcC4TFcDc2aFuTJc7bX9HdJRK0Req6kci8K2u03TA,1588
15
15
  gremlin_python/driver/aiohttp/__init__.py,sha256=xzdixoKYCJCe4aRILYqdartQi4Py5fcQWqif3zzyUC8,787
16
- gremlin_python/driver/aiohttp/transport.py,sha256=qKSvgWZw8Gv2OYnriycphs2Nb2zoaw2tPzol0aMtp3Q,6228
16
+ gremlin_python/driver/aiohttp/transport.py,sha256=x2jmwkHTM8BTxGBqyfwncyh9jgi0CUxSgGqPCRW6aCo,10842
17
17
  gremlin_python/process/__init__.py,sha256=rbOOdo_19nz_mHTXVc5p8ZXLI5pUGMfXLKQiw7Olu7g,850
18
18
  gremlin_python/process/anonymous_traversal.py,sha256=A8evyPIAciRGiauDqUbyo4XnG3QTdO28l-TF2K7Ir2g,2448
19
19
  gremlin_python/process/graph_traversal.py,sha256=XDTC1rcKe0FcqUrchqPVRUnoTkYTa2xVY-dH3c7BSCw,61092
20
20
  gremlin_python/process/strategies.py,sha256=95WIhzvvqejCEDOlhICGji9HgkwTUySGKt-yNCBTTh8,9474
21
- gremlin_python/process/translator.py,sha256=wQUFDmex8g7paYfUreWKhTY3bUnM0nF4bnZOm6H2zbs,6159
21
+ gremlin_python/process/translator.py,sha256=NuaA2WfepvgDm3DrNa_u2Qvz70s9t6ICbFltPglQwBI,11147
22
22
  gremlin_python/process/traversal.py,sha256=kt_2HlRTIvMEnkOR9654eAJESP4bcMFt9BfWlKjQgu8,22451
23
23
  gremlin_python/structure/__init__.py,sha256=zo5zR3kruv1h4_A80IxZ1IZrS0Ud5lVjpGm0PxBAP20,852
24
24
  gremlin_python/structure/graph.py,sha256=JdyP2yiZKK2EnkTn4wIiy-bZb8iGLCvneC8T_VaZgvo,4365
@@ -27,11 +27,11 @@ gremlin_python/structure/io/graphbinaryV1.py,sha256=Ti_eR70jOmJnapiyTq1qhkt90CKf
27
27
  gremlin_python/structure/io/graphsonV2d0.py,sha256=t63IZ6UIVngvQcH8fnnLDmWm0KoCuDrwB5lprM2dFuw,20598
28
28
  gremlin_python/structure/io/graphsonV3d0.py,sha256=bEiZcJduPNGmf5rHdl0Yq9QFwAmnvADDBytmBAAirQM,23918
29
29
  gremlin_python/structure/io/util.py,sha256=x0OEkGGX2ajgOuSbz1j3dO3_IlOPnPLV4m6SGAmNAeM,1846
30
- gremlinpython-3.6.5.data/data/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
31
- gremlinpython-3.6.5.data/data/NOTICE,sha256=cQwbCsygJy_LcRskXIJSOhUxEZWiR_QM6xpJCS1v0_o,170
32
- gremlinpython-3.6.5.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
33
- gremlinpython-3.6.5.dist-info/METADATA,sha256=zCuAXXMo6jPGSIPzmUdh39F4bKGvUQLbD9D1lY93C0w,6351
34
- gremlinpython-3.6.5.dist-info/NOTICE,sha256=cQwbCsygJy_LcRskXIJSOhUxEZWiR_QM6xpJCS1v0_o,170
35
- gremlinpython-3.6.5.dist-info/WHEEL,sha256=k3vXr0c0OitO0k9eCWBlI2yTYnpb_n_I2SGzrrfY7HY,110
36
- gremlinpython-3.6.5.dist-info/top_level.txt,sha256=VVeR1g-oOCZBmKIaVzZ7fF2BYrnqOWpw7C2H71ksTAU,15
37
- gremlinpython-3.6.5.dist-info/RECORD,,
30
+ gremlinpython-3.6.6.data/data/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
31
+ gremlinpython-3.6.6.data/data/NOTICE,sha256=cQwbCsygJy_LcRskXIJSOhUxEZWiR_QM6xpJCS1v0_o,170
32
+ gremlinpython-3.6.6.dist-info/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
33
+ gremlinpython-3.6.6.dist-info/METADATA,sha256=mhEIUOdF3PaNFw-nMo_5jv3o3BfEJTcvTo5qV3jzo0g,6351
34
+ gremlinpython-3.6.6.dist-info/NOTICE,sha256=cQwbCsygJy_LcRskXIJSOhUxEZWiR_QM6xpJCS1v0_o,170
35
+ gremlinpython-3.6.6.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110
36
+ gremlinpython-3.6.6.dist-info/top_level.txt,sha256=VVeR1g-oOCZBmKIaVzZ7fF2BYrnqOWpw7C2H71ksTAU,15
37
+ gremlinpython-3.6.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.0)
2
+ Generator: bdist_wheel (0.37.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any