TuringDB home pagelight logodark logo
  • Discord
  • GitHub
  • Website
TuringDB

Get Started

  • Introduction
  • Get Started
  • Claude Code Skill
  • Commands

Concepts

  • Overview
  • A Columnar Graph Database
  • Versioning System
  • The DataPart System
  • Zero-Locking Architecture
  • Snapshots Isolation

Benchmarks

  • Results Summary
  • Technical Report

Query Language

  • Overview
  • Matching
  • Paths
  • Results and Aggregation
  • Subqueries
  • Functions and Types
  • Writing Data
  • Procedures and Commands
  • CheatSheet

Importing data

  • JSONL
  • CSV
  • Neo4j
  • GML
  • Parquet

Graph Development

  • Create Graph
  • Load Graph
  • Load External data
  • Create a Change
  • List Changes
  • Create Nodes and Edges
  • Update Properties
  • Submit a Change
  • Time Travel
  • Graph Examples

Vector Search

  • Vector Search

Graph Algorithms

  • Shortest Path

Tutorials

  • Example Notebooks

Python SDK

  • Get Started
  • Reference

Troubleshooting

  • Troubleshooting

  • TuringDB Python SDK
  • Getting Started
  • Client backends
  • The native binary protocol
  • Authentication
  • The embedded backend
  • Core Methods
  • list_available_graphs() → list[str]
  • list_loaded_graphs() → list[str]
  • create_graph(graph_name: str)
  • load_graph(graph_name: str, raise_if_loaded: bool = True)
  • query(query: str) → pandas.DataFrame
  • query_raw(query: str) → dict
  • get_graph() → str / set_graph(graph_name: str)
  • is_graph_loaded() → bool
  • new_change() → int
  • Version Control Helpers
  • checkout(change: int | str = "main", commit: str = "HEAD")
  • set_commit(commit: str)
  • set_change(change: int | str)
  • set_graph(graph_name: str)
  • Connection & Timing Helpers
  • reconnect()
  • try_reach(timeout: int = 5) / warmup(timeout: int = 5)
  • get_query_exec_time() → float | None / get_total_exec_time() → float | None
  • S3 / Data Transfer
  • s3_connect(bucket_name, access_key=None, secret_key=None, region=None, use_scratch=True)
  • transfer(src, dst)
  • Response Format
  • Error Handling
  • Example Workflow
  • Notes
Python SDK

Reference

References for TuringDB Python SDK

​
TuringDB Python SDK

The TuringDB Python SDK provides an easy interface for connecting to your local TuringDB server, running queries, and managing graphs programmatically.

Install the PythonSDK:

Using uv package manager (you will need to create a project first):

uv add turingdb

or using pip:

pip install turingdb

The SDK targets TuringDB v3: pin turingdb>=3.0 in your project (older projects may pin 1.x, which uses the previous engine and a much smaller Cypher subset). The wheel supports Python 3.10 to 3.14 on Linux (x86_64, aarch64) and macOS 15 or later (arm64). It also contains the turingdb command-line tool, the turing-parquet import tool, and the in-process engine.

​
Getting Started

from turingdb import TuringDB

# Create TuringDB client
# set host parameter to the URL (as string) on which TuringDB is running,
# default "http://localhost:6666"
client = TuringDB(host="http://localhost:6666")

# List available graphs
print(client.list_available_graphs())

​
Client backends

TuringDB(...) is a facade over three interchangeable backends, chosen with the type argument (or the TURINGDB_TYPE environment variable, default "json"):

typeEncoding / transportConstructor arguments
"json" (default)JSON over HTTP against a running serverhost="http://localhost:6666", optional token
"native"TuringDB’s binary protocol against a running server. Faster for large resultshost="localhost", port=6666, optional token
"embedded"In-process engine, no server or socketdata_dir="/path/to/.turing"
# Default HTTP/JSON client
client = TuringDB(host="http://localhost:6666")

# Native binary protocol
client = TuringDB(type="native", host="localhost", port=6666)

# Embedded, in-process: no server needed
client = TuringDB(type="embedded", data_dir="/home/me/.turing")

Use the default json backend unless you have a reason not to. The other two are optimisations for specific situations:

  • native when you control the server and need more throughput on large results.
  • embedded when you want a self-contained engine with no server to start, stop or connect to.

​
The native binary protocol

The binary protocol is a server-side mode, selected once when the server starts with the environment variable USE_TURING_PROTO=1:

USE_TURING_PROTO=1 turingdb start -demon -p 6666
client = TuringDB(type="native", host="localhost", port=6666)

A server speaks either JSON or the binary protocol on a given port:

Server startedtype="json" clienttype="native" client
normally (JSON, the default)worksreturns Proto header dataLen does not match chunk payload size
with USE_TURING_PROTO=1returns Invalid response from the serverworks

A server in binary mode serves the binary protocol only, so curl, the JSON client and the browser visualizer (-ui) connect to a server running in the default mode. To use both, run two servers on different ports.

  • host accepts "localhost" together with port=, or a full URL such as "http://localhost:6666". Use one of these two forms.
  • The query API is identical, and results come back as the same DataFrames. Embeddings are returned as numpy float32 arrays instead of Python lists.
  • To list the graphs on disk, use the JSON client. On the native backend, list_loaded_graphs() lists the loaded graphs.
  • token, reconnect() and the S3 helpers work as on the JSON backend.

​
Authentication

A server started with -auth-on requires a bearer token. Pass it with token= or set the TURINGDB_AUTH_TOKEN environment variable, which the SDK reads automatically. This works on both the json and native backends:

TURINGDB_AUTH_TOKEN=s3cret turingdb start -demon -auth-on
client = TuringDB(host="http://localhost:6666", token="s3cret")

A missing or incorrect token returns HTTP 401, which the JSON client raises as an httpx.HTTPStatusError. The embedded backend runs in-process and needs no authentication, so it does not take a token.

​
The embedded backend

import os

client = TuringDB(type="embedded", data_dir=os.path.expanduser("~/.turing"))
  • data_dir is the TuringDB root directory (the one that holds graphs/, data/ and vector/). Omit it to use ~/.turing.
  • Use an absolute path, for example with os.path.expanduser("~/..."), since a leading ~ is not expanded.
  • Writes still persist to disk when you submit a change, so your work survives the process ending.
  • The embedded backend is designed for a single process. For the browser visualizer, list_available_graphs(), concurrent access from several processes, the S3 helpers and token=, use a server.

list_available_graphs() is only supported on the default JSON backend. The S3 helpers (s3_connect, transfer) work on the JSON and native backends.

​
Core Methods

​
list_available_graphs() → list[str]

Returns the graphs persisted on disk in the TuringDB data directory (JSON backend only).

client.list_available_graphs()

​
list_loaded_graphs() → list[str]

Returns the currently loaded graphs in memory.

client.list_loaded_graphs()

​
create_graph(graph_name: str)

Creates a new empty graph with the specified name.

client.create_graph("mygraph")

Internally executes CREATE GRAPH "graph_name"

​
load_graph(graph_name: str, raise_if_loaded: bool = True)

Loads a previously created graph into memory.

client.load_graph("mygraph")

If raise_if_loaded=False, it will silently continue if the graph is already loaded.

​
query(query: str) → pandas.DataFrame

Runs a Cypher query on the current graph.

df = client.query("MATCH (n:Person) RETURN n.name, n.age")

Returns results as a pandas.DataFrame, with automatic typing and parsing.

​
query_raw(query: str) → dict

Like query, but returns the raw server response as a dict instead of a DataFrame. Useful for inspecting result metadata or column dtypes directly.

​
get_graph() → str / set_graph(graph_name: str)

Get or set the active graph for subsequent queries.

​
is_graph_loaded() → bool

Returns whether the current graph is loaded in memory.

​
new_change() → int

Creates a new isolated change (equivalent to CHANGE NEW), makes it the active change, and returns its integer ID. The client is already on the new change, so a separate checkout(change=...) is not needed.

change = client.new_change()

new_change() raises if the client is already on a change or on a past commit. Call client.checkout() first.

Submit a change by running client.query("CHANGE SUBMIT"), then call client.checkout() to return to main. The client points at the submitted change until you do, so call checkout() before the next query.

​
Version Control Helpers

TuringDB supports snapshot isolation and versioned commits.

Use the following helpers to navigate graph history or work in isolated changes:

​
checkout(change: int | str = "main", commit: str = "HEAD")

Switches the working context to a specific change or commit.

client.checkout(change=2, commit="abc123")
client.checkout("main")  # Reset to default
  • change: change ID or "main"
  • commit: commit hash or "HEAD"

​
set_commit(commit: str)

Manually set the commit hash to use.

client.set_commit("haax42")

​
set_change(change: int | str)

Manually set the change ID to use (accepts int or hex string).

client.set_change(3)

​
set_graph(graph_name: str)

Change the current graph context.

client.set_graph("another_graph")

You can also read the current context through the current_graph, current_commit (default "HEAD"), and current_change (default "main") properties.

​
Connection & Timing Helpers

​
reconnect()

Resets the connection. A no-op for the HTTP and embedded backends. Reopens the socket for the native backend.

​
try_reach(timeout: int = 5) / warmup(timeout: int = 5)

Probe connectivity (try_reach) or warm the connection with a lightweight query (warmup).

​
get_query_exec_time() → float | None / get_total_exec_time() → float | None

Return the server-side execution time and the full round-trip time (in milliseconds) of the last query.

​
S3 / Data Transfer

These helpers move graph data between local paths, S3, and the TuringDB server. They are available on the JSON and native backends, but not on the embedded backend.

​
s3_connect(bucket_name, access_key=None, secret_key=None, region=None, use_scratch=True)

Connect an S3 client for transfers. Credentials are optional — if omitted, the machine’s configured AWS credentials are used.

client.s3_connect("my-bucket", region="eu-west-1")

​
transfer(src, dst)

Transfer data between a local path, an s3://… URI, or a turingdb://… path. The direction and mechanism are inferred from the URI schemes.

client.transfer("s3://graphs/data.jsonl", "turingdb://data.jsonl")  # S3 → server
client.transfer("./local.gml", "turingdb://local.gml")               # local → server (via scratch)

The equivalent engine commands (issued directly via query) are S3 CONNECT "<key>" "<secret>" "<region>", S3 PULL "<s3-url>" "<dst>", and S3 PUSH "<src>" "<s3-url>".

​
Response Format

All queries return a pandas.DataFrame, typed according to the schema:

Cypher Typepandas dtype
Stringstring
Int64Int64
UInt64UInt64
Doublefloat64
Boolboolean
DateTimedatetime64[us, UTC]
Durationtimedelta64[us]
List, Mapobject (Python list, dict)
Embeddingobject (list over HTTP, numpy float32 array on the native and embedded backends)

Nodes and edges (RETURN n) come back as their internal integer IDs (UInt64), so project the properties you need. A named path comes back as a list of {'type': 'node' | 'edge', 'id': ...} dictionaries. See Functions and data types for the full table.

Over the JSON backend, Doubles are serialised with 6 decimal places. Use the native or embedded backend if you need full precision.

​
Error Handling

Query errors raise TuringDBException. The message starts with the error code (PARSE_ERROR, ANALYZE_ERROR, PLAN_ERROR, EXEC_ERROR, CHANGE_NOT_FOUND, COMMIT_NOT_FOUND, …) and points at the offending part of the query.

from turingdb import TuringDB, TuringDBException

try:
    client.query("MATCH (n RETURN n")
except TuringDBException as e:
    print("Query failed:", e)

On the JSON backend, transport failures (the server is down, or HTTP 401 for a bad or missing token) surface as httpx exceptions instead.

​
Example Workflow

from turingdb import TuringDB

# Create TuringDB client
# set host parameter to the URL (as string) on which TuringDB is running,
# default "http://localhost:6666"
client = TuringDB(host="http://localhost:6666")

# Create a new graph called mygraph
client.create_graph("mygraph")

# Set working graph
client.set_graph("mygraph")

# Create a new change on the graph
change = client.new_change()

# Checkout into the change
client.checkout(change=change)

# Multiple nodes and edges can be created at the same time
# using the following syntax
client.query("""CREATE (apoe_gene:Gene {name: 'APOE', chromosome: '19', location: '19q13.32'}),
(apoe_protein:Protein {name: 'Apolipoprotein E', function: 'Lipid_transport', tissue: 'Brain_and_liver'}),
(alzheimers:Disease {name: 'Alzheimers_Disease', type: 'Neurodegenerative'}),
(cholesterol:Molecule {name: 'Cholesterol', type: 'Lipid'}),
(apoe_gene)-[:ENCODES]->(apoe_protein),
(apoe_protein)-[:BINDS]->(cholesterol),
(apoe_protein)-[:ASSOCIATED_WITH]->(alzheimers)
""")

# Commit the change
client.query("COMMIT")
client.query("CHANGE SUBMIT")

# Checkout into main
client.checkout()

# Query graph
df = client.query("MATCH (n:Gene {name: 'APOE'}) RETURN n.name, n.chromosome")
print(df)

​
Notes

  • The JSON backend (type="json") uses httpx; the native and embedded backends use a compiled extension
  • Only the graph name, change ID, and commit hash are sent with HTTP requests
  • The SDK supports the full TuringDB Cypher dialect, including matching by internal node ID (WHERE n = 1234) and versioned queries against past commits

Need help writing queries? → See the TuringDB Query Cheatsheet

You can also find the TuringDB PythonSDK in Github

Get StartedTroubleshooting
githublinkedinyoutubediscord