Skip to content

Commit

Permalink
Fix #470 - Removed "" from the list of values that ParseResults will …
Browse files Browse the repository at this point in the history
…not save with a results name
  • Loading branch information
ptmcg committed Mar 27, 2023
1 parent 9d789cb commit 24b0b29
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 8 deletions.
24 changes: 17 additions & 7 deletions CHANGES
Expand Up @@ -4,15 +4,25 @@ Change Log

Version 3.1.0a2 - (in development)
----------------------------------
Fixed bug in `SkipTo` where ignore expressions were not properly handled while
scanning for the target expression. Issue #475, reported by elkniwt, thanks
(this bug has been there for a looooong time!).
- Fixed bug when parse actions returned an empty string for an expression that
had a results name, that the results name was not saved. That is:

Updated ci.yml permissions to limit default access to source - submitted by Joyce
Brum of Google. Thanks so much!
expr = Literal("X").add_parse_action(lambda tokens: "")("value")
result = expr.parse_string("X")
print(result["value"])

Updated the lucene_grammar.py example (better support for '*' and '?' wildcards)
and corrected the test cases - brought to my attention by Elijah Nicol, good catch!
would raise a `KeyError`. Now empty strings will be saved with the associated
results name. Raised in Issue #470 by Nicco Kunzmann, thank you.

- Fixed bug in `SkipTo` where ignore expressions were not properly handled while
scanning for the target expression. Issue #475, reported by elkniwt, thanks
(this bug has been there for a looooong time!).

- Updated ci.yml permissions to limit default access to source - submitted by Joyce
Brum of Google. Thanks so much!

- Updated the lucene_grammar.py example (better support for '*' and '?' wildcards)
and corrected the test cases - brought to my attention by Elijah Nicol, good catch!


Version 3.1.0a1 - March, 2023
Expand Down
2 changes: 1 addition & 1 deletion pyparsing/results.py
Expand Up @@ -77,7 +77,7 @@ def test(s, fn=repr):
- year: '1999'
"""

_null_values: Tuple[Any, ...] = (None, [], "", ())
_null_values: Tuple[Any, ...] = (None, [], ())

_name: str
_parent: "ParseResults"
Expand Down
59 changes: 59 additions & 0 deletions tests/test_unit.py
Expand Up @@ -2754,6 +2754,65 @@ def testParseResultsReturningDunderAttribute(self):
with self.assertRaises(AttributeError):
result.__xyz__

def testParseResultsNamedResultWithEmptyString(self):
# from Issue #470

# Check which values can be returned from a parse action
for test_value, expected_in_result_by_name in [
("x", True),
("", True),
(True, True),
(False, True),
(1, True),
(0, True),
(None, True),
(b"", True),
(b"a", True),
([], False),
((), False),
]:
msg = (f"value = {test_value!r},"
f" expected X {'not ' if not expected_in_result_by_name else ''}in result")
with self.subTest(msg):
print(msg)
grammar = ((pp.Suppress("a") + pp.ZeroOrMore("x"))
.add_parse_action(lambda p: test_value)
.set_results_name("X"))
result = grammar.parse_string("a")
print(result.dump())
if expected_in_result_by_name:
self.assertIn("X", result, f"Expected X not found for parse action value {test_value!r}")
print(repr(result["X"]))
else:
self.assertNotIn("X", result, f"Unexpected X found for parse action value {test_value!r}")
with self.assertRaises(KeyError):
print(repr(result["X"]))
print()

# Do not add a parse result.
msg = "value = <no parse action defined>, expected X in result"
with self.subTest(msg):
print(msg)
grammar = (pp.Suppress("a") + pp.ZeroOrMore("x")).set_results_name("X")
result = grammar.parse_string("a")
print(result.dump())
self.assertIn("X", result, f"Expected X not found with no parse action")
print()

# Test by directly creating a ParseResults
print("Create empty string value directly")
result = pp.ParseResults("", name="X")
print(result.dump())
self.assertIn("X", result, "failed to construct ParseResults with named value using empty string")
print(repr(result["X"]))
print()

print("Create empty string value from a dict")
result = pp.ParseResults.from_dict({"X": ""})
print(result.dump())
self.assertIn("X", result, "failed to construct ParseResults with named value using from_dict")
print(repr(result["X"]))

def testMatchOnlyAtCol(self):
"""successfully use matchOnlyAtCol helper function"""

Expand Down

0 comments on commit 24b0b29

Please sign in to comment.