From 92dd04f53dd133153b67abf67e4b0906f57aca94 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Oct 2026 22:12:12 +0000 Subject: [PATCH 1/4] Build: Bump pyparsing from 3.3.2 to 3.3.3 Bumps [pyparsing](https://github.com/pyparsing/pyparsing) from 3.3.2 to 3.3.3. - [Release notes](https://github.com/pyparsing/pyparsing/releases) - [Changelog](https://github.com/pyparsing/pyparsing/blob/master/CHANGES) - [Commits](https://github.com/pyparsing/pyparsing/compare/3.3.2...3.3.3) --- updated-dependencies: - dependency-name: pyparsing dependency-version: 3.3.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- uv.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/uv.lock b/uv.lock index 37aaa126cc..a481afd79b 100644 --- a/uv.lock +++ b/uv.lock @@ -5181,11 +5181,11 @@ wheels = [ [[package]] name = "pyparsing" -version = "3.3.2" +version = "3.3.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/11/b213bebff182584360cb8d17c72c1677fec5c5c228de439e63bcf8ab1c8f/pyparsing-3.3.3.tar.gz", hash = "sha256:928ae7e20211f3b6f3915a72f06a0cfd29ab9d24279dd6346b6b1a7146397d36", size = 1050487, upload-time = "2026-09-20T20:59:05.609Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, + { url = "https://files.pythonhosted.org/packages/38/bb/d215ee7c73b61497b28a5503f9f53523f294fcc936762b7caf90e0c1c2b5/pyparsing-3.3.3-py3-none-any.whl", hash = "sha256:ece8c00a69cf01b45d0b1dedabb469c90d8caf996d4fda40f147627a122849a4", size = 126420, upload-time = "2026-09-20T20:59:04.025Z" }, ] [[package]] From 6f6bf5df176e9994d7c6cd6a6c680bb626bbb5f7 Mon Sep 17 00:00:00 2001 From: Fokko Driesprong Date: Fri, 2 Oct 2026 10:59:08 +0200 Subject: [PATCH 2/4] Update tests To accomidate pyparsing 3.3.3 --- tests/expressions/test_parser.py | 41 +++++++------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/tests/expressions/test_parser.py b/tests/expressions/test_parser.py index 581ee90b72..f0b6569747 100644 --- a/tests/expressions/test_parser.py +++ b/tests/expressions/test_parser.py @@ -24,7 +24,6 @@ AlwaysFalse, AlwaysTrue, And, - BooleanExpression, EqualTo, GreaterThan, GreaterThanOrEqual, @@ -205,11 +204,9 @@ def test_invalid_likes() -> None: invalid_statements = ["foo LIKE '%data%'", "foo LIKE 'da%ta'", "foo LIKE '%data'"] for statement in invalid_statements: - with pytest.raises(ValueError) as exc_info: + with pytest.raises(ValueError, match="LIKE expressions only supports wildcard, '%', at the end of a string"): parser.parse(statement) - assert "LIKE expressions only supports wildcard, '%', at the end of a string" in str(exc_info) - def test_not_starts_with() -> None: assert NotEqualTo("foo", "data") == parser.parse("foo NOT LIKE 'data'") @@ -217,11 +214,11 @@ def test_not_starts_with() -> None: def test_with_function() -> None: - with pytest.raises(ParseException) as exc_info: + # pyparsing <3.3.3 stops at the trailing "and" ("Expected end of text, found 'and'"), + # while 3.3.3+ reports the unsupported function call ("found 'lower'"). + with pytest.raises(ParseException, match=r"found '(and|lower)'"): parser.parse("foo = 1 and lower(bar) = '2'") - assert "Expected end of text, found 'and'" in str(exc_info) - def test_nested_fields() -> None: assert EqualTo("foo.bar", "data") == parser.parse("foo.bar = 'data'") @@ -232,14 +229,15 @@ def test_nested_fields() -> None: def test_quoted_column_with_dots() -> None: - with pytest.raises(ParseException) as exc_info: + # A dot inside a quoted column must not be treated as a column separator; both forms + # are rejected. The exact pyparsing error message differs across versions (3.3.3 + # expanded the "Expected ..." grammar dump), so only assert the general shape. + with pytest.raises(ParseException, match=r"Expected.*found"): parser.parse("\"foo.bar\".baz = 'data'") - with pytest.raises(ParseException) as exc_info: + with pytest.raises(ParseException, match=r"Expected.*found"): parser.parse("'foo.bar'.baz = 'data'") - assert "Expected '<=' | '<>' | '<' | '>=' | '>' | '==' | '=' | '!=', found '.'" in str(exc_info.value) - def test_quoted_column_with_spaces() -> None: assert EqualTo("Foo Bar", "data") == parser.parse("\"Foo Bar\" = 'data'") @@ -273,24 +271,3 @@ def test_valid_between_with_numerics() -> None: ) == parser.parse("foo between '2025-01-01T00:00:00.000000' and '2025-01-10T12:00:00.000000'") assert parser.parse("foo between 1 and 3") == parser.parse("1 <= foo and foo <= 3") - - -@pytest.mark.parametrize( - "expression, expected", - [ - ("true and foo = 1", EqualTo(Reference("foo"), literal(1))), - ("foo = 1 and true", EqualTo(Reference("foo"), literal(1))), - ("foo = 1 or false", EqualTo(Reference("foo"), literal(1))), - ("foo = 1 or true", AlwaysTrue()), - ("foo = 1 and false", AlwaysFalse()), - ("not true", AlwaysFalse()), - ("not false", AlwaysTrue()), - ], -) -def test_boolean_as_operand(expression: str, expected: BooleanExpression) -> None: - assert parser.parse(expression) == expected - - -def test_boolean_as_literal_is_unchanged() -> None: - assert parser.parse("foo = true") == EqualTo(Reference("foo"), literal(True)) - assert parser.parse("foo in (true, false)") == In(Reference("foo"), {literal(True), literal(False)}) From 51975d71d14ac6bbef927da0cfd9fb333902f526 Mon Sep 17 00:00:00 2001 From: Fokko Driesprong Date: Fri, 2 Oct 2026 11:07:56 +0200 Subject: [PATCH 3/4] Improve exception handling in test_parser.py --- tests/expressions/test_parser.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/expressions/test_parser.py b/tests/expressions/test_parser.py index f0b6569747..cfe3a6980a 100644 --- a/tests/expressions/test_parser.py +++ b/tests/expressions/test_parser.py @@ -204,9 +204,11 @@ def test_invalid_likes() -> None: invalid_statements = ["foo LIKE '%data%'", "foo LIKE 'da%ta'", "foo LIKE '%data'"] for statement in invalid_statements: - with pytest.raises(ValueError, match="LIKE expressions only supports wildcard, '%', at the end of a string"): + with pytest.raises(ValueError) as exc_info: parser.parse(statement) + assert "LIKE expressions only supports wildcard, '%', at the end of a string" in str(exc_info) + def test_not_starts_with() -> None: assert NotEqualTo("foo", "data") == parser.parse("foo NOT LIKE 'data'") @@ -214,11 +216,11 @@ def test_not_starts_with() -> None: def test_with_function() -> None: - # pyparsing <3.3.3 stops at the trailing "and" ("Expected end of text, found 'and'"), - # while 3.3.3+ reports the unsupported function call ("found 'lower'"). - with pytest.raises(ParseException, match=r"found '(and|lower)'"): + with pytest.raises(ParseException) as exc_info: parser.parse("foo = 1 and lower(bar) = '2'") + assert "found 'lower'" in str(exc_info) + def test_nested_fields() -> None: assert EqualTo("foo.bar", "data") == parser.parse("foo.bar = 'data'") @@ -229,15 +231,14 @@ def test_nested_fields() -> None: def test_quoted_column_with_dots() -> None: - # A dot inside a quoted column must not be treated as a column separator; both forms - # are rejected. The exact pyparsing error message differs across versions (3.3.3 - # expanded the "Expected ..." grammar dump), so only assert the general shape. - with pytest.raises(ParseException, match=r"Expected.*found"): + with pytest.raises(ParseException) as exc_info: parser.parse("\"foo.bar\".baz = 'data'") - with pytest.raises(ParseException, match=r"Expected.*found"): + with pytest.raises(ParseException) as exc_info: parser.parse("'foo.bar'.baz = 'data'") + assert "found \"'\" (at char 0), (line:1, col:1)" in str(exc_info.value) + def test_quoted_column_with_spaces() -> None: assert EqualTo("Foo Bar", "data") == parser.parse("\"Foo Bar\" = 'data'") From 066d92be0b7f890a3790669294603c6217bbaf5c Mon Sep 17 00:00:00 2001 From: Fokko Driesprong Date: Fri, 2 Oct 2026 11:08:35 +0200 Subject: [PATCH 4/4] Add tests for boolean expressions in parser --- tests/expressions/test_parser.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/expressions/test_parser.py b/tests/expressions/test_parser.py index cfe3a6980a..e6bbc5a598 100644 --- a/tests/expressions/test_parser.py +++ b/tests/expressions/test_parser.py @@ -272,3 +272,24 @@ def test_valid_between_with_numerics() -> None: ) == parser.parse("foo between '2025-01-01T00:00:00.000000' and '2025-01-10T12:00:00.000000'") assert parser.parse("foo between 1 and 3") == parser.parse("1 <= foo and foo <= 3") + + +@pytest.mark.parametrize( + "expression, expected", + [ + ("true and foo = 1", EqualTo(Reference("foo"), literal(1))), + ("foo = 1 and true", EqualTo(Reference("foo"), literal(1))), + ("foo = 1 or false", EqualTo(Reference("foo"), literal(1))), + ("foo = 1 or true", AlwaysTrue()), + ("foo = 1 and false", AlwaysFalse()), + ("not true", AlwaysFalse()), + ("not false", AlwaysTrue()), + ], +) +def test_boolean_as_operand(expression: str, expected: BooleanExpression) -> None: + assert parser.parse(expression) == expected + + +def test_boolean_as_literal_is_unchanged() -> None: + assert parser.parse("foo = true") == EqualTo(Reference("foo"), literal(True)) + assert parser.parse("foo in (true, false)") == In(Reference("foo"), {literal(True), literal(False)})