This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/main by this push:
new 1c1f5744dfe Fix SQL value checks for negative expected values (#69893)
1c1f5744dfe is described below
commit 1c1f5744dfe6d01e5a8a865aead3da41e47a0089
Author: Aaron Chen <[email protected]>
AuthorDate: Sat Aug 1 02:24:50 2026 +0800
Fix SQL value checks for negative expected values (#69893)
---
.../src/airflow/providers/common/sql/operators/sql.py | 13 ++++++++-----
.../sql/tests/unit/common/sql/operators/test_sql.py | 16 ++++++++++++++++
2 files changed, 24 insertions(+), 5 deletions(-)
diff --git
a/providers/common/sql/src/airflow/providers/common/sql/operators/sql.py
b/providers/common/sql/src/airflow/providers/common/sql/operators/sql.py
index 3593c258214..0bdd7ea981e 100644
--- a/providers/common/sql/src/airflow/providers/common/sql/operators/sql.py
+++ b/providers/common/sql/src/airflow/providers/common/sql/operators/sql.py
@@ -1279,12 +1279,14 @@ class SQLValueCheckOperator(BaseSQLOperator):
def _get_string_matches(self, records, pass_value_conv):
return [str(record) == pass_value_conv for record in records]
+ def _get_tolerance_bounds(self, numeric_pass_value_conv):
+ margin = abs(numeric_pass_value_conv) * self.tol
+ return numeric_pass_value_conv - margin, numeric_pass_value_conv +
margin
+
def _get_numeric_matches(self, numeric_records, numeric_pass_value_conv):
if self.has_tolerance:
- return [
- numeric_pass_value_conv * (1 - self.tol) <= record <=
numeric_pass_value_conv * (1 + self.tol)
- for record in numeric_records
- ]
+ lower_bound, upper_bound =
self._get_tolerance_bounds(numeric_pass_value_conv)
+ return [lower_bound <= record <= upper_bound for record in
numeric_records]
return [record == numeric_pass_value_conv for record in
numeric_records]
@@ -1308,7 +1310,8 @@ class SQLValueCheckOperator(BaseSQLOperator):
pass_value_conv = _convert_to_float_if_possible(self.pass_value)
if isinstance(pass_value_conv, float) and isinstance(self.tol,
float):
- expected_str = f">= {pass_value_conv * (1 - self.tol)}, <=
{pass_value_conv * (1 + self.tol)}"
+ lower_bound, upper_bound =
self._get_tolerance_bounds(pass_value_conv)
+ expected_str = f">= {lower_bound}, <= {upper_bound}"
check_type = "accepted_range"
return [
diff --git a/providers/common/sql/tests/unit/common/sql/operators/test_sql.py
b/providers/common/sql/tests/unit/common/sql/operators/test_sql.py
index ef37630d440..573dba93a6b 100644
--- a/providers/common/sql/tests/unit/common/sql/operators/test_sql.py
+++ b/providers/common/sql/tests/unit/common/sql/operators/test_sql.py
@@ -877,6 +877,12 @@ class TestValueCheckOperator:
with pytest.raises(AirflowException, match="Tolerance:100.0%"):
operator.execute(context=MagicMock())
+ @pytest.mark.parametrize("record", [-110, -100, -90])
+ def test_negative_pass_value_with_tolerance(self, record):
+ operator = self._construct_operator("select value from tab1 limit 1;",
-100, 0.1)
+
+ operator.check_value([record])
+
class TestIntervalCheckOperator:
def _construct_operator(self, table, metric_thresholds, ratio_formula,
ignore_zero):
@@ -2045,6 +2051,16 @@ class TestSQLValueCheckOperatorBuildCheckResults:
assert r.expected == ">= 4.5, <= 5.5"
assert r.params == {"pass_value": "5", "tolerance": 0.1}
+ def test_negative_numeric_tolerance_produces_accepted_range(self):
+ op = self._make_operator(pass_value=-100, tolerance=0.1)
+ results = op._build_check_results([-100])
+ assert len(results) == 1
+ r = results[0]
+ assert r.success is True
+ assert r.check_type == "accepted_range"
+ assert r.expected == ">= -110.0, <= -90.0"
+ assert r.params == {"pass_value": "-100", "tolerance": 0.1}
+
def test_non_numeric_pass_value_is_accepted_values(self):
op = self._make_operator(pass_value="hello")
results = op._build_check_results(["hello"])