Start here

Your first query

Install the SDK, compose a query, and choose how to execute it.

MetriCraft is a Python SDK for constructing PromQL and MetricsQL and querying Prometheus or VictoriaMetrics. Rust owns the immutable expression tree; Python provides the fluent API and an independent HTTP client.

Install from PyPI

Requires Python 3.8+. We recommend uv to manage your project’s dependencies and environment. In an existing uv project, run the command below; for a new project, run uv init first:

uv add metricraft

Or use pip in a virtual environment. Create one in your application directory:

python -m venv .venv

Activate it with .venv\Scripts\Activate.ps1 in Windows PowerShell, or source .venv/bin/activate on Linux/macOS, then install:

python -m pip install metricraft

The regression suite covers CPython 3.8–3.15 with the GIL enabled. Python 3.14 and 3.15 also run isolated installed-wheel checks on every precompiled platform.

Matching wheels include the Rust core: you do not need Rust, Cargo, a compiler, or a clone of this repository to use them. With uv, run the Python examples using uv run python in place of python.

Precompiled platforms

SystemPython architectureMinimum runtime
Windowsx86_64 (64-bit)Windows with 64-bit Python
Linuxx86_64glibc 2.28 or newer
macOSx86_64 (Intel)macOS 11 or newer
macOSarm64 (Apple Silicon)macOS 11 or newer

The wheel must match the running Python interpreter, including its architecture. Linux ARM64, Alpine/musl and 32-bit Windows do not currently have precompiled wheels. Source installations require Rust and a platform C linker; see source setup if you need to build the SDK.

To require a precompiled wheel and avoid a source build:

python -m pip install --only-binary=:all: metricraft

If pip reports no matching distribution, check Python’s version and architecture and your package index. A mirror may not have synchronized the release yet; retry with --index-url https://pypi.org/simple when appropriate.

Free-threaded CPython

CPython 3.14t and 3.15t are tested with the GIL disabled, including installed wheels. They use the same platform wheel: the bundled Rust library uses a C ABI and does not link to CPython’s extension ABI. Free threading became an officially supported, optional CPython build in Python 3.14.

Check the actual running mode; a free-threaded interpreter can also enable the GIL:

python -c "import sys, sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'), sys._is_gil_enabled())"

For free-threaded execution the result is 1 False. Immutable query expressions can be shared between threads. Configure clients before use, finish outstanding requests before closing them, and use thread-safe custom transports when sharing a client. Concurrent client cleanup releases each owned transport once; it does not make user-provided callbacks or mutable configuration thread-safe.

Compose a query

from metricraft import QueryBuilder as Q

requests = Q.from_metric("http_requests_total").where_eq("job", "api")
rate = requests.rate("5m").sum().by("job")
text = rate.build("promql")

assert text == 'sum by (job) (rate(http_requests_total{job="api"}[5m]))'
assert requests.build("promql") == 'http_requests_total{job="api"}'
print(text)

Save this as first_query.py and run python first_query.py. It runs offline and prints sum by (job) (rate(http_requests_total{job="api"}[5m])).

The second assertion matters: deriving rate leaves requests unchanged. You can reuse any expression as the starting point for another branch.

Choose "promql" or "metricsql" at build time. The default is "metricsql"; being explicit makes stored queries easier to associate with their destination. Unsupported dialect forms raise an error, including inside nested expressions.

Execute with the client

The following example requires a reachable Prometheus server. Unlike the offline build example, its result depends on the data in that server.

from metricraft import DatabaseClient, PrometheusConfig

with DatabaseClient(PrometheusConfig("http://localhost:9090")) as client:
    result = client.query(text)
    print(result.is_success)

The client also accepts strings loaded from your application’s storage. It does not need a native library when used with strings alone. Use context managers to close transports, or async with for asynchronous calls.

Check which package is loaded

If an existing development installation is still loading a local checkout:

python -m pip show metricraft
python -c "import metricraft; print(metricraft.__file__)"

An Editable project location points at source code. To replace that installation with the published wheel in the same environment:

python -m pip install --force-reinstall --only-binary=:all: --index-url https://pypi.org/simple metricraft

Restart an existing Python process or notebook kernel after replacing the package. Release wheels load their own native library. Remove a development-only METRICRAFT_NATIVE_LIB override if it points to an old or missing library. Keep source development installations in a separate virtual environment.

Where to go next

Explore the docs

Find your next step

Search guides, examples and the Python API.