This is an automated email from the ASF dual-hosted git repository.
andreac pushed a commit to branch 3.7-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/3.7-dev by this push:
new 2cd2748aa4 Integrate Python driver examples into automated build
process (#3231)
2cd2748aa4 is described below
commit 2cd2748aa408854edb004f8c21836432e28619b6
Author: kirill-stepanishin <[email protected]>
AuthorDate: Thu Nov 20 16:53:35 2025 -0800
Integrate Python driver examples into automated build process (#3231)
Integrates Python Gremlin examples into CI to ensure they remain functional
in future releases. Examples now execute automatically after integration tests
and fail the build if broken.
Changes Made
- Added example execution to gremlin-python-integration-tests container in
docker-compose.yml
- Made server URLs configurable via environment variables (replaces
hardcoded localhost:8182)
- Added configurable vertex labels and targeted cleanup using has_label()
- Added graph binding detection - uses gmodern in CI, g locally for proper
environment handling
---
CHANGELOG.asciidoc | 1 +
gremlin-examples/gremlin-python/basic_gremlin.py | 14 +++---
gremlin-examples/gremlin-python/connections.py | 32 +++++++------
gremlin-python/docker-compose.yml | 8 +++-
.../src/main/python/examples/basic_gremlin.py | 16 ++++---
.../src/main/python/examples/connections.py | 53 ++++++++++++++++------
.../src/main/python/examples/modern_traversals.py | 12 ++++-
7 files changed, 92 insertions(+), 44 deletions(-)
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 72b4455741..b292f8939a 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -22,6 +22,7 @@
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
[[release-3-7-6]]
=== TinkerPop 3.7.6 (NOT OFFICIALLY RELEASED YET)
+* Integrated Python driver examples into automated build process to ensure
examples remain functional.
[[release-3-7-5]]
=== TinkerPop 3.7.5 (Release Date: November 12, 2025)
diff --git a/gremlin-examples/gremlin-python/basic_gremlin.py
b/gremlin-examples/gremlin-python/basic_gremlin.py
index 256ed98441..c351270de8 100644
--- a/gremlin-examples/gremlin-python/basic_gremlin.py
+++ b/gremlin-examples/gremlin-python/basic_gremlin.py
@@ -23,15 +23,17 @@ from gremlin_python.process.anonymous_traversal import
traversal
from gremlin_python.process.strategies import *
from gremlin_python.driver.driver_remote_connection import
DriverRemoteConnection
+VERTEX_LABEL = 'person'
def main():
- rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g')
+ server_url = 'ws://localhost:8182/gremlin'
+ rc = DriverRemoteConnection(server_url, 'g')
g = traversal().with_remote(rc)
# basic Gremlin: adding and retrieving data
- v1 = g.add_v('person').property('name', 'marko').next()
- v2 = g.add_v('person').property('name', 'stephen').next()
- v3 = g.add_v('person').property('name', 'vadas').next()
+ v1 = g.add_v(VERTEX_LABEL).property('name', 'marko').next()
+ v2 = g.add_v(VERTEX_LABEL).property('name', 'stephen').next()
+ v3 = g.add_v(VERTEX_LABEL).property('name', 'vadas').next()
# be sure to use a terminating step like next() or iterate() so that the
traversal "executes"
# iterate() does not return any data and is used to just generate
side-effects (i.e. write data to the database)
@@ -39,11 +41,11 @@ def main():
g.V(v1).add_e('knows').to(v3).property('weight', 0.75).iterate()
# retrieve the data from the "marko" vertex
- marko = g.V().has('person', 'name', 'marko').values('name').next()
+ marko = g.V().has(VERTEX_LABEL, 'name', 'marko').values('name').next()
print("name: " + marko)
# find the "marko" vertex and then traverse to the people he "knows" and
return their data
- people_marko_knows = g.V().has('person', 'name',
'marko').out('knows').values('name').to_list()
+ people_marko_knows = g.V().has(VERTEX_LABEL, 'name',
'marko').out('knows').values('name').to_list()
for person in people_marko_knows:
print("marko knows " + person)
diff --git a/gremlin-examples/gremlin-python/connections.py
b/gremlin-examples/gremlin-python/connections.py
index f268e6c27d..9997a181eb 100644
--- a/gremlin-examples/gremlin-python/connections.py
+++ b/gremlin-examples/gremlin-python/connections.py
@@ -24,6 +24,7 @@ from gremlin_python.process.strategies import *
from gremlin_python.driver.driver_remote_connection import
DriverRemoteConnection
from gremlin_python.driver.serializer import GraphBinarySerializersV1
+VERTEX_LABEL = 'connection'
def main():
with_remote()
@@ -40,15 +41,13 @@ def with_remote():
#
# which starts it in "console" mode with an empty in-memory TinkerGraph
ready to go bound to a
# variable named "g" as referenced in the following line.
- rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g')
+ server_url = 'ws://localhost:8182/gremlin'
+ rc = DriverRemoteConnection(server_url, 'g')
g = traversal().with_remote(rc)
- # drop existing vertices
- g.V().drop().iterate()
-
# simple query to verify connection
- v = g.add_v().iterate()
- count = g.V().count().next()
+ v = g.add_v(VERTEX_LABEL).iterate()
+ count = g.V().has_label(VERTEX_LABEL).count().next()
print("Vertex count: " + str(count))
# cleanup
@@ -57,11 +56,12 @@ def with_remote():
# connecting with plain text authentication
def with_auth():
- rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g',
username='stephen', password='password')
+ server_url = 'ws://localhost:8182/gremlin'
+ rc = DriverRemoteConnection(server_url, 'g', username='stephen',
password='password')
g = traversal().with_remote(rc)
- v = g.add_v().iterate()
- count = g.V().count().next()
+ v = g.add_v(VERTEX_LABEL).iterate()
+ count = g.V().has_label(VERTEX_LABEL).count().next()
print("Vertex count: " + str(count))
rc.close()
@@ -69,11 +69,12 @@ def with_auth():
# connecting with Kerberos SASL authentication
def with_kerberos():
- rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g',
kerberized_service='[email protected]')
+ server_url = 'ws://localhost:8182/gremlin'
+ rc = DriverRemoteConnection(server_url, 'g',
kerberized_service='[email protected]')
g = traversal().with_remote(rc)
- v = g.add_v().iterate()
- count = g.V().count().next()
+ v = g.add_v(VERTEX_LABEL).iterate()
+ count = g.V().has_label(VERTEX_LABEL).count().next()
print("Vertex count: " + str(count))
rc.close()
@@ -81,8 +82,9 @@ def with_kerberos():
# connecting with customized configurations
def with_configs():
+ server_url = 'ws://localhost:8182/gremlin'
rc = DriverRemoteConnection(
- 'ws://localhost:8182/gremlin', 'g',
+ server_url, 'g',
username="", password="", kerberized_service='',
message_serializer=GraphBinarySerializersV1(), graphson_reader=None,
graphson_writer=None, headers=None, session=None,
@@ -90,8 +92,8 @@ def with_configs():
)
g = traversal().with_remote(rc)
- v = g.add_v().iterate()
- count = g.V().count().next()
+ v = g.add_v(VERTEX_LABEL).iterate()
+ count = g.V().has_label(VERTEX_LABEL).count().next()
print("Vertex count: " + str(count))
rc.close()
diff --git a/gremlin-python/docker-compose.yml
b/gremlin-python/docker-compose.yml
index 9879ae8a0c..8b9ae9e2ac 100644
--- a/gremlin-python/docker-compose.yml
+++ b/gremlin-python/docker-compose.yml
@@ -72,7 +72,13 @@ services:
&& pip install .[test,kerberos]
&& pytest
&& radish -f dots -e -t -b ./radish ./gremlin-test
--user-data='serializer=application/vnd.gremlin-v3.0+json'
- && radish -f dots -e -t -b ./radish ./gremlin-test
--user-data='serializer=application/vnd.graphbinary-v1.0';
+ && radish -f dots -e -t -b ./radish ./gremlin-test
--user-data='serializer=application/vnd.graphbinary-v1.0'
+ && pip install .
+ && echo 'Running examples...'
+ && python3 examples/basic_gremlin.py
+ && python3 examples/connections.py
+ && python3 examples/modern_traversals.py
+ && echo 'All examples completed successfully';
EXIT_CODE=$$?; chown -R `stat -c "%u:%g" .` .; exit $$EXIT_CODE"
depends_on:
gremlin-server-test-python:
diff --git a/gremlin-python/src/main/python/examples/basic_gremlin.py
b/gremlin-python/src/main/python/examples/basic_gremlin.py
index 256ed98441..2c08621896 100644
--- a/gremlin-python/src/main/python/examples/basic_gremlin.py
+++ b/gremlin-python/src/main/python/examples/basic_gremlin.py
@@ -16,6 +16,7 @@
# under the License.
import sys
+import os
sys.path.append("..")
@@ -23,15 +24,18 @@ from gremlin_python.process.anonymous_traversal import
traversal
from gremlin_python.process.strategies import *
from gremlin_python.driver.driver_remote_connection import
DriverRemoteConnection
+VERTEX_LABEL = os.getenv('VERTEX_LABEL', 'person')
def main():
- rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g')
+ # if there is a port placeholder in the env var then we are running with
docker so set appropriate port
+ server_url = os.getenv('GREMLIN_SERVER_URL',
'ws://localhost:8182/gremlin').format(45940)
+ rc = DriverRemoteConnection(server_url, 'g')
g = traversal().with_remote(rc)
# basic Gremlin: adding and retrieving data
- v1 = g.add_v('person').property('name', 'marko').next()
- v2 = g.add_v('person').property('name', 'stephen').next()
- v3 = g.add_v('person').property('name', 'vadas').next()
+ v1 = g.add_v(VERTEX_LABEL).property('name', 'marko').next()
+ v2 = g.add_v(VERTEX_LABEL).property('name', 'stephen').next()
+ v3 = g.add_v(VERTEX_LABEL).property('name', 'vadas').next()
# be sure to use a terminating step like next() or iterate() so that the
traversal "executes"
# iterate() does not return any data and is used to just generate
side-effects (i.e. write data to the database)
@@ -39,11 +43,11 @@ def main():
g.V(v1).add_e('knows').to(v3).property('weight', 0.75).iterate()
# retrieve the data from the "marko" vertex
- marko = g.V().has('person', 'name', 'marko').values('name').next()
+ marko = g.V().has(VERTEX_LABEL, 'name', 'marko').values('name').next()
print("name: " + marko)
# find the "marko" vertex and then traverse to the people he "knows" and
return their data
- people_marko_knows = g.V().has('person', 'name',
'marko').out('knows').values('name').to_list()
+ people_marko_knows = g.V().has(VERTEX_LABEL, 'name',
'marko').out('knows').values('name').to_list()
for person in people_marko_knows:
print("marko knows " + person)
diff --git a/gremlin-python/src/main/python/examples/connections.py
b/gremlin-python/src/main/python/examples/connections.py
index f268e6c27d..d4e36d4943 100644
--- a/gremlin-python/src/main/python/examples/connections.py
+++ b/gremlin-python/src/main/python/examples/connections.py
@@ -16,6 +16,9 @@
# under the License.
import sys
+import os
+import ssl
+import socket
sys.path.append("..")
@@ -23,7 +26,9 @@ from gremlin_python.process.anonymous_traversal import
traversal
from gremlin_python.process.strategies import *
from gremlin_python.driver.driver_remote_connection import
DriverRemoteConnection
from gremlin_python.driver.serializer import GraphBinarySerializersV1
+from gremlin_python.driver.aiohttp.transport import AiohttpTransport
+VERTEX_LABEL = os.getenv('VERTEX_LABEL', 'connection')
def main():
with_remote()
@@ -40,15 +45,14 @@ def with_remote():
#
# which starts it in "console" mode with an empty in-memory TinkerGraph
ready to go bound to a
# variable named "g" as referenced in the following line.
- rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g')
+ # if there is a port placeholder in the env var then we are running with
docker so set appropriate port
+ server_url = os.getenv('GREMLIN_SERVER_URL',
'ws://localhost:8182/gremlin').format(45940)
+ rc = DriverRemoteConnection(server_url, 'g')
g = traversal().with_remote(rc)
- # drop existing vertices
- g.V().drop().iterate()
-
# simple query to verify connection
- v = g.add_v().iterate()
- count = g.V().count().next()
+ v = g.add_v(VERTEX_LABEL).iterate()
+ count = g.V().has_label(VERTEX_LABEL).count().next()
print("Vertex count: " + str(count))
# cleanup
@@ -57,11 +61,23 @@ def with_remote():
# connecting with plain text authentication
def with_auth():
- rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g',
username='stephen', password='password')
+ # if there is a port placeholder in the env var then we are running with
docker so set appropriate port
+ server_url = os.getenv('GREMLIN_SERVER_BASIC_AUTH_URL',
'ws://localhost:8182/gremlin').format(45941)
+
+ # disable SSL certificate verification for CI environments
+ if ':45941' in server_url:
+ ssl_opts = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
+ ssl_opts.check_hostname = False
+ ssl_opts.verify_mode = ssl.CERT_NONE
+ rc = DriverRemoteConnection(server_url, 'g', username='stephen',
password='password',
+ transport_factory=lambda:
AiohttpTransport(ssl_options=ssl_opts))
+ else:
+ rc = DriverRemoteConnection(server_url, 'g', username='stephen',
password='password')
+
g = traversal().with_remote(rc)
- v = g.add_v().iterate()
- count = g.V().count().next()
+ v = g.add_v(VERTEX_LABEL).iterate()
+ count = g.V().has_label(VERTEX_LABEL).count().next()
print("Vertex count: " + str(count))
rc.close()
@@ -69,11 +85,16 @@ def with_auth():
# connecting with Kerberos SASL authentication
def with_kerberos():
- rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g',
kerberized_service='[email protected]')
+ # if there is a port placeholder in the env var then we are running with
docker so set appropriate port
+ server_url = os.getenv('GREMLIN_SERVER_URL',
'ws://localhost:8182/gremlin').format(45942)
+ kerberos_hostname = os.getenv('KRB_HOSTNAME', socket.gethostname())
+ kerberized_service = f'test-service@{kerberos_hostname}'
+
+ rc = DriverRemoteConnection(server_url, 'g',
kerberized_service=kerberized_service)
g = traversal().with_remote(rc)
- v = g.add_v().iterate()
- count = g.V().count().next()
+ v = g.add_v(VERTEX_LABEL).iterate()
+ count = g.V().has_label(VERTEX_LABEL).count().next()
print("Vertex count: " + str(count))
rc.close()
@@ -81,8 +102,10 @@ def with_kerberos():
# connecting with customized configurations
def with_configs():
+ # if there is a port placeholder in the env var then we are running with
docker so set appropriate port
+ server_url = os.getenv('GREMLIN_SERVER_URL',
'ws://localhost:8182/gremlin').format(45940)
rc = DriverRemoteConnection(
- 'ws://localhost:8182/gremlin', 'g',
+ server_url, 'g',
username="", password="", kerberized_service='',
message_serializer=GraphBinarySerializersV1(), graphson_reader=None,
graphson_writer=None, headers=None, session=None,
@@ -90,8 +113,8 @@ def with_configs():
)
g = traversal().with_remote(rc)
- v = g.add_v().iterate()
- count = g.V().count().next()
+ v = g.add_v(VERTEX_LABEL).iterate()
+ count = g.V().has_label(VERTEX_LABEL).count().next()
print("Vertex count: " + str(count))
rc.close()
diff --git a/gremlin-python/src/main/python/examples/modern_traversals.py
b/gremlin-python/src/main/python/examples/modern_traversals.py
index ae757b10b4..bbab62d110 100644
--- a/gremlin-python/src/main/python/examples/modern_traversals.py
+++ b/gremlin-python/src/main/python/examples/modern_traversals.py
@@ -16,6 +16,7 @@
# under the License.
import sys
+import os
sys.path.append("..")
@@ -31,7 +32,16 @@ def main():
# This example requires the Modern toy graph to be preloaded upon
launching the Gremlin server.
# For details, see
https://tinkerpop.apache.org/docs/current/reference/#gremlin-server-docker-image
and use
# conf/gremlin-server-modern.yaml.
- rc = DriverRemoteConnection('ws://localhost:8182/gremlin', 'g')
+ # if there is a port placeholder in the env var then we are running with
docker so set appropriate port
+ server_url = os.getenv('GREMLIN_SERVER_URL',
'ws://localhost:8182/gremlin').format(45940)
+
+ # CI uses port 45940 with gmodern binding, local uses 8182 with g binding
+ if ':45940' in server_url:
+ graph_binding = 'gmodern' # CI environment
+ else:
+ graph_binding = 'g' # Local environment
+
+ rc = DriverRemoteConnection(server_url, graph_binding)
g = traversal().with_remote(rc)
e1 = g.V(1).both_e().to_list() # (1)