From 0d3d8487bd040608dd2069914b856d92f326f88a Mon Sep 17 00:00:00 2001 From: Devi Manoharan Date: Sun, 26 Apr 2026 18:56:39 -0400 Subject: [PATCH 1/2] Handle case where row count is zero in missing check fix: skip missing_percent check when filter produces zero rows (#2407)When a filter removes all rows (row_count=0), missing_percent was returning 0.0 which incorrectly failed checks like 'fail when < 100'. Added a guard that returns NOT_EVALUATED when row_count is 0, which is semantically correct: there are no rows to evaluate. --- .../contracts/impl/check_types/missing_check.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/soda-core/src/soda_core/contracts/impl/check_types/missing_check.py b/soda-core/src/soda_core/contracts/impl/check_types/missing_check.py index fa198d596..9af187d96 100644 --- a/soda-core/src/soda_core/contracts/impl/check_types/missing_check.py +++ b/soda-core/src/soda_core/contracts/impl/check_types/missing_check.py @@ -81,6 +81,19 @@ def evaluate(self, measurement_values: MeasurementValues) -> CheckResult: missing_count: int = measurement_values.get_value(self.missing_count_metric_impl) row_count: int = measurement_values.get_value(self.row_count_metric_impl) + if row_count == 0: + # Fix #2407: When filter removes all rows, skip the check rather than + # failing with a misleading value. There are no rows to evaluate against. + return CheckResult( + check=self, + outcome=CheckOutcome.NOT_EVALUATED, + diagnostic_metric_values={ + "missing_count": missing_count, + "missing_percent": missing_percent, + "check_rows_tested": row_count, + "dataset_rows_tested": self.contract_impl.dataset_rows_tested, + }, + ) missing_percent: float = measurement_values.get_value(self.missing_percent_metric_impl) diagnostic_metric_values: dict[str, float] = { From 9a503d323ed5c5a63170f85af66f19e5e7194ad9 Mon Sep 17 00:00:00 2001 From: Devi Manoharan Date: Sun, 26 Apr 2026 19:19:09 -0400 Subject: [PATCH 2/2] Fix missing_percent calculation in missing_check.py fix: move missing_percent assignment before row_count guard (SonarCloud)SonarCloud flagged 'missing_percent used before defined' on line 92. Fixed by moving the missing_percent assignment to before the row_count == 0 guard so all variables are defined before they are referenced. --- .../src/soda_core/contracts/impl/check_types/missing_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soda-core/src/soda_core/contracts/impl/check_types/missing_check.py b/soda-core/src/soda_core/contracts/impl/check_types/missing_check.py index 9af187d96..184d314d1 100644 --- a/soda-core/src/soda_core/contracts/impl/check_types/missing_check.py +++ b/soda-core/src/soda_core/contracts/impl/check_types/missing_check.py @@ -81,6 +81,7 @@ def evaluate(self, measurement_values: MeasurementValues) -> CheckResult: missing_count: int = measurement_values.get_value(self.missing_count_metric_impl) row_count: int = measurement_values.get_value(self.row_count_metric_impl) + missing_percent: float = measurement_values.get_value(self.missing_percent_metric_impl) if row_count == 0: # Fix #2407: When filter removes all rows, skip the check rather than # failing with a misleading value. There are no rows to evaluate against. @@ -94,7 +95,6 @@ def evaluate(self, measurement_values: MeasurementValues) -> CheckResult: "dataset_rows_tested": self.contract_impl.dataset_rows_tested, }, ) - missing_percent: float = measurement_values.get_value(self.missing_percent_metric_impl) diagnostic_metric_values: dict[str, float] = { "missing_count": missing_count,