Skip to main content

ematix-probe

Declarative data-quality + load probes for Python. Rust + tokio under the hood.

Assert on the shape of your data and the behavior of your services with one decorator. Postgres, DuckDB, Parquet (local + S3), HTTP — same primitives, one runner.

from ematix_probe import probe, source

@probe.data(
    source=source.postgres("postgres://user:pass@host/db"),
    table="events",
    schema="analytics",
)
def events_are_healthy(t):
    t.row_count(at_least=1_000, at_most=1_000_000)
    t.column("event_id").not_null().unique()
    t.column("received_at").not_null()
pip install ematix-probe
ematix-probe run probes.py

Why ematix-probe

  • Same primitives, every backend. Postgres, DuckDB, Parquet (local
    • S3), HTTP. Cross-engine consistency tests cover the SQL-pushdown vs. Arrow-scan paths.
  • Three runners, one decorator. ematix-probe run, your pytest suite, or directly from Python — same probe code, same verdicts.
  • ematix-flow integration. Probe a target table from inside a flow pipeline via probe_from_table() — the verdict joins the pipeline's run-history row.
  • Run history, opt-in. Append every verdict to a sqlite file and query trends across runs with --run-history-db.

Status: v0.1.2 on PyPI as ematix-probe. PI-1 closed — data probes, load probes, pytest plugin, and ematix-flow integration are shipped and stable.


Table of contents

  1. Install
  2. Sources
  3. Data probes
  4. Assertions
  5. Load probes
  6. pytest plugin
  7. ematix-flow integration
  8. Run history
  9. CLI
  10. Python API
  11. What's shipped
  12. Development
  13. License

Install

pip install ematix-probe

The core install ships every adapter, the ematix-probe CLI binary, and the pytest plugin (auto-loaded via the pytest11 entry point — no pytest_plugins wiring required).

Optional extras

Extra What it adds Install
dev Test runner + linters + maturin + testcontainers (Postgres / LocalStack) for the local development workflow. pip install "ematix-probe[dev]"

The runtime surface (CLI, pytest plugin, every data + load adapter) needs no extras. To build from source, see Development at the bottom.


Sources

Sources are the first thing to set up. Every data probe references a source by call-site; ematix-probe doesn't ship a connection registry the way ematix-flow does — credentials live in the URL or environment variables you pass in.

from ematix_probe import source

postgres   = source.postgres("postgres://user:pass@host/db")
duckdb     = source.duckdb(":memory:")
parquet    = source.parquet("/path/to/file.parquet")
s3_parquet = source.s3_parquet(
    bucket="analytics",
    key="dim/customers.parquet",
    region="us-east-1",
    # endpoint_url= is optional — set it for LocalStack / MinIO.
)

Sources are inert factories — no connection is opened until the probe runs.


Data probes

A data probe declares a target table + the assertions it must satisfy. The decorator returns a DataProbe object you can run directly, collect via pytest, or list / explain through the CLI.

from ematix_probe import probe, source

@probe.data(
    source=source.postgres("postgres://localhost/warehouse"),
    table="dim_customers",
    schema="public",
)
def customer_dim_quality(t):
    t.column("customer_id").not_null().unique()
    t.column("email").not_null().regex(r".+@.+\..+")
    t.column("status").is_in(["active", "churned", "trial"])
    t.column("age").between(0, 120)
    t.row_count(at_least=1_000, at_most=10_000_000)
    t.freshness("updated_at", within="24h")

Run it directly:

report = customer_dim_quality.run()
print(report.verdict)              # "pass" | "fail" | "error"
for a in report.assertions:
    print(a.name, a.verdict, a.message)

Or write it to JUnit / JSON for CI:

from ematix_probe.report import write_junit, write_json

write_junit([report], "build/probe-results.xml")
write_json([report], "build/probe-results.json")

The same probe can be picked up by pytest with no extra wiring — see pytest plugin.


Assertions

The assertion vocabulary is the same across every adapter; the adapter chooses pushdown SQL vs. an Arrow scan internally.

Assertion Meaning
t.column(c).not_null() Every value in c is non-NULL.
t.column(c).unique() Every value in c is unique (NULLs allowed).
t.column(c).between(low, high) Every value in c lies in [low, high] inclusive.
t.column(c).regex(pattern) Every non-NULL value matches pattern (Postgres POSIX flavor on the SQL path; regex crate on the scan path).
t.column(c).is_in([...]) Every value is in the allowed set.
t.row_count(at_least=, at_most=) Table row count falls in [at_least, at_most] (open ends supported).
t.freshness(c, within="24h") The most recent value of c is no older than within (h / m / s / d).
t.percentile_between(c, p=99, low=, high=) The pᵗʰ percentile of c lies in [low, high]. Scan-path only.
t.cardinality_between(c, low=, high=) The count of distinct values in c lies in [low, high]. Scan-path only.
t.schema_match({col: type, ...}) The target's column types match the declared mapping. Scan-path only.

Each assertion produces one AssertionResult with verdict ∈ {"pass", "fail", "error"} and an actionable message on non-pass.


Load probes

Load probes drive a target with synthetic traffic and assert on the resulting samples. v0.1 ships HTTP and Postgres SQL targets under either constant-rate (open-model) or virtual-user (closed-model) schedulers. The Python surface is Rust-only in v0.1 — Python decorators land in v0.2.

Drive the engine directly today:

# Pseudocode mirroring the Rust API; full Python load surface ships in v0.2.
from ematix_probe import load
plan = load.http_plan(
    target=load.HttpTarget.get("https://api.example.com/health"),
    duration="60s",
    mode=load.ConstantRate(rps=100),
    warmup="10s",
    assertions=[
        load.p99_under("latency_ms", 200),
        load.error_rate_below(0.005),
        load.throughput_above(95),
        load.status_code_in([200, 304]),
    ],
)

Or use the Rust API directly via cargo run --example load_probe_demo / --example postgres_load_demo.


pytest plugin

pip install ematix-probe registers a pytest11 plugin; pytest auto-loads it. Any @probe.data instance at module top-level becomes one pytest test node per assertion:

# tests/test_warehouse_quality.py
from ematix_probe import probe, source

@probe.data(
    source=source.postgres("postgres://localhost/warehouse"),
    table="dim_customers",
)
def customer_dim_quality(t):
    t.column("customer_id").not_null()
    t.column("email").regex(r".+@.+\..+")

pytest -v reports:

tests/test_warehouse_quality.py::customer_dim_quality::customer_id.not_null PASSED
tests/test_warehouse_quality.py::customer_dim_quality::email.regex          FAILED

The probe runs once per pytest collection — assertion fan-out caches the RunReport so N assertions don't multiply the underlying database / HTTP work.


ematix-flow integration

Sibling project ematix-flow ships declarative table classes; ematix-probe consumes them through a duck-typed shim:

from ematix_probe.flow import probe_from_table
from ematix_probe import source

# CustomerDim is any class exposing __tablename__, optional
# __schema__, and an iterable `columns` with .name / .nullable /
# .primary_key — ematix-flow's ManagedTable matches out of the box.
quality = probe_from_table(
    CustomerDim,
    source=source.postgres("postgres://warehouse/db"),
    extend=lambda t: t.column("email").regex(r".+@.+\..+"),
)

Auto-derived: not_null on every non-nullable column + unique on each primary key. extend lets you layer extras via the same fluent API. ematix-probe has zero hard dependency on ematix-flow — the protocol-typing means any conforming class participates.


Run history

Opt-in sqlite persistence. Pass --run-history-db <path> to the CLI, or use the API directly:

from ematix_probe.run_history import RunHistory

h = RunHistory("history.sqlite")
h.record(probe.run())

Schema is runs (one row per probe execution) + assertions (one row per assertion result, joined by run_id), tagged with PRAGMA user_version = 1. Designed as the substrate for v0.2 drift detection — additive columns only, no renames.


CLI

ematix-probe run <path>           # discover + run probes; non-zero on fail
ematix-probe run <path> --run-history-db history.sqlite

ematix-probe list <path>          # enumerate probes, no execution
ematix-probe explain <path> <probe>   # print compiled plan for one probe
ematix-probe doctor               # environment health check

<path> points at any Python file containing @probe.* decorators. The CLI imports the file, finds module-level DataProbe attributes, runs each, and exits non-zero if any verdict isn't pass.


Python API

The package exposes:

  • probe.data(source=..., table=..., schema=None) — data-probe decorator.
  • source.postgres / duckdb / parquet / s3_parquet — source factories.
  • DataProbe.run() — execute a probe, return a RunReport.
  • report.write_junit(reports, path) / report.write_json(reports, path) — CI reports.
  • flow.probe_from_table(cls, source=, extend=) — ematix-flow shim.
  • run_history.RunHistory(path) — opt-in sqlite persistence.
  • pytest_plugin — auto-loaded by pytest; not imported directly.

The Rust load-probe surface (engine::load, adapters::load::http, adapters::load::postgres) is exposed through the workspace's example crates today; the Python load surface lands in v0.2.


What's shipped

Data probes: Postgres, DuckDB, local Parquet, S3 Parquet. Assertions: not_null, unique, between, regex, enum, row_count, freshness, percentile_between, cardinality_between, schema_match.

Load probes (Rust API): HTTP + Postgres SQL targets; constant-rate (open-model) and virtual-user (closed-model) schedulers. Assertions: p99_under, error_rate_below, throughput_above, status_code_in. Sample-window warmup filtering. Per-tick Samples shared across HTTP and SQL paths through one evaluate_load entry point.

Reporting: JUnit XML + JSON writers; pytest plugin with per-assertion test nodes; opt-in sqlite run history.

Out of v0.1 (planned for v0.2): async PyO3 (async def probe functions + pyo3-asyncio integration), drift detection, distributed load generation, backends beyond the v0.1 set.


Development

# Build the Rust workspace (core + CLI + Python extension crate)
cargo build --release

# Build + install the Python extension into a venv
python -m venv .venv && source .venv/bin/activate
pip install maturin
maturin develop --release

# Run tests
cargo test --workspace                    # default + integration (Docker)
pytest                                    # full Python suite
coverage run -m pytest && coverage report --fail-under=90

Process docs:

Sibling project: ematix-flow.


License

Apache-2.0.

Metadata

Release files for ematix-probe 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ematix-probe 0.1.3
File Size Uploaded Provenance
ematix_probe-0.1.3.tar.gz 123.0 kB With provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for ematix-probe 0.1.3
File
ematix_probe-0.1.3-cp314-cp314-manylinux_2_28_x86_64.whl CPython 3.14 CPython 3.14 Linux glibc 2.28+ x86-64 Details
ematix_probe-0.1.3-cp314-cp314-macosx_11_0_arm64.whl CPython 3.14 CPython 3.14 macOS 11.0+ ARM64 Details
ematix_probe-0.1.3-cp313-cp313-manylinux_2_28_x86_64.whl CPython 3.13 CPython 3.13 Linux glibc 2.28+ x86-64 Details
ematix_probe-0.1.3-cp313-cp313-macosx_11_0_arm64.whl CPython 3.13 CPython 3.13 macOS 11.0+ ARM64 Details
ematix_probe-0.1.3-cp312-cp312-manylinux_2_28_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.28+ x86-64 Details
ematix_probe-0.1.3-cp312-cp312-macosx_11_0_arm64.whl CPython 3.12 CPython 3.12 macOS 11.0+ ARM64 Details
ematix_probe-0.1.3-cp311-cp311-manylinux_2_28_x86_64.whl CPython 3.11 CPython 3.11 Linux glibc 2.28+ x86-64 Details
ematix_probe-0.1.3-cp311-cp311-macosx_11_0_arm64.whl CPython 3.11 CPython 3.11 macOS 11.0+ ARM64 Details

Total release size: 150.4 MB

Release files / ematix_probe-0.1.3.tar.gz

Download URL ematix_probe-0.1.3.tar.gz
Size 123.0 kB
Tags Source
SHA-256 checksum
How to use checksums
5c737ffc2aabfecd24f16cf3cff4fe5230fe894e1e4d899a2efcde0dd981c0ac
BLAKE2b-256 checksum
How to use checksums
f595f5a9f56959137265587277d25713257c73a9a1c6d71bb7a57e0e49911311
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / ematix_probe-0.1.3-cp314-cp314-manylinux_2_28_x86_64.whl

Download URL ematix_probe-0.1.3-cp314-cp314-manylinux_2_28_x86_64.whl
Size 21.2 MB
Tags CPython 3.14 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
c8df43e101c6a867a5941973d4f0236377bb43500f1045e628e79c2700f00565
BLAKE2b-256 checksum
How to use checksums
68e601605571342a489ba561b5c6df6d4dc37dd3bfb0a1de32e7f30b230c4898
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / ematix_probe-0.1.3-cp314-cp314-macosx_11_0_arm64.whl

Download URL ematix_probe-0.1.3-cp314-cp314-macosx_11_0_arm64.whl
Size 16.3 MB
Tags CPython 3.14 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
75611dc9572b70df0d148083bce27bc0bf988aaef83117dfd876326ed3ce6a92
BLAKE2b-256 checksum
How to use checksums
8c45ce909d9dbeb18d6664f5f4465b7a76536bba1317d9ab24409ed085b2d423
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / ematix_probe-0.1.3-cp313-cp313-manylinux_2_28_x86_64.whl

Download URL ematix_probe-0.1.3-cp313-cp313-manylinux_2_28_x86_64.whl
Size 21.2 MB
Tags CPython 3.13 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
e1b065f13712d8a611583b007c68fbd4b57ae2e94c5bef6465adc80ddc4a075a
BLAKE2b-256 checksum
How to use checksums
21d56c3c2e345e8070db04e929bea6717c425fc0904c760ca4dfb0c974ff66a6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / ematix_probe-0.1.3-cp313-cp313-macosx_11_0_arm64.whl

Download URL ematix_probe-0.1.3-cp313-cp313-macosx_11_0_arm64.whl
Size 16.3 MB
Tags CPython 3.13 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
15844f2e237689e760bc77024455dedc87d4588a95dc8061737c18b33eece013
BLAKE2b-256 checksum
How to use checksums
25b1dfca1587ac26a78fe6e41d6252be106b2892d84db69b71a3da6c8268c628
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / ematix_probe-0.1.3-cp312-cp312-manylinux_2_28_x86_64.whl

Download URL ematix_probe-0.1.3-cp312-cp312-manylinux_2_28_x86_64.whl
Size 21.2 MB
Tags CPython 3.12 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
7e5be174a0e1adfb872fe6fcd4595ea23607f349e9b3c37a7a230ff68283f4c9
BLAKE2b-256 checksum
How to use checksums
620ec626ce98322d71c4f84d79de507ae214a3d6ef677bd8adf6f8d4a1c75141
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / ematix_probe-0.1.3-cp312-cp312-macosx_11_0_arm64.whl

Download URL ematix_probe-0.1.3-cp312-cp312-macosx_11_0_arm64.whl
Size 16.3 MB
Tags CPython 3.12 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
6883d9c26621a470c2f7aecd500254b8b300e888f2dcc3532aa367266840edb4
BLAKE2b-256 checksum
How to use checksums
8a05a635c214ab5d54cab26de307bb3d3a9df5fcb1361803809f81723d28147c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / ematix_probe-0.1.3-cp311-cp311-manylinux_2_28_x86_64.whl

Download URL ematix_probe-0.1.3-cp311-cp311-manylinux_2_28_x86_64.whl
Size 21.2 MB
Tags CPython 3.11 Linux glibc 2.28+ x86-64
SHA-256 checksum
How to use checksums
a48a7c30fc4c21e4c6f0eaf5e292b4680c9cba43cf36cda9ce9af506c0a72428
BLAKE2b-256 checksum
How to use checksums
af70cbbd43b943c45984d99470d4f146fbface3ff3ad098f30a03e2f88b6d2d6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Release files / ematix_probe-0.1.3-cp311-cp311-macosx_11_0_arm64.whl

Download URL ematix_probe-0.1.3-cp311-cp311-macosx_11_0_arm64.whl
Size 16.4 MB
Tags CPython 3.11 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
40425d6dcb81415805ddc5f0cc8c8618c246510e552de9850ab39f4392c0cbeb
BLAKE2b-256 checksum
How to use checksums
4d62a2758669408dfad7278ea4ac627a23f4bcb1c0e878bd24e045156ed8095c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

Security for ematix-probe 0.1.3

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 9 files in this release have been uploaded with provenance metadata.

Select from 9 files

Attestation for ematix_probe-0.1.3.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 17, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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