Geode Python Client Library
A modern async Python client for Geode graph database with QUIC + TLS 1.3 (default) or gRPC transport, query builders, and connection pooling.
Installation
pip install geode-client
Requirements
- Python 3.9+
- aioquic >= 0.9.0 (QUIC transport)
- protobuf >= 4.21.0 (wire format)
- grpcio >= 1.50.0 (gRPC transport)
- Geode server with QUIC or gRPC enabled
Quick Start
import asyncio
from geode_client import Client
async def main():
client = Client(host="127.0.0.1", port=3141, skip_verify=True)
async with client.connection() as conn:
page, _ = await conn.query("RETURN 1 AS x, 'Hello' AS greeting")
for row in page.rows:
x = row["x"].as_int
greeting = row["greeting"].as_string
print(f"x={x}, greeting={greeting}")
asyncio.run(main())
URL Connection Helper
from geode_client import open_database
client = open_database("quic://localhost:3141?insecure_tls_skip_verify=true")
async with client.connection() as conn:
page, _ = await conn.query("MATCH (n) RETURN n LIMIT 10")
gRPC Transport
from geode_client import open_database
client = open_database("grpc://localhost:50051")
Note (v0.3.19+): The gRPC transport now properly handles server-streaming responses. The Execute RPC streams a schema message followed by one or more data pages; earlier versions only read the first message, returning correct column metadata but empty rows. Upgrade to 0.3.19 or later for complete query results over gRPC.
TLS with Self-Signed Certificates
When skip_verify=True is set and the server uses a self-signed certificate, the
gRPC transport automatically extracts the certificate’s Common Name (CN) and uses
it for ssl_target_name_override. This means the hostname override matches the
cert’s CN (e.g. geode.local) rather than the connection hostname, so TLS
negotiation succeeds without additional configuration.
# skip_verify trusts the server cert and derives the hostname override from its CN
client = Client(host="10.0.0.5", port=50051, transport="grpc", skip_verify=True)
DSN Format
Note: See the official DSN specification for complete details.
quic://[username:password@]host[:port][?options] # QUIC transport (default port: 3141)
grpc://[username:password@]host[:port][?options] # gRPC transport (default port: 50051)
host:port # Scheme-less (defaults to QUIC)
Querying
Parameterized Queries
async with client.connection() as conn:
query = "MATCH (p:Person {name: $name}) RETURN p.age AS age"
params = {"name": "Alice"}
page, _ = await conn.query(query, params)
age = page.rows[0]["age"].as_int
print(f"Alice is {age} years old")
Query Builder
from geode_client import QueryBuilder
query_text, params = (
QueryBuilder()
.match("(p:Person {name: $name})-[:KNOWS]->(friend:Person)")
.where("friend.age > 25")
.return_("friend.name AS name", "friend.age AS age")
.order_by("friend.age DESC")
.limit(10)
.with_param("name", "Alice")
.build()
)
page, _ = await conn.query(query_text, params)
Pattern Builder
from geode_client import PatternBuilder, EdgeDirection
pattern = (
PatternBuilder()
.node("a", "Person", {"name": "$person1"})
.edge("knows", "KNOWS", EdgeDirection.UNDIRECTED)
.variable_length(1, 6)
.node("b", "Person", {"name": "$person2"})
.build()
)
Predicate Builder
from geode_client import PredicateBuilder
predicate = (
PredicateBuilder()
.greater_than("p.age", "25")
.is_not_null("p.email")
.in_("p.role", ["admin", "user"])
.build_and()
)
Transactions
async with client.connection() as conn:
await conn.begin()
try:
await conn.execute(
"CREATE (p:Person {name: $name, age: $age})",
{"name": "Bob", "age": 30}
)
await conn.commit()
except Exception:
await conn.rollback()
raise
Savepoints
async with client.connection() as conn:
await conn.begin()
await conn.execute("CREATE (p:Person {name: 'Alice', age: 30})")
sp = await conn.savepoint("before_update")
await conn.execute("MATCH (p:Person {name: 'Alice'}) SET p.age = 40")
await conn.rollback_to(sp)
await conn.commit()
Prepared Statements
stmt = await conn.prepare("MATCH (p:Person {name: $name}) RETURN p")
async with stmt:
page, _ = await stmt.execute({"name": "Alice"})
Connection Pooling
from geode_client import ConnectionPool
pool = ConnectionPool(
host="localhost",
port=3141,
min_size=2,
max_size=10,
timeout=30.0,
page_size=1000,
)
async with pool:
async with pool.acquire() as conn:
page, _ = await conn.query("MATCH (n) RETURN count(n) AS count")
print(page.rows[0]["count"].as_int)
Authentication
from geode_client import AuthClient
async with client.connection() as conn:
auth = AuthClient(conn)
session = await auth.login("admin", "secret")
print(session.token)
Type System
Geode values are returned as Value objects.
from geode_client import Value
page, _ = await conn.query("RETURN 42 AS answer")
value: Value = page.rows[0]["answer"]
print(value.as_int)
Repository
- GitLab: devnw/codepros/geode/geode-client-python
- PyPI: geode-client