-
-
Notifications
You must be signed in to change notification settings - Fork 109
Treat ^ and v as operators even without surrounding whitespace #639
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -210,6 +210,18 @@ def test_classical_operators_name(): | |
| ) # name reflects expression structure | ||
|
|
||
|
|
||
| def test_classical_operators_without_spaces(): | ||
| # "^" and "v" are operators even without surrounding whitespace, like "!", | ||
| # so they must not be swallowed into a single variable name. | ||
| for unspaced, spaced in [ | ||
| ("frodo_has_ring^sam_is_loyal", "frodo_has_ring ^ sam_is_loyal"), | ||
| ("(frodo_has_ring)v(sauron_alive)", "(frodo_has_ring) v (sauron_alive)"), | ||
| ]: | ||
| got = parse_boolean_expr(unspaced, variable_hook, operator_mapping)() | ||
| want = parse_boolean_expr(spaced, variable_hook, operator_mapping)() | ||
| assert got is want, unspaced | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice test, thanks for including it. Since CI stayed green despite the regressions mentioned in def test_unspaced_not_equal_is_a_comparison():
# "!" is an operator, but "!=" is not a negation: it must keep parsing
# as a comparison even without surrounding whitespace.
got = parse_boolean_expr("frodo_age!=51", variable_hook, operator_mapping)()
want = parse_boolean_expr("frodo_age != 51", variable_hook, operator_mapping)()
assert got is want is True
def test_bare_v_is_a_variable_name():
# "v" is only an operator between operands; a lone "v" is a plain variable.
expr = parse_boolean_expr("v", variable_hook, operator_mapping)
assert expr.__name__ == "v"Note the |
||
|
|
||
|
|
||
| def test_empty_expression(): | ||
| expr = "" | ||
| with pytest.raises(SyntaxError): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gating on
patternfixes the reported cases, but it introduces two regressions. I verified both againstdevelop(both fail loudly at class-definition time):Unspaced
!=stops working.patterndeliberately skips!=via the\!(?!=)lookahead, socond="steps!=2"no longer matches, takes the fast-path, and is resolved as a variable literally namedsteps!=2:On
develop, any!character skipped the fast-path, so this parsed as a comparison and worked.A guard literally named
vstops working.\bv\bmatches a barev, socond="v"(a boolean attribute namedv) now goes throughreplace_operators, becomes" or ", and fails with:The invariant the fast-path wants is "this whole string is a single variable name", and Python can check that directly:
This keeps your fix for
a^b/(a)v(b), keeps unspaced!=and barevworking, makes the" "and"In("checks redundant, and as a bonus also fixes the pre-existing sibling bug where unspaced comparisons likex==1/x>=1were swallowed as variable names too.One side effect to be aware of: inputs that were already invalid, like
cond="user.age", now fail withValueError: Unsupported expression structure: Attributeinstead ofInvalidDefinition: Did not found name .... If we want to keep the friendlier error,dispatcher.buildcan catchValueErroralongsideSyntaxError.