Skip to content

Commit 414f479

Browse files
committed
fix(expressions): keep tabs inside string literals
pyparsing expands tabs in the input before matching, so a tab inside a string literal was rewritten into spaces, and the number of spaces depended on where the literal sat in the expression: parse("a = 'x\ty'") and parse("ab = 'x\ty'") returned different values for the same literal. A filter on a value containing a tab silently matched nothing.
1 parent 0d58407 commit 414f479

2 files changed

Lines changed: 15 additions & 0 deletions

File tree

‎pyiceberg/expressions/parser.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,10 @@ def handle_or(result: ParseResults) -> Or:
298298
],
299299
).set_name("expr")
300300

301+
# pyparsing expands tabs in the input by default, which would rewrite a tab inside a string literal
302+
# into spaces, and the number of spaces would depend on where the literal sits in the expression.
303+
boolean_expression.parse_with_tabs()
304+
301305

302306
def parse(expr: str) -> BooleanExpression:
303307
"""Parse a boolean expression."""

‎tests/expressions/test_parser.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,14 @@ def test_boolean_as_operand(expression: str, expected: BooleanExpression) -> Non
294294
def test_boolean_as_literal_is_unchanged() -> None:
295295
assert parser.parse("foo = true") == EqualTo(Reference("foo"), literal(True))
296296
assert parser.parse("foo in (true, false)") == In(Reference("foo"), {literal(True), literal(False)})
297+
298+
299+
def test_literal_with_tab_is_preserved() -> None:
300+
assert EqualTo("foo", "a\tb") == parser.parse("foo = 'a\tb'")
301+
302+
303+
def test_literal_with_tab_does_not_depend_on_its_position() -> None:
304+
one_char_column = parser.parse("a = 'x\ty'")
305+
two_char_column = parser.parse("ab = 'x\ty'")
306+
307+
assert one_char_column.literal.value == two_char_column.literal.value

0 commit comments

Comments
 (0)