diff --git a/great-docs.yml b/great-docs.yml
index 249b4e605c..6121aa9604 100644
--- a/great-docs.yml
+++ b/great-docs.yml
@@ -271,7 +271,11 @@ reference:
- Validate.all_passed
- Validate.assert_passing
- Validate.assert_below_threshold
+ - Validate.assert_dimension_scores
- Validate.above_threshold
+ - Validate.get_dimension_scores
+ - Validate.get_health_score
+ - Validate.get_scorecard
- Validate.n
- Validate.n_passed
- Validate.n_failed
diff --git a/pointblank/_constants.py b/pointblank/_constants.py
index 9b67872a2d..ed74d0075e 100644
--- a/pointblank/_constants.py
+++ b/pointblank/_constants.py
@@ -62,6 +62,89 @@
"col_sum_eq": "sum_eq",
}
+# The canonical set of data quality dimension names used for health scoring. These are the
+# categories that each validation step is tagged with (either inferred automatically from the
+# `assertion_type` or set explicitly via the `dimension=` parameter on a validation method).
+DIMENSION_NAMES: list[str] = [
+ "completeness",
+ "consistency",
+ "validity",
+ "uniqueness",
+ "timeliness",
+ "volume",
+]
+
+# Default mapping of `assertion_type` to a data quality dimension. This enables automatic
+# dimension inference for every validation step with no user effort. Users can remap globally
+# via `pb.config(dimension_map=...)` or override per step via a validation method's `dimension=`
+# parameter. Any assertion type not present here falls back to `"unknown"`.
+ASSERTION_TYPE_TO_DIMENSION: dict[str, str] = {
+ # Completeness: presence/absence of values
+ "col_vals_null": "completeness",
+ "col_vals_not_null": "completeness",
+ "col_pct_null": "completeness",
+ "col_pct_missing": "completeness",
+ "col_missing_coded": "completeness",
+ "col_missing_only_coded": "completeness",
+ "rows_complete": "completeness",
+ # Consistency: internal agreement across columns/rows/tables
+ "col_missing_consistent": "consistency",
+ "conjointly": "consistency",
+ "tbl_match": "consistency",
+ # Validity: values conform to expected rules, ranges, formats, or schema
+ "col_vals_gt": "validity",
+ "col_vals_lt": "validity",
+ "col_vals_eq": "validity",
+ "col_vals_ne": "validity",
+ "col_vals_ge": "validity",
+ "col_vals_le": "validity",
+ "col_vals_between": "validity",
+ "col_vals_outside": "validity",
+ "col_vals_in_set": "validity",
+ "col_vals_not_in_set": "validity",
+ "col_vals_regex": "validity",
+ "col_vals_within_spec": "validity",
+ "col_vals_increasing": "validity",
+ "col_vals_decreasing": "validity",
+ "col_vals_expr": "validity",
+ "col_exists": "validity",
+ "col_schema_match": "validity",
+ "col_sum_eq": "validity",
+ "prompt": "validity",
+ "specially": "validity",
+ # Uniqueness: absence of duplicate rows
+ "rows_distinct": "uniqueness",
+ # Timeliness: data recency/freshness
+ "data_freshness": "timeliness",
+ # Volume: expected row/column counts
+ "row_count_match": "volume",
+ "col_count_match": "volume",
+}
+
+# Two-letter abbreviations used for the compact, color-coded dimension badge shown in the corner of
+# the step-number cell in the validation report.
+DIMENSION_ABBR: dict[str, str] = {
+ "completeness": "CM",
+ "consistency": "CS",
+ "validity": "VA",
+ "uniqueness": "UQ",
+ "timeliness": "TM",
+ "volume": "VO",
+ "unknown": "??",
+}
+
+# Accent colors used to color-code the dimension badge in the validation report. Hues are chosen
+# to read as categorical (distinct from the warning/error/critical severity palette).
+DIMENSION_COLORS: dict[str, str] = {
+ "completeness": "#3C6E9A", # blue
+ "consistency": "#C57B3C", # amber
+ "validity": "#4E9A6B", # green
+ "uniqueness": "#8E6FB5", # purple
+ "timeliness": "#3F9C9C", # teal
+ "volume": "#7A7A8C", # slate
+ "unknown": "#B0B0B0", # gray
+}
+
COMPARISON_OPERATORS = {
"col_vals_gt": ">",
"col_vals_ge": ">=",
@@ -130,6 +213,7 @@
"thresholds",
"label",
"brief",
+ "dimension",
"active",
"all_passed",
"n",
diff --git a/pointblank/_constants_translations.py b/pointblank/_constants_translations.py
index 14f57c58a3..2b3c49e017 100644
--- a/pointblank/_constants_translations.py
+++ b/pointblank/_constants_translations.py
@@ -3447,6 +3447,468 @@
"th": "ล้มเหลว",
"fa": "ناموفق",
},
+ "report_col_dimension": {
+ "en": "DIMENSION",
+ "fr": "DIMENSION",
+ "de": "DIMENSION",
+ "it": "DIMENSIONE",
+ "es": "DIMENSIÓN",
+ "pt": "DIMENSÃO",
+ "ro": "DIMENSIUNE",
+ "tr": "BOYUT",
+ "zh-Hans": "维度",
+ "zh-Hant": "維度",
+ "ja": "ディメンション",
+ "ko": "차원",
+ "vi": "CHIỀU",
+ "ru": "ИЗМЕРЕНИЕ",
+ "cs": "DIMENZE",
+ "pl": "WYMIAR",
+ "da": "DIMENSION",
+ "sv": "DIMENSION",
+ "nb": "DIMENSJON",
+ "nl": "DIMENSIE",
+ "fi": "ULOTTUVUUS",
+ "is": "VÍDD",
+ "ar": "البُعد",
+ "hi": "आयाम",
+ "el": "ΔΙΑΣΤΑΣΗ",
+ "id": "DIMENSI",
+ "uk": "ВИМІР",
+ "bg": "ИЗМЕРЕНИЕ",
+ "hr": "DIMENZIJA",
+ "et": "MÕÕDE",
+ "hu": "DIMENZIÓ",
+ "ga": "TOISE",
+ "lv": "DIMENSIJA",
+ "lt": "DIMENSIJA",
+ "mt": "DIMENSJONI",
+ "sk": "DIMENZIA",
+ "sl": "DIMENZIJA",
+ "he": "מימד",
+ "th": "มิติ",
+ "fa": "بُعد",
+ },
+ "report_col_score": {
+ "en": "SCORE",
+ "fr": "SCORE",
+ "de": "WERT",
+ "it": "PUNTEGGIO",
+ "es": "PUNTUACIÓN",
+ "pt": "PONTUAÇÃO",
+ "ro": "SCOR",
+ "tr": "PUAN",
+ "zh-Hans": "评分",
+ "zh-Hant": "評分",
+ "ja": "スコア",
+ "ko": "점수",
+ "vi": "ĐIỂM",
+ "ru": "ОЦЕНКА",
+ "cs": "SKÓRE",
+ "pl": "WYNIK",
+ "da": "SCORE",
+ "sv": "POÄNG",
+ "nb": "POENG",
+ "nl": "SCORE",
+ "fi": "PISTEET",
+ "is": "STIG",
+ "ar": "الدرجة",
+ "hi": "स्कोर",
+ "el": "ΒΑΘΜΟΛΟΓΙΑ",
+ "id": "SKOR",
+ "uk": "ОЦІНКА",
+ "bg": "РЕЗУЛТАТ",
+ "hr": "REZULTAT",
+ "et": "SKOOR",
+ "hu": "PONTSZÁM",
+ "ga": "SCÓR",
+ "lv": "VĒRTĒJUMS",
+ "lt": "BALAS",
+ "mt": "PUNTEĠĠ",
+ "sk": "SKÓRE",
+ "sl": "OCENA",
+ "he": "ציון",
+ "th": "คะแนน",
+ "fa": "امتیاز",
+ },
+ "report_health_score": {
+ "en": "Health Score",
+ "fr": "Score de santé",
+ "de": "Gesundheitswert",
+ "it": "Punteggio di salute",
+ "es": "Puntuación de salud",
+ "pt": "Pontuação de saúde",
+ "ro": "Scor de sănătate",
+ "tr": "Sağlık Puanı",
+ "zh-Hans": "健康评分",
+ "zh-Hant": "健康評分",
+ "ja": "ヘルススコア",
+ "ko": "상태 점수",
+ "vi": "Điểm sức khỏe",
+ "ru": "Оценка состояния",
+ "cs": "Skóre stavu",
+ "pl": "Wskaźnik kondycji",
+ "da": "Sundhedsscore",
+ "sv": "Hälsopoäng",
+ "nb": "Helsescore",
+ "nl": "Gezondheidsscore",
+ "fi": "Terveyspisteet",
+ "is": "Heilsustig",
+ "ar": "درجة الصحة",
+ "hi": "स्वास्थ्य स्कोर",
+ "el": "Βαθμολογία υγείας",
+ "id": "Skor Kesehatan",
+ "uk": "Оцінка стану",
+ "bg": "Здравен резултат",
+ "hr": "Ocjena zdravlja",
+ "et": "Terviseskoor",
+ "hu": "Egészségpontszám",
+ "ga": "Scór Sláinte",
+ "lv": "Veselības rādītājs",
+ "lt": "Būklės įvertis",
+ "mt": "Punteġġ tas-Saħħa",
+ "sk": "Skóre stavu",
+ "sl": "Ocena zdravja",
+ "he": "ציון תקינות",
+ "th": "คะแนนสุขภาพ",
+ "fa": "امتیاز سلامت",
+ },
+ "report_dimension_scores": {
+ "en": "Dimension Scores",
+ "fr": "Scores par dimension",
+ "de": "Dimensionswerte",
+ "it": "Punteggi per dimensione",
+ "es": "Puntuaciones por dimensión",
+ "pt": "Pontuações por dimensão",
+ "ro": "Scoruri pe dimensiuni",
+ "tr": "Boyut Puanları",
+ "zh-Hans": "各维度评分",
+ "zh-Hant": "各維度評分",
+ "ja": "ディメンションスコア",
+ "ko": "차원별 점수",
+ "vi": "Điểm theo chiều",
+ "ru": "Оценки по измерениям",
+ "cs": "Skóre podle dimenzí",
+ "pl": "Wyniki wymiarów",
+ "da": "Dimensionsscorer",
+ "sv": "Dimensionspoäng",
+ "nb": "Dimensjonsscorer",
+ "nl": "Dimensiescores",
+ "fi": "Ulottuvuuspisteet",
+ "is": "Víddastig",
+ "ar": "درجات الأبعاد",
+ "hi": "आयाम स्कोर",
+ "el": "Βαθμολογίες διαστάσεων",
+ "id": "Skor Dimensi",
+ "uk": "Оцінки за вимірами",
+ "bg": "Резултати по измерения",
+ "hr": "Rezultati po dimenzijama",
+ "et": "Mõõtmete skoorid",
+ "hu": "Dimenziópontszámok",
+ "ga": "Scóir Toise",
+ "lv": "Dimensiju rādītāji",
+ "lt": "Dimensijų balai",
+ "mt": "Punteġġi tad-Dimensjonijiet",
+ "sk": "Skóre podľa dimenzií",
+ "sl": "Ocene po dimenzijah",
+ "he": "ציוני מימדים",
+ "th": "คะแนนตามมิติ",
+ "fa": "امتیازهای ابعاد",
+ },
+ "dimension_completeness": {
+ "en": "Completeness",
+ "fr": "Complétude",
+ "de": "Vollständigkeit",
+ "it": "Completezza",
+ "es": "Completitud",
+ "pt": "Completude",
+ "ro": "Completitudine",
+ "tr": "Eksiksizlik",
+ "zh-Hans": "完整性",
+ "zh-Hant": "完整性",
+ "ja": "完全性",
+ "ko": "완전성",
+ "vi": "Tính đầy đủ",
+ "ru": "Полнота",
+ "cs": "Úplnost",
+ "pl": "Kompletność",
+ "da": "Fuldstændighed",
+ "sv": "Fullständighet",
+ "nb": "Fullstendighet",
+ "nl": "Volledigheid",
+ "fi": "Täydellisyys",
+ "is": "Heilleiki",
+ "ar": "الاكتمال",
+ "hi": "पूर्णता",
+ "el": "Πληρότητα",
+ "id": "Kelengkapan",
+ "uk": "Повнота",
+ "bg": "Пълнота",
+ "hr": "Potpunost",
+ "et": "Terviklikkus",
+ "hu": "Teljesség",
+ "ga": "Iomláine",
+ "lv": "Pilnīgums",
+ "lt": "Išsamumas",
+ "mt": "Kompletezza",
+ "sk": "Úplnosť",
+ "sl": "Popolnost",
+ "he": "שלמות",
+ "th": "ความครบถ้วน",
+ "fa": "کامل بودن",
+ },
+ "dimension_consistency": {
+ "en": "Consistency",
+ "fr": "Cohérence",
+ "de": "Konsistenz",
+ "it": "Coerenza",
+ "es": "Consistencia",
+ "pt": "Consistência",
+ "ro": "Consistență",
+ "tr": "Tutarlılık",
+ "zh-Hans": "一致性",
+ "zh-Hant": "一致性",
+ "ja": "一貫性",
+ "ko": "일관성",
+ "vi": "Tính nhất quán",
+ "ru": "Согласованность",
+ "cs": "Konzistence",
+ "pl": "Spójność",
+ "da": "Konsistens",
+ "sv": "Konsistens",
+ "nb": "Konsistens",
+ "nl": "Consistentie",
+ "fi": "Johdonmukaisuus",
+ "is": "Samkvæmni",
+ "ar": "الاتساق",
+ "hi": "संगति",
+ "el": "Συνέπεια",
+ "id": "Konsistensi",
+ "uk": "Узгодженість",
+ "bg": "Съгласуваност",
+ "hr": "Dosljednost",
+ "et": "Järjepidevus",
+ "hu": "Konzisztencia",
+ "ga": "Comhsheasmhacht",
+ "lv": "Konsekvence",
+ "lt": "Nuoseklumas",
+ "mt": "Konsistenza",
+ "sk": "Konzistentnosť",
+ "sl": "Doslednost",
+ "he": "עקביות",
+ "th": "ความสอดคล้อง",
+ "fa": "سازگاری",
+ },
+ "dimension_validity": {
+ "en": "Validity",
+ "fr": "Validité",
+ "de": "Gültigkeit",
+ "it": "Validità",
+ "es": "Validez",
+ "pt": "Validade",
+ "ro": "Validitate",
+ "tr": "Geçerlilik",
+ "zh-Hans": "有效性",
+ "zh-Hant": "有效性",
+ "ja": "妥当性",
+ "ko": "유효성",
+ "vi": "Tính hợp lệ",
+ "ru": "Валидность",
+ "cs": "Platnost",
+ "pl": "Poprawność",
+ "da": "Gyldighed",
+ "sv": "Giltighet",
+ "nb": "Gyldighet",
+ "nl": "Geldigheid",
+ "fi": "Kelvollisuus",
+ "is": "Gildi",
+ "ar": "الصلاحية",
+ "hi": "वैधता",
+ "el": "Εγκυρότητα",
+ "id": "Validitas",
+ "uk": "Валідність",
+ "bg": "Валидност",
+ "hr": "Valjanost",
+ "et": "Kehtivus",
+ "hu": "Érvényesség",
+ "ga": "Bailíocht",
+ "lv": "Derīgums",
+ "lt": "Galiojimas",
+ "mt": "Validità",
+ "sk": "Platnosť",
+ "sl": "Veljavnost",
+ "he": "תקפות",
+ "th": "ความถูกต้อง",
+ "fa": "اعتبار",
+ },
+ "dimension_uniqueness": {
+ "en": "Uniqueness",
+ "fr": "Unicité",
+ "de": "Eindeutigkeit",
+ "it": "Unicità",
+ "es": "Unicidad",
+ "pt": "Unicidade",
+ "ro": "Unicitate",
+ "tr": "Benzersizlik",
+ "zh-Hans": "唯一性",
+ "zh-Hant": "唯一性",
+ "ja": "一意性",
+ "ko": "고유성",
+ "vi": "Tính duy nhất",
+ "ru": "Уникальность",
+ "cs": "Jedinečnost",
+ "pl": "Unikalność",
+ "da": "Unikhed",
+ "sv": "Unikhet",
+ "nb": "Unikhet",
+ "nl": "Uniekheid",
+ "fi": "Ainutlaatuisuus",
+ "is": "Einkvæmni",
+ "ar": "التفرد",
+ "hi": "विशिष्टता",
+ "el": "Μοναδικότητα",
+ "id": "Keunikan",
+ "uk": "Унікальність",
+ "bg": "Уникалност",
+ "hr": "Jedinstvenost",
+ "et": "Unikaalsus",
+ "hu": "Egyediség",
+ "ga": "Uathúlacht",
+ "lv": "Unikalitāte",
+ "lt": "Unikalumas",
+ "mt": "Uniċità",
+ "sk": "Jedinečnosť",
+ "sl": "Edinstvenost",
+ "he": "ייחודיות",
+ "th": "ความไม่ซ้ำ",
+ "fa": "یکتایی",
+ },
+ "dimension_timeliness": {
+ "en": "Timeliness",
+ "fr": "Actualité",
+ "de": "Aktualität",
+ "it": "Tempestività",
+ "es": "Actualidad",
+ "pt": "Atualidade",
+ "ro": "Actualitate",
+ "tr": "Güncellik",
+ "zh-Hans": "时效性",
+ "zh-Hant": "時效性",
+ "ja": "適時性",
+ "ko": "적시성",
+ "vi": "Tính kịp thời",
+ "ru": "Своевременность",
+ "cs": "Včasnost",
+ "pl": "Aktualność",
+ "da": "Aktualitet",
+ "sv": "Aktualitet",
+ "nb": "Aktualitet",
+ "nl": "Tijdigheid",
+ "fi": "Ajantasaisuus",
+ "is": "Tímanleiki",
+ "ar": "الحداثة",
+ "hi": "समयबद्धता",
+ "el": "Επικαιρότητα",
+ "id": "Ketepatan Waktu",
+ "uk": "Своєчасність",
+ "bg": "Навременност",
+ "hr": "Pravovremenost",
+ "et": "Ajakohasus",
+ "hu": "Időszerűség",
+ "ga": "Tráthúlacht",
+ "lv": "Savlaicīgums",
+ "lt": "Savalaikiškumas",
+ "mt": "Puntwalità",
+ "sk": "Včasnosť",
+ "sl": "Pravočasnost",
+ "he": "עדכניות",
+ "th": "ความทันเวลา",
+ "fa": "بههنگام بودن",
+ },
+ "dimension_volume": {
+ "en": "Volume",
+ "fr": "Volume",
+ "de": "Volumen",
+ "it": "Volume",
+ "es": "Volumen",
+ "pt": "Volume",
+ "ro": "Volum",
+ "tr": "Hacim",
+ "zh-Hans": "数据量",
+ "zh-Hant": "資料量",
+ "ja": "データ量",
+ "ko": "볼륨",
+ "vi": "Khối lượng",
+ "ru": "Объём",
+ "cs": "Objem",
+ "pl": "Wolumen",
+ "da": "Volumen",
+ "sv": "Volym",
+ "nb": "Volum",
+ "nl": "Volume",
+ "fi": "Määrä",
+ "is": "Umfang",
+ "ar": "الحجم",
+ "hi": "मात्रा",
+ "el": "Όγκος",
+ "id": "Volume",
+ "uk": "Обсяг",
+ "bg": "Обем",
+ "hr": "Volumen",
+ "et": "Maht",
+ "hu": "Mennyiség",
+ "ga": "Toirt",
+ "lv": "Apjoms",
+ "lt": "Apimtis",
+ "mt": "Volum",
+ "sk": "Objem",
+ "sl": "Obseg",
+ "he": "נפח",
+ "th": "ปริมาณ",
+ "fa": "حجم",
+ },
+ "dimension_unknown": {
+ "en": "Unknown",
+ "fr": "Inconnu",
+ "de": "Unbekannt",
+ "it": "Sconosciuto",
+ "es": "Desconocido",
+ "pt": "Desconhecido",
+ "ro": "Necunoscut",
+ "tr": "Bilinmeyen",
+ "zh-Hans": "未知",
+ "zh-Hant": "未知",
+ "ja": "不明",
+ "ko": "알 수 없음",
+ "vi": "Không xác định",
+ "ru": "Неизвестно",
+ "cs": "Neznámé",
+ "pl": "Nieznane",
+ "da": "Ukendt",
+ "sv": "Okänd",
+ "nb": "Ukjent",
+ "nl": "Onbekend",
+ "fi": "Tuntematon",
+ "is": "Óþekkt",
+ "ar": "غير معروف",
+ "hi": "अज्ञात",
+ "el": "Άγνωστο",
+ "id": "Tidak diketahui",
+ "uk": "Невідомо",
+ "bg": "Неизвестно",
+ "hr": "Nepoznato",
+ "et": "Teadmata",
+ "hu": "Ismeretlen",
+ "ga": "Anaithnid",
+ "lv": "Nezināms",
+ "lt": "Nežinoma",
+ "mt": "Mhux magħruf",
+ "sk": "Neznáme",
+ "sl": "Neznano",
+ "he": "לא ידוע",
+ "th": "ไม่ทราบ",
+ "fa": "نامشخص",
+ },
"report_column_schema": {
"en": "SCHEMA",
"fr": "SCHÉMA",
diff --git a/pointblank/validate.py b/pointblank/validate.py
index 3ffa68543a..31daadda35 100644
--- a/pointblank/validate.py
+++ b/pointblank/validate.py
@@ -36,11 +36,15 @@
)
from pointblank._constants import (
ASSERTION_TYPE_METHOD_MAP,
+ ASSERTION_TYPE_TO_DIMENSION,
CHECK_MARK_SPAN,
COMPARISON_OPERATORS,
COMPARISON_OPERATORS_AR,
COMPATIBLE_DTYPES,
CROSS_MARK_SPAN,
+ DIMENSION_ABBR,
+ DIMENSION_COLORS,
+ DIMENSION_NAMES,
IBIS_BACKENDS,
LOG_LEVELS_MAP,
MODEL_PROVIDERS,
@@ -318,6 +322,10 @@ def get_validation_summary() -> dict | None:
- `tbl_column_count` (`int`): The number of columns in the target table.
- `tbl_name` (`str`): The name of the target table.
- `validation_duration` (`float`): The duration of the validation in seconds.
+ - `dimension_scores` (`dict`): The test-unit-weighted health score (`0`-`100`) for each data
+ quality dimension present in the validation (e.g., `{"completeness": 99.2, "validity": 97.8}`).
+ - `overall_health_score` (`float`): The overall, test-unit-weighted health score (`0`-`100`)
+ across all dimensions.
Note that the summary dictionary is only available within the context of a final action. If
called outside of a final action (i.e., when no final action is being executed), this function
@@ -400,7 +408,11 @@ class PointblankConfig:
report_incl_footer: bool = True
report_incl_footer_timings: bool = True
report_incl_footer_notes: bool = True
+ report_incl_dimensions: bool = False
preview_incl_header: bool = True
+ dimension_map: dict[str, str] | None = None
+ dimension_weights: dict[str, float] | None = None
+ dimension_thresholds: dict[str, float] | None = None
def __repr__(self) -> str:
return (
@@ -408,7 +420,11 @@ def __repr__(self) -> str:
f"report_incl_footer={self.report_incl_footer}, "
f"report_incl_footer_timings={self.report_incl_footer_timings}, "
f"report_incl_footer_notes={self.report_incl_footer_notes}, "
- f"preview_incl_header={self.preview_incl_header})"
+ f"report_incl_dimensions={self.report_incl_dimensions}, "
+ f"preview_incl_header={self.preview_incl_header}, "
+ f"dimension_map={self.dimension_map}, "
+ f"dimension_weights={self.dimension_weights}, "
+ f"dimension_thresholds={self.dimension_thresholds})"
)
@@ -421,7 +437,11 @@ def config(
report_incl_footer: bool = True,
report_incl_footer_timings: bool = True,
report_incl_footer_notes: bool = True,
+ report_incl_dimensions: bool = False,
preview_incl_header: bool = True,
+ dimension_map: dict[str, str] | None = None,
+ dimension_weights: dict[str, float] | None = None,
+ dimension_thresholds: dict[str, float] | None = None,
) -> PointblankConfig:
"""
Configuration settings for the Pointblank library.
@@ -441,9 +461,32 @@ def config(
report_incl_footer_notes
Controls whether the notes from validation steps should be displayed in the footer. Only
applies when `report_incl_footer=True`.
+ report_incl_dimensions
+ Controls whether the data quality dimension display is included in the validation report by
+ default. When `True`, each step's report shows a color-coded dimension badge on the step
+ number and a health-score summary block in the footer. This is `False` by default (opt-in);
+ it can also be toggled per-report via `get_tabular_report(incl_dimensions=...)`.
preview_incl_header
Whether the header should be present in any preview table (generated via the
[`preview()`](`pointblank.preview`) function).
+ dimension_map
+ An optional mapping of `assertion_type` (e.g., `"col_vals_gt"`) to a data quality dimension
+ name (e.g., `"validity"`). This is merged on top of the built-in inference map, letting you
+ remap how validation steps are categorized for health scoring. Only affects steps where the
+ dimension is not set explicitly via a validation method's `dimension=` parameter.
+ dimension_weights
+ An optional mapping of dimension name to a relative weight (a positive number) used when
+ computing the overall health score. A weight scales that dimension's *test-unit*
+ contribution to the overall score, so a dimension's influence is its weight multiplied by
+ its number of test units (a heavily-weighted dimension with few test units still
+ contributes modestly). Dimensions not present in the mapping default to a weight of `1.0`;
+ when omitted entirely, the overall score is a pure test-unit-weighted pass rate.
+ dimension_thresholds
+ An optional mapping of dimension name to a minimum acceptable health score (`0`-`100`).
+ This is used as the default by
+ [`assert_dimension_scores()`](`pointblank.Validate.assert_dimension_scores`), which raises
+ an `AssertionError` when any dimension's score falls below its minimum (e.g., to fail a CI
+ run when the completeness score drops below `95`).
Returns
-------
@@ -456,10 +499,49 @@ def config(
global_config.report_incl_footer = report_incl_footer # pragma: no cover
global_config.report_incl_footer_timings = report_incl_footer_timings # pragma: no cover
global_config.report_incl_footer_notes = report_incl_footer_notes # pragma: no cover
+ global_config.report_incl_dimensions = report_incl_dimensions # pragma: no cover
global_config.preview_incl_header = preview_incl_header # pragma: no cover
+ global_config.dimension_map = dimension_map # pragma: no cover
+ global_config.dimension_weights = dimension_weights # pragma: no cover
+ global_config.dimension_thresholds = dimension_thresholds # pragma: no cover
return global_config # pragma: no cover
+def _base_dimension_from_assertion_type(assertion_type: str | None) -> str | None:
+ """
+ Infer the data quality dimension from the built-in defaults only (ignoring any config override).
+
+ Uses `ASSERTION_TYPE_TO_DIMENSION`, with a regex fallback for the dynamically-generated
+ aggregate comparison methods (e.g., `col_sum_eq`, `col_avg_gt`, `col_sd_le`). Assertion types
+ not covered are categorized as `"unknown"`. Returns `None` if `assertion_type` is `None`.
+ """
+ if assertion_type is None:
+ return None
+ if assertion_type in ASSERTION_TYPE_TO_DIMENSION:
+ return ASSERTION_TYPE_TO_DIMENSION[assertion_type]
+ if re.match(
+ r"^col_(sum|avg|mean|median|min|max|sd|std|var)_(eq|ne|gt|ge|lt|le|between|outside)$",
+ assertion_type,
+ ):
+ return "validity"
+ return "unknown"
+
+
+def _infer_dimension_from_assertion_type(assertion_type: str | None) -> str | None:
+ """
+ Infer the data quality dimension for a validation step from its `assertion_type`.
+
+ Any `pb.config(dimension_map=...)` override takes precedence over the built-in
+ `ASSERTION_TYPE_TO_DIMENSION` defaults. Returns `None` if `assertion_type` is `None`.
+ """
+ if assertion_type is None:
+ return None
+ override = getattr(global_config, "dimension_map", None) or {}
+ if assertion_type in override:
+ return override[assertion_type]
+ return _base_dimension_from_assertion_type(assertion_type)
+
+
def load_dataset(
dataset: Literal["small_table", "game_revenue", "nycflights", "global_sales"] = "small_table",
tbl_type: Literal["polars", "pandas", "duckdb"] = "polars",
@@ -3977,6 +4059,9 @@ class _ValidationInfo:
A brief description of the validation step.
autobrief
An automatically-generated brief for the validation step.
+ dimension
+ The data quality dimension for the validation step (e.g., `"completeness"`, `"validity"`,
+ `"uniqueness"`, etc.). If not set explicitly, it is inferred from the `assertion_type`.
active
Whether the validation step is active.
all_passed
@@ -4026,6 +4111,7 @@ def from_agg_validator(
brief: str | bool = False,
actions: Actions | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> _ValidationInfo:
# This factory method creates a `_ValidationInfo` instance for aggregate
# methods. The reason this is created, is because all agg methods share the same
@@ -4041,6 +4127,7 @@ def from_agg_validator(
brief=_transform_auto_brief(brief=brief),
actions=actions,
active=active,
+ dimension=dimension,
)
# Validation plan
@@ -4061,6 +4148,7 @@ def from_agg_validator(
label: str | None = None
brief: str | None = None
autobrief: str | None = None
+ dimension: str | None = None
active: bool | Callable | None = None
# Interrogation results
eval_error: bool | None = None
@@ -4522,6 +4610,12 @@ def _columns_param() -> None:
if vi.brief is not None and vi.brief is not False:
params["brief"] = True if vi.brief == "{auto}" else vi.brief
+ # Emit `dimension=` only when it deviates from the built-in default inference (i.e., an
+ # explicit per-step override or a `dimension_map` remap), so generated plans reproduce the
+ # same dimensions without depending on global config
+ if vi.dimension is not None and vi.dimension != _base_dimension_from_assertion_type(at):
+ params["dimension"] = vi.dimension
+
if vi.active is not None and vi.active is not True:
if callable(vi.active):
params["active"] = _placeholder(
@@ -5653,6 +5747,7 @@ def _add_agg_validation(
brief=False,
actions=None,
active=True,
+ dimension: str | None = None,
):
"""
Add an aggregation-based validation step to the validation plan.
@@ -5701,6 +5796,12 @@ def _add_agg_validation(
active
Whether this validation step is active.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -5735,6 +5836,7 @@ def _add_agg_validation(
actions=self.actions if actions is None else actions,
brief=self.brief if brief is None else brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -5890,6 +5992,7 @@ def col_vals_gt(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Are column data greater than a fixed value or data in another column?
@@ -5952,6 +6055,12 @@ def col_vals_gt(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -6163,6 +6272,7 @@ def col_vals_gt(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -6181,6 +6291,7 @@ def col_vals_lt(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Are column data less than a fixed value or data in another column?
@@ -6243,6 +6354,12 @@ def col_vals_lt(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -6461,6 +6578,7 @@ def col_vals_lt(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -6479,6 +6597,7 @@ def col_vals_eq(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Are column data equal to a fixed value or data in another column?
@@ -6541,6 +6660,12 @@ def col_vals_eq(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -6759,6 +6884,7 @@ def col_vals_eq(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -6777,6 +6903,7 @@ def col_vals_ne(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Are column data not equal to a fixed value or data in another column?
@@ -6839,6 +6966,12 @@ def col_vals_ne(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -7055,6 +7188,7 @@ def col_vals_ne(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -7073,6 +7207,7 @@ def col_vals_ge(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Are column data greater than or equal to a fixed value or data in another column?
@@ -7135,6 +7270,12 @@ def col_vals_ge(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -7354,6 +7495,7 @@ def col_vals_ge(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -7372,6 +7514,7 @@ def col_vals_le(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Are column data less than or equal to a fixed value or data in another column?
@@ -7434,6 +7577,12 @@ def col_vals_le(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -7653,6 +7802,7 @@ def col_vals_le(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -7673,6 +7823,7 @@ def col_vals_between(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Do column data lie between two specified values or data in other columns?
@@ -7745,6 +7896,12 @@ def col_vals_between(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -7980,6 +8137,7 @@ def col_vals_between(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -8000,6 +8158,7 @@ def col_vals_outside(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Do column data lie outside of two specified values or data in other columns?
@@ -8072,6 +8231,12 @@ def col_vals_outside(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -8307,6 +8472,7 @@ def col_vals_outside(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -8324,6 +8490,7 @@ def col_vals_in_set(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether column values are in a set of values.
@@ -8381,6 +8548,12 @@ def col_vals_in_set(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -8631,6 +8804,7 @@ class Color(Enum):
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -8648,6 +8822,7 @@ def col_vals_not_in_set(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether column values are not in a set of values.
@@ -8705,6 +8880,12 @@ def col_vals_not_in_set(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -8927,6 +9108,7 @@ class InvalidStatus(Enum):
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -8946,6 +9128,7 @@ def col_vals_increasing(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Are column data increasing by row?
@@ -9014,6 +9197,12 @@ def col_vals_increasing(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -9125,6 +9314,7 @@ def col_vals_increasing(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
val_info={
"allow_stationary": allow_stationary,
"decreasing_tol": decreasing_tol if decreasing_tol else 0.0,
@@ -9148,6 +9338,7 @@ def col_vals_decreasing(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Are column data decreasing by row?
@@ -9216,6 +9407,12 @@ def col_vals_decreasing(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -9327,6 +9524,7 @@ def col_vals_decreasing(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
val_info={
"allow_stationary": allow_stationary,
"increasing_tol": increasing_tol if increasing_tol else 0.0,
@@ -9346,6 +9544,7 @@ def col_vals_null(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether values in a column are Null.
@@ -9397,6 +9596,12 @@ def col_vals_null(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -9579,6 +9784,7 @@ def col_vals_null(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -9594,6 +9800,7 @@ def col_vals_not_null(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether values in a column are not Null.
@@ -9645,6 +9852,12 @@ def col_vals_not_null(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -9827,6 +10040,7 @@ def col_vals_not_null(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -9846,6 +10060,7 @@ def col_vals_regex(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether column values match a regular expression pattern.
@@ -9906,6 +10121,12 @@ def col_vals_regex(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -10098,6 +10319,7 @@ def col_vals_regex(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -10116,6 +10338,7 @@ def col_vals_within_spec(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether column values fit within a specification.
@@ -10177,6 +10400,12 @@ def col_vals_within_spec(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -10390,6 +10619,7 @@ def col_vals_within_spec(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -10405,6 +10635,7 @@ def col_vals_expr(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate column values using a custom expression.
@@ -10457,6 +10688,12 @@ def col_vals_expr(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -10621,6 +10858,7 @@ def col_vals_expr(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -10634,6 +10872,7 @@ def col_exists(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether one or more columns exist in the table.
@@ -10675,6 +10914,12 @@ def col_exists(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -10800,6 +11045,7 @@ def col_exists(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -10815,6 +11061,7 @@ def col_pct_null(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether a column has a specific percentage of Null values.
@@ -10867,6 +11114,12 @@ def col_pct_null(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -11101,6 +11354,7 @@ def col_pct_null(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -11118,6 +11372,7 @@ def col_pct_missing(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate that the percentage of *structured* missing values stays within a limit.
@@ -11173,6 +11428,12 @@ def col_pct_missing(
active. Using `False` will make the validation step inactive (still reporting its
presence and keeping indexes for the steps unchanged).
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -11301,6 +11562,7 @@ def col_pct_missing(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -11317,6 +11579,7 @@ def col_missing_coded(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate that all missing values in a column are *coded* (no uncoded nulls).
@@ -11367,6 +11630,12 @@ def col_missing_coded(
active. Using `False` will make the validation step inactive (still reporting its
presence and keeping indexes for the steps unchanged).
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -11481,6 +11750,7 @@ def col_missing_coded(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -11500,6 +11770,7 @@ def col_missing_only_coded(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate that a column contains only documented codes and legitimate values.
@@ -11555,6 +11826,12 @@ def col_missing_only_coded(
active. Using `False` will make the validation step inactive (still reporting its
presence and keeping indexes for the steps unchanged).
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -11685,6 +11962,7 @@ def col_missing_only_coded(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -11700,6 +11978,7 @@ def rows_distinct(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether rows in the table are distinct.
@@ -11751,6 +12030,12 @@ def rows_distinct(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -11931,6 +12216,7 @@ def rows_distinct(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -11946,6 +12232,7 @@ def rows_complete(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether row data are complete by having no missing values.
@@ -11997,6 +12284,12 @@ def rows_complete(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -12177,6 +12470,7 @@ def rows_complete(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -12194,6 +12488,7 @@ def col_missing_consistent(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate that related columns share a consistent missingness pattern for a given reason.
@@ -12246,6 +12541,12 @@ def col_missing_consistent(
active. Using `False` will make the validation step inactive (still reporting its
presence and keeping indexes for the steps unchanged).
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -12378,6 +12679,7 @@ def col_missing_consistent(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -12398,6 +12700,7 @@ def prompt(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate rows using AI/LLM-powered analysis.
@@ -12490,6 +12793,12 @@ def prompt(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -12857,6 +13166,7 @@ def prompt(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -12876,6 +13186,7 @@ def col_schema_match(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Do columns in the table (and their types) match a predefined schema?
@@ -12943,6 +13254,12 @@ def col_schema_match(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -13085,6 +13402,7 @@ def col_schema_match(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -13101,6 +13419,7 @@ def row_count_match(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether the row count of the table matches a specified count.
@@ -13161,6 +13480,12 @@ def row_count_match(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -13309,6 +13634,7 @@ def row_count_match(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -13327,6 +13653,7 @@ def data_freshness(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate that data in a datetime column is not older than a specified maximum age.
@@ -13392,6 +13719,12 @@ def data_freshness(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -13677,6 +14010,7 @@ def data_freshness(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -13692,6 +14026,7 @@ def col_count_match(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether the column count of the table matches a specified count.
@@ -13744,6 +14079,12 @@ def col_count_match(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -13858,6 +14199,7 @@ def col_count_match(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -13872,6 +14214,7 @@ def tbl_match(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Validate whether the target table matches a comparison table.
@@ -13928,6 +14271,12 @@ def tbl_match(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -14132,6 +14481,7 @@ def tbl_match(
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -14146,6 +14496,7 @@ def conjointly(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Perform multiple row-wise validations for joint validity.
@@ -14198,6 +14549,12 @@ def conjointly(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -14385,6 +14742,7 @@ def filter_by_c_gt_5(df):
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -14399,6 +14757,7 @@ def specially(
actions: Actions | None = None,
brief: str | bool | None = None,
active: bool | Callable = True,
+ dimension: str | None = None,
) -> Validate:
"""
Perform a specialized validation with customized logic.
@@ -14466,6 +14825,12 @@ def specially(
[`has_rows()`](`pointblank.has_rows`) can be used here to conditionally activate a step
based on properties of the target table.
+ dimension
+ An optional data quality dimension to categorize this validation step for health
+ scoring. One of `"completeness"`, `"validity"`, `"uniqueness"`, `"consistency"`,
+ `"timeliness"`, or `"volume"` (or any custom string). If `None` (the default), the
+ dimension is inferred automatically from the assertion type. This label appears in the
+ validation report and feeds the overall and per-dimension health scores.
Returns
-------
Validate
@@ -14735,6 +15100,7 @@ def validate_pointblank_version():
actions=actions,
brief=brief,
active=active,
+ dimension=dimension,
)
self._add_validation(validation_info=val_info)
@@ -17955,6 +18321,359 @@ def from_prompt(
max_reprompts=max_reprompts,
)
+ def get_dimension_scores(self) -> dict[str, float]:
+ """
+ Get per-dimension health scores from the validation results.
+
+ Each validation step is associated with a data quality dimension (e.g., `"completeness"`,
+ `"validity"`, `"uniqueness"`, `"consistency"`, `"timeliness"`, or `"volume"`), either
+ inferred automatically from the assertion type or set explicitly via the `dimension=`
+ parameter on a validation method. This method rolls the per-step results up into a
+ test-unit-weighted pass rate (`0`-`100`) for each dimension present in the plan.
+
+ Scores are weighted by test units, so larger tables and steps with more test units
+ contribute proportionally more to each dimension's score. Only steps that have been
+ interrogated contribute; inactive steps are excluded.
+
+ Returns
+ -------
+ dict[str, float]
+ A dictionary mapping each dimension name to its score (a percentage from `0` to `100`).
+ Returns an empty dictionary if the validation has not been interrogated.
+
+ Examples
+ --------
+ ```python
+ import pointblank as pb
+
+ validation = (
+ pb.Validate(data=pb.load_dataset("small_table"))
+ .col_vals_not_null(columns="c")
+ .col_vals_gt(columns="d", value=0)
+ .rows_distinct()
+ .interrogate()
+ )
+
+ validation.get_dimension_scores()
+ ```
+
+ See Also
+ --------
+ Use [`get_health_score()`](`pointblank.Validate.get_health_score`) for a single overall
+ score across all dimensions.
+ """
+ return _compute_dimension_scores(self.validation_info)
+
+ def get_health_score(self) -> float:
+ """
+ Get the overall data quality health score from the validation results.
+
+ The health score is a single number (a percentage from `0` to `100`) that summarizes the
+ overall quality of the data across all validation steps. It is computed as a test-unit
+ weighted pass rate: the total number of passing test units divided by the total number of
+ test units. This means larger tables and steps operating over more rows contribute
+ proportionally more to the score, so it tracks data volume rather than mere step count.
+
+ Per-dimension weights can be set globally via
+ [`config(dimension_weights=...)`](`pointblank.config`) for organizations that consider some
+ dimensions (e.g., completeness) more critical than others. A weight scales that dimension's
+ test-unit contribution to the score (so a dimension's influence is its weight times its
+ test-unit count); the returned score is always within `[0, 100]`.
+
+ Returns
+ -------
+ float
+ The overall health score as a percentage from `0` to `100`. Returns `100.0` if the
+ validation has not been interrogated or contains no scorable steps.
+
+ Examples
+ --------
+ ```python
+ import pointblank as pb
+
+ validation = (
+ pb.Validate(data=pb.load_dataset("small_table"))
+ .col_vals_not_null(columns="c")
+ .col_vals_gt(columns="d", value=0)
+ .interrogate()
+ )
+
+ validation.get_health_score()
+ ```
+
+ See Also
+ --------
+ Use [`get_dimension_scores()`](`pointblank.Validate.get_dimension_scores`) for a per-dimension
+ breakdown of the score.
+ """
+ weights = getattr(global_config, "dimension_weights", None)
+ return _compute_health_score(self.validation_info, dimension_weights=weights)
+
+ def assert_dimension_scores(
+ self,
+ thresholds: dict[str, float] | None = None,
+ message: str | None = None,
+ ) -> None:
+ """
+ Raise an `AssertionError` if any dimension's health score falls below a minimum.
+
+ The `assert_dimension_scores()` method checks each data quality dimension's score (from
+ [`get_dimension_scores()`](`pointblank.Validate.get_dimension_scores`)) against a minimum
+ acceptable value. This is useful in automated testing and CI environments where you want to
+ fail the run when, say, the completeness score drops below `95`.
+
+ Parameters
+ ----------
+ thresholds
+ A mapping of dimension name to a minimum acceptable score (`0`-`100`). If `None`, the
+ minimums set via [`config(dimension_thresholds=...)`](`pointblank.config`) are used. A
+ dimension present in the thresholds but absent from the validation is ignored.
+ message
+ Custom error message to use if the assertion fails. If `None`, a default message that
+ lists the offending dimensions (with actual vs. required scores) is generated.
+
+ Returns
+ -------
+ None
+
+ Raises
+ ------
+ AssertionError
+ If any dimension's score is below its specified minimum.
+
+ Examples
+ --------
+ ```python
+ import pointblank as pb
+
+ validation = (
+ pb.Validate(data=pb.load_dataset("small_table"))
+ .col_vals_not_null(columns="c")
+ .interrogate()
+ )
+
+ # Fail if the completeness score is below 95
+ validation.assert_dimension_scores(thresholds={"completeness": 95})
+ ```
+
+ See Also
+ --------
+ Use [`get_dimension_scores()`](`pointblank.Validate.get_dimension_scores`) to retrieve the
+ scores without raising, and [`config()`](`pointblank.config`) to set default per-dimension
+ thresholds globally.
+ """
+ if thresholds is None:
+ thresholds = getattr(global_config, "dimension_thresholds", None) or {}
+
+ if not thresholds:
+ return
+
+ # Auto-interrogate with default parameters if not already done (matches the behavior of
+ # `assert_below_threshold()`), so scores reflect actual results rather than an empty plan
+ if not hasattr(self, "time_start") or self.time_start is None:
+ self.interrogate()
+
+ dimension_scores = self.get_dimension_scores()
+
+ failures = []
+ for dimension, minimum in thresholds.items():
+ score = dimension_scores.get(dimension)
+ if score is not None and score < minimum:
+ failures.append((dimension, score, minimum))
+
+ if failures:
+ if message is None:
+ parts = [
+ f"{dimension} ({score:g}% < {minimum:g}%)"
+ for dimension, score, minimum in failures
+ ]
+ message = "Dimension health score(s) below the required minimum: " + ", ".join(
+ parts
+ )
+ raise AssertionError(message)
+
+ def get_scorecard(self, title: str | None = ":default:") -> GT:
+ """
+ Get a data quality scorecard as a GT table.
+
+ The `get_scorecard()` method produces a compact, standalone scorecard that summarizes data
+ quality across dimensions. It shows the overall health score prominently, along with a
+ per-dimension breakdown (a color-coded bar, the dimension's score, and its passing/total
+ test units). Unlike the full validation report, the scorecard focuses purely on the
+ aggregate health picture, making it well-suited for dashboards and executive summaries.
+
+ The returned object is a Great Tables `GT` object, so it can be displayed directly, exported
+ to HTML (via `.as_raw_html()`), or saved to an image file (via `.save()`).
+
+ Parameters
+ ----------
+ title
+ Options for customizing the title of the scorecard. The default `":default:"` produces
+ a generic title (optionally including the table name). Use `":tbl_name:"` to show just
+ the table name, `":none:"` for no title, or provide your own Markdown text.
+
+ Returns
+ -------
+ GT
+ A `GT` object representing the scorecard.
+
+ Examples
+ --------
+ ```python
+ import pointblank as pb
+
+ validation = (
+ pb.Validate(data=pb.load_dataset("small_table"), tbl_name="small_table")
+ .col_vals_not_null(columns="c")
+ .col_vals_gt(columns="d", value=0)
+ .rows_distinct()
+ .interrogate()
+ )
+
+ validation.get_scorecard()
+ ```
+
+ See Also
+ --------
+ Use [`get_dimension_scores()`](`pointblank.Validate.get_dimension_scores`) and
+ [`get_health_score()`](`pointblank.Validate.get_health_score`) for the underlying numbers,
+ and [`get_tabular_report()`](`pointblank.Validate.get_tabular_report`) for the full per-step
+ validation report.
+ """
+ # Do we have a DataFrame library to work with?
+ _check_any_df_lib(method_used="get_scorecard")
+
+ # Select the DataFrame library
+ df_lib = _select_df_lib(preference="polars")
+
+ lang = self.lang or "en"
+
+ dimension_scores = _compute_dimension_scores(self.validation_info)
+ scorecard_title = _get_report_text("report_dimension_scores", lang)
+
+ # Resolve the title text
+ if title == ":default:":
+ if self.tbl_name:
+ title_text = f"{scorecard_title} — {self.tbl_name}"
+ else:
+ title_text = scorecard_title
+ elif title == ":tbl_name:":
+ title_text = f"{self.tbl_name}" if self.tbl_name else scorecard_title
+ elif title in (":none:", None):
+ title_text = None
+ else:
+ title_text = commonmark.commonmark(title)
+
+ # If there are no scorable steps, return a minimal table with an informative message.
+ # Distinguish "not interrogated yet" from "interrogated but nothing scorable" (an empty
+ # plan, or all steps inactive/errored) so the message is accurate in each case.
+ if not dimension_scores:
+ interrogated = getattr(self, "time_start", None) is not None
+ msg_key = (
+ "no_validation_steps_text" if interrogated else "no_interrogation_performed_text"
+ )
+ no_steps_text = VALIDATION_REPORT_TEXT[msg_key].get(
+ lang, VALIDATION_REPORT_TEXT[msg_key]["en"]
+ )
+ df = df_lib.DataFrame({"scorecard": [no_steps_text]})
+ gt_tbl = (
+ GT(df, id="pb_scorecard")
+ .opt_table_font(font=google_font(name="IBM Plex Sans"))
+ .cols_label(cases={"scorecard": ""})
+ .tab_style(style=style.text(color="#666666", weight="bold"), locations=loc.body())
+ )
+ if title_text is not None:
+ gt_tbl = gt_tbl.tab_header(title=html(title_text))
+ if version("great_tables") >= "0.17.0":
+ gt_tbl = gt_tbl.tab_options(quarto_disable_processing=True)
+ return gt_tbl
+
+ weights = getattr(global_config, "dimension_weights", None)
+ overall = _compute_health_score(self.validation_info, dimension_weights=weights)
+
+ agg = _aggregate_dimension_units(self.validation_info)
+
+ # Order dimensions using the canonical order, appending any custom dimensions at the end
+ ordered_dimensions = [d for d in DIMENSION_NAMES if d in dimension_scores]
+ ordered_dimensions += [d for d in dimension_scores if d not in DIMENSION_NAMES]
+
+ dimension_cells: list[str] = []
+ score_cells: list[str] = []
+ units_cells: list[str] = []
+ for dimension in ordered_dimensions:
+ n_passed, n = agg[dimension]
+ score = dimension_scores[dimension]
+ color = DIMENSION_COLORS.get(dimension, DIMENSION_COLORS["unknown"])
+ label = html_module.escape(_get_dimension_label(dimension, lang))
+ dimension_cells.append(
+ f''
+ f"{label}"
+ )
+ score_cells.append(
+ '