"" as add_parse_action's result removes result name from ParseResults
niccokunzmann opened this issue · comments
It might be a use-case to remove the result name from the ParseResults
in a parse action. However, it looks a bit like an inconsistency to me: ""
removes the named value but a filled string does not.
Tests:
import pyparsing as pp
import pytest
def assert_X_is_present(grammar, X):
"""Check that X is present and has a certain value."""
parse_results = grammar.parse_string("a")
print(parse_results, list(parse_results.items()))
assert "X" in parse_results, f"value = {repr(X)}"
assert parse_results["X"] == X
@pytest.mark.parametrize("value",
[
"x",
"", # removes named value
True,
False,
1,
0,
None, # consistent with test_no_parse_action
b"",
b"a",
]
)
def test_with_parse_action(value):
"""Check which values are in the named result."""
print("value =", repr(value))
grammar = (pp.Suppress("a") + pp.ZeroOrMore("x")).add_parse_action(lambda p: value).set_results_name("X")
assert_X_is_present(grammar, value)
def test_no_parse_action():
"""Do not add a parse result."""
grammar = (pp.Suppress("a") + pp.ZeroOrMore("x")).set_results_name("X")
assert_X_is_present(grammar, "")
These are the tests running:
py39 installed: attrs==22.2.0,black==23.1.0,cffi==1.15.0,click==8.1.3,coverage==6.5.0,cssselect==1.2.0,distlib==0.3.6,exceptiongroup==1.1.0,filelock==3.9.0,greenlet==0.4.13,hpy==0.0.3,iniconfig==2.0.0,inkex @ git+https://gitlab.com/inkscape/extensions@b47d2bc6b11595cd6ecbf4d16aa59d9f5e597141,lxml==4.9.2,mypy-extensions==1.0.0,numpy==1.24.2,packaging==23.0,pathspec==0.11.0,Pillow==9.4.0,platformdirs==3.0.0,pluggy==1.0.0,py==1.11.0,pycairo==1.23.0,pycparser==2.21,PyGObject==3.42.2,pyparsing==3.0.9,pypdf==3.5.0,pyserial==3.5,pytest==7.2.1,pytest-cov==3.0.0,readline==6.2.4.1,scour==0.37,six==1.16.0,tomli==2.0.1,tox==3.28.0,typing_extensions==4.5.0,virtualenv==20.19.0,zstandard==0.20.0 py39 run-test-pre: PYTHONHASHSEED='1228586876' py39 run-test: commands[0] | pytest tests/test_pyparsing.py ============================ test session starts ============================= platform linux -- Python 3.9.12[pypy-7.3.9-final], pytest-7.2.1, pluggy-1.0.0 cachedir: .tox/py39/.pytest_cache rootdir: /home/sabin/extension-ai, configfile: pyproject.toml plugins: cov-3.0.0 collected 10 items tests/test_pyparsing.py .F....F..F ================================== FAILURES ================================== _________________________ test_with_parse_action[0] __________________________ value = '' @pytest.mark.parametrize("value", [ "x", "", # removes named value True, False, 1, 0, None, # consistent with test_no_parse_action b"", b"a", ] ) def test_with_parse_action(value): """Check which values are in the named result.""" print("value =", repr(value)) grammar = (pp.Suppress("a") + pp.ZeroOrMore("x")).add_parse_action(lambda p: value).set_results_name("X") > assert_X_is_present(grammar, value) tests/test_pyparsing.py:30: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ grammar = {Suppress:('a') ['x']...}, X = '' def assert_X_is_present(grammar, X): """Check that X is present and has a certain value.""" parse_results = grammar.parse_string("a") print(parse_results, list(parse_results.items())) > assert "X" in parse_results, f"value = {repr(X)}" E AssertionError: value = '' E assert 'X' in ParseResults([''], {}) tests/test_pyparsing.py:10: AssertionError ---------------------------- Captured stdout call ---------------------------- value = '' [''] [] ________________________ test_with_parse_action[None] ________________________ value = None @pytest.mark.parametrize("value", [ "x", "", # removes named value True, False, 1, 0, None, # consistent with test_no_parse_action b"", b"a", ] ) def test_with_parse_action(value): """Check which values are in the named result.""" print("value =", repr(value)) grammar = (pp.Suppress("a") + pp.ZeroOrMore("x")).add_parse_action(lambda p: value).set_results_name("X") > assert_X_is_present(grammar, value) tests/test_pyparsing.py:30: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ grammar = {Suppress:('a') ['x']...}, X = None def assert_X_is_present(grammar, X): """Check that X is present and has a certain value.""" parse_results = grammar.parse_string("a") print(parse_results, list(parse_results.items())) assert "X" in parse_results, f"value = {repr(X)}" > assert parse_results["X"] == X E assert ParseResults([], {}) == None tests/test_pyparsing.py:11: AssertionError ---------------------------- Captured stdout call ---------------------------- value = None [] [('X', ParseResults([], {}))] ____________________________ test_no_parse_action ____________________________ def test_no_parse_action(): """Do not add a parse result.""" grammar = (pp.Suppress("a") + pp.ZeroOrMore("x")).set_results_name("X") > assert_X_is_present(grammar, "") tests/test_pyparsing.py:36: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ grammar = {Suppress:('a') ['x']...}, X = '' def assert_X_is_present(grammar, X): """Check that X is present and has a certain value.""" parse_results = grammar.parse_string("a") print(parse_results, list(parse_results.items())) assert "X" in parse_results, f"value = {repr(X)}" > assert parse_results["X"] == X E AssertionError: assert ParseResults([], {}) == '' tests/test_pyparsing.py:11: AssertionError ---------------------------- Captured stdout call ---------------------------- [] [('X', ParseResults([], {}))] ============================== warnings summary ============================== <frozen importlib._bootstrap>:228 <frozen importlib._bootstrap>:228: ImportWarning: can't resolve package from __spec__ or __package__, falling back on __name__ and __path__ -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html ========================== short test summary info =========================== FAILED tests/test_pyparsing.py::test_with_parse_action[0] - AssertionError: value = '' FAILED tests/test_pyparsing.py::test_with_parse_action[None] - assert ParseResults([], {}) == None FAILED tests/test_pyparsing.py::test_no_parse_action - AssertionError: assert ParseResults([], {}) == '' =================== 3 failed, 7 passed, 1 warning in 0.34s =================== ERROR: InvocationError for command /home/sabin/extension-ai/.tox/py39/bin/pytest tests/test_pyparsing.py (exited with code 1) __________________________________ summary ___________________________________ ERROR: py39: commands failed
I wonder: It looks like an inconsistency but it could also be intentional. I thought, I will better get in contact before I start digging in too much. If this is a bug, I am happy to work on it.
Looking at this this afternoon.
ParseResults
will not add a "nullish" value, like [], () or "". But we all know that "" is rarely an empty sequence like [] or () are, but very often a legitimate string value. If I remove "" from the list of null values that ParseResults
drops on the floor, all of my unit tests still pass. This may be because this is a benign change, or because my unit tests are not very good. Since I am looking at dropping a2 release, this might be a decent time to try this change, before 3.1.0 becomes official.