Skip to main content

Aerospike Python SDK - a modern, developer-friendly interface for Aerospike

Project description

Aerospike Python SDK

A modern, developer-friendly interface for Aerospike. Async-first, Pythonic API with a chainable session model, fluent query builder, and AEL string filters over the Aerospike Python Async Client.

Status: Public preview (alpha). Not yet production-ready; feedback welcome via GitHub Issues.

Resources

Installation

pip install aerospike-sdk

Pin to a specific release if you need reproducible builds:

pip install aerospike-sdk==0.9.0a2

This installs the SDK plus its dependency on the Aerospike Python Async Client (aerospike-async). No Rust toolchain or git checkout required for ordinary use — pre-built wheels are available for Linux, macOS, and Windows on Python 3.10–3.14.

Quick start

import asyncio
from aerospike_sdk import Behavior, Client, DataSet


async def main():
    async with Client("localhost:3000") as client:
        session = client.create_session(Behavior.DEFAULT)
        users = DataSet.of("test", "users")

        # High-level key-value writes
        await session.upsert(users.id(1)).put({"name": "Alice", "age": 28, "country": "UK"}).execute()
        await session.upsert(users.id(2)).put({"name": "Bob", "age": 35, "country": "US"}).execute()

        # Filtered query with AEL — streams results memory-efficiently
        results = await (
            session.query(users)
            .where("$.age > 25 and $.country == 'US'")
            .execute()
        )
        async for row in results:
            if row.is_ok and row.record is not None:
                print(row.record.bins)

        # Or drain the entire stream into a list
        all_users = await session.query(users).execute()
        rows = await all_users.collect()


asyncio.run(main())

Sync

The same surface is available without asyncio via SyncClient. No async/await, no event loop — useful for sync codebases or when a dependency forbids asyncio.

from aerospike_sdk import Behavior, DataSet, SyncClient


def main():
    with SyncClient("localhost:3000") as client:
        session = client.create_session(Behavior.DEFAULT)
        users = DataSet.of("test", "users")

        # High-level key-value writes
        session.upsert(users.id(1)).put({"name": "Alice", "age": 28, "country": "UK"}).execute()
        session.upsert(users.id(2)).put({"name": "Bob", "age": 35, "country": "US"}).execute()

        # Filtered query with AEL — same builder API as async
        results = (
            session.query(users)
            .where("$.age > 25 and $.country == 'US'")
            .execute()
        )
        for row in results:
            if row.is_ok and row.record is not None:
                print(row.record.bins)


main()

SyncClient is a thin façade over the PAC _blocking surface — there is no per-call event loop and no per-thread loop runner. Sessions, behaviors, builders, and AEL filters are identical to the async path.

See the Quick Start guide for a deeper walkthrough; the API reference covers every public class and method in detail.

Performance modes

PSDK offers two API shapes — pick based on what your code needs.

API Use when Trade-off
Chained builder (session.query(k).execute(), session.upsert(k).put(...).execute()) You need filters (where(...)), batch ops, error handlers, secondary-index queries, TTL overrides, generation checks, etc. Same shape as the Aerospike Java SDK. Builder + stream wrapping costs ~60 µs/op of Python overhead.
Fast-path (session.get(key), session.put(key, bins)) Single-key reads/writes where you want the lowest per-op overhead. Single-key only; no filters, no error-handler callbacks, no batch semantics. Errors raise directly.

Both shapes work in sync and async modes. Use whichever fits each call site — they share the same Session and Behavior.

Free-threaded Python

For high-throughput multi-threaded workloads, run PSDK on the free-threaded build with the GIL disabled:

# uv example — install once, then always launch with PYTHON_GIL=0
uv python install 3.14.5+freethreaded
PYTHON_GIL=0 python my_app.py

Verify with sys._is_gil_enabled() == False after imports — if any non-FT-safe C extension is imported, the interpreter silently re-enables the GIL and your multi-threaded perf collapses 4-6×.

AsyncPool (multi-loop async) is a free-threading feature — don't use it on regular Python, it's slower than a single-client setup there. Each pool spawns N event loops on N OS threads, each with its own Client; coroutines submitted via pool.run(...) round-robin across loops:

from aerospike_sdk import AsyncPool, Behavior, Client, DataSet


async def main():
    pool = AsyncPool(
        client_factory=lambda: Client("localhost:3000"),
        loop_count=4,
    )
    async with pool:
        users = DataSet.of("test", "users")

        # Submit a coroutine — picks an idle loop round-robin
        await pool.run(
            lambda client: client.create_session(Behavior.DEFAULT)
                                 .upsert(users.id(1))
                                 .put({"name": "Alice"})
                                 .execute()
        )

Tune loop_count based on your workload — os.cpu_count() is the default. Cluster-wide index metadata is shared via a single IndexesMonitor across the pool, so sindex-list load doesn't scale with loop_count.

For the full decision guide, the trade-offs, and measured TPS/latency across all modes, see docs/guide/performance.md. For the raw bench data and methodology, see docs/guide/benchmarking.md.

Documentation

The two complement each other: the guide site introduces concepts and works through realistic examples, while the API reference is the exhaustive source for Client, Session, query/update builders, AEL, behavior policies, and every public symbol.

Versioning

PSDK follows SemVer. Pre-releases use the MAJOR.MINOR.PATCH-{alpha,beta,rc}.N form (e.g. 0.9.0-alpha.1). PyPI normalizes these on upload to the equivalent PEP 440 spelling (0.9.0a1).

The top-level VERSION file is the single source of truth; pyproject.toml reads it dynamically, so the wheel and the working tree are guaranteed to match. See the Development section below for the bump procedure.

License

Apache License 2.0. See LICENSE for details.


Development / Contributing

The sections below are for SDK contributors. Downstream users do not need any of this — pip install aerospike-sdk is sufficient to use the package.

Prerequisites

  • Python 3.10 - 3.14, or 3.14t (free-threaded) for high-throughput / AsyncPool work. Recommended installer: uv (uv python install 3.14.5+freethreaded) or pyenv with a dedicated environment. Free-threaded wheels (cp313t / cp314t) ship across the same platform matrix as the regular CPython wheels starting with aerospike-async v0.5.0-alpha.1.
  • Aerospike server — required for integration tests
  • Rust toolchain (rustc + cargo) — required only when building the Aerospike Python Async Client from source (e.g. for an unreleased PAC feature)
  • Java 11+ — required for the one-time AEL parser build (make generate-ael)

Setting up a dev environment

make generate-ael          # one-time: build the ANTLR AEL parser (requires Java 11+)
pip install -e ".[dev]"    # install with dev extras

make generate-ael only needs to be re-run if aerospike_sdk/ael/antlr4/Condition.g4 changes.

Local PAC checkout

To test against a sibling Aerospike Python Async Client working tree (e.g. for a feature not yet on PyPI), install it editable first and pass --no-deps to this SDK so pip doesn't try to re-resolve PAC from PyPI:

pip install -e /path/to/aerospike-client-python-async
pip install -e ".[dev]" --no-deps

Or use requirements-local.txt (gitignored path example).

Configuration

Copy aerospike.env.example to aerospike.env in the repo root and adjust hosts or ports. aerospike.env is not committed.

cp aerospike.env.example aerospike.env
source aerospike.env

Pytest loads aerospike.env when present; otherwise conftest.py loads aerospike.env.example for unset variables only (so CI env vars still win).

Running tests

make test          # all tests
make test-unit     # unit tests only
make test-int      # integration tests only (requires running Aerospike server)

macOS file descriptor limit. On macOS, you may encounter OSError: [Errno 24] Too many open files when running the full test suite. The default limit (256) is not enough for the concurrent async connections created during testing.

ulimit -n 4096

To make this permanent, add it to your shell profile (~/.zshrc or ~/.bash_profile).

Building docs locally

API docs are built with Sphinx (Furo theme, MyST-Parser for Markdown). The same Sphinx config is what Read the Docs builds from.

pip install -e ".[docs]"   # one-time: install Sphinx toolchain
make docs                  # build static HTML to docs/_build/html/
make docs-serve            # live-reloading local preview

Docstrings use Google style with Sphinx cross-references (:meth:, :class:, etc.).

Lint

ruff check .

Bumping the version

Bumps are manual and happen in PRs against dev. Promotion workflows (dev → stage → main) do not mutate the version.

# 1. Edit VERSION:
#    e.g. 0.9.0-alpha.1  →  0.9.0-alpha.2
echo '0.9.0-alpha.2' > VERSION

# 2. Confirm:
bin/get-version    # prints 0.9.0-alpha.2

# 3. Open a PR against dev with just this change.

Bumping the PAC pin

PSDK depends on a published release of the Aerospike Python Async Client on PyPI as aerospike-async. On dev and downstream release branches the pin must be a published PyPI version. The pin lives in pyproject.toml under [project] dependencies:

[project]
dependencies = [
    "aerospike-async==0.5.0a1",
    # ...other deps
]

To bump: change the version to the new release on PyPI, then reinstall:

pip install --upgrade "aerospike-async==0.5.0aN"

Open the PR against dev. PSDK's own VERSION does not need to change for a PAC pin bump unless the underlying API contract has shifted enough to warrant it.

Mid-cycle: pinning a tagged but unpublished PAC

During a breaking-change cycle, the new PAC may be git-tagged on GitHub before its PyPI wheel is published. Feature branches (not dev) may temporarily pin to the git ref to validate against the new PAC before publish:

[project]
dependencies = [
    #"aerospike-async==0.5.0a1",   # ← restore this form before merging to dev
    "aerospike-async @ git+ssh://git@github.com/aerospike/aerospike-client-python-async.git@v0.5.0-alpha.1",
    # ...other deps
]

Use git refs only on feature branches; switch back to the ==X.Y.ZaN form before opening a PR against dev. CI reads the PAC ref out of pyproject.toml at job start, so both forms work transparently for the build matrix.

Reading the version programmatically

Anywhere a build script, CI step, or release tool needs the version:

bin/get-version    # → 0.9.0-alpha.1

The script reads VERSION and trims trailing whitespace. No Python or setuptools runtime dependency — usable from any shell, container, or CI environment.

Project details


Download files

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

Source Distribution

aerospike_sdk-0.9.0a5.tar.gz (264.2 kB view details)

Uploaded Source

Built Distribution

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

aerospike_sdk-0.9.0a5-py3-none-any.whl (309.6 kB view details)

Uploaded Python 3

File details

Details for the file aerospike_sdk-0.9.0a5.tar.gz.

File metadata

  • Download URL: aerospike_sdk-0.9.0a5.tar.gz
  • Upload date:
  • Size: 264.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for aerospike_sdk-0.9.0a5.tar.gz
Algorithm Hash digest
SHA256 275a8f3df3761b87676a02409e314a87f7218a0bb7f1ac28fd373b4d3d3a3486
MD5 ec327cea50f58dca158411c922808efa
BLAKE2b-256 932f2a04731ff95ea114c3148218ac43febb9f28361e7e21bf77d5e7464e9d77

See more details on using hashes here.

Provenance

The following attestation bundles were made for aerospike_sdk-0.9.0a5.tar.gz:

Publisher: publish-artifact.yaml on citrusleaf/artifact-publisher

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

File details

Details for the file aerospike_sdk-0.9.0a5-py3-none-any.whl.

File metadata

  • Download URL: aerospike_sdk-0.9.0a5-py3-none-any.whl
  • Upload date:
  • Size: 309.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for aerospike_sdk-0.9.0a5-py3-none-any.whl
Algorithm Hash digest
SHA256 6ac1cfcae00c5e49117d081559f39855d4d1859fbb94e5fbb1769ead0e4acd19
MD5 2c65c51c165c7ccbb560732f445d8c15
BLAKE2b-256 e1e1a3e7671fc455fab91dfefe1eba3bf3f236d1174cdc704df61cbaa1021174

See more details on using hashes here.

Provenance

The following attestation bundles were made for aerospike_sdk-0.9.0a5-py3-none-any.whl:

Publisher: publish-artifact.yaml on citrusleaf/artifact-publisher

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page