diff --git a/diffly/cli.py b/diffly/cli.py index 7177e58..5a34406 100644 --- a/diffly/cli.py +++ b/diffly/cli.py @@ -12,18 +12,10 @@ from ._compat import typer from ._utils import ABS_TOL_DEFAULT, ABS_TOL_TEMPORAL_DEFAULT, REL_TOL_DEFAULT -from .metrics import Metric, MetricFn -from .metrics.change import DEFAULT_CHANGE_METRICS -from .metrics.data import DEFAULT_DATA_METRICS +from .metrics import DEFAULT_METRICS app = typer.Typer() -#: All metric presets selectable via ``--metric``, combining the change and data sets. -AVAILABLE_METRICS: dict[str, MetricFn | Metric] = { - **DEFAULT_CHANGE_METRICS, - **DEFAULT_DATA_METRICS, -} - @app.command() def main( @@ -147,8 +139,9 @@ def main( list[str], typer.Option( help=( - "Metric presets to display per column. Repeatable. " - f"Available: {', '.join(AVAILABLE_METRICS)}." + "Metric presets to display. Repeatable. Change metrics appear as " + "extra columns in the Columns table; data metrics appear in the Data " + f"Inspection section. Available: {', '.join(DEFAULT_METRICS)}." ) ), ] = [], @@ -162,11 +155,11 @@ def main( hidden_column = [*hidden_column, *hidden_columns] for name in metric: - if name not in AVAILABLE_METRICS: + if name not in DEFAULT_METRICS: raise typer.BadParameter( - f"Unknown metric: {name!r}. Available: {', '.join(AVAILABLE_METRICS)}." + f"Unknown metric: {name!r}. Available: {', '.join(DEFAULT_METRICS)}." ) - metrics = {name: AVAILABLE_METRICS[name] for name in metric} + metrics = {name: DEFAULT_METRICS[name] for name in metric} comparison = compare_frames( pl.scan_parquet(left), diff --git a/diffly/comparison.py b/diffly/comparison.py index 6976b9c..7649751 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,12 +26,16 @@ lazy_len, make_and_validate_mapping, ) -from .metrics import Metric, MetricFn, _make_numeric_metric +from .metrics._common import Metric, MetricFn +from .metrics.change import ChangeMetric +from .metrics.data import DataMetric if TYPE_CHECKING: # pragma: no cover # NOTE: We cannot import at runtime as we're otherwise running into circular # imports. We're importing again below where we need `Summary` for more than # type annotations. + from .metrics.change import ChangeMetricFn + from .metrics.data import DataMetricFn from .summary import Summary @@ -951,16 +956,14 @@ 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.change.ChangeMetric`, a + :class:`~diffly.metrics.data.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 + (e.g. ``ChangeMetric(fn, selector=cs.numeric())``). 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: @@ -978,10 +981,7 @@ def summary( from .summary import Summary resolved_metrics = ( - { - label: v if isinstance(v, Metric) else _make_numeric_metric(v) - for label, v in metrics.items() - } + {label: _resolve_metric(v) for label, v in metrics.items()} if metrics is not None else None ) @@ -1239,3 +1239,30 @@ def _list_length_exprs( for e in _list_length_exprs(expr.struct[field.name], field.dtype) ] return [] + + +def _resolve_metric(v: MetricFn | Metric) -> Metric: + if isinstance(v, Metric): + return v + # Infer the metric family from the number of required positional parameters: a + # single-argument callable describes one side (data), two arguments describe a + # change. Ambiguous signatures (variadic or a different arity) are rejected so the + # user wraps them explicitly in `DataMetric`/`ChangeMetric`. + params = inspect.signature(v).parameters.values() + required_positional = [ + p + for p in params + if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD) + and p.default is p.empty + ] + has_variadic = any(p.kind is p.VAR_POSITIONAL for p in params) + if has_variadic or len(required_positional) not in (1, 2): + raise ValueError( + "Cannot infer the metric family from the callable's signature: expected " + "exactly one required positional argument (data metric) or two (change " + "metric), but got an ambiguous signature. Wrap it explicitly in " + "`DataMetric` or `ChangeMetric`." + ) + if len(required_positional) == 2: + return ChangeMetric(fn=cast("ChangeMetricFn", v)) + return DataMetric(fn=cast("DataMetricFn", v)) diff --git a/diffly/metrics/__init__.py b/diffly/metrics/__init__.py index a3a165b..b8f8d49 100644 --- a/diffly/metrics/__init__.py +++ b/diffly/metrics/__init__.py @@ -1,50 +1,18 @@ # Copyright (c) QuantCo 2025-2026 # SPDX-License-Identifier: BSD-3-Clause - """Metrics computed per column when generating a summary. Two families are provided: -- Metrics in :mod:`~diffly.metrics.change` describe the change between numeric - columns itself by aggregating over ``right - left``. -- Metrics in :mod:`~diffly.metrics.data` describe the left and right datasets - individually, explaining how a change affects the data. +- :class:`~diffly.metrics.change.ChangeMetric`s in :mod:`~diffly.metrics.change` describe the change between + numeric columns itself by aggregating over ``right - left``. +- :class:`~diffly.metrics.data.DataMetric`s in :mod:`~diffly.metrics.data` describe the left and right + datasets individually, explaining how a change affects the data. """ from __future__ import annotations from . import change, data -from ._common import Metric, MetricFn -from .change import ( - _make_numeric_metric, - max, - mean, - mean_absolute_deviation, - mean_relative_deviation, - median, - min, - quantile, - std, -) - -DEFAULT_METRICS: dict[str, MetricFn | Metric] = { - **change.DEFAULT_CHANGE_METRICS, -} -"""The default preset metrics, consisting of the change default set.""" +from ._common import DEFAULT_METRICS -__all__ = [ - "DEFAULT_METRICS", - "Metric", - "MetricFn", - "change", - "data", - "max", - "mean", - "mean_absolute_deviation", - "mean_relative_deviation", - "median", - "min", - "quantile", - "std", - "_make_numeric_metric", -] +__all__ = ["DEFAULT_METRICS", "change", "data"] diff --git a/diffly/metrics/_common.py b/diffly/metrics/_common.py index 5ba7c38..2d8f334 100644 --- a/diffly/metrics/_common.py +++ b/diffly/metrics/_common.py @@ -1,27 +1,17 @@ # Copyright (c) QuantCo 2025-2026 # SPDX-License-Identifier: BSD-3-Clause -from __future__ import annotations +from .change import DEFAULT_CHANGE_METRICS, ChangeMetric, ChangeMetricFn +from .data import DEFAULT_DATA_METRICS, DataMetric, DataMetricFn -from collections.abc import Callable -from dataclasses import dataclass +Metric = ChangeMetric | DataMetric +"""A change or data metric paired with a column-applicability selector.""" -import polars as pl -import polars.selectors as cs +MetricFn = ChangeMetricFn | DataMetricFn +"""A bare change or data metric callable, resolved to a :data:`Metric` by arity.""" - -@dataclass(frozen=True) -class Metric: - """A metric function paired with a column-applicability selector.""" - - fn: MetricFn - selector: cs.Selector - - -MetricFn = Callable[[pl.Expr, pl.Expr], pl.Expr] -"""A metric function maps ``(left_expr, right_expr)`` to a scalar aggregation -expression. - -The expressions refer to the left-side and right-side values of a single column across -all joined rows. -""" +DEFAULT_METRICS: dict[str, Metric] = { + **DEFAULT_CHANGE_METRICS, + **DEFAULT_DATA_METRICS, +} +"""All preset metrics, combining the change and data default sets.""" diff --git a/diffly/metrics/change.py b/diffly/metrics/change.py index f4965f1..e3f7541 100644 --- a/diffly/metrics/change.py +++ b/diffly/metrics/change.py @@ -1,21 +1,37 @@ # Copyright (c) QuantCo 2025-2026 # SPDX-License-Identifier: BSD-3-Clause -"""Metrics describing the change between numeric columns. - -These aggregate over ``right - left`` to characterize the change itself. -""" - from __future__ import annotations +from collections.abc import Callable +from dataclasses import dataclass, field + import polars as pl import polars.selectors as cs -from ._common import Metric, MetricFn +ChangeMetricFn = Callable[[pl.Expr, pl.Expr], pl.Expr] +"""A `ChangeMetricFn` maps a pair of column expressions to a scalar aggregation +expression.""" + + +@dataclass(frozen=True) +class ChangeMetric: + """A metric quantifying the *change* in a column between the two sides of a + comparison. + + Change metrics are rendered as extra columns in the "Columns" table, alongside the + match rate. + """ + + fn: ChangeMetricFn + """Aggregates over ``right - left`` (e.g. the mean delta) to describe the change + itself.""" + + selector: cs.Selector = field(default_factory=cs.numeric) + """Selects the columns the metric applies to; defaults to numeric columns.""" -def _make_numeric_metric(fn: MetricFn) -> Metric: - return Metric(fn=fn, selector=cs.numeric()) +# ---------------------------------- CHANGE METRICS ---------------------------------- # def mean(left: pl.Expr, right: pl.Expr) -> pl.Expr: @@ -54,7 +70,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,13 +82,13 @@ def _quantile(left: pl.Expr, right: pl.Expr) -> pl.Expr: return _quantile -DEFAULT_CHANGE_METRICS: dict[str, MetricFn] = { - "Mean": mean, - "Median": median, - "Min": min, - "Max": max, - "Std": std, - "Mean absolute deviation": mean_absolute_deviation, - "Mean relative deviation": mean_relative_deviation, +DEFAULT_CHANGE_METRICS: dict[str, ChangeMetric] = { + "Mean": ChangeMetric(fn=mean), + "Median": ChangeMetric(fn=median), + "Min": ChangeMetric(fn=min), + "Max": ChangeMetric(fn=max), + "Std": ChangeMetric(fn=std), + "Mean absolute deviation": ChangeMetric(fn=mean_absolute_deviation), + "Mean relative deviation": ChangeMetric(fn=mean_relative_deviation), } """Preset metrics describing the change between numeric columns.""" diff --git a/diffly/metrics/data.py b/diffly/metrics/data.py index 066a06b..c3babd5 100644 --- a/diffly/metrics/data.py +++ b/diffly/metrics/data.py @@ -1,75 +1,60 @@ # Copyright (c) QuantCo 2025-2026 # SPDX-License-Identifier: BSD-3-Clause -"""Metrics describing the left and right datasets individually. - -These characterize each side of a change so you can understand how the change affects -the data, rather than describing the change itself. -""" - from __future__ import annotations from collections.abc import Callable +from dataclasses import dataclass, field +from typing import Any import polars as pl import polars.selectors as cs -from ._common import Metric, MetricFn +DataMetricFn = Callable[[pl.Expr], pl.Expr] +"""A data metric maps a single column expression to a scalar aggregation expression.""" -def null_fraction_change(left: pl.Expr, right: pl.Expr) -> pl.Expr: - """Change in the fraction of null entries, rendered as `` -> ()``. +@dataclass(frozen=True) +class DataMetric: + """A metric describing each dataset *individually*. - ``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. + 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. """ - return _render_change( - left.is_null().mean(), - right.is_null().mean(), - lambda value, signed: _percentage_string( - value, signed=signed, percent_sign=not signed - ), - ) + fn: DataMetricFn + """Applied to the left and right side separately, characterizing the data rather + than the change between the sides.""" -DEFAULT_DATA_METRICS: dict[str, MetricFn | Metric] = { - "Null%": Metric(fn=null_fraction_change, selector=cs.all()), -} -"""Preset metrics describing the left and right datasets individually.""" + selector: cs.Selector = field(default_factory=cs.all) + """Selects the columns the metric applies to; defaults to all columns.""" + + formatter: Callable[[Any], str] | None = None + """Formats a single left/right value for display. + + Falls back to the default numeric precision when unset. + """ + delta_formatter: Callable[[Any], str] | None = None + """Formats the magnitude of the delta, which is rendered with an explicit sign. -# ------------------------------------------------------------------------------------ # -# UTILITY METHODS # -# ------------------------------------------------------------------------------------ # + Falls back to ``formatter`` when ``None``. + """ -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 +# ----------------------------------- DATA METRICS ----------------------------------- # -def _render_change( - old: pl.Expr, - new: pl.Expr, - format_value: Callable[[pl.Expr, bool], pl.Expr], -) -> pl.Expr: - """Render a change as `` -> ()``. +def null_fraction(col: pl.Expr) -> pl.Expr: + """Fraction of null entries in a column.""" + return col.is_null().mean() - ``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), - ) + +DEFAULT_DATA_METRICS: dict[str, DataMetric] = { + "Null%": DataMetric( + fn=null_fraction, + 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.""" diff --git a/diffly/summary.py b/diffly/summary.py index ac3dda7..0086af7 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,9 @@ from rich.text import Text from ._utils import Side, capitalize_first -from .metrics import Metric +from .metrics._common import Metric +from .metrics.change import ChangeMetric +from .metrics.data import DataMetric if TYPE_CHECKING: # pragma: no cover from .comparison import DataFrameComparison @@ -131,9 +133,11 @@ 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]}], + "change_metrics": null } ], + "data_inspection": null, "sample_rows_left_only": [], "sample_rows_right_only": [] } @@ -179,6 +183,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,15 +576,14 @@ 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 - matches = Table(show_header=bool(metric_labels)) + matches = Table(show_header=bool(self._data._change_metric_labels)) matches.add_column( "Column", max_width=COLUMN_SECTION_COLUMN_WIDTH, overflow=OVERFLOW, ) matches.add_column("Match Rate", justify="right") - for label in metric_labels: + for label in self._data._change_metric_labels: matches.add_column(label, justify="right") has_top_changes_column = any( c.changes is not None for c in columns if c.match_rate < 1 @@ -592,8 +596,10 @@ def _section_columns(self) -> RenderableType: Text(col.name, style="cyan"), f"{_format_fraction_as_percentage(col.match_rate)}", ] - for label in metric_labels: - value = col.metrics.get(label) if col.metrics else None + for label in self._data._change_metric_labels: + 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 = [] @@ -632,6 +638,41 @@ def _section_columns(self) -> RenderableType: return Group(*display_items) + # ------------------------------- DATA INSPECTION -------------------------------- # + + def _print_data_inspection(self, console: Console) -> None: + if not self._data.data_inspection or not self._data._data_metrics: + return + _print_section( + console, + "Data Inspection", + self._section_data_inspection(), + ) + + def _section_data_inspection(self) -> RenderableType: + assert self._data.data_inspection is not None + + table = Table() + table.add_column( + "Column", + max_width=COLUMN_SECTION_COLUMN_WIDTH, + overflow=OVERFLOW, + ) + for label in self._data._data_metrics: + table.add_column(label, justify="right", overflow=OVERFLOW) + for col in self._data.data_inspection: + row_items: list[RenderableType] = [Text(col.name, style="cyan")] + for label in self._data._data_metrics: + result = col.data_metrics.get(label) + metric = self._data._data_metrics[label] + row_items.append( + _format_data_metric_result( + result, metric.formatter, metric.delta_formatter + ) + ) + table.add_row(*row_items) + return table + # ------------------------------ ROWS ONLY ONE SIDE ------------------------------ # def _print_sample_rows_only_one_side(self, console: Console, side: Side) -> None: @@ -709,13 +750,27 @@ class SummaryDataColumnChange: sample_pk: tuple[Any, ...] | None +@dataclass +class DataMetricResult: + """A data metric evaluated on each side of the comparison.""" + + left: Any + right: Any + + @dataclass class SummaryDataColumn: name: str match_rate: float n_total_changes: int changes: list[SummaryDataColumnChange] | None - metrics: dict[str, Any] | None + change_metrics: dict[str, Any] | None + + +@dataclass +class SummaryDataInspectionColumn: + name: str + data_metrics: dict[str, DataMetricResult] @dataclass @@ -727,13 +782,15 @@ class SummaryData: schemas: SummaryDataSchemas | None rows: SummaryDataRows | None columns: list[SummaryDataColumn] | None + data_inspection: list[SummaryDataInspectionColumn] | None sample_rows_left_only: list[tuple[Any, ...]] | None sample_rows_right_only: list[tuple[Any, ...]] | None _is_empty: bool _other_common_columns: list[str] _truncated_left_name: str _truncated_right_name: str - _metric_labels: list[str] + _change_metric_labels: list[str] + _data_metrics: dict[str, DataMetric] def to_dict(self) -> dict[str, Any]: def _convert(obj: Any) -> Any: @@ -830,18 +887,26 @@ def _validate_primary_key_hidden_columns() -> None: schemas=None, rows=None, columns=None, + data_inspection=None, sample_rows_left_only=None, sample_rows_right_only=None, _is_empty=is_empty, _other_common_columns=comp._other_common_columns, _truncated_left_name=truncated_left, _truncated_right_name=truncated_right, - _metric_labels=[], + _change_metric_labels=[], + _data_metrics={}, ) metrics_resolved: dict[str, Metric] = dict(metrics or {}) - metrics_by_column = _compute_column_metrics(comp, metrics_resolved) - metric_labels = list(metrics_resolved.keys()) + change_metrics = { + label: m for label, m in metrics_resolved.items() if isinstance(m, ChangeMetric) + } + data_metrics = { + label: m for label, m in metrics_resolved.items() if isinstance(m, DataMetric) + } + change_metrics_by_column = _compute_change_metrics(comp, change_metrics) + change_metric_labels = list(change_metrics) schemas = _compute_schemas(comp, slim) rows = _compute_rows(comp, slim) @@ -851,8 +916,9 @@ def _validate_primary_key_hidden_columns() -> None: show_perfect_column_matches, top_k_changes_by_column, show_sample_primary_key_per_change, - metrics_by_column, + change_metrics_by_column, ) + data_inspection = _compute_data_inspection(comp, data_metrics) sample_rows_left_only, sample_rows_right_only = _compute_sample_rows( comp, sample_k_rows_only ) @@ -865,13 +931,15 @@ def _validate_primary_key_hidden_columns() -> None: schemas=schemas, rows=rows, columns=columns, + data_inspection=data_inspection, sample_rows_left_only=sample_rows_left_only, sample_rows_right_only=sample_rows_right_only, _is_empty=is_empty, _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_metrics=data_metrics, ) @@ -933,28 +1001,38 @@ def _compute_rows(comp: DataFrameComparison, slim: bool) -> SummaryDataRows | No ) -def _compute_column_metrics( - comp: DataFrameComparison, - metrics: Mapping[str, Metric], -) -> dict[str, dict[str, Any]]: - if comp.primary_key is None or comp.num_rows_joined() == 0: - return {} +def _select_metric_columns( + comp: DataFrameComparison, selector: cs.Selector +) -> set[str]: + left = set(cs.expand_selector(comp.left_schema, selector)) + right = set(cs.expand_selector(comp.right_schema, selector)) + return (left & right) & set(comp._other_common_columns) - def select_columns(selector: cs.Selector) -> set[str]: - left = set(cs.expand_selector(comp.left_schema, selector)) - right = set(cs.expand_selector(comp.right_schema, selector)) - return (left & right) & set(comp._other_common_columns) - metric_to_columns = { - label: select_columns(m.selector) for label, m in metrics.items() +def _metric_target_columns( + comp: DataFrameComparison, metrics: Mapping[str, Metric] +) -> dict[str, set[str]]: + """Map each metric label to the columns it applies to.""" + return { + label: _select_metric_columns(comp, m.selector) for label, m in metrics.items() } - all_columns = sorted(set().union(*metric_to_columns.values())) - if not all_columns: + +def _compute_change_metrics( + comp: DataFrameComparison, + metrics: Mapping[str, ChangeMetric], +) -> dict[str, dict[str, Any]]: + """Compute change metrics over the joined (matched) rows only. + + Change metrics compare matched rows and therefore require a primary key and at least + one joined row. + """ + if comp.primary_key is None or comp.num_rows_joined() == 0: + return {} + metric_to_columns = _metric_target_columns(comp, metrics) + if not any(metric_to_columns.values()): return {} - 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}"), @@ -963,20 +1041,50 @@ def select_columns(selector: cs.Selector) -> set[str]: for label, metric in metrics.items() for column in sorted(metric_to_columns[label]) ] - row = joined.select(agg_exprs).collect().row(0, named=True) - for label, columns in metric_to_columns.items(): - for column in columns: + + row = comp.joined(lazy=True).select(agg_exprs).collect().row(0, named=True) + out: dict[str, dict[str, Any]] = { + c: {} for c in set().union(*metric_to_columns.values()) + } + for label in metrics: + for column in metric_to_columns[label]: out[column][label] = row[f"{label}__{column}"] return out +def _compute_data_metrics( + comp: DataFrameComparison, + metrics: Mapping[str, DataMetric], + metric_to_columns: dict[str, set[str]], +) -> dict[str, dict[str, Any]]: + """Compute data metrics over the entire left and right columns, including rows that + are not part of the join.""" + agg_exprs: list[pl.Expr] = [] + for label, metric in metrics.items(): + for column in sorted(metric_to_columns[label]): + agg_exprs.append(metric.fn(pl.col(column)).alias(f"{label}__{column}")) + + left_row = comp.left.select(agg_exprs).collect().row(0, named=True) + right_row = comp.right.select(agg_exprs).collect().row(0, named=True) + out: dict[str, dict[str, Any]] = { + c: {} for c in set().union(*metric_to_columns.values()) + } + for label in metrics: + for column in metric_to_columns[label]: + out[column][label] = DataMetricResult( + left=left_row[f"{label}__{column}"], + right=right_row[f"{label}__{column}"], + ) + return out + + def _compute_columns( comp: DataFrameComparison, slim: bool, show_perfect_column_matches: bool, top_k_changes_by_column: dict[str, int], show_sample_primary_key_per_change: bool, - metrics_by_column: dict[str, dict[str, Any]], + change_metrics_by_column: dict[str, dict[str, Any]], ) -> list[SummaryDataColumn] | None: # NOTE: We can only compute column matches if there are primary key columns and at # least one joined row. @@ -1023,12 +1131,31 @@ def _compute_columns( match_rate=rate, n_total_changes=n_total_changes, changes=changes, - metrics=metrics_by_column.get(col_name), + change_metrics=change_metrics_by_column.get(col_name), ) ) return columns +def _compute_data_inspection( + comp: DataFrameComparison, + metrics: Mapping[str, DataMetric], +) -> list[SummaryDataInspectionColumn] | None: + # NOTE: Data metrics describe each side individually and do not need a join, but we + # still require the columns to be present on both sides so left/right values are + # comparable. + metric_to_columns = _metric_target_columns(comp, metrics) + if not any(metric_to_columns.values()): + return None + data_metrics_by_column = _compute_data_metrics(comp, metrics, metric_to_columns) + return [ + SummaryDataInspectionColumn( + name=col_name, data_metrics=data_metrics_by_column[col_name] + ) + for col_name in sorted(data_metrics_by_column) + ] + + def _compute_sample_rows( comp: DataFrameComparison, sample_k_rows_only: int ) -> tuple[list[tuple[Any, ...]] | None, list[tuple[Any, ...]] | None]: @@ -1141,5 +1268,41 @@ def _format_metric_value(value: Any) -> str: return _format_value(value, float_format=".4g") +def _format_data_metric_result( + result: DataMetricResult | None, + 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 result is None: + return "" + + def _fmt(v: Any, fn: Callable[[Any], str] | None) -> str: + if v is None: + return "None" + if fn is not None: + return fn(v) + if isinstance(v, float): + return format(v, ".4g") + return str(v) + + text = f"{_fmt(result.left, formatter)} -> {_fmt(result.right, formatter)}" + if _is_numeric(result.left) and _is_numeric(result.right): + delta = result.right - result.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..b89200c 100644 --- a/diffly/testing.py +++ b/diffly/testing.py @@ -19,7 +19,9 @@ from ._compat import dy from .comparison import DataFrameComparison, compare_frames -from .metrics import Metric, MetricFn +from .metrics._common import Metric +from .metrics.change import ChangeMetricFn +from .metrics.data import DataMetricFn def assert_collection_equal( @@ -40,7 +42,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 +86,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.change.ChangeMetric`, :class:`~diffly.metrics.data.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 +179,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 +230,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.change.ChangeMetric`, :class:`~diffly.metrics.data.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/index.rst b/docs/api/index.rst index e0a44a9..741b9e0 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -27,7 +27,7 @@ API Reference :link: metrics :link-type: doc - Built-in metric presets and the ``MetricFn`` callable for ``summary(metrics=...)``. + Built-in metric presets and the metric types for ``summary(metrics=...)``. .. grid-item-card:: Testing :link: testing diff --git a/docs/api/metrics.rst b/docs/api/metrics.rst index 84c8f82..3680690 100644 --- a/docs/api/metrics.rst +++ b/docs/api/metrics.rst @@ -6,14 +6,24 @@ 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:`~diffly.metrics.change.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:`~diffly.metrics.data.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:`~diffly.metrics.change.ChangeMetric` (computed for numerical columns only), +a one-argument callable becomes a :class:`~diffly.metrics.data.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: @@ -22,15 +32,9 @@ Presets come in two families, each with its own module and default set: - :mod:`diffly.metrics.data` describes the left and right datasets *individually*, so you can see how a change affects the data. -The change default set is exposed as :data:`DEFAULT_METRICS`. - -.. autodata:: MetricFn - :no-value: - -.. autoclass:: Metric - -.. autodata:: DEFAULT_METRICS - :no-value: +The preset default sets are :data:`~diffly.metrics.change.DEFAULT_CHANGE_METRICS` +and :data:`~diffly.metrics.data.DEFAULT_DATA_METRICS`. The union of both families is +also available as :data:`~diffly.metrics.DEFAULT_METRICS`. Change metrics ============== @@ -40,6 +44,11 @@ Change metrics Metrics that describe the change between numeric columns by aggregating over ``right - left``. +.. autodata:: ChangeMetricFn + :no-value: + +.. autoclass:: ChangeMetric + .. autosummary:: :toctree: _gen/ @@ -63,10 +72,15 @@ Data metrics Metrics that describe the left and right datasets individually, so you can understand how a change affects the data. +.. autodata:: DataMetricFn + :no-value: + +.. autoclass:: DataMetric + .. autosummary:: :toctree: _gen/ - null_fraction_change + null_fraction .. autodata:: DEFAULT_DATA_METRICS :no-value: diff --git a/docs/guides/features/summary.ipynb b/docs/guides/features/summary.ipynb index bec4877..9c43e9d 100644 --- a/docs/guides/features/summary.ipynb +++ b/docs/guides/features/summary.ipynb @@ -544,20 +544,7 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "from diffly import metrics\n", - "\n", - "print(\n", - " comparison.summary(\n", - " top_k_column_changes=3,\n", - " metrics={\n", - " \"Mean\": metrics.mean,\n", - " \"Mean relative deviation\": metrics.mean_relative_deviation,\n", - " \"Max absolute deviation\": lambda l, r: (r - l).abs().max(),\n", - " },\n", - " )\n", - ")" - ] + "source": "from diffly import metrics\n\nprint(\n comparison.summary(\n top_k_column_changes=3,\n metrics={\n \"Mean\": metrics.change.mean,\n \"Mean relative deviation\": metrics.change.mean_relative_deviation,\n \"Max absolute deviation\": lambda left, right: (right - left).abs().max(),\n },\n )\n)" }, { "cell_type": "markdown", diff --git a/pixi.lock b/pixi.lock index 184fd51..0a6bc50 100644 --- a/pixi.lock +++ b/pixi.lock @@ -2068,7 +2068,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.3-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.8-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda @@ -2085,6 +2085,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/untokenize-0.1.1-pyhcf101f3_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.5.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda linux-aarch64: @@ -2140,7 +2141,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.3-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.8-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda @@ -2157,6 +2158,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/untokenize-0.1.1-pyhcf101f3_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.5.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda osx-64: @@ -2164,7 +2166,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.3-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.8-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda @@ -2181,6 +2183,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/untokenize-0.1.1-pyhcf101f3_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.5.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-64/_openmp_mutex-4.5-7_kmp_llvm.conda @@ -2232,7 +2235,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.3-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.8-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda @@ -2249,6 +2252,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/untokenize-0.1.1-pyhcf101f3_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.5.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/osx-arm64/_openmp_mutex-4.5-7_kmp_llvm.conda @@ -2301,7 +2305,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.3-pyhcf101f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.8-pyhc364b38_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.7-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.5-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda @@ -2318,6 +2322,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/untokenize-0.1.1-pyhcf101f3_3.conda - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.5.1-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda - conda: https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h0ad9c76_9.conda @@ -7366,18 +7371,18 @@ packages: run_exports: {} size: 303705 timestamp: 1781320269259 -- conda: https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.8-pyhc364b38_0.conda - sha256: 3e57149faca76593a869d91242dd166a9cc816cb7f01e3b39bda90e44407818e - md5: 2207be19c7b2f72e46e9d4049cb4cabc +- conda: https://conda.anaconda.org/conda-forge/noarch/docformatter-1.7.7-pyhd8ed1ab_0.conda + sha256: 290a1d9935947c72d90781efad59d7be36fc3e6c9ce4bf5d5478804ce9070006 + md5: b1e2509c25d36f7b19ceb42193120071 depends: - charset-normalizer >=3.0.0 - - python >=3.10 - - python + - python >=3.9 + - untokenize >=0.1.1 license: MIT license_family: MIT run_exports: {} - size: 41556 - timestamp: 1777489364203 + size: 30130 + timestamp: 1746994987190 - conda: https://conda.anaconda.org/conda-forge/noarch/docutils-0.22.4-pyhd8ed1ab_0.conda sha256: 0d605569a77350fb681f9ed8d357cc71649b59a304099dc9d09fbeec5e84a65e md5: d6bd3cd217e62bbd7efe67ff224cd667 @@ -9526,6 +9531,17 @@ packages: run_exports: {} size: 119135 timestamp: 1767016325805 +- conda: https://conda.anaconda.org/conda-forge/noarch/untokenize-0.1.1-pyhcf101f3_3.conda + sha256: 557f4cef95e3f239d9b7c2e75b32840f0fe1b2c62a9832da76bb51ae3d080687 + md5: 5ab2494adac58ab85da2e8e4ed0fa057 + depends: + - python >=3.10 + - python + license: MIT + license_family: MIT + run_exports: {} + size: 11029 + timestamp: 1767727736121 - conda: https://conda.anaconda.org/conda-forge/noarch/uri-template-1.3.0-pyhd8ed1ab_1.conda sha256: e0eb6c8daf892b3056f08416a96d68b0a358b7c46b99c8a50481b22631a4dfc0 md5: e7cb0f5745e4c5035a460248334af7eb diff --git a/pixi.toml b/pixi.toml index aa10b3d..b359b8c 100644 --- a/pixi.toml +++ b/pixi.toml @@ -49,7 +49,7 @@ build-wheel = "python -m build --no-isolation ." check-wheel = "twine check dist/*" [feature.lint.dependencies] -docformatter = "*" +docformatter = "<1.7.8" insert-license-header = "*" pre-commit = "*" pre-commit-hooks = "*" diff --git a/tests/summary/fixtures/metrics_custom/test_metrics_custom.py b/tests/summary/fixtures/metrics_custom/test_metrics_custom.py index 61d257d..2bb1f75 100644 --- a/tests/summary/fixtures/metrics_custom/test_metrics_custom.py +++ b/tests/summary/fixtures/metrics_custom/test_metrics_custom.py @@ -30,8 +30,8 @@ def test_generate() -> None: generate_summaries( comp, metrics={ - "mean_delta": metrics.mean, - "p95_delta": metrics.quantile(0.95), + "mean_delta": metrics.change.mean, + "p95_delta": metrics.change.quantile(0.95), "max_abs_delta": lambda left, right: (right - left).abs().max(), }, ) diff --git a/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..b6a38d4 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Diffly Summary ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt new file mode 100644 index 0000000..b6a38d4 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Diffly Summary ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..288a3cf --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt new file mode 100644 index 0000000..288a3cf --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..b6a38d4 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Diffly Summary ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt new file mode 100644 index 0000000..b6a38d4 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Diffly Summary ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..288a3cf --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt new file mode 100644 index 0000000..288a3cf --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..b6a38d4 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Diffly Summary ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt new file mode 100644 index 0000000..b6a38d4 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Diffly Summary ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..288a3cf --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt new file mode 100644 index 0000000..288a3cf --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..b6a38d4 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Diffly Summary ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt new file mode 100644 index 0000000..b6a38d4 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃ Diffly Summary ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..288a3cf --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt new file mode 100644 index 0000000..288a3cf --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_False_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃ Null% ┃ Distinct ┃ Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..1016d10 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃  Diffly Summary  ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt new file mode 100644 index 0000000..1016d10 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃  Diffly Summary  ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..036091a --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt new file mode 100644 index 0000000..036091a --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..1016d10 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃  Diffly Summary  ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt new file mode 100644 index 0000000..1016d10 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃  Diffly Summary  ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..036091a --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt new file mode 100644 index 0000000..036091a --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_False_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..1016d10 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃  Diffly Summary  ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt new file mode 100644 index 0000000..1016d10 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_False_slim_False_sample_rows_True_sample_pk_False.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃  Diffly Summary  ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..036091a --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt new file mode 100644 index 0000000..036091a --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_False_slim_True_sample_rows_True_sample_pk_False.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..1016d10 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃  Diffly Summary  ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt new file mode 100644 index 0000000..1016d10 --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_True_slim_False_sample_rows_True_sample_pk_True.txt @@ -0,0 +1,23 @@ +┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ +┃  Diffly Summary  ┃ +┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Schemas + ▔▔▔▔▔▔▔ + Schemas match exactly (column count: 3). + + Rows + ▔▔▔▔ + The number of rows matches exactly (row count: 5). + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt new file mode 100644 index 0000000..036091a --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_False_sample_pk_False.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt new file mode 100644 index 0000000..036091a --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/gen/pretty_True_perfect_True_top_True_slim_True_sample_rows_True_sample_pk_True.txt @@ -0,0 +1,12 @@ + Attention: the data frames do not match exactly, but as no primary key columns are  + provided, the row and column matches cannot be computed. + + Data Inspection + ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔ + ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┓ + ┃ Column ┃  Null% ┃  Distinct ┃  Max ┃ + ┡━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━┩ + │ id  │ 0.0% -> 0.0% (+0.0) │ 5 -> 5 (+0) │ │ + │ 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_data_no_pk/test_metrics_data_no_pk.py b/tests/summary/fixtures/metrics_data_no_pk/test_metrics_data_no_pk.py new file mode 100644 index 0000000..acf053f --- /dev/null +++ b/tests/summary/fixtures/metrics_data_no_pk/test_metrics_data_no_pk.py @@ -0,0 +1,39 @@ +# Copyright (c) QuantCo 2025-2026 +# SPDX-License-Identifier: BSD-3-Clause + +import polars as pl +import polars.selectors as cs +import pytest + +from diffly import compare_frames +from diffly.metrics.data import DEFAULT_DATA_METRICS, DataMetric +from tests.utils import generate_summaries + + +@pytest.mark.generate +def test_generate() -> None: + # No primary key: row and column matches cannot be computed, but data metrics still + # characterize each side individually and are shown in the Data Inspection section. + left = pl.DataFrame( + { + "id": [1, 2, 3, 4, 5], + "price": [10.0, 20.0, None, 40.0, 50.0], + "status": ["a", "b", "c", "d", "e"], + } + ) + right = pl.DataFrame( + { + "id": [1, 2, 3, 4, 6], + "price": [10.0, 21.0, 30.0, 42.0, 50.0], + "status": ["a", None, "x", None, "e"], + } + ) + comp = compare_frames(left, right) + generate_summaries( + comp, + metrics={ + "Null%": DEFAULT_DATA_METRICS["Null%"], + "Distinct": DataMetric(fn=lambda col: col.n_unique()), + "Max": DataMetric(fn=lambda col: col.max(), selector=cs.string()), + }, + ) diff --git a/tests/summary/fixtures/metrics_long_labels/test_metrics_long_labels.py b/tests/summary/fixtures/metrics_long_labels/test_metrics_long_labels.py index 1972e22..4ee1b38 100644 --- a/tests/summary/fixtures/metrics_long_labels/test_metrics_long_labels.py +++ b/tests/summary/fixtures/metrics_long_labels/test_metrics_long_labels.py @@ -31,12 +31,12 @@ def test_generate() -> None: generate_summaries( comp, metrics={ - "Mean Delta": metrics.mean, - "Median Delta": metrics.median, - "Minimum Delta": metrics.min, - "Maximum Delta": metrics.max, - "Standard Deviation": metrics.std, - "Mean Absolute Deviation": metrics.mean_absolute_deviation, - "Mean Relative Deviation": metrics.mean_relative_deviation, + "Mean Delta": metrics.change.mean, + "Median Delta": metrics.change.median, + "Minimum Delta": metrics.change.min, + "Maximum Delta": metrics.change.max, + "Standard Deviation": metrics.change.std, + "Mean Absolute Deviation": metrics.change.mean_absolute_deviation, + "Mean Relative Deviation": metrics.change.mean_relative_deviation, }, ) 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..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 @@ -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% ┃ 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 f3d3d5f..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 @@ -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% ┃ 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 2f849f9..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 @@ -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% ┃ 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 2f849f9..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 @@ -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% ┃ 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 18568f4..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 @@ -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% ┃ 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 f2a498b..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 @@ -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% ┃ 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 06d07fe..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 @@ -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% ┃ 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 01c654b..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 @@ -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% ┃ 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 f3d3d5f..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 @@ -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% ┃ 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 f3d3d5f..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 @@ -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% ┃ 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 2f849f9..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 @@ -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% ┃ 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 2f849f9..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 @@ -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% ┃ 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 18568f4..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 @@ -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% ┃ 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 f2a498b..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 @@ -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% ┃ 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 06d07fe..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 @@ -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% ┃ 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 01c654b..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 @@ -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% ┃ 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 3a2a43b..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 @@ -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% ┃  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 3a2a43b..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 @@ -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% ┃  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 1316f6b..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 @@ -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% ┃  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 1316f6b..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 @@ -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% ┃  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 bdca125..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 @@ -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% ┃  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 cdd7114..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 @@ -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% ┃  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 370a2d3..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 @@ -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% ┃  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 4a10c0c..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 @@ -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% ┃  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 3a2a43b..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 @@ -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% ┃  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 3a2a43b..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 @@ -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% ┃  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 1316f6b..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 @@ -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% ┃  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 1316f6b..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 @@ -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% ┃  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 bdca125..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 @@ -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% ┃  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 cdd7114..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 @@ -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% ┃  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 370a2d3..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 @@ -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% ┃  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 4a10c0c..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 @@ -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% ┃  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..9fbd539 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,8 +6,8 @@ import pytest from diffly import compare_frames, metrics -from diffly.metrics import Metric -from diffly.metrics.data import DEFAULT_DATA_METRICS +from diffly.metrics.change import ChangeMetric +from diffly.metrics.data import DEFAULT_DATA_METRICS, DataMetric from tests.utils import generate_summaries @@ -32,10 +32,14 @@ def test_generate() -> None: comp, metrics={ # Numeric-only preset alongside a metric applied to all columns. - "Mean": metrics.mean, + "Mean": metrics.change.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/fixtures/metrics_presets_few/test_metrics_presets_few.py b/tests/summary/fixtures/metrics_presets_few/test_metrics_presets_few.py index 4fcd6d1..54bb42d 100644 --- a/tests/summary/fixtures/metrics_presets_few/test_metrics_presets_few.py +++ b/tests/summary/fixtures/metrics_presets_few/test_metrics_presets_few.py @@ -29,5 +29,5 @@ def test_generate() -> None: comp = compare_frames(left, right, primary_key=["id"]) generate_summaries( comp, - metrics={"Mean": metrics.mean, "Max": metrics.max}, + metrics={"Mean": metrics.change.mean, "Max": metrics.change.max}, ) diff --git a/tests/summary/fixtures/metrics_presets_many/test_metrics_presets_many.py b/tests/summary/fixtures/metrics_presets_many/test_metrics_presets_many.py index ede52cc..4b1f080 100644 --- a/tests/summary/fixtures/metrics_presets_many/test_metrics_presets_many.py +++ b/tests/summary/fixtures/metrics_presets_many/test_metrics_presets_many.py @@ -30,12 +30,12 @@ def test_generate() -> None: generate_summaries( comp, metrics={ - "Mean": metrics.mean, - "Median": metrics.median, - "Min": metrics.min, - "Max": metrics.max, - "Std": metrics.std, - "Mean absolute deviation": metrics.mean_absolute_deviation, - "Mean relative deviation": metrics.mean_relative_deviation, + "Mean": metrics.change.mean, + "Median": metrics.change.median, + "Min": metrics.change.min, + "Max": metrics.change.max, + "Std": metrics.change.std, + "Mean absolute deviation": metrics.change.mean_absolute_deviation, + "Mean relative deviation": metrics.change.mean_relative_deviation, }, ) diff --git a/tests/summary/test_summary.py b/tests/summary/test_summary.py index 6e43832..14f75dd 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, DataMetric from diffly.summary import _format_fraction_as_percentage, to_json_safe @@ -131,6 +132,48 @@ def test_zero_top_k_column_changes_with_show_sample_primary_key() -> None: ) +def test_change_and_data_metrics_routed_to_separate_fields() -> None: + # 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.change.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 the column's `change_metrics`, data metric in the separate + # `data_inspection` section. + assert value_col["change_metrics"] == {"Mean": pytest.approx(2.5)} + assert "data_metrics" not in value_col + (value_inspection,) = result["data_inspection"] + assert value_inspection["name"] == "value" + assert value_inspection["data_metrics"] == { + "Null%": {"left": pytest.approx(0.0), "right": pytest.approx(1 / 3)} + } + + +def test_data_metrics_consider_unjoined_rows() -> None: + # Joined rows are id=1,2,3. The extreme `value`s live in unjoined rows: id=4 is + # left-only (999.0) and id=5 is right-only (888.0). A data metric that only looked at + # the joined rows would report max 30.0 on both sides, so the metric picking these up + # proves it considers values from unjoined rows. + left = pl.DataFrame({"id": [1, 2, 3, 4], "value": [10.0, 20.0, 30.0, 999.0]}) + right = pl.DataFrame({"id": [1, 2, 3, 5], "value": [10.0, 25.0, 30.0, 888.0]}) + comp = compare_frames(left, right, primary_key="id") + + summary = comp.summary(metrics={"Max": DataMetric(fn=lambda col: col.max())}) + result = json.loads(summary.to_json()) + + (value_inspection,) = result["data_inspection"] + assert value_inspection["name"] == "value" + assert value_inspection["data_metrics"] == {"Max": {"left": 999.0, "right": 888.0}} + + 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 @@ -181,7 +224,11 @@ def test_summary_data_parametrized( comp = _make_comparison() top_k = 3 if show_top_column_changes else 0 hidden_columns = ["value"] if hide_value else None - metrics_arg = {"Mean": metrics.mean, "Max": metrics.max} if with_metrics else None + metrics_arg = ( + {"Mean": metrics.change.mean, "Max": metrics.change.max} + if with_metrics + else None + ) summary = comp.summary( show_perfect_column_matches=show_perfect_column_matches, top_k_column_changes=top_k, @@ -228,7 +275,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, } expected_columns = [] if show_perfect_column_matches: @@ -238,7 +287,7 @@ def test_summary_data_parametrized( "match_rate": 1.0, "n_total_changes": 0, "changes": None, - "metrics": None, + "change_metrics": None, } ) expected_columns.append(value_col) @@ -258,6 +307,8 @@ def test_summary_data_parametrized( "n_right_only": 1, }, "columns": expected_columns, + # Only change metrics are supplied, so the data inspection section is absent. + "data_inspection": None, "sample_rows_left_only": [[4]] if sample_rows else None, "sample_rows_right_only": [[5]] if sample_rows else None, } diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 27f5825..3410fac 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -8,7 +8,10 @@ import pytest from diffly import metrics -from diffly.metrics import MetricFn, data +from diffly.comparison import _resolve_metric +from diffly.metrics import data +from diffly.metrics.change import ChangeMetric, ChangeMetricFn +from diffly.metrics.data import DataMetric @pytest.fixture @@ -17,29 +20,29 @@ def frame() -> pl.DataFrame: return pl.DataFrame({"l": [1, 2, 3, None], "r": [1, 2, 5, 4]}) -def _apply(metric: MetricFn, frame: pl.DataFrame) -> Any: +def _apply(metric: ChangeMetricFn, frame: pl.DataFrame) -> Any: return frame.select(metric(pl.col("l"), pl.col("r"))).item() def test_mean(frame: pl.DataFrame) -> None: - assert _apply(metrics.mean, frame) == pytest.approx(2 / 3) + assert _apply(metrics.change.mean, frame) == pytest.approx(2 / 3) def test_median(frame: pl.DataFrame) -> None: - assert _apply(metrics.median, frame) == 0 + assert _apply(metrics.change.median, frame) == 0 def test_min(frame: pl.DataFrame) -> None: - assert _apply(metrics.min, frame) == 0 + assert _apply(metrics.change.min, frame) == 0 def test_max(frame: pl.DataFrame) -> None: - assert _apply(metrics.max, frame) == 2 + assert _apply(metrics.change.max, frame) == 2 def test_std(frame: pl.DataFrame) -> None: sample_mean = 2 / 3 - assert _apply(metrics.std, frame) == pytest.approx( + assert _apply(metrics.change.std, frame) == pytest.approx( math.sqrt( ((0 - sample_mean) ** 2 + (0 - sample_mean) ** 2 + (2 - sample_mean) ** 2) / 2 @@ -50,54 +53,85 @@ def test_std(frame: pl.DataFrame) -> None: def test_mean_absolute_deviation() -> None: # deltas: [-1, 0, 2, null]; |deltas|: [1, 0, 2, null]; mean = 1.0 frame = pl.DataFrame({"l": [2, 2, 3, None], "r": [1, 2, 5, 4]}) - assert _apply(metrics.mean_absolute_deviation, frame) == pytest.approx(1.0) + assert _apply(metrics.change.mean_absolute_deviation, frame) == pytest.approx(1.0) def test_mean_relative_deviation() -> None: # left: [1, 2, 4, None]; delta: [0, 0, 2, null]; rel: [0, 0, 0.5, null]; mean = 1/6 frame = pl.DataFrame({"l": [1, 2, 4, None], "r": [1, 2, 6, 4]}) - assert _apply(metrics.mean_relative_deviation, frame) == pytest.approx(1 / 6) + assert _apply(metrics.change.mean_relative_deviation, frame) == pytest.approx(1 / 6) def test_mean_relative_deviation_div_by_zero() -> None: # Matches numpy: x/0 -> inf, so .abs().mean() -> inf frame = pl.DataFrame({"l": [0.0, 1.0], "r": [1.0, 1.0]}) - assert math.isinf(_apply(metrics.mean_relative_deviation, frame)) + assert math.isinf(_apply(metrics.change.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: # deltas [0, 0, 2]: p50 = 0, p100 = 2 - assert _apply(metrics.quantile(0.5), frame) == 0 - assert _apply(metrics.quantile(1.0), frame) == 2 + assert _apply(metrics.change.quantile(0.5), frame) == 0 + assert _apply(metrics.change.quantile(1.0), frame) == 2 def test_quantile_out_of_range() -> None: with pytest.raises(ValueError, match="q must be in"): - metrics.quantile(1.5) + metrics.change.quantile(1.5) def test_default_metrics_partition() -> None: from diffly.metrics import change - # The top-level defaults consist of the change metrics only. - assert metrics.DEFAULT_METRICS == {**change.DEFAULT_CHANGE_METRICS} + # The change and data preset sets are disjoint. assert set(change.DEFAULT_CHANGE_METRICS) & set(data.DEFAULT_DATA_METRICS) == set() - assert list(metrics.DEFAULT_METRICS) == [*change.DEFAULT_CHANGE_METRICS] + + +@pytest.mark.parametrize( + "metric", + [ChangeMetric(fn=metrics.change.mean), DataMetric(fn=data.null_fraction)], +) +def test_resolve_metric_passthrough(metric: Any) -> None: + assert _resolve_metric(metric) is metric + + +@pytest.mark.parametrize( + "fn, expected", + [ + # One required positional argument → data metric, two → change metric. Optional + # parameters do not count towards the arity. + (lambda col: col.max(), DataMetric), + (lambda left, right: right - left, ChangeMetric), + # A closure over a tuning parameter binds it away, so only the columns remain as + # required positional arguments: a single-column data metric vs. the + # `metrics.change.quantile` factory whose closure takes `(left, right)`. + (lambda col, q=0.95: col.quantile(q), DataMetric), + (metrics.change.quantile(0.95), ChangeMetric), + ], +) +def test_resolve_metric_infers_family_from_arity(fn: Any, expected: type) -> None: + assert isinstance(_resolve_metric(fn), expected) + + +@pytest.mark.parametrize( + "fn", + [ + lambda: pl.lit(0), # no positional arguments + lambda a, b, c: a, # too many required positional arguments + lambda *cols: cols[0], # variadic + ], +) +def test_resolve_metric_rejects_ambiguous_signature(fn: Any) -> None: + with pytest.raises(ValueError, match="Cannot infer the metric family"): + _resolve_metric(fn)