gremlinpython 3.6.4__tar.gz → 3.6.6__tar.gz

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.
Files changed (42) hide show
  1. {gremlinpython-3.6.4/gremlinpython.egg-info → gremlinpython-3.6.6}/PKG-INFO +9 -9
  2. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/README.rst +8 -8
  3. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/__version__.py +2 -2
  4. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/aiohttp/transport.py +96 -0
  5. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/client.py +27 -9
  6. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/connection.py +1 -0
  7. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/protocol.py +68 -3
  8. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/serializer.py +5 -2
  9. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/useragent.py +2 -6
  10. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/process/graph_traversal.py +26 -26
  11. gremlinpython-3.6.6/gremlin_python/process/translator.py +297 -0
  12. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/process/traversal.py +1 -1
  13. {gremlinpython-3.6.4 → gremlinpython-3.6.6/gremlinpython.egg-info}/PKG-INFO +9 -9
  14. gremlinpython-3.6.4/gremlin_python/process/translator.py +0 -173
  15. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/LICENSE +0 -0
  16. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/MANIFEST.in +0 -0
  17. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/NOTICE +0 -0
  18. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/__init__.py +0 -0
  19. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/__init__.py +0 -0
  20. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/aiohttp/__init__.py +0 -0
  21. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/driver_remote_connection.py +0 -0
  22. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/remote_connection.py +0 -0
  23. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/request.py +0 -0
  24. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/resultset.py +0 -0
  25. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/driver/transport.py +0 -0
  26. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/process/__init__.py +0 -0
  27. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/process/anonymous_traversal.py +0 -0
  28. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/process/strategies.py +0 -0
  29. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/statics.py +0 -0
  30. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/structure/__init__.py +0 -0
  31. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/structure/graph.py +0 -0
  32. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/structure/io/__init__.py +0 -0
  33. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/structure/io/graphbinaryV1.py +0 -0
  34. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/structure/io/graphsonV2d0.py +0 -0
  35. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/structure/io/graphsonV3d0.py +0 -0
  36. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlin_python/structure/io/util.py +0 -0
  37. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlinpython.egg-info/SOURCES.txt +0 -0
  38. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlinpython.egg-info/dependency_links.txt +0 -0
  39. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlinpython.egg-info/requires.txt +0 -0
  40. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/gremlinpython.egg-info/top_level.txt +0 -0
  41. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/setup.cfg +0 -0
  42. {gremlinpython-3.6.4 → gremlinpython-3.6.6}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gremlinpython
3
- Version: 3.6.4
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
@@ -59,16 +59,16 @@ from the Python shell looks like this:
59
59
 
60
60
  >>> from gremlin_python.process.anonymous_traversal import traversal
61
61
  >>> from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
62
- >>> g = traversal().withRemote(DriverRemoteConnection('ws://localhost:8182/gremlin','g'))
62
+ >>> g = traversal().with_remote(DriverRemoteConnection('ws://localhost:8182/gremlin','g'))
63
63
 
64
64
  Once "g" has been created using a connection, it is then possible to start writing Gremlin traversals to query the
65
65
  remote graph:
66
66
 
67
- >>> g.V().both()[1:3].toList()
67
+ >>> g.V().both()[1:3].to_list()
68
68
  [v[2], v[4]]
69
- >>> g.V().both()[1].toList()
69
+ >>> g.V().both()[1].to_list()
70
70
  [v[2]]
71
- >>> g.V().both().name.toList()
71
+ >>> g.V().both().name.to_list()
72
72
  [lop, vadas, josh, marko, marko, josh, peter, ripple, lop, marko, josh, lop]
73
73
 
74
74
  -----------------
@@ -101,7 +101,7 @@ Create Vertex
101
101
 
102
102
  def create_vertex(self, vid, vlabel):
103
103
  # default database cardinality is used when Cardinality argument is not specified
104
- g.addV(vlabel).property(id, vid). \
104
+ g.add_v(vlabel).property(id, vid). \
105
105
  property(single, 'name', 'Apache'). \
106
106
  property('lastname', 'Tinkerpop'). \
107
107
  next()
@@ -112,13 +112,13 @@ Find Vertices
112
112
  .. code:: python
113
113
 
114
114
  def list_all(self, limit=500):
115
- g.V().limit(limit).elementMap().toList()
115
+ g.V().limit(limit).element_map().to_list()
116
116
 
117
117
  def find_vertex(self, vid):
118
- g.V(vid).elementMap().next()
118
+ g.V(vid).element_map().next()
119
119
 
120
120
  def list_by_label_name(self, vlabel, name):
121
- g.V().has(vlabel, 'name', name).elementMap().toList()
121
+ g.V().has(vlabel, 'name', name).element_map().to_list()
122
122
 
123
123
  Update Vertex
124
124
  ^^^^^^^^^^^^^
@@ -42,16 +42,16 @@ from the Python shell looks like this:
42
42
 
43
43
  >>> from gremlin_python.process.anonymous_traversal import traversal
44
44
  >>> from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
45
- >>> g = traversal().withRemote(DriverRemoteConnection('ws://localhost:8182/gremlin','g'))
45
+ >>> g = traversal().with_remote(DriverRemoteConnection('ws://localhost:8182/gremlin','g'))
46
46
 
47
47
  Once "g" has been created using a connection, it is then possible to start writing Gremlin traversals to query the
48
48
  remote graph:
49
49
 
50
- >>> g.V().both()[1:3].toList()
50
+ >>> g.V().both()[1:3].to_list()
51
51
  [v[2], v[4]]
52
- >>> g.V().both()[1].toList()
52
+ >>> g.V().both()[1].to_list()
53
53
  [v[2]]
54
- >>> g.V().both().name.toList()
54
+ >>> g.V().both().name.to_list()
55
55
  [lop, vadas, josh, marko, marko, josh, peter, ripple, lop, marko, josh, lop]
56
56
 
57
57
  -----------------
@@ -84,7 +84,7 @@ Create Vertex
84
84
 
85
85
  def create_vertex(self, vid, vlabel):
86
86
  # default database cardinality is used when Cardinality argument is not specified
87
- g.addV(vlabel).property(id, vid). \
87
+ g.add_v(vlabel).property(id, vid). \
88
88
  property(single, 'name', 'Apache'). \
89
89
  property('lastname', 'Tinkerpop'). \
90
90
  next()
@@ -95,13 +95,13 @@ Find Vertices
95
95
  .. code:: python
96
96
 
97
97
  def list_all(self, limit=500):
98
- g.V().limit(limit).elementMap().toList()
98
+ g.V().limit(limit).element_map().to_list()
99
99
 
100
100
  def find_vertex(self, vid):
101
- g.V(vid).elementMap().next()
101
+ g.V(vid).element_map().next()
102
102
 
103
103
  def list_by_label_name(self, vlabel, name):
104
- g.V().has(vlabel, 'name', name).elementMap().toList()
104
+ g.V().has(vlabel, 'name', name).element_map().to_list()
105
105
 
106
106
  Update Vertex
107
107
  ^^^^^^^^^^^^^
@@ -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.4'
20
- timestamp = 1684346759
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:
@@ -161,6 +176,9 @@ class Client:
161
176
  return self.submit_async(message, bindings, request_options)
162
177
 
163
178
  def submit_async(self, message, bindings=None, request_options=None):
179
+ if self.is_closed():
180
+ raise Exception("Client is closed")
181
+
164
182
  log.debug("message '%s'", str(message))
165
183
  args = {'gremlin': message, 'aliases': {'g': self._traversal_source}}
166
184
  processor = ''
@@ -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,20 +18,16 @@
18
18
  #
19
19
  import platform
20
20
 
21
+ gremlin_version = "3.6.6" # DO NOT MODIFY - Configured automatically by Maven Replacer Plugin
21
22
 
22
23
  def _generate_user_agent():
23
24
  application_name = "NotAvailable"
24
- try:
25
- from gremlin_python import __version__
26
- driver_version = __version__.version.replace(" ", "_")
27
- except ImportError:
28
- driver_version = "NotAvailable"
29
25
  runtime_version = platform.python_version().replace(" ", "_")
30
26
  os_name = platform.system().replace(" ", "_")
31
27
  os_version = platform.release().replace(" ", "_")
32
28
  architecture = platform.machine().replace(" ", "_")
33
29
  user_agent = "{appName} Gremlin-Python.{driverVersion} {runtimeVersion} {osName}.{osVersion} {cpuArch}".format(
34
- appName=application_name, driverVersion=driver_version, runtimeVersion=runtime_version,
30
+ appName=application_name, driverVersion=gremlin_version, runtimeVersion=runtime_version,
35
31
  osName=os_name, osVersion=os_version, cpuArch=architecture)
36
32
 
37
33
  return user_agent
@@ -134,7 +134,7 @@ class GraphTraversalSource(object):
134
134
  val = True if v is None else v
135
135
  if options_strategy is None:
136
136
  options_strategy = OptionsStrategy({k: val})
137
- source = self.withStrategies(options_strategy)
137
+ source = self.with_strategies(options_strategy)
138
138
  else:
139
139
  options_strategy[1].configuration[k] = val
140
140
 
@@ -1587,7 +1587,7 @@ def V(*args):
1587
1587
 
1588
1588
 
1589
1589
  def addE(*args):
1590
- return __.addE(*args)
1590
+ return __.add_e(*args)
1591
1591
 
1592
1592
 
1593
1593
  def add_e(*args):
@@ -1595,7 +1595,7 @@ def add_e(*args):
1595
1595
 
1596
1596
 
1597
1597
  def addV(*args):
1598
- return __.addV(*args)
1598
+ return __.add_v(*args)
1599
1599
 
1600
1600
 
1601
1601
  def add_v(*args):
@@ -1623,7 +1623,7 @@ def both(*args):
1623
1623
 
1624
1624
 
1625
1625
  def bothE(*args):
1626
- return __.bothE(*args)
1626
+ return __.both_e(*args)
1627
1627
 
1628
1628
 
1629
1629
  def both_e(*args):
@@ -1631,7 +1631,7 @@ def both_e(*args):
1631
1631
 
1632
1632
 
1633
1633
  def bothV(*args):
1634
- return __.bothV(*args)
1634
+ return __.both_v(*args)
1635
1635
 
1636
1636
 
1637
1637
  def both_v(*args):
@@ -1671,7 +1671,7 @@ def count(*args):
1671
1671
 
1672
1672
 
1673
1673
  def cyclicPath(*args):
1674
- return __.cyclicPath(*args)
1674
+ return __.cyclic_path(*args)
1675
1675
 
1676
1676
 
1677
1677
  def cyclic_path(*args):
@@ -1691,7 +1691,7 @@ def element(*args):
1691
1691
 
1692
1692
 
1693
1693
  def elementMap(*args):
1694
- return __.elementMap(*args)
1694
+ return __.element_map(*args)
1695
1695
 
1696
1696
 
1697
1697
  def element_map(*args):
@@ -1711,7 +1711,7 @@ def filter_(*args):
1711
1711
 
1712
1712
 
1713
1713
  def flatMap(*args):
1714
- return __.flatMap(*args)
1714
+ return __.flat_map(*args)
1715
1715
 
1716
1716
 
1717
1717
  def flat_map(*args):
@@ -1727,7 +1727,7 @@ def group(*args):
1727
1727
 
1728
1728
 
1729
1729
  def groupCount(*args):
1730
- return __.groupCount(*args)
1730
+ return __.group_count(*args)
1731
1731
 
1732
1732
 
1733
1733
  def group_count(*args):
@@ -1739,7 +1739,7 @@ def has(*args):
1739
1739
 
1740
1740
 
1741
1741
  def hasId(*args):
1742
- return __.hasId(*args)
1742
+ return __.has_id(*args)
1743
1743
 
1744
1744
 
1745
1745
  def has_id(*args):
@@ -1747,7 +1747,7 @@ def has_id(*args):
1747
1747
 
1748
1748
 
1749
1749
  def hasKey(*args):
1750
- return __.hasKey(*args)
1750
+ return __.has_key_(*args)
1751
1751
 
1752
1752
 
1753
1753
  def has_key_(*args):
@@ -1755,7 +1755,7 @@ def has_key_(*args):
1755
1755
 
1756
1756
 
1757
1757
  def hasLabel(*args):
1758
- return __.hasLabel(*args)
1758
+ return __.has_label(*args)
1759
1759
 
1760
1760
 
1761
1761
  def has_label(*args):
@@ -1763,7 +1763,7 @@ def has_label(*args):
1763
1763
 
1764
1764
 
1765
1765
  def hasNot(*args):
1766
- return __.hasNot(*args)
1766
+ return __.has_not(*args)
1767
1767
 
1768
1768
 
1769
1769
  def has_not(*args):
@@ -1771,7 +1771,7 @@ def has_not(*args):
1771
1771
 
1772
1772
 
1773
1773
  def hasValue(*args):
1774
- return __.hasValue(*args)
1774
+ return __.has_value(*args)
1775
1775
 
1776
1776
 
1777
1777
  def has_value(*args):
@@ -1787,7 +1787,7 @@ def identity(*args):
1787
1787
 
1788
1788
 
1789
1789
  def inE(*args):
1790
- return __.inE(*args)
1790
+ return __.in_e(*args)
1791
1791
 
1792
1792
 
1793
1793
  def in_e(*args):
@@ -1795,7 +1795,7 @@ def in_e(*args):
1795
1795
 
1796
1796
 
1797
1797
  def inV(*args):
1798
- return __.inV(*args)
1798
+ return __.in_v(*args)
1799
1799
 
1800
1800
 
1801
1801
  def in_v(*args):
@@ -1887,7 +1887,7 @@ def order(*args):
1887
1887
 
1888
1888
 
1889
1889
  def otherV(*args):
1890
- return __.otherV(*args)
1890
+ return __.other_v(*args)
1891
1891
 
1892
1892
 
1893
1893
  def other_v(*args):
@@ -1899,7 +1899,7 @@ def out(*args):
1899
1899
 
1900
1900
 
1901
1901
  def outE(*args):
1902
- return __.outE(*args)
1902
+ return __.out_e(*args)
1903
1903
 
1904
1904
 
1905
1905
  def out_e(*args):
@@ -1907,7 +1907,7 @@ def out_e(*args):
1907
1907
 
1908
1908
 
1909
1909
  def outV(*args):
1910
- return __.outV(*args)
1910
+ return __.out_v(*args)
1911
1911
 
1912
1912
 
1913
1913
  def out_v(*args):
@@ -1931,7 +1931,7 @@ def property(*args):
1931
1931
 
1932
1932
 
1933
1933
  def propertyMap(*args):
1934
- return __.propertyMap(*args)
1934
+ return __.property_map(*args)
1935
1935
 
1936
1936
 
1937
1937
  def property_map(*args):
@@ -1959,7 +1959,7 @@ def select(*args):
1959
1959
 
1960
1960
 
1961
1961
  def sideEffect(*args):
1962
- return __.sideEffect(*args)
1962
+ return __.side_effect(*args)
1963
1963
 
1964
1964
 
1965
1965
  def side_effect(*args):
@@ -1967,7 +1967,7 @@ def side_effect(*args):
1967
1967
 
1968
1968
 
1969
1969
  def simplePath(*args):
1970
- return __.simplePath(*args)
1970
+ return __.simple_path(*args)
1971
1971
 
1972
1972
 
1973
1973
  def simple_path(*args):
@@ -1995,7 +1995,7 @@ def tail(*args):
1995
1995
 
1996
1996
 
1997
1997
  def timeLimit(*args):
1998
- return __.timeLimit(*args)
1998
+ return __.time_limit(*args)
1999
1999
 
2000
2000
 
2001
2001
  def time_limit(*args):
@@ -2011,7 +2011,7 @@ def to(*args):
2011
2011
 
2012
2012
 
2013
2013
  def toE(*args):
2014
- return __.toE(*args)
2014
+ return __.to_e(*args)
2015
2015
 
2016
2016
 
2017
2017
  def to_e(*args):
@@ -2019,7 +2019,7 @@ def to_e(*args):
2019
2019
 
2020
2020
 
2021
2021
  def toV(*args):
2022
- return __.toV(*args)
2022
+ return __.to_v(*args)
2023
2023
 
2024
2024
 
2025
2025
  def to_v(*args):
@@ -2047,7 +2047,7 @@ def value(*args):
2047
2047
 
2048
2048
 
2049
2049
  def valueMap(*args):
2050
- return __.valueMap(*args)
2050
+ return __.value_map(*args)
2051
2051
 
2052
2052
 
2053
2053
  def value_map(*args):
@@ -0,0 +1,297 @@
1
+ #
2
+ # Licensed to the Apache Software Foundation (ASF) under one
3
+ # or more contributor license agreements. See the NOTICE file
4
+ # distributed with this work for additional information
5
+ # regarding copyright ownership. The ASF licenses this file
6
+ # to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance
8
+ # with the License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing,
13
+ # software distributed under the License is distributed on an
14
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ # KIND, either express or implied. See the License for the
16
+ # specific language governing permissions and limitations
17
+ # under the License.
18
+ #
19
+
20
+ """
21
+ Class that can turn traversals back into Gremlin Groovy format text queries.
22
+ Those queries can then be run in the Gremlin console or using the GLV submit(<String>) API or
23
+ sent to any TinkerPop compliant HTTP endpoint.
24
+ """
25
+ __author__ = 'Kelvin R. Lawrence (gfxman)'
26
+
27
+ import math
28
+ import numbers
29
+ import re
30
+
31
+ from gremlin_python.process.traversal import *
32
+ from gremlin_python.process.strategies import *
33
+ from gremlin_python.structure.graph import Vertex, Edge, VertexProperty
34
+ from datetime import datetime
35
+
36
+
37
+ class Translator:
38
+ """
39
+ Turn a bytecode object back into a textual query (Gremlin Groovy script).
40
+ """
41
+
42
+ # Dictionary used to reverse-map token IDs to strings
43
+ options = {
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'
54
+ }
55
+
56
+ conn_p = ['and', 'or']
57
+
58
+ def __init__(self, traversal_source=None):
59
+ self.traversal_source = traversal_source
60
+
61
+ def get_traversal_source(self):
62
+ return self.traversal_source
63
+
64
+ def get_target_language(self):
65
+ return "gremlin-groovy"
66
+
67
+ def of(self, traversal_source):
68
+ self.traversal_source = traversal_source
69
+ return self
70
+
71
+ # Do any needed special processing for the representation
72
+ # of strings and dates and boolean.
73
+ def fixup(self, v):
74
+ if isinstance(v, str):
75
+ return f'{v!r}' # use repr() format for canonical string rep
76
+ elif type(v) == datetime:
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'
95
+ else:
96
+ return str(v)
97
+
98
+ # Turn a Python datetime into the equivalent new Date(...)
99
+ def process_date(self, date):
100
+ y = date.year - 1900
101
+ mo = date.month
102
+ d = date.day
103
+ h = date.hour
104
+ mi = date.minute
105
+ s = date.second
106
+ return f'new Date({y},{mo},{d},{h},{mi},{s})'
107
+
108
+ # Do special processing needed to format predicates that come in
109
+ # such as "gt(a)" correctly.
110
+ def process_predicate(self, p):
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
117
+
118
+ # process the value of the predicates
119
+ def process_p_value(self, p):
120
+ res = str(p).split('(')[0] + '('
121
+ if type(p.value) == list:
122
+ res += '['
123
+ for v in p.value:
124
+ res += self.fixup(v) + ','
125
+ res = (res[0:-1] + ']') if len(p.value) > 0 else (res + ']')
126
+ else:
127
+ res += self.fixup(p.value)
128
+ if p.other is not None:
129
+ res += f',{self.fixup(p.other)}'
130
+ res += ')'
131
+ return res
132
+
133
+ # Special processing to handle strategies
134
+ def process_strategy(self, s):
135
+ c = 0
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"
201
+ else:
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)
211
+ c += 1
212
+ res += ']'
213
+ return res
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)})'
218
+
219
+ # Main driver of the translation. Different parts of
220
+ # a Traversal are handled appropriately.
221
+ def do_translation(self, step):
222
+ script = ''
223
+ params = step[1:]
224
+ script += '.' + step[0] + '('
225
+ if len(params) > 0:
226
+ c = 0
227
+ with_opts = False
228
+ is_merge_op = (step[0] == 'mergeV') or (step[0] == 'mergeE')
229
+ for p in params:
230
+ script += ',' if c > 0 else ''
231
+ if with_opts:
232
+ script += f'WithOptions.{self.options[p]}'
233
+ elif type(p) == Bytecode:
234
+ script += self.translate(p, True)
235
+ elif isinstance(p, P):
236
+ script += self.process_predicate(p)
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
248
+ tmp = str(p)
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
251
+ script += self.process_strategy(p)
252
+ elif type(p) == datetime:
253
+ script += self.process_date(p)
254
+ elif p == WithOptions.tokens:
255
+ script += 'WithOptions.tokens'
256
+ with_opts = True
257
+ elif isinstance(p, str):
258
+ script += f'{p!r}' # use repr() format for canonical string rep
259
+ elif type(p) == bool:
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)
265
+ elif p is None:
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)
277
+ else:
278
+ script += str(p)
279
+ c += 1
280
+ script += ')'
281
+ return script
282
+
283
+ # Translation starts here. There are two main parts to a
284
+ # traversal. Source instructions such as "withSideEffect"
285
+ # and "withStrategies", and step instructions such as
286
+ # "addV" and "repeat". If child is True we will generate
287
+ # anonymous traversal style syntax.
288
+ def translate(self, bytecode, child=False):
289
+ script = '__' if child else self.traversal_source
290
+
291
+ for step in bytecode.source_instructions:
292
+ script += self.do_translation(step)
293
+
294
+ for step in bytecode.step_instructions:
295
+ script += self.do_translation(step)
296
+
297
+ return script
@@ -77,7 +77,7 @@ class Traversal(object):
77
77
  def iterate(self):
78
78
  self.bytecode.add_step("none")
79
79
  while True:
80
- try: self.nextTraverser()
80
+ try: self.next_traverser()
81
81
  except StopIteration: return self
82
82
 
83
83
  def nextTraverser(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: gremlinpython
3
- Version: 3.6.4
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
@@ -59,16 +59,16 @@ from the Python shell looks like this:
59
59
 
60
60
  >>> from gremlin_python.process.anonymous_traversal import traversal
61
61
  >>> from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
62
- >>> g = traversal().withRemote(DriverRemoteConnection('ws://localhost:8182/gremlin','g'))
62
+ >>> g = traversal().with_remote(DriverRemoteConnection('ws://localhost:8182/gremlin','g'))
63
63
 
64
64
  Once "g" has been created using a connection, it is then possible to start writing Gremlin traversals to query the
65
65
  remote graph:
66
66
 
67
- >>> g.V().both()[1:3].toList()
67
+ >>> g.V().both()[1:3].to_list()
68
68
  [v[2], v[4]]
69
- >>> g.V().both()[1].toList()
69
+ >>> g.V().both()[1].to_list()
70
70
  [v[2]]
71
- >>> g.V().both().name.toList()
71
+ >>> g.V().both().name.to_list()
72
72
  [lop, vadas, josh, marko, marko, josh, peter, ripple, lop, marko, josh, lop]
73
73
 
74
74
  -----------------
@@ -101,7 +101,7 @@ Create Vertex
101
101
 
102
102
  def create_vertex(self, vid, vlabel):
103
103
  # default database cardinality is used when Cardinality argument is not specified
104
- g.addV(vlabel).property(id, vid). \
104
+ g.add_v(vlabel).property(id, vid). \
105
105
  property(single, 'name', 'Apache'). \
106
106
  property('lastname', 'Tinkerpop'). \
107
107
  next()
@@ -112,13 +112,13 @@ Find Vertices
112
112
  .. code:: python
113
113
 
114
114
  def list_all(self, limit=500):
115
- g.V().limit(limit).elementMap().toList()
115
+ g.V().limit(limit).element_map().to_list()
116
116
 
117
117
  def find_vertex(self, vid):
118
- g.V(vid).elementMap().next()
118
+ g.V(vid).element_map().next()
119
119
 
120
120
  def list_by_label_name(self, vlabel, name):
121
- g.V().has(vlabel, 'name', name).elementMap().toList()
121
+ g.V().has(vlabel, 'name', name).element_map().to_list()
122
122
 
123
123
  Update Vertex
124
124
  ^^^^^^^^^^^^^
@@ -1,173 +0,0 @@
1
- #
2
- # Licensed to the Apache Software Foundation (ASF) under one
3
- # or more contributor license agreements. See the NOTICE file
4
- # distributed with this work for additional information
5
- # regarding copyright ownership. The ASF licenses this file
6
- # to you under the Apache License, Version 2.0 (the
7
- # "License"); you may not use this file except in compliance
8
- # with the License. You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing,
13
- # software distributed under the License is distributed on an
14
- # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
- # KIND, either express or implied. See the License for the
16
- # specific language governing permissions and limitations
17
- # under the License.
18
- #
19
-
20
- """
21
- Class that can turn traversals back into Gremlin Groovy format text queries.
22
- Those queries can then be run in the Gremlin console or using the GLV submit(<String>) API or
23
- sent to any TinkerPop compliant HTTP endpoint.
24
- """
25
- __author__ = 'Kelvin R. Lawrence (gfxman)'
26
-
27
- from gremlin_python.process.graph_traversal import __
28
- from gremlin_python.process.anonymous_traversal import traversal
29
- from gremlin_python.process.traversal import *
30
- from gremlin_python.driver.driver_remote_connection import DriverRemoteConnection
31
- from gremlin_python.process.strategies import *
32
- from datetime import datetime
33
-
34
-
35
- class Translator:
36
- """
37
- Turn a bytecode object back into a textual query (Gremlin Groovy script).
38
- """
39
-
40
- # Dictionary used to reverse-map token IDs to strings
41
- 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'
52
- }
53
-
54
- def __init__(self, traversal_source=None):
55
- self.traversal_source = traversal_source
56
-
57
- def get_traversal_source(self):
58
- return self.traversal_source
59
-
60
- def get_target_language(self):
61
- return "gremlin-groovy"
62
-
63
- def of(self,traversal_source):
64
- self.traversal_source = traversal_source
65
- return self
66
-
67
- # Do any needed special processing for the representation
68
- # of strings and dates.
69
- def fixup(self, v):
70
- if type(v) == str:
71
- return f'\'{v}\''
72
- elif type(v) == datetime:
73
- return self.process_date(v)
74
- else:
75
- return str(v)
76
-
77
- # Turn a Python datetime into the equivalent new Date(...)
78
- def process_date(self, date):
79
- y = date.year - 1900
80
- mo = date.month
81
- d = date.day
82
- h = date.hour
83
- mi = date.minute
84
- s = date.second
85
- return f'new Date({y},{mo},{d},{h},{mi},{s})'
86
-
87
- # Do special processing needed to format predicates that come in
88
- # such as "gt(a)" correctly.
89
- def process_predicate(self, p):
90
- res = str(p).split('(')[0] + '('
91
-
92
- if type(p.value) == list:
93
- res += '['
94
- for v in p.value:
95
- res += self.fixup(v) + ','
96
- res = res[0:-1] + ']'
97
- else:
98
- res += self.fixup(p.value)
99
- if p.other is not None:
100
- res+= ',' + self.fixup(p.other)
101
- res += ')'
102
- return res
103
-
104
- # Special processing to handle strategies
105
- def process_strategy(self, s):
106
- 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)
114
- else:
115
- res += self.fixup(val)
116
- c += 1
117
- res += ')'
118
- return res
119
- pass
120
-
121
- # Main driver of the translation. Different parts of
122
- # a Traversal are handled appropriately.
123
- def do_translation(self, step):
124
- script = ''
125
- params = step[1:]
126
- script += '.' + step[0] + '('
127
- if len(params) > 0:
128
- c = 0
129
- with_opts = False
130
- for p in params:
131
- script += ',' if c > 0 else ''
132
- if with_opts:
133
- script += f'WithOptions.{self.options[p]}'
134
- elif type(p) == Bytecode:
135
- script += self.translate(p, True)
136
- elif type(p) == P:
137
- script += self.process_predicate(p)
138
- elif type(p) in [Cardinality, Pop, Operator]:
139
- tmp = str(p)
140
- script += tmp[0:-1] if tmp.endswith('_') else tmp
141
- elif type(p) in [ReadOnlyStrategy, SubgraphStrategy, VertexProgramStrategy,
142
- OptionsStrategy, PartitionStrategy]:
143
- script += self.process_strategy(p)
144
- elif type(p) == datetime:
145
- script += self.process_date(p)
146
- elif p == WithOptions.tokens:
147
- script += 'WithOptions.tokens'
148
- with_opts = True
149
- elif type(p) == str:
150
- script += f'\'{p}\''
151
- elif type(p) == bool:
152
- script += 'true' if p else 'false'
153
- else:
154
- script += str(p)
155
- c += 1
156
- script += ')'
157
- return script
158
-
159
- # Translation starts here. There are two main parts to a
160
- # traversal. Source instructions such as "withSideEffect"
161
- # and "withStrategies", and step instructions such as
162
- # "addV" and "repeat". If child is True we will generate
163
- # anonymous traversal style syntax.
164
- def translate(self, bytecode, child=False):
165
- script = '__' if child else self.traversal_source
166
-
167
- for step in bytecode.source_instructions:
168
- script += self.do_translation(step)
169
-
170
- for step in bytecode.step_instructions:
171
- script += self.do_translation(step)
172
-
173
- return script
File without changes
File without changes
File without changes
File without changes
File without changes