diff --git a/CHANGES b/CHANGES index 8796c861..05e026f8 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,9 @@ Change Log Version 3.0.7 - --------------- +- Fixed bug #345, in which delimitedList changed expressions in place + using expr.streamline(). Reported by Kim Gräsman, thanks! + - Added optional "min" and "max" arguments to `delimited_list`. PR submitted by Marius, thanks! diff --git a/pyparsing/__init__.py b/pyparsing/__init__.py index cd4d41f3..7b5bb1df 100644 --- a/pyparsing/__init__.py +++ b/pyparsing/__init__.py @@ -126,7 +126,7 @@ def __repr__(self): __version_info__ = version_info(3, 0, 7, "final", 0) -__version_time__ = "04 Dec 2021 08:48 UTC" +__version_time__ = "15 Dec 2021 05:56 UTC" __version__ = __version_info__.__version__ __versionTime__ = __version_time__ __author__ = "Paul McGuire " diff --git a/pyparsing/helpers.py b/pyparsing/helpers.py index 8d61301a..19dd0e04 100644 --- a/pyparsing/helpers.py +++ b/pyparsing/helpers.py @@ -40,7 +40,7 @@ def delimited_list( expr = ParserElement._literalStringClass(expr) dlName = "{expr} [{delim} {expr}]...{end}".format( - expr=str(expr.streamline()), + expr=str(expr.copy().streamline()), delim=str(delim), end=" [{}]".format(str(delim)) if allow_trailing_delim else "", ) diff --git a/tests/test_unit.py b/tests/test_unit.py index 95183a3a..0d957f1b 100644 --- a/tests/test_unit.py +++ b/tests/test_unit.py @@ -6721,6 +6721,43 @@ def add_total(tokens): "noop parse action changed ParseResults structure", ) + def testParseActionWithDelimitedList(self): + class AnnotatedToken(object): + def __init__(self, kind, elements): + self.kind = kind + self.elements = elements + + def __str__(self): + return 'AnnotatedToken(%r, %r)' % (self.kind, self.elements) + + def __eq__(self, other): + return type(self) == type(other) and self.kind == other.kind and self.elements == other.elements + + __repr__ = __str__ + + def annotate(name): + def _(t): + return AnnotatedToken(name, t.asList()) + return _ + + identifier = pp.Word(pp.srange('[a-z0-9]')) + numeral = pp.Word(pp.nums) + + named_number_value = pp.Suppress('(') + numeral + pp.Suppress(')') + named_number = identifier + named_number_value + + named_number_list = (pp.Suppress('{') + + pp.Group(pp.Optional(pp.delimitedList(named_number))) + + pp.Suppress('}')) + + # repro but in #345 - delimitedList silently changes contents of named_number + named_number_value.setParseAction(annotate("val")) + + test_string = "{ x1(1), x2(2) }" + expected = [['x1', AnnotatedToken("val", ['1']), 'x2', AnnotatedToken("val", ['2'])]] + + self.assertParseAndCheckList(named_number_list, test_string, expected) + def testParseResultsNameBelowUngroupedName(self): rule_num = pp.Regex("[0-9]+")("LIT_NUM*")