From bff2594c6d7c6bae31af40992e6341194334638a Mon Sep 17 00:00:00 2001 From: Moritz Potthoff Date: Fri, 17 Jul 2026 14:01:24 +0200 Subject: [PATCH 1/8] init --- diffly/metrics/_common.py | 9 ++- diffly/metrics/data.py | 2 +- diffly/summary.py | 76 +++++++++++++++++-- ...alse_sample_rows_False_sample_pk_False.txt | 21 +++-- ...False_sample_rows_True_sample_pk_False.txt | 21 +++-- ...True_sample_rows_False_sample_pk_False.txt | 21 +++-- ..._True_sample_rows_True_sample_pk_False.txt | 21 +++-- ...alse_sample_rows_False_sample_pk_False.txt | 34 +++++---- ..._False_sample_rows_True_sample_pk_True.txt | 37 ++++----- ...True_sample_rows_False_sample_pk_False.txt | 34 +++++---- ...m_True_sample_rows_True_sample_pk_True.txt | 37 ++++----- ...alse_sample_rows_False_sample_pk_False.txt | 21 +++-- ...False_sample_rows_True_sample_pk_False.txt | 21 +++-- ...True_sample_rows_False_sample_pk_False.txt | 21 +++-- ..._True_sample_rows_True_sample_pk_False.txt | 21 +++-- ...alse_sample_rows_False_sample_pk_False.txt | 34 +++++---- ..._False_sample_rows_True_sample_pk_True.txt | 37 ++++----- ...True_sample_rows_False_sample_pk_False.txt | 34 +++++---- ...m_True_sample_rows_True_sample_pk_True.txt | 37 ++++----- ...alse_sample_rows_False_sample_pk_False.txt | 21 +++-- ...False_sample_rows_True_sample_pk_False.txt | 21 +++-- ...True_sample_rows_False_sample_pk_False.txt | 21 +++-- ..._True_sample_rows_True_sample_pk_False.txt | 21 +++-- ...alse_sample_rows_False_sample_pk_False.txt | 34 +++++---- ..._False_sample_rows_True_sample_pk_True.txt | 37 ++++----- ...True_sample_rows_False_sample_pk_False.txt | 34 +++++---- ...m_True_sample_rows_True_sample_pk_True.txt | 37 ++++----- ...alse_sample_rows_False_sample_pk_False.txt | 21 +++-- ...False_sample_rows_True_sample_pk_False.txt | 21 +++-- ...True_sample_rows_False_sample_pk_False.txt | 21 +++-- ..._True_sample_rows_True_sample_pk_False.txt | 21 +++-- ...alse_sample_rows_False_sample_pk_False.txt | 34 +++++---- ..._False_sample_rows_True_sample_pk_True.txt | 37 ++++----- ...True_sample_rows_False_sample_pk_False.txt | 34 +++++---- ...m_True_sample_rows_True_sample_pk_True.txt | 37 ++++----- tests/summary/test_summary.py | 2 + 36 files changed, 640 insertions(+), 353 deletions(-) diff --git a/diffly/metrics/_common.py b/diffly/metrics/_common.py index 5ba7c38..73996f3 100644 --- a/diffly/metrics/_common.py +++ b/diffly/metrics/_common.py @@ -5,6 +5,7 @@ from collections.abc import Callable from dataclasses import dataclass +from typing import Literal import polars as pl import polars.selectors as cs @@ -12,10 +13,16 @@ @dataclass(frozen=True) class Metric: - """A metric function paired with a column-applicability selector.""" + """A metric function paired with a column-applicability selector. + + ``kind`` selects the summary section the metric is rendered in: ``"change"`` metrics + appear as columns in the "Columns" table, while ``"data"`` metrics get their own + "Data Inspection" section. + """ fn: MetricFn selector: cs.Selector + kind: Literal["change", "data"] = "change" MetricFn = Callable[[pl.Expr, pl.Expr], pl.Expr] diff --git a/diffly/metrics/data.py b/diffly/metrics/data.py index 066a06b..bea08d3 100644 --- a/diffly/metrics/data.py +++ b/diffly/metrics/data.py @@ -35,7 +35,7 @@ def null_fraction_change(left: pl.Expr, right: pl.Expr) -> pl.Expr: DEFAULT_DATA_METRICS: dict[str, MetricFn | Metric] = { - "Null%": Metric(fn=null_fraction_change, selector=cs.all()), + "Null%": Metric(fn=null_fraction_change, selector=cs.all(), kind="data"), } """Preset metrics describing the left and right datasets individually.""" diff --git a/diffly/summary.py b/diffly/summary.py index ac3dda7..c811127 100644 --- a/diffly/summary.py +++ b/diffly/summary.py @@ -131,7 +131,9 @@ def to_json(self, **kwargs: Any) -> str: "name": "value", "match_rate": 0.667, "n_total_changes": 1, - "changes": [{"old": 1.0, "new": 2.0, "count": 1, "sample_pk": [1]}] + "changes": [{"old": 1.0, "new": 2.0, "count": 1, "sample_pk": [1]}], + "metrics": null, + "data_metrics": null } ], "sample_rows_left_only": [], @@ -179,6 +181,7 @@ def _print_diff(self, console: Console) -> None: self._print_schemas(console) self._print_rows(console) self._print_columns(console) + self._print_data_inspection(console) self._print_sample_rows_only_one_side(console, side=Side.LEFT) self._print_sample_rows_only_one_side(console, side=Side.RIGHT) @@ -571,7 +574,7 @@ def _section_columns(self) -> RenderableType: elif not columns: display_items.append(Text("All columns match perfectly.", style="italic")) else: - metric_labels = self._data._metric_labels + metric_labels = self._data._change_metric_labels matches = Table(show_header=bool(metric_labels)) matches.add_column( "Column", @@ -632,6 +635,40 @@ def _section_columns(self) -> RenderableType: return Group(*display_items) + # ------------------------------- DATA INSPECTION -------------------------------- # + + def _print_data_inspection(self, console: Console) -> None: + columns = self._data.columns + data_metric_labels = self._data._data_metric_labels + if not columns or not data_metric_labels: + return + _print_section( + console, + "Data Inspection", + self._section_data_inspection(), + ) + + def _section_data_inspection(self) -> RenderableType: + columns = self._data.columns + assert columns is not None + data_metric_labels = self._data._data_metric_labels + + table = Table() + table.add_column( + "Column", + max_width=COLUMN_SECTION_COLUMN_WIDTH, + overflow=OVERFLOW, + ) + for label in data_metric_labels: + table.add_column(label, justify="right") + for col in columns: + row_items: list[RenderableType] = [Text(col.name, style="cyan")] + for label in data_metric_labels: + value = col.data_metrics.get(label) if col.data_metrics else None + row_items.append(_format_metric_value(value)) + table.add_row(*row_items) + return table + # ------------------------------ ROWS ONLY ONE SIDE ------------------------------ # def _print_sample_rows_only_one_side(self, console: Console, side: Side) -> None: @@ -716,6 +753,7 @@ class SummaryDataColumn: n_total_changes: int changes: list[SummaryDataColumnChange] | None metrics: dict[str, Any] | None + data_metrics: dict[str, Any] | None @dataclass @@ -733,7 +771,8 @@ class SummaryData: _other_common_columns: list[str] _truncated_left_name: str _truncated_right_name: str - _metric_labels: list[str] + _change_metric_labels: list[str] + _data_metric_labels: list[str] def to_dict(self) -> dict[str, Any]: def _convert(obj: Any) -> Any: @@ -836,12 +875,18 @@ def _validate_primary_key_hidden_columns() -> None: _other_common_columns=comp._other_common_columns, _truncated_left_name=truncated_left, _truncated_right_name=truncated_right, - _metric_labels=[], + _change_metric_labels=[], + _data_metric_labels=[], ) metrics_resolved: dict[str, Metric] = dict(metrics or {}) metrics_by_column = _compute_column_metrics(comp, metrics_resolved) - metric_labels = list(metrics_resolved.keys()) + change_metric_labels = [ + label for label, m in metrics_resolved.items() if m.kind == "change" + ] + data_metric_labels = [ + label for label, m in metrics_resolved.items() if m.kind == "data" + ] schemas = _compute_schemas(comp, slim) rows = _compute_rows(comp, slim) @@ -852,6 +897,8 @@ def _validate_primary_key_hidden_columns() -> None: top_k_changes_by_column, show_sample_primary_key_per_change, metrics_by_column, + change_metric_labels, + data_metric_labels, ) sample_rows_left_only, sample_rows_right_only = _compute_sample_rows( comp, sample_k_rows_only @@ -871,7 +918,8 @@ def _validate_primary_key_hidden_columns() -> None: _other_common_columns=comp._other_common_columns, _truncated_left_name=truncated_left, _truncated_right_name=truncated_right, - _metric_labels=metric_labels, + _change_metric_labels=change_metric_labels, + _data_metric_labels=data_metric_labels, ) @@ -977,6 +1025,8 @@ def _compute_columns( top_k_changes_by_column: dict[str, int], show_sample_primary_key_per_change: bool, metrics_by_column: dict[str, dict[str, Any]], + change_metric_labels: list[str], + data_metric_labels: list[str], ) -> list[SummaryDataColumn] | None: # NOTE: We can only compute column matches if there are primary key columns and at # least one joined row. @@ -1017,13 +1067,25 @@ def _compute_columns( sample_pk=sample_pk, ) ) + col_metrics = metrics_by_column.get(col_name) or {} + change_metrics = { + label: col_metrics[label] + for label in change_metric_labels + if label in col_metrics + } + data_metrics = { + label: col_metrics[label] + for label in data_metric_labels + if label in col_metrics + } columns.append( SummaryDataColumn( name=col_name, match_rate=rate, n_total_changes=n_total_changes, changes=changes, - metrics=metrics_by_column.get(col_name), + metrics=change_metrics or None, + data_metrics=data_metrics or None, ) ) return columns diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt index f3d3d5f..93abb0f 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt index f3d3d5f..93abb0f 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt index 2f849f9..e076120 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt index 2f849f9..e076120 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt index 18568f4..b194b1f 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,17 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt index f2a498b..bc7dd6b 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -20,20 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt index 06d07fe..6b6fb7e 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,17 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt index 01c654b..f44867a 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -8,20 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt index f3d3d5f..93abb0f 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt index f3d3d5f..93abb0f 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt index 2f849f9..e076120 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt index 2f849f9..e076120 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt index 18568f4..b194b1f 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,17 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt index f2a498b..bc7dd6b 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -20,20 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt index 06d07fe..6b6fb7e 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,17 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt index 01c654b..f44867a 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -8,20 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃ Null% ┃ str_len_delta ┃ Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt index 3a2a43b..05e8662 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt index 3a2a43b..05e8662 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt index 1316f6b..a9a2422 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt index 1316f6b..a9a2422 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt index bdca125..b070abb 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,17 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt index cdd7114..5b88e39 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -20,20 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt index 370a2d3..f588b90 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,17 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt index 4a10c0c..21be51f 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -8,20 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt index 3a2a43b..05e8662 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt index 3a2a43b..05e8662 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -20,9 +20,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt index 1316f6b..a9a2422 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt index 1316f6b..a9a2422 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -8,9 +8,18 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% (-20.0) │ │ - │ status │ 40.00% │ │ 0.0% -> 40.0% (+40.0) │ 0 │ - └────────┴────────────┴──────┴───────────────────────┴───────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ + │ status │ 40.00% │ │ 0 │ + └────────┴────────────┴──────┴───────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt index bdca125..b070abb 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -20,17 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt index cdd7114..5b88e39 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -20,20 +20,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt index 370a2d3..f588b90 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -8,17 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x) │ - │ │ │ │ (+40.0) │ │ "c" -> "x" (1x) │ - │ │ │ │ │ │ "b" -> None (1x) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x) │ + │ │ │ │ │ 40.0 -> 42.0 (1x) │ + │ │ │ │ │ 20.0 -> 21.0 (1x) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x) │ + │ │ │ │ │ "c" -> "x" (1x) │ + │ │ │ │ │ "b" -> None (1x) │ + └────────┴────────────┴──────┴───────────────┴───────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt index 4a10c0c..21be51f 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -8,20 +8,23 @@ Columns ▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Match Rate ┃ Mean ┃  Null% ┃ str_len_delta ┃  Top Changes ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━┩ - │ price  │ 40.00% │ 0.75 │ 20.0% -> 0.0% │ │ None -> 30.0 │ - │ │ │ │ (-20.0) │ │ (1x, e.g. 3) │ - │ │ │ │ │ │ 40.0 -> 42.0 │ - │ │ │ │ │ │ (1x, e.g. 4) │ - │ │ │ │ │ │ 20.0 -> 21.0 │ - │ │ │ │ │ │ (1x, e.g. 2) │ - ├────────┼────────────┼──────┼───────────────────┼───────────────┼──────────────────┤ - │ status │ 40.00% │ │ 0.0% -> 40.0% │ 0 │ "d" -> None (1x, │ - │ │ │ │ (+40.0) │ │ e.g. 4) │ - │ │ │ │ │ │ "c" -> "x" (1x, │ - │ │ │ │ │ │ e.g. 3) │ - │ │ │ │ │ │ "b" -> None (1x, │ - │ │ │ │ │ │ e.g. 2) │ - └────────┴────────────┴──────┴───────────────────┴───────────────┴──────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃ Match Rate ┃ Mean ┃ str_len_delta ┃  Top Changes ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 40.00% │ 0.75 │ │ None -> 30.0 (1x, e.g. 3) │ + │ │ │ │ │ 40.0 -> 42.0 (1x, e.g. 4) │ + │ │ │ │ │ 20.0 -> 21.0 (1x, e.g. 2) │ + ├────────┼────────────┼──────┼───────────────┼───────────────────────────┤ + │ status │ 40.00% │ │ 0 │ "d" -> None (1x, e.g. 4) │ + │ │ │ │ │ "c" -> "x" (1x, e.g. 3) │ + │ │ │ │ │ "b" -> None (1x, e.g. 2) │ + └────────┴────────────┴──────┴───────────────┴───────────────────────────┘ + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ Column ┃  Null% ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ + │ status │ 0.0% -> 40.0% (+40.0) │ + └────────┴───────────────────────┘ diff --git a/tests/summary/test_summary.py b/tests/summary/test_summary.py index 6e43832..ef6c70b 100644 --- a/tests/summary/test_summary.py +++ b/tests/summary/test_summary.py @@ -229,6 +229,7 @@ def test_summary_data_parametrized( ), # Joined rows (id=1,2,3): value deltas = [0, 5, 0]. "metrics": {"Mean": pytest.approx(5 / 3), "Max": 5.0} if with_metrics else None, + "data_metrics": None, } expected_columns = [] if show_perfect_column_matches: @@ -239,6 +240,7 @@ def test_summary_data_parametrized( "n_total_changes": 0, "changes": None, "metrics": None, + "data_metrics": None, } ) expected_columns.append(value_col) From 51fbda298ea9e9e24e10045d81f6191982d8daa7 Mon Sep 17 00:00:00 2001 From: Moritz Potthoff Date: Fri, 17 Jul 2026 14:08:36 +0200 Subject: [PATCH 2/8] add test --- tests/summary/test_summary.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/summary/test_summary.py b/tests/summary/test_summary.py index ef6c70b..d5757c1 100644 --- a/tests/summary/test_summary.py +++ b/tests/summary/test_summary.py @@ -131,6 +131,27 @@ def test_zero_top_k_column_changes_with_show_sample_primary_key() -> None: ) +def test_change_and_data_metrics_routed_to_separate_fields() -> None: + from diffly.metrics.data import DEFAULT_DATA_METRICS + + # Joined rows id=1,2,3. value deltas (right - left) = [0, 5, null] → Mean = 2.5. + # value nulls: left 0/3 = 0%, right 1/3 = 33.33% → Null% = "0.0% -> 33.33% (+33.33)". + left = pl.DataFrame({"id": [1, 2, 3], "value": [10.0, 20.0, 30.0]}) + right = pl.DataFrame({"id": [1, 2, 3], "value": [10.0, 25.0, None]}) + comp = compare_frames(left, right, primary_key="id") + + summary = comp.summary( + metrics={"Mean": metrics.mean, "Null%": DEFAULT_DATA_METRICS["Null%"]}, + ) + result = json.loads(summary.to_json()) + + (value_col,) = result["columns"] + assert value_col["name"] == "value" + # Change metric lands in `metrics`, data metric in `data_metrics`. + assert value_col["metrics"] == {"Mean": pytest.approx(2.5)} + assert value_col["data_metrics"] == {"Null%": "0.0% -> 33.33% (+33.33)"} + + def _make_comparison() -> DataFrameComparison: # Designed so every parametrized flag affects the expected JSON output: # - Same columns in both frames → schemas equal → slim suppresses schemas section From cb086ef782fd5cca81bdf43a252d9daf984f68cc Mon Sep 17 00:00:00 2001 From: Moritz Potthoff Date: Fri, 17 Jul 2026 14:39:13 +0200 Subject: [PATCH 3/8] refactor --- diffly/metrics/__init__.py | 2 ++ diffly/metrics/data.py | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/diffly/metrics/__init__.py b/diffly/metrics/__init__.py index a3a165b..1f39c10 100644 --- a/diffly/metrics/__init__.py +++ b/diffly/metrics/__init__.py @@ -26,6 +26,7 @@ quantile, std, ) +from .data import _make_data_metric DEFAULT_METRICS: dict[str, MetricFn | Metric] = { **change.DEFAULT_CHANGE_METRICS, @@ -47,4 +48,5 @@ "quantile", "std", "_make_numeric_metric", + "_make_data_metric", ] diff --git a/diffly/metrics/data.py b/diffly/metrics/data.py index bea08d3..4516a9e 100644 --- a/diffly/metrics/data.py +++ b/diffly/metrics/data.py @@ -17,6 +17,11 @@ from ._common import Metric, MetricFn +def _make_data_metric(fn: MetricFn, selector: cs.Selector = cs.all()) -> Metric: + """Wrap a metric function as a data metric, applicable to all columns by default.""" + return Metric(fn=fn, selector=selector, kind="data") + + def null_fraction_change(left: pl.Expr, right: pl.Expr) -> pl.Expr: """Change in the fraction of null entries, rendered as `` -> ()``. @@ -35,7 +40,7 @@ def null_fraction_change(left: pl.Expr, right: pl.Expr) -> pl.Expr: DEFAULT_DATA_METRICS: dict[str, MetricFn | Metric] = { - "Null%": Metric(fn=null_fraction_change, selector=cs.all(), kind="data"), + "Null%": _make_data_metric(null_fraction_change), } """Preset metrics describing the left and right datasets individually.""" From 526c94436a00496b93e8470e8cd1b600f378a384 Mon Sep 17 00:00:00 2001 From: Moritz Potthoff Date: Fri, 17 Jul 2026 14:44:09 +0200 Subject: [PATCH 4/8] simplify --- diffly/summary.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/diffly/summary.py b/diffly/summary.py index c811127..74af592 100644 --- a/diffly/summary.py +++ b/diffly/summary.py @@ -638,9 +638,7 @@ def _section_columns(self) -> RenderableType: # ------------------------------- DATA INSPECTION -------------------------------- # def _print_data_inspection(self, console: Console) -> None: - columns = self._data.columns - data_metric_labels = self._data._data_metric_labels - if not columns or not data_metric_labels: + if not self._data.columns or not self._data._data_metric_labels: return _print_section( console, @@ -649,9 +647,7 @@ def _print_data_inspection(self, console: Console) -> None: ) def _section_data_inspection(self) -> RenderableType: - columns = self._data.columns - assert columns is not None - data_metric_labels = self._data._data_metric_labels + assert self._data.columns is not None table = Table() table.add_column( @@ -659,11 +655,11 @@ def _section_data_inspection(self) -> RenderableType: max_width=COLUMN_SECTION_COLUMN_WIDTH, overflow=OVERFLOW, ) - for label in data_metric_labels: - table.add_column(label, justify="right") - for col in columns: + for label in self._data._data_metric_labels: + table.add_column(label, justify="right", overflow=OVERFLOW) + for col in self._data.columns: row_items: list[RenderableType] = [Text(col.name, style="cyan")] - for label in data_metric_labels: + for label in self._data._data_metric_labels: value = col.data_metrics.get(label) if col.data_metrics else None row_items.append(_format_metric_value(value)) table.add_row(*row_items) From 5732c371230022e20b19c30b6dd0763a45bd9de0 Mon Sep 17 00:00:00 2001 From: Moritz Potthoff Date: Fri, 17 Jul 2026 15:54:01 +0200 Subject: [PATCH 5/8] fix --- tests/summary/test_summary.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/summary/test_summary.py b/tests/summary/test_summary.py index d5757c1..e5c2d0c 100644 --- a/tests/summary/test_summary.py +++ b/tests/summary/test_summary.py @@ -13,6 +13,7 @@ from diffly import compare_frames, metrics from diffly.comparison import DataFrameComparison +from diffly.metrics.data import DEFAULT_DATA_METRICS from diffly.summary import _format_fraction_as_percentage, to_json_safe @@ -132,8 +133,6 @@ def test_zero_top_k_column_changes_with_show_sample_primary_key() -> None: def test_change_and_data_metrics_routed_to_separate_fields() -> None: - from diffly.metrics.data import DEFAULT_DATA_METRICS - # Joined rows id=1,2,3. value deltas (right - left) = [0, 5, null] → Mean = 2.5. # value nulls: left 0/3 = 0%, right 1/3 = 33.33% → Null% = "0.0% -> 33.33% (+33.33)". left = pl.DataFrame({"id": [1, 2, 3], "value": [10.0, 20.0, 30.0]}) From 5867021aa8c0a053f30885642d6c36a600d4ae02 Mon Sep 17 00:00:00 2001 From: Moritz Potthoff Date: Wed, 22 Jul 2026 19:07:22 +0200 Subject: [PATCH 6/8] review --- diffly/summary.py | 10 ++++++---- tests/summary/test_summary.py | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/diffly/summary.py b/diffly/summary.py index 74af592..8d2bae5 100644 --- a/diffly/summary.py +++ b/diffly/summary.py @@ -132,7 +132,7 @@ def to_json(self, **kwargs: Any) -> str: "match_rate": 0.667, "n_total_changes": 1, "changes": [{"old": 1.0, "new": 2.0, "count": 1, "sample_pk": [1]}], - "metrics": null, + "change_metrics": null, "data_metrics": null } ], @@ -596,7 +596,9 @@ def _section_columns(self) -> RenderableType: f"{_format_fraction_as_percentage(col.match_rate)}", ] for label in metric_labels: - value = col.metrics.get(label) if col.metrics else None + value = ( + col.change_metrics.get(label) if col.change_metrics else None + ) row_items.append(_format_metric_value(value)) if col.changes is not None: change_lines = [] @@ -748,7 +750,7 @@ class SummaryDataColumn: match_rate: float n_total_changes: int changes: list[SummaryDataColumnChange] | None - metrics: dict[str, Any] | None + change_metrics: dict[str, Any] | None data_metrics: dict[str, Any] | None @@ -1080,7 +1082,7 @@ def _compute_columns( match_rate=rate, n_total_changes=n_total_changes, changes=changes, - metrics=change_metrics or None, + change_metrics=change_metrics or None, data_metrics=data_metrics or None, ) ) diff --git a/tests/summary/test_summary.py b/tests/summary/test_summary.py index e5c2d0c..cf9e6c1 100644 --- a/tests/summary/test_summary.py +++ b/tests/summary/test_summary.py @@ -146,8 +146,8 @@ def test_change_and_data_metrics_routed_to_separate_fields() -> None: (value_col,) = result["columns"] assert value_col["name"] == "value" - # Change metric lands in `metrics`, data metric in `data_metrics`. - assert value_col["metrics"] == {"Mean": pytest.approx(2.5)} + # Change metric lands in `change_metrics`, data metric in `data_metrics`. + assert value_col["change_metrics"] == {"Mean": pytest.approx(2.5)} assert value_col["data_metrics"] == {"Null%": "0.0% -> 33.33% (+33.33)"} @@ -248,7 +248,9 @@ def test_summary_data_parametrized( else None ), # Joined rows (id=1,2,3): value deltas = [0, 5, 0]. - "metrics": {"Mean": pytest.approx(5 / 3), "Max": 5.0} if with_metrics else None, + "change_metrics": {"Mean": pytest.approx(5 / 3), "Max": 5.0} + if with_metrics + else None, "data_metrics": None, } expected_columns = [] @@ -259,7 +261,7 @@ def test_summary_data_parametrized( "match_rate": 1.0, "n_total_changes": 0, "changes": None, - "metrics": None, + "change_metrics": None, "data_metrics": None, } ) From 6b705e7338f73bde2e0d9b340ef96a170586c810 Mon Sep 17 00:00:00 2001 From: Moritz Potthoff Date: Wed, 22 Jul 2026 19:09:23 +0200 Subject: [PATCH 7/8] review --- diffly/metrics/_common.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/diffly/metrics/_common.py b/diffly/metrics/_common.py index 73996f3..aefa92c 100644 --- a/diffly/metrics/_common.py +++ b/diffly/metrics/_common.py @@ -15,9 +15,14 @@ class Metric: """A metric function paired with a column-applicability selector. - ``kind`` selects the summary section the metric is rendered in: ``"change"`` metrics - appear as columns in the "Columns" table, while ``"data"`` metrics get their own - "Data Inspection" section. + ``kind`` distinguishes two semantically different metric families: + + - ``"change"`` metrics aggregate over ``right - left`` to quantify the *change* + between the two sides (e.g. the mean delta). They describe the change itself and + are rendered as extra columns in the "Columns" table, alongside the match rate. + - ``"data"`` metrics describe each dataset *individually* (e.g. the fraction of null + entries on each side), characterizing the data rather than the change between the + sides. They are rendered in a dedicated "Data Inspection" section. """ fn: MetricFn From 6c868d68b3a1fc1bea5ae09173c016cee04d0e12 Mon Sep 17 00:00:00 2001 From: Moritz Potthoff Date: Wed, 22 Jul 2026 19:48:59 +0200 Subject: [PATCH 8/8] review --- diffly/cli.py | 4 +- diffly/comparison.py | 47 ++++++---- diffly/metrics/__init__.py | 15 +++- diffly/metrics/_common.py | 70 ++++++++++----- diffly/metrics/change.py | 10 +-- diffly/metrics/data.py | 71 +++------------ diffly/summary.py | 87 +++++++++++++++---- diffly/testing.py | 32 +++---- docs/api/metrics.rst | 36 +++++--- ...alse_sample_rows_False_sample_pk_False.txt | 12 +-- ...False_sample_rows_True_sample_pk_False.txt | 12 +-- ...True_sample_rows_False_sample_pk_False.txt | 12 +-- ..._True_sample_rows_True_sample_pk_False.txt | 12 +-- ...alse_sample_rows_False_sample_pk_False.txt | 12 +-- ..._False_sample_rows_True_sample_pk_True.txt | 12 +-- ...True_sample_rows_False_sample_pk_False.txt | 12 +-- ...m_True_sample_rows_True_sample_pk_True.txt | 12 +-- ...alse_sample_rows_False_sample_pk_False.txt | 12 +-- ...False_sample_rows_True_sample_pk_False.txt | 12 +-- ...True_sample_rows_False_sample_pk_False.txt | 12 +-- ..._True_sample_rows_True_sample_pk_False.txt | 12 +-- ...alse_sample_rows_False_sample_pk_False.txt | 12 +-- ..._False_sample_rows_True_sample_pk_True.txt | 12 +-- ...True_sample_rows_False_sample_pk_False.txt | 12 +-- ...m_True_sample_rows_True_sample_pk_True.txt | 12 +-- ...alse_sample_rows_False_sample_pk_False.txt | 12 +-- ...False_sample_rows_True_sample_pk_False.txt | 12 +-- ...True_sample_rows_False_sample_pk_False.txt | 12 +-- ..._True_sample_rows_True_sample_pk_False.txt | 12 +-- ...alse_sample_rows_False_sample_pk_False.txt | 12 +-- ..._False_sample_rows_True_sample_pk_True.txt | 12 +-- ...True_sample_rows_False_sample_pk_False.txt | 12 +-- ...m_True_sample_rows_True_sample_pk_True.txt | 12 +-- ...alse_sample_rows_False_sample_pk_False.txt | 12 +-- ...False_sample_rows_True_sample_pk_False.txt | 12 +-- ...True_sample_rows_False_sample_pk_False.txt | 12 +-- ..._True_sample_rows_True_sample_pk_False.txt | 12 +-- ...alse_sample_rows_False_sample_pk_False.txt | 12 +-- ..._False_sample_rows_True_sample_pk_True.txt | 12 +-- ...True_sample_rows_False_sample_pk_False.txt | 12 +-- ...m_True_sample_rows_True_sample_pk_True.txt | 12 +-- .../test_metrics_null_fraction.py | 10 ++- tests/summary/test_summary.py | 4 +- tests/test_metrics.py | 22 ++--- 44 files changed, 434 insertions(+), 358 deletions(-) diff --git a/diffly/cli.py b/diffly/cli.py index 7177e58..9eb736a 100644 --- a/diffly/cli.py +++ b/diffly/cli.py @@ -12,14 +12,14 @@ from ._compat import typer from ._utils import ABS_TOL_DEFAULT, ABS_TOL_TEMPORAL_DEFAULT, REL_TOL_DEFAULT -from .metrics import Metric, MetricFn +from .metrics import ChangeMetricFn, Metric from .metrics.change import DEFAULT_CHANGE_METRICS from .metrics.data import DEFAULT_DATA_METRICS app = typer.Typer() #: All metric presets selectable via ``--metric``, combining the change and data sets. -AVAILABLE_METRICS: dict[str, MetricFn | Metric] = { +AVAILABLE_METRICS: dict[str, ChangeMetricFn | Metric] = { **DEFAULT_CHANGE_METRICS, **DEFAULT_DATA_METRICS, } diff --git a/diffly/comparison.py b/diffly/comparison.py index 6976b9c..622d8ee 100644 --- a/diffly/comparison.py +++ b/diffly/comparison.py @@ -4,10 +4,11 @@ from __future__ import annotations import datetime as dt +import inspect import warnings from collections.abc import Iterable, Mapping, Sequence from functools import cached_property -from typing import TYPE_CHECKING, Literal, Self, overload +from typing import TYPE_CHECKING, Literal, Self, cast, overload import polars as pl from polars.schema import Schema as PolarsSchema @@ -25,7 +26,13 @@ lazy_len, make_and_validate_mapping, ) -from .metrics import Metric, MetricFn, _make_numeric_metric +from .metrics import ( + ChangeMetric, + ChangeMetricFn, + DataMetric, + DataMetricFn, + Metric, +) if TYPE_CHECKING: # pragma: no cover # NOTE: We cannot import at runtime as we're otherwise running into circular @@ -920,7 +927,7 @@ def summary( right_name: str = Side.RIGHT, slim: bool = False, hidden_columns: list[str] | None = None, - metrics: Mapping[str, MetricFn | Metric] | None = None, + metrics: Mapping[str, ChangeMetricFn | DataMetricFn | Metric] | None = None, ) -> Summary: """Generate a summary of all aspects of the comparison. @@ -951,16 +958,16 @@ def summary( hidden_columns: Columns for which no values are printed, e.g. because they contain sensitive information. metrics: Optional mapping from display label to a metric. A value may be a - callable ``(left_expr, right_expr) -> pl.Expr`` or a - :class:`~diffly.metrics.Metric`. Each callable receives two - :class:`polars.Expr` referring to the left and right values of a single - column across all joined rows, and must return a scalar aggregation - expression. Bare callables are only computed for numerical columns; wrap - one in a :class:`~diffly.metrics.Metric` with a column selector to target - other column types (e.g. ``Metric(fn, selector=cs.all())``). - See :doc:`/api/metrics` for the full list of presets and the - :data:`~diffly.metrics.MetricFn` type. When ``None`` (default), no metrics - are computed; presets are not applied automatically. Prefer short labels — + :class:`~diffly.metrics.ChangeMetric` (callable + ``(left_expr, right_expr) -> pl.Expr`` aggregating over the change), a + :class:`~diffly.metrics.DataMetric` (callable ``(col_expr) -> pl.Expr`` + evaluated on each side to describe the data), or a bare callable resolved + by its arity (two arguments → change metric on numerical columns, one + argument → data metric on all columns). To target other column types, + construct the metric explicitly with a column selector + (e.g. ``ChangeMetric(fn, selector=cs.all())``). See :doc:`/api/metrics` + for the full list of presets. When ``None`` (default), no metrics are + computed; presets are not applied automatically. Prefer short labels — the summary has a fixed width and many or long labels degrade rendering. Returns: @@ -977,11 +984,17 @@ def summary( # NOTE: We're importing here to prevent circular imports from .summary import Summary + def _resolve(v: ChangeMetricFn | DataMetricFn | Metric) -> Metric: + if isinstance(v, (ChangeMetric, DataMetric)): + return v + # Infer the metric family from the callable's arity: a single-argument + # callable describes one side (data), two arguments describe a change. + if len(inspect.signature(v).parameters) >= 2: + return ChangeMetric(fn=cast(ChangeMetricFn, v)) + return DataMetric(fn=cast(DataMetricFn, v)) + resolved_metrics = ( - { - label: v if isinstance(v, Metric) else _make_numeric_metric(v) - for label, v in metrics.items() - } + {label: _resolve(v) for label, v in metrics.items()} if metrics is not None else None ) diff --git a/diffly/metrics/__init__.py b/diffly/metrics/__init__.py index 1f39c10..d338253 100644 --- a/diffly/metrics/__init__.py +++ b/diffly/metrics/__init__.py @@ -14,7 +14,14 @@ from __future__ import annotations from . import change, data -from ._common import Metric, MetricFn +from ._common import ( + ChangeMetric, + ChangeMetricFn, + DataMetric, + DataMetricFn, + Metric, + MetricFn, +) from .change import ( _make_numeric_metric, max, @@ -26,7 +33,6 @@ quantile, std, ) -from .data import _make_data_metric DEFAULT_METRICS: dict[str, MetricFn | Metric] = { **change.DEFAULT_CHANGE_METRICS, @@ -35,6 +41,10 @@ __all__ = [ "DEFAULT_METRICS", + "ChangeMetric", + "ChangeMetricFn", + "DataMetric", + "DataMetricFn", "Metric", "MetricFn", "change", @@ -48,5 +58,4 @@ "quantile", "std", "_make_numeric_metric", - "_make_data_metric", ] diff --git a/diffly/metrics/_common.py b/diffly/metrics/_common.py index aefa92c..b7e9038 100644 --- a/diffly/metrics/_common.py +++ b/diffly/metrics/_common.py @@ -4,36 +4,64 @@ from __future__ import annotations from collections.abc import Callable -from dataclasses import dataclass -from typing import Literal +from dataclasses import dataclass, field +from typing import Any import polars as pl import polars.selectors as cs +ChangeMetricFn = Callable[[pl.Expr, pl.Expr], pl.Expr] +"""A change metric maps ``(left_expr, right_expr)`` to a scalar aggregation expression. -@dataclass(frozen=True) -class Metric: - """A metric function paired with a column-applicability selector. +The expressions refer to the left-side and right-side values of a single column across +all joined rows. +""" + +DataMetricFn = Callable[[pl.Expr], pl.Expr] +"""A data metric maps a single column expression to a scalar aggregation expression. - ``kind`` distinguishes two semantically different metric families: +It is evaluated on the left and right side separately to describe each dataset on its +own, rather than the change between them. +""" + +# Retained for backwards compatibility; a plain metric callable is a change metric. +MetricFn = ChangeMetricFn + + +@dataclass(frozen=True) +class ChangeMetric: + """A metric quantifying the *change* between the two sides of a comparison. - - ``"change"`` metrics aggregate over ``right - left`` to quantify the *change* - between the two sides (e.g. the mean delta). They describe the change itself and - are rendered as extra columns in the "Columns" table, alongside the match rate. - - ``"data"`` metrics describe each dataset *individually* (e.g. the fraction of null - entries on each side), characterizing the data rather than the change between the - sides. They are rendered in a dedicated "Data Inspection" section. + ``fn`` aggregates over ``right - left`` (e.g. the mean delta) to describe the change + itself. Change metrics are rendered as extra columns in the "Columns" table, + alongside the match rate. """ - fn: MetricFn - selector: cs.Selector - kind: Literal["change", "data"] = "change" + fn: ChangeMetricFn + selector: cs.Selector = field(default_factory=cs.numeric) -MetricFn = Callable[[pl.Expr, pl.Expr], pl.Expr] -"""A metric function maps ``(left_expr, right_expr)`` to a scalar aggregation -expression. +@dataclass(frozen=True) +class DataMetric: + """A metric describing each dataset *individually*. -The expressions refer to the left-side and right-side values of a single column across -all joined rows. -""" + ``fn`` is applied to the left and right side separately (e.g. the fraction of null + entries on each side), characterizing the data rather than the change between the + sides. Data metrics are rendered in a dedicated "Data Inspection" section, showing + the left and right value side by side, followed by their signed delta for numeric + values. + + ``formatter`` formats a single left/right value for display. ``delta_formatter`` + formats the (always non-negative) magnitude of the delta, which is rendered with an + explicit sign; when ``None``, it falls back to ``formatter``. Both fall back to the + default numeric precision when unset. + """ + + fn: DataMetricFn + selector: cs.Selector = field(default_factory=cs.all) + formatter: Callable[[Any], str] | None = None + delta_formatter: Callable[[Any], str] | None = None + + +Metric = ChangeMetric | DataMetric +"""A change or data metric paired with a column-applicability selector.""" diff --git a/diffly/metrics/change.py b/diffly/metrics/change.py index f4965f1..cadf17a 100644 --- a/diffly/metrics/change.py +++ b/diffly/metrics/change.py @@ -11,11 +11,11 @@ import polars as pl import polars.selectors as cs -from ._common import Metric, MetricFn +from ._common import ChangeMetric, ChangeMetricFn -def _make_numeric_metric(fn: MetricFn) -> Metric: - return Metric(fn=fn, selector=cs.numeric()) +def _make_numeric_metric(fn: ChangeMetricFn) -> ChangeMetric: + return ChangeMetric(fn=fn, selector=cs.numeric()) def mean(left: pl.Expr, right: pl.Expr) -> pl.Expr: @@ -54,7 +54,7 @@ def mean_relative_deviation(left: pl.Expr, right: pl.Expr) -> pl.Expr: return ((right - left) / left).abs().mean() -def quantile(q: float) -> MetricFn: +def quantile(q: float) -> ChangeMetricFn: """Factory returning a metric that computes the ``q``-quantile of ``right - left``.""" if not 0 <= q <= 1: @@ -66,7 +66,7 @@ def _quantile(left: pl.Expr, right: pl.Expr) -> pl.Expr: return _quantile -DEFAULT_CHANGE_METRICS: dict[str, MetricFn] = { +DEFAULT_CHANGE_METRICS: dict[str, ChangeMetricFn] = { "Mean": mean, "Median": median, "Min": min, diff --git a/diffly/metrics/data.py b/diffly/metrics/data.py index 4516a9e..12544f2 100644 --- a/diffly/metrics/data.py +++ b/diffly/metrics/data.py @@ -9,72 +9,27 @@ from __future__ import annotations -from collections.abc import Callable - import polars as pl import polars.selectors as cs -from ._common import Metric, MetricFn - - -def _make_data_metric(fn: MetricFn, selector: cs.Selector = cs.all()) -> Metric: - """Wrap a metric function as a data metric, applicable to all columns by default.""" - return Metric(fn=fn, selector=selector, kind="data") +from ._common import DataMetric -def null_fraction_change(left: pl.Expr, right: pl.Expr) -> pl.Expr: - """Change in the fraction of null entries, rendered as `` -> ()``. +def null_fraction(col: pl.Expr) -> pl.Expr: + """Fraction of null entries in a column. - ``old`` and ``new`` are the null percentages of the left and right side, and - ``delta`` is their signed difference (``+`` when the right side has proportionally - more nulls, ``-`` when it has fewer). This metric function can be applied to columns - of any type. + Evaluated on each side separately and rendered as a percentage. This metric can be + applied to columns of any type. """ - return _render_change( - left.is_null().mean(), - right.is_null().mean(), - lambda value, signed: _percentage_string( - value, signed=signed, percent_sign=not signed - ), - ) + return col.is_null().mean() -DEFAULT_DATA_METRICS: dict[str, MetricFn | Metric] = { - "Null%": _make_data_metric(null_fraction_change), +DEFAULT_DATA_METRICS: dict[str, DataMetric] = { + "Null%": DataMetric( + fn=null_fraction, + selector=cs.all(), + formatter=lambda value: f"{round(value * 100, 2)}%", + delta_formatter=lambda value: f"{round(value * 100, 2)}", + ), } """Preset metrics describing the left and right datasets individually.""" - - -# ------------------------------------------------------------------------------------ # -# UTILITY METHODS # -# ------------------------------------------------------------------------------------ # - - -def _percentage_string( - fraction: pl.Expr, *, signed: bool = False, percent_sign: bool = True -) -> pl.Expr: - """Format a fraction as a percentage string, optionally with an explicit sign.""" - pct = (fraction * 100).round(2) - body = pl.format("{}%", pct) if percent_sign else pl.format("{}", pct) - if signed: - return pl.when(pct >= 0).then(pl.format("+{}", body)).otherwise(body) - return body - - -def _render_change( - old: pl.Expr, - new: pl.Expr, - format_value: Callable[[pl.Expr, bool], pl.Expr], -) -> pl.Expr: - """Render a change as `` -> ()``. - - ``format_value(value, signed)`` formats a value for display; ``old`` and ``new`` are - rendered unsigned and the delta ``new - old`` is rendered signed (with an explicit - ``+`` prefix for positive values). - """ - return pl.format( - "{} -> {} ({})", - format_value(old, False), - format_value(new, False), - format_value(new - old, True), - ) diff --git a/diffly/summary.py b/diffly/summary.py index 8d2bae5..e157581 100644 --- a/diffly/summary.py +++ b/diffly/summary.py @@ -6,7 +6,7 @@ import dataclasses import io import json -from collections.abc import Mapping +from collections.abc import Callable, Mapping from dataclasses import dataclass from datetime import date, datetime, timedelta from decimal import Decimal @@ -23,7 +23,7 @@ from rich.text import Text from ._utils import Side, capitalize_first -from .metrics import Metric +from .metrics import ChangeMetric, DataMetric, Metric if TYPE_CHECKING: # pragma: no cover from .comparison import DataFrameComparison @@ -663,7 +663,12 @@ def _section_data_inspection(self) -> RenderableType: row_items: list[RenderableType] = [Text(col.name, style="cyan")] for label in self._data._data_metric_labels: value = col.data_metrics.get(label) if col.data_metrics else None - row_items.append(_format_metric_value(value)) + metric = self._data._data_metrics[label] + row_items.append( + _format_data_metric_value( + value, metric.formatter, metric.delta_formatter + ) + ) table.add_row(*row_items) return table @@ -771,6 +776,7 @@ class SummaryData: _truncated_right_name: str _change_metric_labels: list[str] _data_metric_labels: list[str] + _data_metrics: dict[str, DataMetric] def to_dict(self) -> dict[str, Any]: def _convert(obj: Any) -> Any: @@ -875,16 +881,20 @@ def _validate_primary_key_hidden_columns() -> None: _truncated_right_name=truncated_right, _change_metric_labels=[], _data_metric_labels=[], + _data_metrics={}, ) metrics_resolved: dict[str, Metric] = dict(metrics or {}) metrics_by_column = _compute_column_metrics(comp, metrics_resolved) change_metric_labels = [ - label for label, m in metrics_resolved.items() if m.kind == "change" + label for label, m in metrics_resolved.items() if isinstance(m, ChangeMetric) ] data_metric_labels = [ - label for label, m in metrics_resolved.items() if m.kind == "data" + label for label, m in metrics_resolved.items() if isinstance(m, DataMetric) ] + data_metrics = { + label: m for label, m in metrics_resolved.items() if isinstance(m, DataMetric) + } schemas = _compute_schemas(comp, slim) rows = _compute_rows(comp, slim) @@ -918,6 +928,7 @@ def _validate_primary_key_hidden_columns() -> None: _truncated_right_name=truncated_right, _change_metric_labels=change_metric_labels, _data_metric_labels=data_metric_labels, + _data_metrics=data_metrics, ) @@ -1001,18 +1012,27 @@ def select_columns(selector: cs.Selector) -> set[str]: out: dict[str, dict[str, Any]] = {c: {} for c in all_columns} joined = comp.joined(lazy=True) - agg_exprs = [ - metric.fn( - pl.col(f"{column}_{Side.LEFT}"), - pl.col(f"{column}_{Side.RIGHT}"), - ).alias(f"{label}__{column}") - for label, metric in metrics.items() - for column in sorted(metric_to_columns[label]) - ] + agg_exprs: list[pl.Expr] = [] + for label, metric in metrics.items(): + for column in sorted(metric_to_columns[label]): + left = pl.col(f"{column}_{Side.LEFT}") + right = pl.col(f"{column}_{Side.RIGHT}") + if isinstance(metric, ChangeMetric): + agg_exprs.append(metric.fn(left, right).alias(f"{label}__{column}")) + else: + agg_exprs.append(metric.fn(left).alias(f"{label}__{column}__left")) + agg_exprs.append(metric.fn(right).alias(f"{label}__{column}__right")) + row = joined.select(agg_exprs).collect().row(0, named=True) - for label, columns in metric_to_columns.items(): - for column in columns: - out[column][label] = row[f"{label}__{column}"] + for label, metric in metrics.items(): + for column in metric_to_columns[label]: + if isinstance(metric, ChangeMetric): + out[column][label] = row[f"{label}__{column}"] + else: + out[column][label] = { + "left": row[f"{label}__{column}__left"], + "right": row[f"{label}__{column}__right"], + } return out @@ -1201,5 +1221,40 @@ def _format_metric_value(value: Any) -> str: return _format_value(value, float_format=".4g") +def _format_data_metric_value( + value: Any, + formatter: Callable[[Any], str] | None, + delta_formatter: Callable[[Any], str] | None, +) -> str: + """Format a data metric's ``{"left", "right"}`` pair as `` -> ``. + + Numeric values additionally show the signed delta ``()``; non-numeric + values omit it. ``formatter`` formats a left/right value and ``delta_formatter`` the + delta magnitude (rendered with an explicit sign); either falling back to ``.4g`` + precision for floats when unset. + """ + if value is None: + return "" + + def _fmt(v: Any, fn: Callable[[Any], str] | None) -> str: + if fn is not None: + return fn(v) + if isinstance(v, float): + return format(v, ".4g") + return str(v) + + left, right = value["left"], value["right"] + text = f"{_fmt(left, formatter)} -> {_fmt(right, formatter)}" + if _is_numeric(left) and _is_numeric(right): + delta = right - left + sign = "+" if delta >= 0 else "-" + text += f" ({sign}{_fmt(abs(delta), delta_formatter or formatter)})" + return _yellow(text) + + +def _is_numeric(value: Any) -> bool: + return isinstance(value, (int, float)) and not isinstance(value, bool) + + def _trim_whitespaces(s: str) -> str: return "\n".join(line.rstrip() for line in s.splitlines()) diff --git a/diffly/testing.py b/diffly/testing.py index 9a36458..31ff6cb 100644 --- a/diffly/testing.py +++ b/diffly/testing.py @@ -19,7 +19,7 @@ from ._compat import dy from .comparison import DataFrameComparison, compare_frames -from .metrics import Metric, MetricFn +from .metrics import ChangeMetricFn, DataMetricFn, Metric def assert_collection_equal( @@ -40,7 +40,7 @@ def assert_collection_equal( right_name: str = Side.RIGHT, slim: bool = False, hidden_columns: list[str] | None = None, - metrics: Mapping[str, MetricFn | Metric] | None = None, + metrics: Mapping[str, ChangeMetricFn | DataMetricFn | Metric] | None = None, ) -> None: """Assert that two :mod:`dataframely` collections are equal. @@ -84,12 +84,13 @@ def assert_collection_equal( advanced users who are familiar with the summary format. hidden_columns: Columns for which no values are printed, e.g. because they contain sensitive information. - metrics: Optional mapping from display label to a metric callable - ``(left_expr, right_expr) -> pl.Expr`` or a :class:`~diffly.metrics.Metric`. - Bare callables are only computed for numerical columns; wrap one in a - :class:`~diffly.metrics.Metric` with a column selector to target other column - types. See :mod:`diffly.metrics` for presets. When ``None`` (default), no - metrics are computed; presets are not applied automatically. + metrics: Optional mapping from display label to a + :class:`~diffly.metrics.ChangeMetric`, :class:`~diffly.metrics.DataMetric`, + or a bare callable resolved by its arity (two arguments → change metric on + numerical columns, one argument → data metric on all columns). To target + other column types, construct the metric explicitly with a column selector. + See :mod:`diffly.metrics` for presets. When ``None`` (default), no metrics + are computed; presets are not applied automatically. Raises: AssertionError: If the collections are not equal. @@ -176,7 +177,7 @@ def assert_frame_equal( right_name: str = Side.RIGHT, slim: bool = False, hidden_columns: list[str] | None = None, - metrics: Mapping[str, MetricFn | Metric] | None = None, + metrics: Mapping[str, ChangeMetricFn | DataMetricFn | Metric] | None = None, ) -> None: """Assert that two :mod:`polars` data frames are equal. @@ -227,12 +228,13 @@ def assert_frame_equal( advanced users who are familiar with the summary format. hidden_columns: Columns for which no values are printed, e.g. because they contain sensitive information. - metrics: Optional mapping from display label to a metric callable - ``(left_expr, right_expr) -> pl.Expr`` or a :class:`~diffly.metrics.Metric`. - Bare callables are only computed for numerical columns; wrap one in a - :class:`~diffly.metrics.Metric` with a column selector to target other column - types. See :mod:`diffly.metrics` for presets. When ``None`` (default), no - metrics are computed; presets are not applied automatically. + metrics: Optional mapping from display label to a + :class:`~diffly.metrics.ChangeMetric`, :class:`~diffly.metrics.DataMetric`, + or a bare callable resolved by its arity (two arguments → change metric on + numerical columns, one argument → data metric on all columns). To target + other column types, construct the metric explicitly with a column selector. + See :mod:`diffly.metrics` for presets. When ``None`` (default), no metrics + are computed; presets are not applied automatically. Raises: AssertionError: If the data frames are not equal. diff --git a/docs/api/metrics.rst b/docs/api/metrics.rst index 84c8f82..0ddb6d5 100644 --- a/docs/api/metrics.rst +++ b/docs/api/metrics.rst @@ -6,14 +6,23 @@ Metrics Metrics are scalar aggregations computed per column when generating a :meth:`~diffly.comparison.DataFrameComparison.summary`. Pass them via the -``metrics`` argument as a mapping from display label to a :data:`MetricFn` -callable. :mod:`diffly.metrics` ships a set of presets; you can also supply -your own callable ``(left_expr, right_expr) -> pl.Expr``. - -A bare callable is only computed for numerical columns. To target a different -set of columns, wrap it in a :class:`Metric` with a column selector, e.g. -``Metric(fn, selector=cs.all())``, ``Metric(fn, selector=cs.boolean())``, or -``Metric(fn, selector=cs.by_name("my_column_name"))``. +``metrics`` argument as a mapping from display label to a metric. There are two +families: + +- A :class:`ChangeMetric` describes the *change* between the two sides. Its + callable takes ``(left_expr, right_expr)`` and aggregates over the difference + (e.g. the mean delta). It is rendered as a column in the "Columns" table. +- A :class:`DataMetric` describes each dataset *individually*. Its callable takes + a single column expression and is evaluated on the left and right side + separately (e.g. the fraction of null entries). It is rendered in the + "Data Inspection" section, showing the left and right value side by side. + +A bare callable is resolved by its arity: a two-argument callable becomes a +:class:`ChangeMetric` (computed for numerical columns only), a one-argument +callable becomes a :class:`DataMetric` (computed for all columns). To target a +different set of columns, construct the metric explicitly with a column selector, +e.g. ``ChangeMetric(fn, selector=cs.all())`` or +``DataMetric(fn, selector=cs.boolean())``. Presets come in two families, each with its own module and default set: @@ -24,10 +33,15 @@ Presets come in two families, each with its own module and default set: The change default set is exposed as :data:`DEFAULT_METRICS`. -.. autodata:: MetricFn +.. autodata:: ChangeMetricFn + :no-value: + +.. autodata:: DataMetricFn :no-value: -.. autoclass:: Metric +.. autoclass:: ChangeMetric + +.. autoclass:: DataMetric .. autodata:: DEFAULT_METRICS :no-value: @@ -66,7 +80,7 @@ understand how a change affects the data. .. autosummary:: :toctree: _gen/ - null_fraction_change + null_fraction .. autodata:: DEFAULT_DATA_METRICS :no-value: diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt index 93abb0f..8df6788 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -29,9 +29,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt index 93abb0f..8df6788 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -29,9 +29,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt index e076120..b202aac 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -17,9 +17,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt index e076120..b202aac 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -17,9 +17,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt index b194b1f..ff0578d 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -34,9 +34,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt index bc7dd6b..5c5d96f 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -34,9 +34,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt index 6b6fb7e..a15e074 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -22,9 +22,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt index f44867a..7b844e8 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -22,9 +22,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt index 93abb0f..8df6788 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -29,9 +29,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt index 93abb0f..8df6788 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -29,9 +29,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt index e076120..b202aac 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -17,9 +17,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt index e076120..b202aac 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -17,9 +17,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt index b194b1f..ff0578d 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -34,9 +34,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt index bc7dd6b..5c5d96f 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -34,9 +34,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt index 6b6fb7e..a15e074 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -22,9 +22,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt index f44867a..7b844e8 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -22,9 +22,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃ Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt index 05e8662..eb2719e 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -29,9 +29,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt index 05e8662..eb2719e 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -29,9 +29,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt index a9a2422..573f85a 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -17,9 +17,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt index a9a2422..573f85a 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -17,9 +17,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt index b070abb..0aa07e7 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -34,9 +34,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt index 5b88e39..a21fa2c 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -34,9 +34,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt index f588b90..e74afd8 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -22,9 +22,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt index 21be51f..c5446f4 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -22,9 +22,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt index 05e8662..eb2719e 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -29,9 +29,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt index 05e8662..eb2719e 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -29,9 +29,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt index a9a2422..573f85a 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -17,9 +17,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt index a9a2422..573f85a 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -17,9 +17,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt index b070abb..0aa07e7 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -34,9 +34,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt index 5b88e39..a21fa2c 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -34,9 +34,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt index f588b90..e74afd8 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -22,9 +22,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt index 21be51f..c5446f4 100644 --- a/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt +++ b/tests/summary/fixtures/metrics_null_fraction/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -22,9 +22,9 @@ Data Inspection ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ - ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ Column ┃  Null% ┃ - ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩ - │ price  │ 20.0% -> 0.0% (-20.0) │ - │ status │ 0.0% -> 40.0% (+40.0) │ - └────────┴───────────────────────┘ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ price  │ 20.0% -> 0.0% (-20.0) │ 5 -> 5 (+0) │ │ + │ status │ 0.0% -> 40.0% (+40.0) │ 5 -> 4 (-1) │ e -> x │ + └────────┴───────────────────────┴─────────────┴────────┘ diff --git a/tests/summary/fixtures/metrics_null_fraction/test_metrics_null_fraction.py b/tests/summary/fixtures/metrics_null_fraction/test_metrics_null_fraction.py index 9e26bd4..376d2d7 100644 --- a/tests/summary/fixtures/metrics_null_fraction/test_metrics_null_fraction.py +++ b/tests/summary/fixtures/metrics_null_fraction/test_metrics_null_fraction.py @@ -6,7 +6,7 @@ import pytest from diffly import compare_frames, metrics -from diffly.metrics import Metric +from diffly.metrics import ChangeMetric, DataMetric from diffly.metrics.data import DEFAULT_DATA_METRICS from tests.utils import generate_summaries @@ -34,8 +34,12 @@ def test_generate() -> None: # Numeric-only preset alongside a metric applied to all columns. "Mean": metrics.mean, "Null%": DEFAULT_DATA_METRICS["Null%"], - # A user-supplied metric with a custom (string-only) selector. - "str_len_delta": Metric( + # A second, numeric data metric to render more than one data column. + "Distinct": DataMetric(fn=lambda col: col.n_unique()), + # A non-numeric data metric: rendered as ``left -> right`` without a delta. + "Max": DataMetric(fn=lambda col: col.max(), selector=cs.string()), + # A user-supplied change metric with a custom (string-only) selector. + "str_len_delta": ChangeMetric( fn=lambda left, right: ( right.str.len_chars() - left.str.len_chars() ).mean(), diff --git a/tests/summary/test_summary.py b/tests/summary/test_summary.py index cf9e6c1..d10f4cb 100644 --- a/tests/summary/test_summary.py +++ b/tests/summary/test_summary.py @@ -148,7 +148,9 @@ def test_change_and_data_metrics_routed_to_separate_fields() -> None: assert value_col["name"] == "value" # Change metric lands in `change_metrics`, data metric in `data_metrics`. assert value_col["change_metrics"] == {"Mean": pytest.approx(2.5)} - assert value_col["data_metrics"] == {"Null%": "0.0% -> 33.33% (+33.33)"} + assert value_col["data_metrics"] == { + "Null%": {"left": pytest.approx(0.0), "right": pytest.approx(1 / 3)} + } def _make_comparison() -> DataFrameComparison: diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 27f5825..8d88bc8 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -65,22 +65,16 @@ def test_mean_relative_deviation_div_by_zero() -> None: assert math.isinf(_apply(metrics.mean_relative_deviation, frame)) -def test_null_fraction_change() -> None: - # left nulls: 1/4 = 25%; right nulls: 3/4 = 75%; delta = +50% - frame = pl.DataFrame({"l": [1, None, 3, 4], "r": [None, None, 3, None]}) - assert _apply(data.null_fraction_change, frame) == "25.0% -> 75.0% (+50.0)" +def test_null_fraction() -> None: + # A data metric describes a single side: 1 null out of 4 rows. + frame = pl.DataFrame({"l": [1, None, 3, 4]}) + assert frame.select(data.null_fraction(pl.col("l"))).item() == pytest.approx(0.25) -def test_null_fraction_change_negative_delta() -> None: - # left nulls: 1/2 = 50%; right nulls: 0%; delta = -50% - frame = pl.DataFrame({"l": [1, None], "r": [1, 2]}) - assert _apply(data.null_fraction_change, frame) == "50.0% -> 0.0% (-50.0)" - - -def test_null_fraction_change_non_numeric() -> None: - # Applies to any column type; here strings. left nulls: 0%; right nulls: 50% - frame = pl.DataFrame({"l": ["a", "b"], "r": ["a", None]}) - assert _apply(data.null_fraction_change, frame) == "0.0% -> 50.0% (+50.0)" +def test_null_fraction_non_numeric() -> None: + # Applies to any column type; here strings. 1 null out of 2 rows. + frame = pl.DataFrame({"l": ["a", None]}) + assert frame.select(data.null_fraction(pl.col("l"))).item() == pytest.approx(0.5) def test_quantile(frame: pl.DataFrame) -> None: