Skip to main content

cypher-graphdb

One Python API for Cypher graph databases — Apache AGE (a PostgreSQL extension) and Memgraph (Bolt) today, others behind the same seam. Plus optional Pydantic typing and an interactive CLI over the same surface.

Cypher is close to a standard; the databases that speak it are not. AGE keeps properties in a single agtype column and cannot bind parameters inside UNWIND; Memgraph is a native graph store with per-property indexes and real streaming. cypher-graphdb absorbs those differences without pretending they do not exist.

Why cypher-graphdb

  1. Portable, honestly. One API across backends, with the differences declared rather than discovered. Anything a backend may not support sits behind has_capability(...), so you branch on a fact instead of catching a failure mid-load.

  2. Never in your way. Every layer above raw Cypher is optional and the database stays reachable — down to execute_sql() against PostgreSQL/AGE directly. Dropping a level for one awkward query is a supported move.

  3. Typing you opt into. Register Pydantic models on a ModelProvider you construct and results hydrate into your own classes. No global registry, so importing a module has no process-wide effect and two graphs can use the same label for different things.

  4. Built for bulk. bulk_create_nodes / bulk_create_edges batch through UNWIND (or a direct SQL path), and property indexing is first-class — because a graph load that ignores indexes is a graph load that never finishes.

  5. Safe by construction. Query building returns (query, params); read-only mode rejects writing clauses in the parser before they reach the backend; results and their statistics come back as one immutable value, which is what makes pooling and concurrency safe.

Feature shortlist

  • Backendsage (Apache AGE on PostgreSQL) and memgraph (Bolt). Both drivers ship as regular dependencies; there is no per-backend extra. Add another by implementing the CypherBackend ABC.
  • Capability modelBackendCapability covers property indexes, unique constraints, full-text and vector indexes, streaming, pagination, multiple labels and more. Optional methods raise NotImplementedError; the check is how you avoid that.
  • Typed modelsmp.node() / mp.edge() / mp.relation() on an explicit ModelProvider, with Cardinality on declared relationships and JSON-schema generation from the models.
  • Queries — parameterized execute(cypher, params=…), optional result unnesting, QueryResult with execution statistics, chunked streaming, and pagination via Page.
  • Graph objectsGraphNode, GraphEdge, GraphPath, Graph, with match criteria (MatchNodeCriteria, MatchEdgeCriteria, MatchNodeById, …) that build parameterized Cypher rather than concatenated strings.
  • Bulk + indexes — batched node/edge creation, create_property_index, drop_index, list_indexes returning normalized IndexInfo.
  • Client-side analysisgraphops over a materialized Graph: root_nodes, incoming_nodes / outgoing_nodes, build_tree, has_cycles, density.
  • Import / export — a format registry: CSV, JSON and YAML built in, Excel via [excel], and your own formats registrable with @data_format. Includes a hierarchical round-trip format with gid_ deduplication.
  • Safety — read-only mode, connection guards, credential-redacting settings.
  • PoolingCypherGraphDBPool with a size bound and idle TTL.
  • CLIcypher-graphdb, interactive or scripted, over every backend.

Levels of abstraction

Four layers, each usable on its own, all on the same connection and transaction.

TYPED OBJECTS     your Pydantic classes, registered on a ModelProvider
GRAPH OBJECTS     GraphNode / GraphEdge / GraphPath / Graph + match criteria
CYPHER            execute(cypher, params=…) → QueryResult
BACKEND SQL       execute_sql() — straight to PostgreSQL/AGE

CypherGraphDB is a facade composed of mixins — connection, batch, indexing, schema, search, SQL, streaming, pagination — so every layer is reachable from one object. Details in docs/usage/index.md.

Example

from cypher_graphdb import CypherGraphDB, GraphNode, GraphEdge

with CypherGraphDB(backend="memgraph", connect_url="bolt://localhost:7687") as db:
    alice = db.create_or_merge(GraphNode(label_="Person",
                                         properties_={"name": "Alice", "age": 30}))
    acme  = db.create_or_merge(GraphNode(label_="Company",
                                         properties_={"name": "TechCorp"}))
    db.create_or_merge(
        GraphEdge.build(alice, acme, label_="WORKS_FOR", properties_={"since": 2020})
    )
    db.commit()

    for name, company in db.execute(
        "MATCH (p:Person)-[:WORKS_FOR]->(c:Company) RETURN p.name, c.name"
    ):
        print(f"{name} works for {company}")

Swap backend="age" and a postgresql:// URL and the rest is unchanged. Note that nothing commits implicitly — not create_or_merge, not leaving the with block.

With typed models

Models register on a provider you construct, and the provider is wired to the connection:

from cypher_graphdb import CypherGraphDB, GraphNode, GraphEdge, ModelProvider

mp = ModelProvider()

@mp.node(label="Product")
@mp.relation(rel_type="USES_TECHNOLOGY", to_type="Technology")
class Product(GraphNode):
    name: str
    multi_tenancy: bool | None = None

@mp.edge(label="USES_TECHNOLOGY")
class UsesTechnology(GraphEdge):
    version: str | None = None

db = CypherGraphDB(backend="age", model_provider=mp)

There is no global registry — importing this module has no process-wide effect, so two graphs may define the same label without colliding. See docs/adr/0001-explicit-model-providers.md.

Loading data in bulk

db.bulk_create_nodes(rows, label="Component", batch_size=200)
db.create_property_index("Component", "symbol", "name")   # before the edges
db.bulk_create_edges(edges, src_refs=, dst_refs=,
                     src_label="Component", dst_label="Component",
                     src_ref_prop="symbol", dst_ref_prop="symbol")

Order matters: nodes, then the indexes the edge load matches on, then edges. docs/usage/bulk-and-indexes.md explains why, and what each backend actually does with an index.

Install

Requires Python 3.14+.

Lean core, optional CLI. The default install carries only what the library needs — both backend drivers included, so there is no per-backend extra. The interactive CLI's dependencies (typer, rich, prompt_toolkit, art, lark) and Excel support (openpyxl) are opt-in. The core has no numpy and no terminal-UI stack.

Install Adds Use when
cypher-graphdb core library, both backends embedding the library in your own program
cypher-graphdb[excel] openpyxl you need Excel import/export
cypher-graphdb[cli] typer, rich, prompt_toolkit, art, lark (+ [excel]) you want the cypher-graphdb command
cypher-graphdb[dev] cli + toolchain development (implies [cli])
pip install cypher-graphdb          # library only
pip install 'cypher-graphdb[cli]'   # + the cypher-graphdb command
# or
uv add 'cypher-graphdb[cli]'

The distribution is cypher-graphdb; the import name is cypher_graphdb. cypher-graphdb appears on your PATH with the [cli] extra; invoking it without that extra reports which install you need rather than a bare import error.

Connection details come from arguments, the environment, or a .env file:

export CGDB_BACKEND=age
export CGDB_CINFO=postgresql://postgres:postgres@localhost:5432/graphdb
export CGDB_GRAPH=my_graph

Then start with docs/usage/getting-started.md.

The CLI

cypher-graphdb --graph my_graph                    # interactive REPL
cypher-graphdb --graph my_graph -e "labels"        # execute and exit
cypher-graphdb --graph my_graph --json -e "indexes"
cypher-graphdb schema generate -m ./graph_models/ -o ./schemas/   # no database needed

Anything that is not a recognised command runs as Cypher. Output is a table interactively and JSON when scripted. Full command set in docs/usage/cli.md.

Develop

Requires uv and task; integration tests need Docker.

task install           # venv + editable install
task fct               # format + check + typecheck + unit tests — the local loop
task test:all          # unit + integration
task run:cli           # run cypher-graphdb from the venv

Conventions and the release flow are in CONTRIBUTING.md.

Layout

src/cypher_graphdb/
  backend.py            the CypherBackend ABC + BackendCapability
  cyphergraphdb/        the facade and its mixins (connection, batch, indexing,
                        schema, search, sql, streaming, pagination, criteria)
  backends/             age/ and memgraph/ implementations
  cypherquery/          the opt-in fluent query builder
  cypherbuilder.py      parameterized Cypher construction
  cypherparser.py       query parsing (drives read-only mode)
  modelprovider.py      explicit model registries
  models.py             GraphNode / GraphEdge / GraphPath / Graph
  graphops.py           client-side analysis over a materialized Graph
  tools/                import / export (CSV, Excel, JSON, YAML) -- needs [cli]
  cli/                  cypher-graphdb — REPL, commands, rendering
docs/                   usage/, design/, adr/

Documentation

Plain markdown with OKF frontmatter; there is no doc build and no generated API reference. Docstrings in the code are the API reference.

Contributing & License

Contributions welcome — see CONTRIBUTING.md (and AGENTS.md if you use an AI coding assistant). Licensed under the Apache License 2.0 — see LICENSE.md.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cypher_graphdb-0.7.1.tar.gz (694.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cypher_graphdb-0.7.1-py3-none-any.whl (535.3 kB view details)

Uploaded Python 3

File details

Details for the file cypher_graphdb-0.7.1.tar.gz.

File metadata

  • Download URL: cypher_graphdb-0.7.1.tar.gz
  • Upload date:
  • Size: 694.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for cypher_graphdb-0.7.1.tar.gz
Algorithm Hash digest
SHA256 0630097f8688efa589dad183ac8b78b1dcacc1daaf63d3d37b3b8b272d20cbbb
MD5 9aee44f9dd58644ec509d62e3ce7b5c6
BLAKE2b-256 fec215f3c0695cd4d0012efbc8317059d2f4fa7c5cf6a1ef20c7eb11b23d0e6e

See more details on using hashes here.

Provenance

The following attestation bundles were made for cypher_graphdb-0.7.1.tar.gz:

Publisher: publish.yml on petrarca/cypher-graphdb-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cypher_graphdb-0.7.1-py3-none-any.whl.

File metadata

  • Download URL: cypher_graphdb-0.7.1-py3-none-any.whl
  • Upload date:
  • Size: 535.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for cypher_graphdb-0.7.1-py3-none-any.whl
Algorithm Hash digest
SHA256 09bfff3a6175469e9dfc0829d52fee8d53c9bd5ce87d1e842861dbc27a380bb9
MD5 56770d96b713d206f75c9f2649cd8539
BLAKE2b-256 2925d0724ce948bf89c98089c87259941014540103ea1ff7778d8a66a3aea95b

See more details on using hashes here.

Provenance

The following attestation bundles were made for cypher_graphdb-0.7.1-py3-none-any.whl:

Publisher: publish.yml on petrarca/cypher-graphdb-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.7.1 This release

2 files

0.7.0

2 files

0.6.0

2 files

0.5.0

2 files

0.4.0

2 files

0.3.1

2 files

0.3.0

2 files

0.2.9

2 files

0.2.8

2 files

0.2.7

2 files

0.2.6

2 files

0.2.5

2 files

0.2.4

2 files

0.2.3

2 files

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

0.1.2

2 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page