Skip to content

Commit 6a8f876

Browse files
authored
Merge pull request #126 from posit-dev/feat-actions-all-parameter
feat: add `default=` parameter to `Actions`
2 parents db801c8 + 5e59906 commit 6a8f876

File tree

2 files changed

+113
-1
lines changed

2 files changed

+113
-1
lines changed

pointblank/thresholds.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,9 @@ class Actions:
304304
to different levels of severity when a threshold is reached. Those thresholds can be defined
305305
using the [`Thresholds`](`pointblank.Thresholds`) class or various shorthand forms. Actions
306306
don't have to be defined for all threshold levels; if an action is not defined for a level in
307-
exceedance, no action will be taken.
307+
exceedance, no action will be taken. Likewise, there is no negative consequence (other than a
308+
no-op) for defining actions for thresholds that don't exist (e.g., setting an action for the
309+
'critical' level when no corresponding 'critical' threshold has been set).
308310
309311
Parameters
310312
----------
@@ -317,6 +319,10 @@ class Actions:
317319
critical
318320
A string, `Callable`, or list of `Callable`/string values for the 'critical' level. Using
319321
`None` means no action should be performed at the 'critical' level.
322+
default
323+
A string, `Callable`, or list of `Callable`/string values for all threshold levels. This
324+
parameter can be used to set the same action for all threshold levels. If an action is
325+
defined for a specific threshold level, it will override the action set for all levels.
320326
highest_only
321327
A boolean value that, when set to `True` (the default), results in executing only the action
322328
for the highest threshold level that is exceeded. Useful when you want to ensure that only
@@ -442,13 +448,25 @@ def dq_issue():
442448
warning: str | Callable | list[str | Callable] | None = None
443449
error: str | Callable | list[str | Callable] | None = None
444450
critical: str | Callable | list[str | Callable] | None = None
451+
default: str | Callable | list[str | Callable] | None = None
445452
highest_only: bool = True
446453

447454
def __post_init__(self):
448455
self.warning = self._ensure_list(self.warning)
449456
self.error = self._ensure_list(self.error)
450457
self.critical = self._ensure_list(self.critical)
451458

459+
if self.default is not None:
460+
self.default = self._ensure_list(self.default)
461+
462+
# For any unset threshold level, set the default action
463+
if self.warning is None:
464+
self.warning = self.default
465+
if self.error is None:
466+
self.error = self.default
467+
if self.critical is None:
468+
self.critical = self.default
469+
452470
def _ensure_list(
453471
self, value: str | Callable | list[str | Callable] | None
454472
) -> list[str | Callable]:

tests/test_validate.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,6 +1669,100 @@ def test_validation_actions_local_all(tbl_type, capsys):
16691669
assert "W_local" in captured.out
16701670

16711671

1672+
@pytest.mark.parametrize("tbl_type", ["pandas", "polars", "duckdb"])
1673+
def test_validation_actions_default_global(tbl_type, capsys):
1674+
(
1675+
Validate(
1676+
data=load_dataset(dataset="small_table", tbl_type=tbl_type),
1677+
thresholds=Thresholds(warning=1, error=2, critical=3),
1678+
actions=Actions(default="{level} default_action", highest_only=False),
1679+
)
1680+
.col_vals_gt(columns="d", value=10000)
1681+
.interrogate()
1682+
)
1683+
1684+
# Capture the output and verify that all three level messages are printed to the console
1685+
captured = capsys.readouterr()
1686+
assert "critical default_action" in captured.out
1687+
assert "error default_action" in captured.out
1688+
assert "warning default_action" in captured.out
1689+
1690+
1691+
@pytest.mark.parametrize("tbl_type", ["pandas", "polars", "duckdb"])
1692+
def test_validation_actions_default_global_override(tbl_type, capsys):
1693+
(
1694+
Validate(
1695+
data=load_dataset(dataset="small_table", tbl_type=tbl_type),
1696+
thresholds=Thresholds(warning=1, error=2, critical=3),
1697+
actions=Actions(
1698+
warning="warning override", default="{level} default_action", highest_only=False
1699+
),
1700+
)
1701+
.col_vals_gt(columns="d", value=10000)
1702+
.interrogate()
1703+
)
1704+
1705+
# Capture the output and verify that all three level messages are printed to the console
1706+
captured = capsys.readouterr()
1707+
assert "critical default_action" in captured.out
1708+
assert "error default_action" in captured.out
1709+
assert "warning override" in captured.out
1710+
1711+
1712+
@pytest.mark.parametrize("tbl_type", ["pandas", "polars", "duckdb"])
1713+
def test_validation_actions_default_local(tbl_type, capsys):
1714+
(
1715+
Validate(
1716+
data=load_dataset(dataset="small_table", tbl_type=tbl_type),
1717+
thresholds=Thresholds(warning=1, error=2, critical=3),
1718+
actions=Actions(default="{level} default_action_global", highest_only=False),
1719+
)
1720+
.col_vals_gt(
1721+
columns="d",
1722+
value=10000,
1723+
actions=Actions(default="{level} default_action_local", highest_only=False),
1724+
)
1725+
.interrogate()
1726+
)
1727+
1728+
# Capture the output and verify that all three level messages are printed to the console
1729+
captured = capsys.readouterr()
1730+
assert "critical default_action_local" in captured.out
1731+
assert "error default_action_local" in captured.out
1732+
assert "warning default_action_local" in captured.out
1733+
1734+
1735+
@pytest.mark.parametrize("tbl_type", ["pandas", "polars", "duckdb"])
1736+
def test_validation_actions_default_local_override(tbl_type, capsys):
1737+
(
1738+
Validate(
1739+
data=load_dataset(dataset="small_table", tbl_type=tbl_type),
1740+
thresholds=Thresholds(warning=1, error=2, critical=3),
1741+
actions=Actions(
1742+
warning="warning override_global",
1743+
default="{level} default_action_global",
1744+
highest_only=False,
1745+
),
1746+
)
1747+
.col_vals_gt(
1748+
columns="d",
1749+
value=10000,
1750+
actions=Actions(
1751+
warning="warning override_local",
1752+
default="{level} default_action_local",
1753+
highest_only=False,
1754+
),
1755+
)
1756+
.interrogate()
1757+
)
1758+
1759+
# Capture the output and verify that all three level messages are printed to the console
1760+
captured = capsys.readouterr()
1761+
assert "critical default_action_local" in captured.out
1762+
assert "error default_action_local" in captured.out
1763+
assert "warning override_local" in captured.out
1764+
1765+
16721766
@pytest.mark.parametrize("tbl_type", ["pandas", "polars", "duckdb"])
16731767
def test_validation_actions_get_action_metadata(tbl_type, capsys):
16741768
def log_issue():

0 commit comments

Comments
 (0)