Skip to content

Commit fee9056

Browse files
committed
Merge branch 'pr-1515' into 3.5-dev
2 parents 11f2b6e + 5a0a835 commit fee9056

File tree

16 files changed

+706
-68
lines changed

16 files changed

+706
-68
lines changed

.github/workflows/build-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ jobs:
163163
run: |
164164
touch gremlin-python/.glv
165165
mvn clean install -pl -:gremlin-javascript,-gremlin-dotnet,-:gremlin-dotnet-source,-:gremlin-dotnet-tests,-:gremlint -q -DskipTests -Dci
166-
mvn verify -pl gremlin-python
166+
mvn verify -pl gremlin-python -DincludeNeo4j
167167
dotnet:
168168
name: .NET
169169
timeout-minutes: 1200 # 20 minutes

CHANGELOG.asciidoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
2323
[[release-3-5-2]]
2424
=== TinkerPop 3.5.2 (Release Date: NOT OFFICIALLY RELEASED YET)
2525
26+
* Added support for `g.Tx()` in Python.
27+
* Added logging in in Python.
28+
* Fixed shutdown cleanup issue in Python aiohttp transport layer.
2629
* Added a `NoSugarTranslator` translator to `PythonTranslator` which translates Gremlin queries to Python without syntactic sugar (ex `g.V().limit(1)` instead of `g.V()[0:1]`)
2730
* Added support for `g.Tx()` in .NET.
2831
* Added support for `with()` constant options to `io()`.

docs/src/reference/gremlin-variants.asciidoc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,37 @@ Apache TinkerPop's JVM-based Gremlin traversal machine. As such, their `apply(Tr
913913
the strategy is encoded in the Gremlin-Python bytecode and transmitted to the Gremlin traversal machine for
914914
re-construction machine-side.
915915
916+
[[gremlin-python-transactions]]
917+
=== Transactions
918+
919+
To get a full understanding of this section, it would be good to start by reading the <<transactions,Transactions>>
920+
section of this documentation, which discusses transactions in the general context of TinkerPop itself. This section
921+
builds on that content by demonstrating the transactional syntax for Javascript.
922+
923+
[source,python]
924+
----
925+
g = traversal().withRemote(DriverRemoteConnection('ws://localhost:8182/gremlin'))
926+
927+
# Create a Transaction.
928+
tx = g.tx()
929+
930+
# Spawn a new GraphTraversalSource, binding all traversals established from it to tx.
931+
gtx = tx.begin()
932+
933+
try:
934+
# Execute a traversal within the transaction.
935+
gtx.addV("person").property("name", "Lyndon").iterate(),
936+
937+
# Commit the transaction. The transaction can no longer be used and cannot be re-used.
938+
# A new transaction can be spawned through g.tx().
939+
# The context of g remains sessionless throughout the process.
940+
gtx.commit()
941+
except Exception e:
942+
# Rollback the transaction if an error occurs.
943+
gtx.rollback()
944+
945+
----
946+
916947
[[gremlin-python-lambda]]
917948
=== The Lambda Solution
918949

docs/src/upgrade/release-3.5.x.asciidoc

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,20 @@ complete list of all the modifications that are part of this release.
3030
3131
=== Upgrading for Users
3232
33-
==== tx() in .NET
33+
==== Tx() in .NET and tx() in Python
3434
35-
After Javascript, .NET is now the second non-JVM variant of Gremlin to get support for
36-
link:https://tinkerpop.apache.org/docs/3.5.2/reference/#transactions[remote transactions]. An example of the `Tx()`
37-
syntax can be found in the .NET link:https://tinkerpop.apache.org/docs/3.5.2/reference/#gremlin-dotnet-transactions[Transaction Section].
35+
After Javascript, .NET and Python are now the second and third non-JVM variants of Gremlin to get support for
36+
link:https://tinkerpop.apache.org/docs/3.5.2/reference/#transactions[remote transactions].
3837
39-
See: link:https://issues.apache.org/jira/browse/TINKERPOP-2556[TINKERPOP-2556]
38+
An example of the .NET `Tx()` syntax can be found in the
39+
link:https://tinkerpop.apache.org/docs/3.5.2/reference/#gremlin-dotnet-transactions[.NET Transaction Section].
40+
41+
An example of the Python `tx()` syntax can be found in the
42+
link:https://tinkerpop.apache.org/docs/3.5.2/reference/#gremlin-dotnet-transactions[Python Transaction Section]
43+
44+
45+
See: link:https://issues.apache.org/jira/browse/TINKERPOP-2556[TINKERPOP-2556] for .NET and
46+
link:https://issues.apache.org/jira/browse/TINKERPOP-2555[TINKERPOP-2555] for Python
4047
4148
==== datetime()
4249

gremlin-python/pom.xml

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ limitations under the License.
2929
<!-- provides a way to convert maven.test.skip value to skipTests for use in skipping python tests -->
3030
<maven.test.skip>false</maven.test.skip>
3131
<skipTests>${maven.test.skip}</skipTests>
32+
<TEST_TRANSACTIONS>false</TEST_TRANSACTIONS>
3233
<gremlin.server.dir>${project.parent.basedir}/gremlin-server</gremlin.server.dir>
3334
</properties>
3435
<build>
@@ -216,6 +217,7 @@ limitations under the License.
216217
<target>
217218
<exec executable="env/bin/python" dir="${project.build.directory}/python3"
218219
failonerror="true">
220+
<env key="TEST_TRANSACTIONS" value="${TEST_TRANSACTIONS}"/>
219221
<env key="PYTHONPATH" value=""/>
220222
<env key="KRB5_CONFIG" value="${project.build.directory}/kdc/krb5.conf"/>
221223
<env key="KRB5CCNAME" value="${project.build.directory}/kdc/test-tkt.cc"/>
@@ -224,19 +226,22 @@ limitations under the License.
224226
<!-- radish seems to like all dependencies in place -->
225227
<exec executable="env/bin/python" dir="${project.build.directory}/python3"
226228
failonerror="true">
229+
<env key="TEST_TRANSACTIONS" value="${TEST_TRANSACTIONS}"/>
227230
<env key="PYTHONPATH" value=""/>
228231
<arg line="setup.py install"/>
229232
</exec>
230233
<!-- run for graphson 3.0 -->
231234
<exec executable="env/bin/radish" dir="${project.build.directory}/python3"
232235
failonerror="true">
236+
<env key="TEST_TRANSACTIONS" value="${TEST_TRANSACTIONS}"/>
233237
<env key="PYTHONPATH" value=""/>
234238
<env key="PYTHONIOENCODING" value="utf-8:surrogateescape"/>
235239
<arg line="-f dots -e -t -b ${project.build.directory}/python3/radish ${project.basedir}/../gremlin-test/features/ --user-data=&quot;serializer=application/vnd.gremlin-v3.0+json&quot;"/> <!-- -no-line-jump -->
236240
</exec>
237241
<!-- run for graphbinary 1.0 -->
238242
<exec executable="env/bin/radish" dir="${project.build.directory}/python3"
239243
failonerror="true">
244+
<env key="TEST_TRANSACTIONS" value="${TEST_TRANSACTIONS}"/>
240245
<env key="PYTHONPATH" value=""/>
241246
<env key="PYTHONIOENCODING" value="utf-8:surrogateescape"/>
242247
<arg line="-f dots -e -t -b ${project.build.directory}/python3/radish ${project.basedir}/../gremlin-test/features/ --user-data=&quot;serializer=application/vnd.graphbinary-v1.0&quot;"/> <!-- -no-line-jump -->
@@ -260,6 +265,11 @@ limitations under the License.
260265
<artifactId>gremlin-test</artifactId>
261266
<version>${project.version}</version>
262267
</dependency>
268+
<dependency>
269+
<groupId>org.apache.tinkerpop</groupId>
270+
<artifactId>neo4j-gremlin</artifactId>
271+
<version>${project.version}</version>
272+
</dependency>
263273
<dependency>
264274
<groupId>org.codehaus.groovy</groupId>
265275
<artifactId>groovy-all</artifactId>
@@ -354,6 +364,118 @@ limitations under the License.
354364
</plugins>
355365
</build>
356366
</profile>
367+
<!--
368+
This profile will include neo4j for purposes of transactional testing within Gremlin Server.
369+
Tests that require neo4j specifically will be "ignored" if this profile is not turned on.
370+
-->
371+
<profile>
372+
<id>include-neo4j</id>
373+
<activation>
374+
<activeByDefault>false</activeByDefault>
375+
<property>
376+
<name>includeNeo4j</name>
377+
</property>
378+
</activation>
379+
<properties>
380+
<TEST_TRANSACTIONS>true</TEST_TRANSACTIONS>
381+
</properties>
382+
<build>
383+
<plugins>
384+
<plugin>
385+
<groupId>org.codehaus.gmavenplus</groupId>
386+
<artifactId>gmavenplus-plugin</artifactId>
387+
<dependencies>
388+
<dependency>
389+
<groupId>org.neo4j</groupId>
390+
<artifactId>neo4j-tinkerpop-api-impl</artifactId>
391+
<version>0.9-3.4.0</version>
392+
<exclusions>
393+
<exclusion>
394+
<groupId>org.neo4j</groupId>
395+
<artifactId>neo4j-kernel</artifactId>
396+
</exclusion>
397+
<exclusion>
398+
<groupId>org.apache.commons</groupId>
399+
<artifactId>commons-lang3</artifactId>
400+
</exclusion>
401+
<exclusion>
402+
<groupId>org.apache.commons</groupId>
403+
<artifactId>commons-text</artifactId>
404+
</exclusion>
405+
<exclusion>
406+
<groupId>com.github.ben-manes.caffeine</groupId>
407+
<artifactId>caffeine</artifactId>
408+
</exclusion>
409+
<exclusion>
410+
<groupId>org.scala-lang</groupId>
411+
<artifactId>scala-library</artifactId>
412+
</exclusion>
413+
<exclusion>
414+
<groupId>org.scala-lang</groupId>
415+
<artifactId>scala-reflect</artifactId>
416+
</exclusion>
417+
<exclusion>
418+
<groupId>org.slf4j</groupId>
419+
<artifactId>slf4j-api</artifactId>
420+
</exclusion>
421+
<exclusion>
422+
<groupId>org.slf4j</groupId>
423+
<artifactId>slf4j-nop</artifactId>
424+
</exclusion>
425+
<exclusion>
426+
<groupId>org.apache.lucene</groupId>
427+
<artifactId>lucene-core</artifactId>
428+
</exclusion>
429+
<exclusion>
430+
<groupId>io.dropwizard.metrics</groupId>
431+
<artifactId>metrics-core</artifactId>
432+
</exclusion>
433+
<exclusion>
434+
<groupId>io.netty</groupId>
435+
<artifactId>netty-all</artifactId>
436+
</exclusion>
437+
<exclusion>
438+
<groupId>org.ow2.asm</groupId>
439+
<artifactId>asm</artifactId>
440+
</exclusion>
441+
</exclusions>
442+
</dependency>
443+
<dependency>
444+
<groupId>org.scala-lang</groupId>
445+
<artifactId>scala-library</artifactId>
446+
<version>2.11.8</version>
447+
</dependency>
448+
<dependency>
449+
<groupId>org.scala-lang</groupId>
450+
<artifactId>scala-reflect</artifactId>
451+
<version>2.11.8</version>
452+
</dependency>
453+
<dependency>
454+
<groupId>org.apache.lucene</groupId>
455+
<artifactId>lucene-core</artifactId>
456+
<version>5.5.0</version>
457+
</dependency>
458+
<dependency>
459+
<groupId>io.dropwizard.metrics</groupId>
460+
<artifactId>metrics-core</artifactId>
461+
<version>4.0.2</version>
462+
</dependency>
463+
<dependency>
464+
<groupId>org.neo4j</groupId>
465+
<artifactId>neo4j-kernel</artifactId>
466+
<version>3.4.11</version>
467+
<exclusions>
468+
<exclusion>
469+
<groupId>io.netty</groupId>
470+
<artifactId>netty-all</artifactId>
471+
</exclusion>
472+
</exclusions>
473+
</dependency>
474+
</dependencies>
475+
</plugin>
476+
</plugins>
477+
</build>
478+
</profile>
357479
<!--
358480
Provides a way to deploy the gremlinpython GLV to pypi. This cannot be part of the standard maven execution
359481
because pypi does not have a staging environment like sonatype for releases. As soon as the release is

gremlin-python/src/main/python/gremlin_python/driver/aiohttp/transport.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@
1616
# specific language governing permissions and limitations
1717
# under the License.
1818
#
19-
20-
2119
import aiohttp
2220
import asyncio
2321
import async_timeout
2422
from aiohttp import ClientResponseError
23+
import logging
2524

2625
from gremlin_python.driver.transport import AbstractBaseTransport
2726

@@ -58,6 +57,11 @@ def __init__(self, call_from_event_loop=None, read_timeout=None, write_timeout=N
5857
if "ssl_options" in self._aiohttp_kwargs:
5958
self._aiohttp_kwargs["ssl"] = self._aiohttp_kwargs.pop("ssl_options")
6059

60+
def __del__(self):
61+
# Close will only actually close if things are left open, so this is safe to call.
62+
# Clean up any connection resources and close the event loop.
63+
self.close()
64+
6165
def connect(self, url, headers=None):
6266
# Inner function to perform async connect.
6367
async def async_connect():
@@ -116,10 +120,13 @@ async def async_read():
116120
def close(self):
117121
# Inner function to perform async close.
118122
async def async_close():
119-
if not self._websocket.closed:
123+
if self._websocket is not None and not self._websocket.closed:
120124
await self._websocket.close()
121-
if not self._client_session.closed:
125+
self._websocket = None
126+
127+
if self._client_session is not None and not self._client_session.closed:
122128
await self._client_session.close()
129+
self._client_session = None
123130

124131
# If the loop is not closed (connection hasn't already been closed)
125132
if not self._loop.is_closed():

0 commit comments

Comments
 (0)