Imported Upstream version 3.0.1 upstream/3.0.1
authorDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 18 Jul 2022 05:42:35 +0000 (14:42 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Mon, 18 Jul 2022 05:42:35 +0000 (14:42 +0900)
CHANGES
PKG-INFO
pyparsing.egg-info/PKG-INFO
pyparsing/__init__.py
pyparsing/core.py
pyparsing/helpers.py
pyparsing/results.py
pyparsing/testing.py
tests/test_unit.py

diff --git a/CHANGES b/CHANGES
index 0d0a407589179b7e8bd62475a35c89af3921da31..a1f1d377ca9924522154559d70872aa852bc3b8d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,18 @@
 Change Log
 ==========
 
+Version 3.0.1 -
+---------------
+- Fixed bug where Word(max=n) did not match word groups less than length 'n'.
+  Thanks to Joachim Metz for catching this!
+
+- Fixed bug where ParseResults accidentally created recursive contents.
+  Joachim Metz on this one also!
+
+- Fixed bug where warn_on_multiple_string_args_to_oneof warning is raised
+  even when not enabled.
+
+
 Version 3.0.0 -
 ---------------
 - A consolidated list of all the changes in the 3.0.0 release can be found in
index dea3767823ac8d907e666509fad6bca67ba03a3d..26ae34ed30d154251867480129c749c6da9f4ee5 100644 (file)
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: pyparsing
-Version: 3.0.0
+Version: 3.0.1
 Summary: Python parsing module
 Home-page: https://github.com/pyparsing/pyparsing/
 Author: Paul McGuire
index dea3767823ac8d907e666509fad6bca67ba03a3d..26ae34ed30d154251867480129c749c6da9f4ee5 100644 (file)
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: pyparsing
-Version: 3.0.0
+Version: 3.0.1
 Summary: Python parsing module
 Home-page: https://github.com/pyparsing/pyparsing/
 Author: Paul McGuire
index 0fd39438366586e29422bf6a35126d80cbf7e267..6fbb7c9d69c23b76099c0cdddd5c9f9d63a5780a 100644 (file)
@@ -96,7 +96,7 @@ classes inherit from. Use the docstrings for examples of how to:
 from collections import namedtuple
 
 version_info = namedtuple("version_info", "major minor micro release_level serial")
-__version_info__ = version_info(3, 0, 0, "final", 0)
+__version_info__ = version_info(3, 0, 1, "final", 0)
 __version__ = "{}.{}.{}".format(*__version_info__[:3]) + (
     "{}{}{}".format(
         "r" if __version_info__.release_level[0] == "c" else "",
@@ -105,7 +105,7 @@ __version__ = "{}.{}.{}".format(*__version_info__[:3]) + (
     ),
     "",
 )[__version_info__.release_level == "final"]
-__version_time__ = "23 October 2021 17:05 UTC"
+__version_time__ = "24 October 2021 17:43 UTC"
 __versionTime__ = __version_time__
 __author__ = "Paul McGuire <ptmcg.gm+pyparsing@gmail.com>"
 
index 11c685f59dd977ada922fc213e572444ca49e63d..960f6fc57d8058bb5576c62566ad1df84c55c907 100644 (file)
@@ -176,7 +176,9 @@ def enable_all_warnings():
 del __config_flags
 
 
-def _should_enable_warnings(cmd_line_warn_options: List[str], warn_env_var: str) -> bool:
+def _should_enable_warnings(
+    cmd_line_warn_options: List[str], warn_env_var: str
+) -> bool:
     enable = bool(warn_env_var)
     for warn_opt in cmd_line_warn_options:
         w_action, w_message, w_category, w_module, w_line = (warn_opt + "::::").split(
@@ -191,7 +193,9 @@ def _should_enable_warnings(cmd_line_warn_options: List[str], warn_env_var: str)
     return enable
 
 
-if _should_enable_warnings(sys.warnoptions, os.environ.get("PYPARSINGENABLEALLWARNINGS")):
+if _should_enable_warnings(
+    sys.warnoptions, os.environ.get("PYPARSINGENABLEALLWARNINGS")
+):
     enable_all_warnings()
 
 
@@ -560,7 +564,9 @@ class ParserElement(ABC):
                 self._parse = self._parse._originalParseMethod
         return self
 
-    def set_parse_action(self, *fns: ParseAction, **kwargs) -> OptionalType["ParserElement"]:
+    def set_parse_action(
+        self, *fns: ParseAction, **kwargs
+    ) -> OptionalType["ParserElement"]:
         """
         Define one or more actions to perform when successfully matching parse element definition.
 
@@ -1691,6 +1697,7 @@ class ParserElement(ABC):
             # -> ['ablaj', 'lskjd']
         """
         import typing
+
         if isinstance(other, str_type):
             other = Suppress(other)
 
@@ -2673,6 +2680,7 @@ class Word(Token):
         self.mayIndexError = False
         self.asKeyword = asKeyword
 
+        # see if we can make a regex for this Word
         if " " not in self.initChars | self.bodyChars and (min == 1 and exact == 0):
             if self.bodyChars == self.initChars:
                 if max == 0:
@@ -2680,7 +2688,10 @@ class Word(Token):
                 elif max == 1:
                     repeat = ""
                 else:
-                    repeat = "{{{}}}".format(max)
+                    repeat = "{{{},{}}}".format(
+                        self.minLen,
+                        "" if self.maxLen == _MAX_INT else self.maxLen
+                    )
                 self.reString = "[{}]{}".format(
                     _collapseStringToRanges(self.initChars),
                     repeat,
@@ -3528,8 +3539,8 @@ class ParseExpression(ParserElement):
 
     def __init__(self, exprs: IterableType[ParserElement], savelist: bool = False):
         super().__init__(savelist)
-        self.exprs : List[ParserElement]
-        exprs : Iterable[ParserElement]
+        self.exprs: List[ParserElement]
+        exprs: Iterable[ParserElement]
         if isinstance(exprs, _generatorType):
             exprs = list(exprs)
 
index 1aa8b5e5c2e7036345b8d3b2d8cb13832fee335d..2d112de2e42886eae4c49ecd1fd828431a61718a 100644 (file)
@@ -1,6 +1,7 @@
 # helpers.py
 import html.entities
 
+from . import __diag__
 from .core import *
 from .util import _bslash, _flatten, _escapeRegexRangeChars
 
@@ -223,7 +224,10 @@ def one_of(
     asKeyword = asKeyword or as_keyword
     useRegex = useRegex and use_regex
 
-    if isinstance(caseless, str_type):
+    if (
+        isinstance(caseless, str_type)
+        and __diag__.warn_on_multiple_string_args_to_oneof
+    ):
         warnings.warn(
             "More than one string argument passed to one_of, pass"
             " choices as a list or space-delimited string",
@@ -651,9 +655,9 @@ any_open_tag, any_close_tag = make_html_tags(
 )
 
 _htmlEntityMap = {k.rstrip(";"): v for k, v in html.entities.html5.items()}
-common_html_entity = Regex(
-    "&(?P<entity>" + "|".join(_htmlEntityMap) + ");"
-).set_name("common HTML entity")
+common_html_entity = Regex("&(?P<entity>" + "|".join(_htmlEntityMap) + ");").set_name(
+    "common HTML entity"
+)
 
 
 def replace_html_entity(t):
index a93abd8f2c6ef47d44599b1d74f7444751068041..194c3d91f38534e458d82f178ad71c849ba6d1d2 100644 (file)
@@ -183,7 +183,10 @@ class ParseResults:
                     try:
                         self[name] = toklist[0]
                     except (KeyError, TypeError, IndexError):
-                        self[name] = toklist
+                        if toklist is not self:
+                            self[name] = toklist
+                        else:
+                            self._name = name
 
     def __getitem__(self, i):
         if isinstance(i, (int, slice)):
index 9175d2cbd2a4085fd6db00ef162f93bbdf0557e3..c086876aa44a57a72c864ec382580724de4a7e45 100644 (file)
@@ -292,7 +292,7 @@ class pyparsing_test:
         if mark_control != "unicode":
             s_lines = s.splitlines()[start_line - 1 : end_line]
         else:
-            s_lines = [line+"␊" for line in s.split("␊")[start_line - 1 : end_line]]
+            s_lines = [line + "␊" for line in s.split("␊")[start_line - 1 : end_line]]
         if not s_lines:
             return ""
 
index 944b25dc21a4be928415e77e56b2848ec890986b..fe4253deab3c1285f65ea8ff73835f92cbdaf84f 100644 (file)
@@ -11,10 +11,12 @@ import contextlib
 import datetime
 import re
 import sys
+import warnings
 from types import SimpleNamespace
 from io import StringIO
 from textwrap import dedent
-from unittest import TestCase
+from typing import Any
+import unittest
 
 import pyparsing as pp
 from examples.jsonParser import jsonObject
@@ -87,6 +89,41 @@ def __():
     return current_method_name(3) + ": "
 
 
+class TestCase(unittest.TestCase):
+    @contextlib.contextmanager
+    def assertRaises(self, expected_exception_type: Any, msg: Any = None):
+        """
+        Simple wrapper to print out the exceptions raised after assertRaises
+        """
+        with super().assertRaises(expected_exception_type, msg=msg) as ar:
+            yield
+
+        if getattr(ar, "exception", None) is not None:
+            print(
+                "Raised expected exception: {}: {}".format(
+                    type(ar.exception).__name__, str(ar.exception)
+                )
+            )
+        else:
+            print(
+                "Expected {} exception not raised".format(
+                    expected_exception_type.__name__
+                )
+            )
+        return ar
+
+    @contextlib.contextmanager
+    def assertDoesNotWarn(self, msg: str = None):
+        if msg is None:
+            msg = "unexpected warning raised"
+        with warnings.catch_warnings(record=True) as w:
+            warnings.simplefilter("error")
+            try:
+                yield
+            except Exception as e:
+                self.fail("{}: {}".format(msg, e))
+
+
 class Test01_PyparsingTestInit(TestCase):
     def runTest(self):
         from pyparsing import (
@@ -105,6 +142,7 @@ class Test01_PyparsingTestInit(TestCase):
 class Test01a_PyparsingEnvironmentTests(TestCase):
     def runTest(self):
         # test warnings enable detection
+        # fmt: off
         tests = [
             (([], "",), False),
             ((["d", ], "",), True),
@@ -121,6 +159,7 @@ class Test01a_PyparsingEnvironmentTests(TestCase):
             ((["d:::blah", ], "1",), True),
             ((["i", ], "1",), False),
         ]
+        # fmt: on
 
         all_success = True
         for args, expected in tests:
@@ -140,29 +179,6 @@ class Test02_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
     def setUp(self):
         self.suite_context.restore()
 
-    @contextlib.contextmanager
-    def assertRaises(self, expected_exception_type, msg=None):
-        """
-        Simple wrapper to print out the exceptions raised after assertRaises
-        """
-        try:
-            with super().assertRaises(expected_exception_type, msg=msg) as ar:
-                yield
-        finally:
-            if getattr(ar, "exception", None) is not None:
-                print(
-                    "Raised expected exception: {}: {}".format(
-                        type(ar.exception).__name__, str(ar.exception)
-                    )
-                )
-            else:
-                print(
-                    "Expected {} exception not raised".format(
-                        expected_exception_type.__name__
-                    )
-                )
-        return ar
-
     def test000_assert_packrat_status(self):
         print("Packrat enabled:", ParserElement._packratEnabled)
         self.assertFalse(ParserElement._packratEnabled, "packrat enabled")
@@ -1892,28 +1908,32 @@ class Test02_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
         self.assertParseResultsEquals(testVal, expected_list=expected)
 
     def testHTMLEntities(self):
-        html_source = dedent("""\
-        This &amp; that
-        2 &gt; 1
-        0 &lt; 1
-        Don&apos;t get excited!
-        I said &quot;Don&apos;t get excited!&quot;
-        Copyright &copy; 2021
-        Dot &longrightarrow; &dot;
-        """)
+        html_source = dedent(
+            """\
+            This &amp; that
+            2 &gt; 1
+            0 &lt; 1
+            Don&apos;t get excited!
+            I said &quot;Don&apos;t get excited!&quot;
+            Copyright &copy; 2021
+            Dot &longrightarrow; &dot;
+            """
+        )
         transformer = pp.common_html_entity.add_parse_action(pp.replace_html_entity)
         transformed = transformer.transform_string(html_source)
         print(transformed)
 
-        expected = dedent("""\
-        This & that
-        2 > 1
-        0 < 1
-        Don't get excited!
-        I said "Don't get excited!"
-        Copyright © 2021
-        Dot ⟶ ˙
-        """)
+        expected = dedent(
+            """\
+            This & that
+            2 > 1
+            0 < 1
+            Don't get excited!
+            I said "Don't get excited!"
+            Copyright © 2021
+            Dot ⟶ ˙
+            """
+        )
         self.assertEqual(expected, transformed)
 
     def testInfixNotationBasicArithEval(self):
@@ -2944,6 +2964,13 @@ class Test02_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
             result, compare_list, msg="issue with ParseResults.insert()"
         )
 
+    def testParseResultsAddingSuppressedTokenWithResultsName(self):
+        parser = "aaa" + (pp.NoMatch() | pp.Suppress("-"))("B")
+        try:
+            dd = parser.parse_string("aaa -").as_dict()
+        except RecursionError:
+            self.fail("fail getting named result when empty")
+
     def testIgnoreString(self):
         """test ParserElement.ignore() passed a string arg"""
 
@@ -4315,6 +4342,44 @@ class Test02_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
             msg="using different openers and closers shouldn't affect resulting ParseResults",
         )
 
+    def testWordMinMaxArgs(self):
+        parsers = [
+            "A" + pp.Word(pp.nums),
+            "A" + pp.Word(pp.nums, min=1),
+            "A" + pp.Word(pp.nums, max=6),
+            "A" + pp.Word(pp.nums, min=1, max=6),
+            "A" + pp.Word(pp.nums, min=1),
+            "A" + pp.Word(pp.nums, min=2),
+            "A" + pp.Word(pp.nums, min=2, max=6),
+            pp.Word("A", pp.nums),
+            pp.Word("A", pp.nums, min=1),
+            pp.Word("A", pp.nums, max=6),
+            pp.Word("A", pp.nums, min=1, max=6),
+            pp.Word("A", pp.nums, min=1),
+            pp.Word("A", pp.nums, min=2),
+            pp.Word("A", pp.nums, min=2, max=6),
+            pp.Word(pp.alphas, pp.nums),
+            pp.Word(pp.alphas, pp.nums, min=1),
+            pp.Word(pp.alphas, pp.nums, max=6),
+            pp.Word(pp.alphas, pp.nums, min=1, max=6),
+            pp.Word(pp.alphas, pp.nums, min=1),
+            pp.Word(pp.alphas, pp.nums, min=2),
+            pp.Word(pp.alphas, pp.nums, min=2, max=6),
+        ]
+
+        fails = []
+        for p in parsers:
+            print(p, getattr(p, "reString", "..."), end=" ", flush=True)
+            try:
+                p.parseString("A123")
+            except Exception as e:
+                print("      <<< FAIL")
+                fails.append(p)
+            else:
+                print()
+        if fails:
+            self.fail("{} failed to match".format(",".join(str(f) for f in fails)))
+
     def testWordExclude(self):
 
         allButPunc = pp.Word(pp.printables, excludeChars=".,:;-_!?")
@@ -5740,6 +5805,7 @@ class Test02_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
 
     def testCommonUrlParts(self):
         from urllib.parse import urlparse
+
         sample_url = "https://bob:secret@www.example.com:8080/path/to/resource?filter=int#book-mark"
 
         parts = urlparse(sample_url)
@@ -7402,6 +7468,10 @@ class Test02_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
         - warn_on_multiple_string_args_to_oneof - flag to enable warnings when oneOf is
           incorrectly called with multiple str arguments (default=True)
         """
+        with self.assertDoesNotWarn(
+            "warn_on_multiple_string_args_to_oneof warning raised when not enabled"
+        ):
+            a = pp.oneOf("A", "B")
 
         with ppt.reset_pyparsing_context():
             pp.enable_diag(pp.Diagnostics.warn_on_multiple_string_args_to_oneof)
@@ -7427,8 +7497,8 @@ class Test02_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
             self.assertFalse(a.customName)
             pp.autoname_elements()
             self.assertTrue(a.debug)
-            self.assertEqual('a', a.name)
-            self.assertEqual('bbb', b.name)
+            self.assertEqual("a", a.name)
+            self.assertEqual("bbb", b.name)
 
     def testEnableDebugOnNamedExpressions(self):
         """
@@ -8286,7 +8356,6 @@ class Test02_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
         )
 
     def testWarnUsingLshiftForward(self):
-        import warnings
 
         print(
             "verify that using '<<' operator with a Forward raises a warning if there is a dangling '|' operator"
@@ -8319,15 +8388,12 @@ class Test02_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
         c = fwd | pp.Word("c")
 
         print("safe << and (|), should not warn")
-        with warnings.catch_warnings(record=True) as w:
-            warnings.simplefilter("error")
-
+        with self.assertDoesNotWarn(
+            "warning raised on safe use of << with Forward and MatchFirst"
+        ):
             fwd = pp.Forward()
             fwd << (pp.Word("a") | pp.Word("b"))
-            try:
-                c = fwd | pp.Word("c")
-            except Exception as e:
-                self.fail("raised warning when it should not have")
+            c = fwd | pp.Word("c")
 
     def testParseExpressionsWithRegex(self):
         from itertools import product
@@ -8560,6 +8626,7 @@ class Test02_WithoutPackrat(ppt.TestParseResultsAsserts, TestCase):
 
     def testEmptyExpressionsAreHandledProperly(self):
         from pyparsing.diagram import to_railroad
+
         for cls in (pp.And, pp.Or, pp.MatchFirst, pp.Each):
             print("testing empty", cls.__name__)
             expr = cls([])