×
tina4-ultipa
The Ultipa graph driver for Python
A full-fidelity gRPC client for the Ultipa graph database — every GQL type decoded, no Tina4 lock-in.
Quick Start • Type Support • Ultipa Docs • Protocol • tina4.com
A thin, standalone gRPC driver for the Ultipa graph
database (ultipa-gqldb). It is the Ultipa driver behind
Tina4's graph data layer — but has no Tina4 dependency and
is perfectly usable on its own. Tina4's core stays zero-dependency; this driver is
an optional package loaded only for ultipa:// connections, speaking gRPC directly
through grpcio — with no protobuf runtime dependency. This package's own
hand-rolled proto3 codec (src/tina4_ultipa/_pb.py) covers the 8 gqldb messages
we consume, so pip install never drags in protobuf and its version churn.
Ultipa is a high-performance graph database with a GQL (ISO/IEC 39075) query surface. Learn more at ultipa.com · docs at ultipa.com/docs.
Why this driver
- Complete value decoding. Every gqldb
PropertyTypeis decoded to a natural Python value — including the composites and temporals most thin clients skip (see Type support). - Real gRPC, no protobuf runtime. Uses
grpciofor HTTP/2 + gRPC framing, and this package's own hand-rolled proto3 codec (src/tina4_ultipa/_pb.py) for the payloads — sopip installnever drags inprotobufand its version churn, and there is no protoc reflection round-trip or codegen step at install time. - Fails loud. A bad statement raises; it never returns a falsy value you might
miss. An unreachable host raises within your
connect_timeout. - Cross-language parity. The same driver exists for Python, Node.js, Ruby and PHP, decoding byte-for-byte identically.
Install
pip install tina4-ultipa
Quick start
from tina4_ultipa import UltipaClient
# from a URL...
db = UltipaClient.from_url("ultipa://admin:password@localhost:60061/mygraph")
# ...or explicitly
db = UltipaClient("localhost", 60061, username="admin", password="password", graph="mygraph")
# read — GQL text + optional named params
for row in db.query("MATCH (n:Person) WHERE n.age > $min RETURN n.name AS name",
params={"min": 21}):
print(row["name"])
# write — dml stats on success, raises on a bad statement
r = db.execute("INSERT (:Person {name: 'Alice', age: 30})")
print(r.dml_stats["inserted_nodes"]) # 1
db.close()
query() runs a read, execute() a write — both take GQL and optional params
and return an UltipaResult:
| Member | Meaning |
|---|---|
.columns |
column names |
.rows |
decoded rows (lists of Python values) |
.dicts() |
rows as dicts keyed by column |
.scalar() |
first cell of the first row |
.rows_affected, .dml_stats, .warnings |
write metadata |
Errors: a bad statement raises UltipaError; an unreachable host raises
UltipaConnectError within connect_timeout, naming host, port and elapsed time.
Type support
Every gqldb PropertyType decodes to a natural Python value:
| Category | Types | Decodes to |
|---|---|---|
| Numeric | int32/uint32/int64/uint64, float, double | int / float |
| Text | string, text | str |
| Boolean / null | bool, null, unset | bool / None |
| Binary | blob | bytes (e.g. an image, round-trips intact) |
| Decimal | decimal | str (precision-preserving) |
| Temporal | date, local/zoned time, local/zoned datetime, timestamp | ISO-8601 str |
| Interval | year-to-month, day-to-second | {"months": …} / {"seconds": …, "nanoseconds": …} |
| Spatial | point, point3d | {"x", "y"[, "z"], "srid"} |
| Vector | vector | list[float] |
| Graph | node, edge, path | dict (_kind node/edge/path; nodes/edges carry id, labels/type, properties, internal uuid) |
| Tabular | list, set, map, record, table | list / dict |
| Error | error | {"code", "message"} |
Node/edge dicts include the 8-byte internal-id (uuid) trailer emitted by
gqldb 6.1.147+.
Protocol
ultipa-gqldb speaks gRPC (default port 60061, protobuf package gqldb). The
driver authenticates with SessionService.Login, passes the returned session_id
on every call as the session-id metadata header (as an unsigned decimal), then
runs QueryService.Gql. Each value is a TypedValue{type, bytes}; all multi-byte
integers are little-endian. The full byte-level encoding is documented in
PROTOCOL.md — grounded in Ultipa's official gqldb SDK and proto,
and verified live against gqldb-grpc 6.2.130 CE.
Sample data pack
Get a real graph into your community-edition instance in seconds — 10 people (with photos), 3 companies, 3 projects, 5 skills and 62 relationships:
python examples/seed.py ultipa://admin:PASSWORD@HOST:60061
# graph defaults to "default"; override with TINA4_ULTIPA_GRAPH
Then explore it:
MATCH (n:Person)-[e]->(m) RETURN n, e, m LIMIT 100
RETURN db.overview()
The pack lives in examples/ — people.json describes the graph and
sample_data/faces/*.jpg are 64px portraits of AI-generated, non-existent people
(thispersondoesnotexist.com) stored as BLOB
properties, so it also demonstrates binary round-tripping through gqldb. Re-running is
safe — it clears the demo labels (Person/Company/Project/Skill) first.
Testing
Real, no-mock tests run against a live server:
TINA4_TEST_ULTIPA_URL=ultipa://admin:password@host:60061 python tests/test_driver.py
They cover scalars, node/edge/list/map decoding, the full temporal/spatial/interval set, path decoding, and a BLOB image round-trip.
Links
- Ultipa — website ultipa.com · docs ultipa.com/docs · GQL query language reference in the docs
- Tina4 — tina4.com · the framework this driver powers
- This driver — github.com/tina4stack/ultipa-python · sibling drivers for Node.js, Ruby, PHP
License
MIT. Note: the Ultipa community-edition server is licensed by Ultipa for personal / non-commercial use — review Ultipa's terms before you deploy it. This driver is an independent client and may not be officially supported by Ultipa.
Sponsored by Code Infinity · part of the Tina4 stack.
Release files for tina4-ultipa 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tina4_ultipa-0.2.1.tar.gz | 19.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tina4_ultipa-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 35.6 kB
Release files / tina4_ultipa-0.2.1.tar.gz
| Download URL | tina4_ultipa-0.2.1.tar.gz |
|---|---|
| Size | 19.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0ef692b395ccb27d64e81079f08f700889a0fb22d4c0536d54b069ad55a0324c
|
|
BLAKE2b-256 checksum How to use checksums |
1a14a97f0de934d86d267478c7fccafb72c6d4ddeb65e6d1e03b9a1273d5a497
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / tina4_ultipa-0.2.1-py3-none-any.whl
| Download URL | tina4_ultipa-0.2.1-py3-none-any.whl |
|---|---|
| Size | 15.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fd635e1eedc317e24e478e9bbdf3aa6f5a5f9d63856c9f08790a5240d082d005
|
|
BLAKE2b-256 checksum How to use checksums |
49572dccaa99ef745eaf5066a403780c11e36f31ba6727edf959f598b8d7dd1b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|