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
- Install
- Sources
- Data probes
- Assertions
- Load probes
- pytest plugin
- ematix-flow integration
- Run history
- CLI
- Python API
- What's shipped
- Development
- 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 aRunReport.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:
- Product Requirements — locked v0.1 scope
- Engineering process — TDD + sprint cadence + retros
- PI plan — current PI, sprint map, risks
- Sprints — per-sprint plans + retros
- Learnings — append-only log
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)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ematix_probe-0.1.3.tar.gz | 123.0 kB | With provenance | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| 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 logRelease 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 logRelease 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 logRelease 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 logRelease 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 logRelease 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 logRelease 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 logRelease 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 logRelease 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 logSecurity 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.
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 logA 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.