From 24b0b29ea9e6335a465711d3d6e157effeaf583e Mon Sep 17 00:00:00 2001 From: ptmcg Date: Mon, 27 Mar 2023 01:13:38 -0500 Subject: Fix #470 - Removed "" from the list of values that ParseResults will not save with a results name --- CHANGES | 24 ++++++++++++++------- pyparsing/results.py | 2 +- tests/test_unit.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 8 deletions(-) diff --git a/CHANGES b/CHANGES index 2886034..a73e2c0 100644 --- a/CHANGES +++ b/CHANGES @@ -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 diff --git a/pyparsing/results.py b/pyparsing/results.py index 1134456..92f89f4 100644 --- a/pyparsing/results.py +++ b/pyparsing/results.py @@ -77,7 +77,7 @@ class ParseResults: - year: '1999' """ - _null_values: Tuple[Any, ...] = (None, [], "", ()) + _null_values: Tuple[Any, ...] = (None, [], ()) _name: str _parent: "ParseResults" diff --git a/tests/test_unit.py b/tests/test_unit.py index 0f1cb5a..8c98a3e 100644 --- a/tests/test_unit.py +++ b/tests/test_unit.py @@ -2754,6 +2754,65 @@ class Test02_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase): 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 = , 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""" -- cgit v1.2.1