Skip to main content

Row-by-row, column-by-column comparison of pandas/PySpark tables, ranked by mismatch.

Project description

juxtapy

Row-by-row, column-by-column comparison of two tables — pandas or PySpark — ranked by mismatch, with drill-down into the rows actually causing the disagreement.

pip install juxtapy          # pandas only
pip install juxtapy[spark]   # pandas + PySpark

Why juxtapy

Most table-diffing tools hand you either a full row-level diff or a flat report. juxtapy is built around a different workflow: join two tables on a key, see which columns disagree the most, and immediately look at sample rows for the worst offenders — without writing a separate query for each investigation.

  • Ranked, not just reported. column_summary() sorts columns worst-mismatch-first, so the columns most likely to matter are first, not buried in an alphabetical or column-order list.
  • Drill-down is first-class. sample_mismatches("amount") returns the key + both values for the actual disagreeing rows — the thing you need to root-cause why two tables disagree, not just that they do.
  • CI-ready. assert_match(threshold=0.99) raises if the match rate drops below a bar, so a comparison can gate a pipeline or CI job directly.
  • Schema drift is explicit. Columns only on one side, or with a changed dtype, show up in the report rather than being silently dropped.
  • Notebook-friendly. CompareReport renders as a color-highlighted HTML table automatically in Jupyter/Databricks.
  • Same API for pandas and PySpark. Pass either kind of dataframe; PySpark is an optional extra, not a hard dependency.

Usage

from juxtapy import Compare

cmp = Compare(prod_df, staging_df, join_columns="id", df1_name="prod", df2_name="staging")

cmp.row_summary()                  # only-in-1 / only-in-2 / common / duplicate-key counts
cmp.column_summary()               # ColumnSummary list, worst-mismatch-first
cmp.sample_mismatches("amount", n=5)   # key + both values, for the actual mismatched rows
cmp.schema_diff()                  # columns only on one side, or with a changed dtype
cmp.matches()                      # bool: do the tables fully agree?
cmp.assert_match(threshold=0.99)   # raise MismatchThresholdError below the bar — CI gate

print(cmp.report())                # everything above, as one readable report
cmp.report()                       # in Jupyter/Databricks: auto-renders as an HTML table

Functional shortcut for the common case:

from juxtapy import compare

report = compare(prod_df, staging_df, join_columns="id")

PySpark

Works the same way with pyspark.sql.DataFrame inputs — both tables must use the same backend:

cmp = Compare(spark_df1, spark_df2, join_columns=["id"])

On Databricks, install with %pip install juxtapy (no [spark] extra) — Databricks Runtime already bundles a pinned PySpark, and installing a different version via the extra risks a conflict. Compare just takes DataFrames you already have (e.g. from spark.table(...)).

Development

uv sync --extra spark          # install with dev tools + PySpark for the full test suite
uv run pytest -m "not spark"   # fast loop (pandas only)
uv run pytest                  # full suite, including PySpark (requires Java locally)
uv run ruff check src tests

License

MIT

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

juxtapy-0.1.0.tar.gz (9.2 kB view details)

Uploaded Source

Built Distribution

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

juxtapy-0.1.0-py3-none-any.whl (13.8 kB view details)

Uploaded Python 3

File details

Details for the file juxtapy-0.1.0.tar.gz.

File metadata

  • Download URL: juxtapy-0.1.0.tar.gz
  • Upload date:
  • Size: 9.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for juxtapy-0.1.0.tar.gz
Algorithm Hash digest
SHA256 25646ccd338ded82d944a30efdce82311d24921826eba738645d6c4250c568f3
MD5 bfcc2547830a7e9e10f7b891570434d7
BLAKE2b-256 619a14215fb59ef214d9059888ab7c9a3096dd5b0edf699ca65eb817cbbba54e

See more details on using hashes here.

File details

Details for the file juxtapy-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: juxtapy-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for juxtapy-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4a9ba317f4e3903d59567810ea29ed20f3e1e85483fe541b685f6ee13d699239
MD5 15d664710e08d921fac9ed18ffb23a2f
BLAKE2b-256 d6cb2a1a9e62a63e22d8c87cb3db435ece6deb5731c619759fb4e397bb13f137

See more details on using hashes here.

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