diff --git a/pointblank/validate.py b/pointblank/validate.py index 1e5e5010a..1aeb143ce 100644 --- a/pointblank/validate.py +++ b/pointblank/validate.py @@ -1792,6 +1792,12 @@ class Validate: The actions to take when validation steps meet or exceed any set threshold levels. This should be provided in the form of an `Actions` object. If `None` then no default actions will be set. + brief + A global setting for briefs, which are optional brief descriptions for validation steps + (they be displayed in the reporting table). For such a global setting, templating elements + like `"{step}"` (to insert the step number) or `"{auto}"` (to include an automatically + generated brief) are useful. If `True` then each brief will be automatically generated. If + `None` (the default) then briefs aren't globally set. lang The language to use for automatic creation of briefs (short descriptions for each validation step). By default, `None` will create English (`"en"`) text. Other options include French @@ -1906,6 +1912,7 @@ class Validate: label: str | None = None thresholds: int | float | bool | tuple | dict | Thresholds | None = None actions: Actions | None = None + brief: str | bool | None = None lang: str | None = None locale: str | None = None @@ -1924,6 +1931,9 @@ def __post_init__(self): if self.locale is None: self.locale = self.lang + # Transform any shorthands of `brief` to string representations + self.brief = _transform_auto_brief(brief=self.brief) + # TODO: Add functionality to obtain the column names and types from the table self.col_names = None self.col_types = None @@ -2089,8 +2099,8 @@ def col_vals_gt( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -2262,8 +2272,8 @@ def col_vals_lt( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -2434,8 +2444,8 @@ def col_vals_eq( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -2604,8 +2614,8 @@ def col_vals_ne( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -2778,8 +2788,8 @@ def col_vals_ge( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -2952,8 +2962,8 @@ def col_vals_le( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -3149,8 +3159,8 @@ def col_vals_between( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -3350,8 +3360,8 @@ def col_vals_outside( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -3510,8 +3520,8 @@ def col_vals_in_set( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -3669,8 +3679,8 @@ def col_vals_not_in_set( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -3820,8 +3830,8 @@ def col_vals_null( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -3970,8 +3980,8 @@ def col_vals_not_null( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -4131,8 +4141,8 @@ def col_vals_regex( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -4263,8 +4273,8 @@ def col_vals_expr( self.thresholds if thresholds is None else _normalize_thresholds_creation(thresholds) ) - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) val_info = _ValidationInfo( assertion_type=assertion_type, @@ -4409,8 +4419,8 @@ def col_exists( if isinstance(columns, (Column, str)): columns = [columns] - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) # Iterate over the columns and create a validation step for each for column in columns: @@ -4559,8 +4569,8 @@ def rows_distinct( # TODO: incorporate Column object - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) val_info = _ValidationInfo( assertion_type=assertion_type, @@ -4741,8 +4751,8 @@ def col_schema_match( "full_match_dtypes": full_match_dtypes, } - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) val_info = _ValidationInfo( assertion_type=assertion_type, @@ -4918,8 +4928,8 @@ def row_count_match( # Package up the `count=` and boolean params into a dictionary for later interrogation values = {"count": count, "inverse": inverse, "abs_tol_bounds": bounds} - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) val_info = _ValidationInfo( assertion_type=assertion_type, @@ -5052,8 +5062,8 @@ def col_count_match( # Package up the `count=` and boolean params into a dictionary for later interrogation values = {"count": count, "inverse": inverse} - # Transform any shorthands of `brief=` to string representations - brief = _transform_auto_brief(brief=brief) + # Determine brief to use (global or local) and transform any shorthands of `brief=` + brief = self.brief if brief is None else _transform_auto_brief(brief=brief) val_info = _ValidationInfo( assertion_type=assertion_type, diff --git a/tests/snapshots/test_validate/test_validation_report_briefs_global_local_html/validation_report_briefs_global_local.html b/tests/snapshots/test_validate/test_validation_report_briefs_global_local_html/validation_report_briefs_global_local.html new file mode 100644 index 000000000..bb7dafff4 --- /dev/null +++ b/tests/snapshots/test_validate/test_validation_report_briefs_global_local_html/validation_report_briefs_global_local.html @@ -0,0 +1,310 @@ +
+ + ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Pointblank Validation
Validation example with briefs
Polarssmall_tableWARNING0.1ERROR0.25CRITICAL0.35
STEPCOLUMNSVALUESTBLEVALUNITSPASSFAILWECEXT
#FF33001 +
+ + + col_vals_equal + + + + + + + +
+
+
col_vals_eq()
+
+

Global Brief: Expect that values in a should be == 3.

+
+
a3 + + + + + + + +133
0.23
10
0.77
#FF33002 +
+ + + col_vals_lt + + + + + + + +
+
+
col_vals_lt()
+
+ +
c5 + + + + + + + +135
0.38
8
0.62
#4CA64C3 +
+ + + col_vals_gt + + + + + + + +
+
+
col_vals_gt()
+
+

Expect that values in d should be > 100.

+
+
d100 + + + + + + + +1313
1.00
0
0.00
#4CA64C664 +
+ + + col_vals_lte + + + + + + + +
+
+
col_vals_le()
+
+

This is a custom local brief for the assertion

+
+
a7 + + + + + + + +1312
0.92
1
0.08
#AAAAAA5 +
+ + + col_vals_gte + + + + + + + +
+
+
col_vals_ge()
+
+

Step 5: Expect that values in d should be >= 500.

+
+
d500 + + + + + + + +1311
0.85
2
0.15
+ +
+ \ No newline at end of file diff --git a/tests/test_validate.py b/tests/test_validate.py index 1f2d0bae4..164f3adfc 100644 --- a/tests/test_validate.py +++ b/tests/test_validate.py @@ -5431,6 +5431,35 @@ def test_validation_report_briefs_html(snapshot): snapshot.assert_match(edited_report_html_str, "validation_report_with_briefs.html") +def test_validation_report_briefs_global_local_html(snapshot): + validation = ( + Validate( + data=load_dataset(), + tbl_name="small_table", + label="Validation example with briefs", + thresholds=Thresholds(warning=0.10, error=0.25, critical=0.35), + brief="**Global Brief**: {auto}", + ) + .col_vals_eq(columns="a", value=3) # global brief + .col_vals_lt(columns="c", value=5, brief=False) # no brief (global brief cancelled) + .col_vals_gt(columns="d", value=100, brief=True) # local brief, default auto-generated one + .col_vals_le(columns="a", value=7, brief="This is a custom local brief for the assertion") + .col_vals_ge(columns="d", value=500, na_pass=True, brief="**Step** {step}: {auto}") + .interrogate() + ) + + html_str = validation.get_tabular_report().as_raw_html() + + # Define the regex pattern to match the entire tag with class "gt_sourcenote" + pattern = r'.*?' + + # Use re.sub to remove the tag + edited_report_html_str = re.sub(pattern, "", html_str, flags=re.DOTALL) + + # Use the snapshot fixture to create and save the snapshot + snapshot.assert_match(edited_report_html_str, "validation_report_briefs_global_local.html") + + def test_no_interrogation_validation_report_html_snap(snapshot): validation = ( Validate(