Skip to content

"" as add_parse_action's result removes result name from ParseResults #470

@niccokunzmann

Description

@niccokunzmann

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions