Parity
Run old and new code on the same calls. Keep reproducible evidence of what changed.
Parity checks dependency upgrades, backend replacements and rewrites when the old implementation still exists. Targets run in separate processes and can use different Python environments, checkouts or languages. It compares returned values, exceptions and input mutation, then saves confirmed differences for exact replay.
Try a real behaviour difference
Install the controller with Python 3.11 or later:
python -m pip install parity-check
Save these requests as calls.jsonl:
{"args":["hello"]}
{"args":["hello world"]}
{"args":["a/b"]}
Compare two standard-library URL encoders:
parity compare urllib.parse:quote urllib.parse:quote_plus --calls calls.jsonl
The ordinary word matches. Spaces and slashes expose a behavioural difference.
Parity exits 1, identifies the first differing call and retains an exact replay
artifact. This example needs no application code or configuration.
For your code, supply importable functions and representative requests:
parity compare old_orders:quote new_orders:quote --calls tests/orders.jsonl \
--json .parity/report.json --junit .parity/junit.xml
parity evidence verify .parity/report.json
Each line is {"args": [...], "kwargs": {...}}; either field may be omitted.
Whole calls stay together, including correlated arguments. Exit codes are 0 for
matching behaviour, 1 for differences and 2 for invalid or unreliable execution.
Numbers compare exactly by default; set --rtol or --atol to accept a tolerance.
A pass covers the supplied calls, not every possible input. Direct comparisons do not generate or shrink inputs. Empty and malformed corpora fail before targets run. See the direct comparison guide for the full contract.
When to use it
| Situation | Best starting point |
|---|---|
| Two simple functions in one environment | pytest, with Hypothesis if you need generated inputs |
| An upgrade needs conflicting dependencies | Parity with separate target environments |
| Existing requests must survive a rewrite | parity compare --calls |
| A dataframe migration needs order, dtype, null or numeric policies | A configured Parity campaign |
| Differences need repeatable CI evidence and exact replay | Parity reports and retained findings |
| No examples, reference or agreed behaviour exist | Define the contract first; Parity cannot infer it |
The value is the integrated isolation, comparison policy and evidence workflow. It does not determine business intent or replace ordinary tests. The usefulness review records the evidence and limitations.
Dependency versions and checkouts
Run an unchanged wrapper in two existing environments:
parity compare migration:run migration:run --calls calls.jsonl \
--reference-python .venv-old/bin/python \
--candidate-python .venv-new/bin/python \
--record-distribution your-library
Each target environment needs its application dependencies and PyArrow, not the full
Parity installation. For different source checkouts, add --reference-workdir ../before
and --candidate-workdir ../after. The same module name can resolve to different source
on each side. Small wrappers can map different APIs into a shared input/output contract.
To have Parity prepare independently locked environments:
parity migration init \
--reference-path ../before-upgrade \
--candidate-path ../after-upgrade
Released targets use --reference-package 'your-library==1.2.3' and
--candidate-package 'your-library==2.0.0'. See the user guide
for setup, review and execution.
Search beyond known examples
parity init
parity check
This creates a runnable example campaign. Replace its functions and input domain with the behaviour you are migrating. Configured campaigns support Hypothesis search, shrinking, dataframe schemas, relational inputs, multiple findings and optional performance measurements after semantic success.
Parity's unit of work is an explicit callable(*args, **kwargs) contract. A complete
call can combine ordinary JSON, frames and project-generated structures such as
recursive programs and event streams. Install parity-check[pandas] or
parity-check[polars] when the controller needs those dataframe adapters.
Use parity.verify for live functions and a Hypothesis strategy.
Cross-language targets use the adapter SDK.
For a configured campaign in GitHub Actions:
- uses: leighshepperson/parity@v0
with:
config: parity.toml
performance: "false"
Python and pytest
from parity import compare
result = compare("old_orders:quote", "new_orders:quote", calls="calls.jsonl")
assert result.passed
The pytest fixture adds a readable failure summary:
def test_upgrade(parity):
parity.compare("old_orders:quote", "new_orders:quote", calls="tests/orders.jsonl")
Executable evidence
| Case | What it establishes |
|---|---|
| Pydantic order requests | Five supplied calls expose four documented changes; control passes and all findings replay |
| Generated Pydantic campaign | Search and shrinking across conflicting dependency environments |
| pandas 2.3 → 3.0 | An unchanged group-by callable exposes a changed default |
| PyTimeTK pandas → Polars | Five public API comparisons with stock and repaired candidates |
| JavaScript → Python | Recursive programs, domain exceptions and minimized defects |
| C++ → Python | Stateful event streams and replay |
These are bounded engineering studies using synthetic inputs, not evidence that every application is compatible or that independent teams have adopted Parity. More studies are listed in the external validation log.
Evidence and boundaries
Terminal, JSON and JUnit reports omit compared values. Finding directories contain
actual inputs and outputs; keep them private. parity replay <artifact-directory>
reproduces a saved comparison and still exits 1 when the difference remains.
parity evidence verify .parity/report.json exits 0 when all findings reproduce.
Direct-comparison findings do not need the original calls file to replay.
Targets must be trusted and repeatable. Process isolation handles failures and dependency conflicts; it is not a security sandbox. Wrappers own filesystem, database and network cleanup. For stateful behaviour, pass a complete event stream and reset state within the wrapper. Parity does not capture production traffic.
| Need | Documentation |
|---|---|
| Compare existing calls | Direct comparison |
| Build a generated campaign | User guide |
| Look up TOML fields | Configuration reference |
| Integrate with CI | GitHub Action |
| Review intentional differences | Compatibility budgets |
| Retire the old implementation | Distilled contracts |
| Understand execution and evidence | Architecture, security |
Apache-2.0 licensed and pre-1.0. The current minor release is the supported line; minor releases may change public contracts.
Metadata
Release files for parity-check 0.21.0
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 | |
|---|---|---|---|---|
| parity_check-0.21.0.tar.gz | 811.6 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| parity_check-0.21.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.1 MB
Release files / parity_check-0.21.0.tar.gz
| Download URL | parity_check-0.21.0.tar.gz |
|---|---|
| Size | 811.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5ba840b173a6e6fc55a635319c3d3cc98b45783082473be12672cc390c01f89f
|
|
BLAKE2b-256 checksum How to use checksums |
dde5664c9044ceffdd9589b3181d092ffc4445959221a8ccef4730b9d1ca30f7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 6, 2026.
Transparency logRelease files / parity_check-0.21.0-py3-none-any.whl
| Download URL | parity_check-0.21.0-py3-none-any.whl |
|---|---|
| Size | 263.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
64be26942c73d6619693733ac9a92e36d4744390dd17f61a31c57c563d5ea86b
|
|
BLAKE2b-256 checksum How to use checksums |
c52985c44b7efc864fe6b6f6646c22f972d0b706ab74b78fec91a487fc21d1ce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Sep 6, 2026.
Transparency logSecurity for parity-check 0.21.0
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 2 files in this release have been uploaded with provenance metadata.
Attestation for parity_check-0.21.0.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 Sep 6, 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.