diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2024-09-15 00:01:34 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2024-09-15 00:09:43 +0300 |
commit | aef4832c0a5e57f13a63b9248f32b61a7bd2b97a (patch) | |
tree | 62106da64d5eb602fffa2f86409deabe65658d19 | |
parent | 616250021dbd2936aed9368d3c4044045fbb91c6 (diff) | |
download | ydb-aef4832c0a5e57f13a63b9248f32b61a7bd2b97a.tar.gz |
Intermediate changes
commit_hash:ced60bdb33f400d18d13d42a274f9015c16b4ece
-rw-r--r-- | contrib/python/pyparsing/py3/.dist-info/METADATA | 2 | ||||
-rw-r--r-- | contrib/python/pyparsing/py3/pyparsing/__init__.py | 6 | ||||
-rw-r--r-- | contrib/python/pyparsing/py3/pyparsing/actions.py | 2 | ||||
-rw-r--r-- | contrib/python/pyparsing/py3/pyparsing/common.py | 23 | ||||
-rw-r--r-- | contrib/python/pyparsing/py3/pyparsing/core.py | 405 | ||||
-rw-r--r-- | contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py | 45 | ||||
-rw-r--r-- | contrib/python/pyparsing/py3/pyparsing/exceptions.py | 3 | ||||
-rw-r--r-- | contrib/python/pyparsing/py3/pyparsing/helpers.py | 10 | ||||
-rw-r--r-- | contrib/python/pyparsing/py3/pyparsing/results.py | 16 | ||||
-rw-r--r-- | contrib/python/pyparsing/py3/pyparsing/unicode.py | 32 | ||||
-rw-r--r-- | contrib/python/pyparsing/py3/pyparsing/util.py | 2 | ||||
-rw-r--r-- | contrib/python/pyparsing/py3/ya.make | 2 |
12 files changed, 324 insertions, 224 deletions
diff --git a/contrib/python/pyparsing/py3/.dist-info/METADATA b/contrib/python/pyparsing/py3/.dist-info/METADATA index cac4d35d87..1aa7a1fc04 100644 --- a/contrib/python/pyparsing/py3/.dist-info/METADATA +++ b/contrib/python/pyparsing/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pyparsing -Version: 3.1.2 +Version: 3.1.4 Summary: pyparsing module - Classes and methods to define and execute parsing grammars Author-email: Paul McGuire <ptmcg.gm+pyparsing@gmail.com> Requires-Python: >=3.6.8 diff --git a/contrib/python/pyparsing/py3/pyparsing/__init__.py b/contrib/python/pyparsing/py3/pyparsing/__init__.py index 79d8153ce3..a440cfbefa 100644 --- a/contrib/python/pyparsing/py3/pyparsing/__init__.py +++ b/contrib/python/pyparsing/py3/pyparsing/__init__.py @@ -120,8 +120,8 @@ class version_info(NamedTuple): return f"{__name__}.{type(self).__name__}({', '.join('{}={!r}'.format(*nv) for nv in zip(self._fields, self))})" -__version_info__ = version_info(3, 1, 2, "final", 1) -__version_time__ = "06 Mar 2024 07:08 UTC" +__version_info__ = version_info(3, 1, 4, "final", 1) +__version_time__ = "25 Aug 2024 14:40 UTC" __version__ = __version_info__.__version__ __versionTime__ = __version_time__ __author__ = "Paul McGuire <ptmcg.gm+pyparsing@gmail.com>" @@ -143,7 +143,7 @@ from .common import ( _builtin_exprs as common_builtin_exprs, ) -# define backward compat synonyms +# Compatibility synonyms if "pyparsing_unicode" not in globals(): pyparsing_unicode = unicode # type: ignore[misc] if "pyparsing_common" not in globals(): diff --git a/contrib/python/pyparsing/py3/pyparsing/actions.py b/contrib/python/pyparsing/py3/pyparsing/actions.py index ce51b3957c..1d2dce99e1 100644 --- a/contrib/python/pyparsing/py3/pyparsing/actions.py +++ b/contrib/python/pyparsing/py3/pyparsing/actions.py @@ -196,7 +196,7 @@ def with_class(classname, namespace=""): return with_attribute(**{classattr: classname}) -# pre-PEP8 compatibility symbols +# Compatibility synonyms # fmt: off replaceWith = replaced_by_pep8("replaceWith", replace_with) removeQuotes = replaced_by_pep8("removeQuotes", remove_quotes) diff --git a/contrib/python/pyparsing/py3/pyparsing/common.py b/contrib/python/pyparsing/py3/pyparsing/common.py index 74faa46085..649aad0096 100644 --- a/contrib/python/pyparsing/py3/pyparsing/common.py +++ b/contrib/python/pyparsing/py3/pyparsing/common.py @@ -418,20 +418,15 @@ class pyparsing_common: # fmt: on # pre-PEP8 compatibility names - convertToInteger = convert_to_integer - """Deprecated - use :class:`convert_to_integer`""" - convertToFloat = convert_to_float - """Deprecated - use :class:`convert_to_float`""" - convertToDate = convert_to_date - """Deprecated - use :class:`convert_to_date`""" - convertToDatetime = convert_to_datetime - """Deprecated - use :class:`convert_to_datetime`""" - stripHTMLTags = strip_html_tags - """Deprecated - use :class:`strip_html_tags`""" - upcaseTokens = upcase_tokens - """Deprecated - use :class:`upcase_tokens`""" - downcaseTokens = downcase_tokens - """Deprecated - use :class:`downcase_tokens`""" + # fmt: off + convertToInteger = staticmethod(replaced_by_pep8("convertToInteger", convert_to_integer)) + convertToFloat = staticmethod(replaced_by_pep8("convertToFloat", convert_to_float)) + convertToDate = staticmethod(replaced_by_pep8("convertToDate", convert_to_date)) + convertToDatetime = staticmethod(replaced_by_pep8("convertToDatetime", convert_to_datetime)) + stripHTMLTags = staticmethod(replaced_by_pep8("stripHTMLTags", strip_html_tags)) + upcaseTokens = staticmethod(replaced_by_pep8("upcaseTokens", upcase_tokens)) + downcaseTokens = staticmethod(replaced_by_pep8("downcaseTokens", downcase_tokens)) + # fmt: on _builtin_exprs = [ diff --git a/contrib/python/pyparsing/py3/pyparsing/core.py b/contrib/python/pyparsing/py3/pyparsing/core.py index b19d122160..cbe73c987a 100644 --- a/contrib/python/pyparsing/py3/pyparsing/core.py +++ b/contrib/python/pyparsing/py3/pyparsing/core.py @@ -53,6 +53,11 @@ from .unicode import pyparsing_unicode _MAX_INT = sys.maxsize str_type: Tuple[type, ...] = (str, bytes) +if sys.version_info >= (3, 7): + _RePattern = re.Pattern +else: + _RePattern = typing.Pattern + # # Copyright (c) 2003-2022 Paul T. McGuire # @@ -218,19 +223,11 @@ if _should_enable_warnings( # build list of single arg builtins, that can be used as parse actions +# fmt: off _single_arg_builtins = { - sum, - len, - sorted, - reversed, - list, - tuple, - set, - any, - all, - min, - max, + sum, len, sorted, reversed, list, tuple, set, any, all, min, max } +# fmt: on _generatorType = types.GeneratorType ParseImplReturnType = Tuple[int, Any] @@ -255,13 +252,13 @@ DebugSuccessAction = Callable[ DebugExceptionAction = Callable[[str, int, "ParserElement", Exception, bool], None] -alphas = string.ascii_uppercase + string.ascii_lowercase -identchars = pyparsing_unicode.Latin1.identchars -identbodychars = pyparsing_unicode.Latin1.identbodychars -nums = "0123456789" -hexnums = nums + "ABCDEFabcdef" -alphanums = alphas + nums -printables = "".join([c for c in string.printable if c not in string.whitespace]) +alphas: str = string.ascii_uppercase + string.ascii_lowercase +identchars: str = pyparsing_unicode.Latin1.identchars +identbodychars: str = pyparsing_unicode.Latin1.identbodychars +nums: str = "0123456789" +hexnums: str = nums + "ABCDEFabcdef" +alphanums: str = alphas + nums +printables: str = "".join([c for c in string.printable if c not in string.whitespace]) _trim_arity_call_line: traceback.StackSummary = None # type: ignore[assignment] @@ -280,7 +277,7 @@ def _trim_arity(func, max_limit=3): # user's parse action 'func', so that we don't incur call penalty at parse time # fmt: off - LINE_DIFF = 7 + LINE_DIFF = 9 # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!! _trim_arity_call_line = (_trim_arity_call_line or traceback.extract_stack(limit=2)[-1]) @@ -288,6 +285,8 @@ def _trim_arity(func, max_limit=3): def wrapper(*args): nonlocal found_arity, limit + if found_arity: + return func(*args[limit:]) while 1: try: ret = func(*args[limit:]) @@ -476,7 +475,7 @@ class ParserElement(ABC): self.streamlined = False # optimize exception handling for subclasses that don't advance parse index self.mayIndexError = True - self.errmsg = "" + self.errmsg: Union[str, None] = "" # mark results names as modal (report only last) or cumulative (list all) self.modalResults = True # custom debug actions @@ -582,15 +581,15 @@ class ParserElement(ABC): listAllMatches = listAllMatches or list_all_matches return self._setResultsName(name, listAllMatches) - def _setResultsName(self, name, listAllMatches=False): + def _setResultsName(self, name, list_all_matches=False) -> "ParserElement": if name is None: return self newself = self.copy() if name.endswith("*"): name = name[:-1] - listAllMatches = True + list_all_matches = True newself.resultsName = name - newself.modalResults = not listAllMatches + newself.modalResults = not list_all_matches return newself def set_break(self, break_flag: bool = True) -> "ParserElement": @@ -602,12 +601,12 @@ class ParserElement(ABC): if break_flag: _parseMethod = self._parse - def breaker(instring, loc, doActions=True, callPreParse=True): + def breaker(instring, loc, do_actions=True, callPreParse=True): import pdb # this call to pdb.set_trace() is intentional, not a checkin error pdb.set_trace() - return _parseMethod(instring, loc, doActions, callPreParse) + return _parseMethod(instring, loc, do_actions, callPreParse) breaker._originalParseMethod = _parseMethod # type: ignore [attr-defined] self._parse = breaker # type: ignore [assignment] @@ -615,7 +614,7 @@ class ParserElement(ABC): self._parse = self._parse._originalParseMethod # type: ignore [attr-defined, assignment] return self - def set_parse_action(self, *fns: ParseAction, **kwargs) -> "ParserElement": + def set_parse_action(self, *fns: ParseAction, **kwargs: Any) -> "ParserElement": """ Define one or more actions to perform when successfully matching parse element definition. @@ -691,19 +690,19 @@ class ParserElement(ABC): ''') """ if list(fns) == [None]: - self.parseAction = [] + self.parseAction.clear() return self if not all(callable(fn) for fn in fns): raise TypeError("parse actions must be callable") - self.parseAction = [_trim_arity(fn) for fn in fns] + self.parseAction[:] = [_trim_arity(fn) for fn in fns] self.callDuringTry = kwargs.get( "call_during_try", kwargs.get("callDuringTry", False) ) return self - def add_parse_action(self, *fns: ParseAction, **kwargs) -> "ParserElement": + def add_parse_action(self, *fns: ParseAction, **kwargs: Any) -> "ParserElement": """ Add one or more parse actions to expression's list of parse actions. See :class:`set_parse_action`. @@ -715,7 +714,7 @@ class ParserElement(ABC): ) return self - def add_condition(self, *fns: ParseCondition, **kwargs) -> "ParserElement": + def add_condition(self, *fns: ParseCondition, **kwargs: Any) -> "ParserElement": """Add a boolean predicate function to expression's list of parse actions. See :class:`set_parse_action` for function call signatures. Unlike ``set_parse_action``, functions passed to ``add_condition`` need to return boolean success/fail of the condition. @@ -801,7 +800,7 @@ class ParserElement(ABC): return loc - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: return loc, [] def postParse(self, instring, loc, tokenlist): @@ -809,10 +808,10 @@ class ParserElement(ABC): # @profile def _parseNoCache( - self, instring, loc, doActions=True, callPreParse=True + self, instring, loc, do_actions=True, callPreParse=True ) -> Tuple[int, ParseResults]: TRY, MATCH, FAIL = 0, 1, 2 - debugging = self.debug # and doActions) + debugging = self.debug # and do_actions) len_instring = len(instring) if debugging or self.failAction: @@ -827,11 +826,11 @@ class ParserElement(ABC): self.debugActions.debug_try(instring, tokens_start, self, False) if self.mayIndexError or pre_loc >= len_instring: try: - loc, tokens = self.parseImpl(instring, pre_loc, doActions) + loc, tokens = self.parseImpl(instring, pre_loc, do_actions) except IndexError: raise ParseException(instring, len_instring, self.errmsg, self) else: - loc, tokens = self.parseImpl(instring, pre_loc, doActions) + loc, tokens = self.parseImpl(instring, pre_loc, do_actions) except Exception as err: # print("Exception raised:", err) if self.debugActions.debug_fail: @@ -849,18 +848,18 @@ class ParserElement(ABC): tokens_start = pre_loc if self.mayIndexError or pre_loc >= len_instring: try: - loc, tokens = self.parseImpl(instring, pre_loc, doActions) + loc, tokens = self.parseImpl(instring, pre_loc, do_actions) except IndexError: raise ParseException(instring, len_instring, self.errmsg, self) else: - loc, tokens = self.parseImpl(instring, pre_loc, doActions) + loc, tokens = self.parseImpl(instring, pre_loc, do_actions) tokens = self.postParse(instring, loc, tokens) ret_tokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults ) - if self.parseAction and (doActions or self.callDuringTry): + if self.parseAction and (do_actions or self.callDuringTry): if debugging: try: for fn in self.parseAction: @@ -919,7 +918,7 @@ class ParserElement(ABC): do_actions: bool = False, ) -> int: try: - return self._parse(instring, loc, doActions=do_actions)[0] + return self._parse(instring, loc, do_actions=do_actions)[0] except ParseFatalException: if raise_fatal: raise @@ -960,18 +959,18 @@ class ParserElement(ABC): # this method gets repeatedly called during backtracking with the same arguments - # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression def _parseCache( - self, instring, loc, doActions=True, callPreParse=True + self, instring, loc, do_actions=True, callPreParse=True ) -> Tuple[int, ParseResults]: HIT, MISS = 0, 1 TRY, MATCH, FAIL = 0, 1, 2 - lookup = (self, instring, loc, callPreParse, doActions) + lookup = (self, instring, loc, callPreParse, do_actions) with ParserElement.packrat_cache_lock: cache = ParserElement.packrat_cache value = cache.get(lookup) if value is cache.not_in_cache: ParserElement.packrat_cache_stats[MISS] += 1 try: - value = self._parseNoCache(instring, loc, doActions, callPreParse) + value = self._parseNoCache(instring, loc, do_actions, callPreParse) except ParseBaseException as pe: # cache a copy of the exception, without the traceback cache.set(lookup, pe.__class__(*pe.args)) @@ -1190,7 +1189,7 @@ class ParserElement(ABC): loc, tokens = self._parse(instring, 0) if parseAll: loc = self.preParse(instring, loc) - se = Empty() + StringEnd() + se = Empty() + StringEnd().set_debug(False) se._parse(instring, loc) except ParseBaseException as exc: if ParserElement.verbose_stacktrace: @@ -1887,9 +1886,14 @@ class ParserElement(ABC): Child classes must define this method, which defines how the ``default_name`` is set. """ - def set_name(self, name: str) -> "ParserElement": + def set_name(self, name: typing.Optional[str]) -> "ParserElement": """ - Define name for this expression, makes debugging and exception messages clearer. + Define name for this expression, makes debugging and exception messages clearer. If + `__diag__.enable_debug_on_named_expressions` is set to True, setting a name will also + enable debug for this expression. + + If `name` is None, clears any custom name for this expression, and clears the + debug flag is it was enabled via `__diag__.enable_debug_on_named_expressions`. Example:: @@ -1900,9 +1904,11 @@ class ParserElement(ABC): integer.parse_string("ABC") # -> Exception: Expected integer (at char 0), (line:1, col:1) """ self.customName = name - self.errmsg = f"Expected {self.name}" + self.errmsg = f"Expected {str(self)}" + if __diag__.enable_debug_on_named_expressions: - self.set_debug() + self.set_debug(name is not None) + return self @property @@ -1910,6 +1916,10 @@ class ParserElement(ABC): # This will use a user-defined name if available, but otherwise defaults back to the auto-generated name return self.customName if self.customName is not None else self.default_name + @name.setter + def name(self, new_name) -> None: + self.set_name(new_name) + def __str__(self) -> str: return self.name @@ -2014,7 +2024,9 @@ class ParserElement(ABC): full_dump: bool = True, print_results: bool = True, failure_tests: bool = False, - post_parse: typing.Optional[Callable[[str, ParseResults], str]] = None, + post_parse: typing.Optional[ + Callable[[str, ParseResults], typing.Optional[str]] + ] = None, file: typing.Optional[TextIO] = None, with_line_numbers: bool = False, *, @@ -2022,7 +2034,9 @@ class ParserElement(ABC): fullDump: bool = True, printResults: bool = True, failureTests: bool = False, - postParse: typing.Optional[Callable[[str, ParseResults], str]] = None, + postParse: typing.Optional[ + Callable[[str, ParseResults], typing.Optional[str]] + ] = None, ) -> Tuple[bool, List[Tuple[str, Union[ParseResults, Exception]]]]: """ Execute the parse expression on a series of test strings, showing each @@ -2159,7 +2173,7 @@ class ParserElement(ABC): f"{nlstr}{nlstr.join(comments) if comments else ''}", pyparsing_test.with_line_numbers(t) if with_line_numbers else t, ] - comments = [] + comments.clear() try: # convert newline marks to actual newlines, and strip leading BOM if present t = NL.transform_string(t.lstrip(BOM)) @@ -2264,10 +2278,15 @@ class ParserElement(ABC): # Compatibility synonyms # fmt: off - inlineLiteralsUsing = replaced_by_pep8("inlineLiteralsUsing", inline_literals_using) - setDefaultWhitespaceChars = replaced_by_pep8( + inlineLiteralsUsing = staticmethod(replaced_by_pep8("inlineLiteralsUsing", inline_literals_using)) + setDefaultWhitespaceChars = staticmethod(replaced_by_pep8( "setDefaultWhitespaceChars", set_default_whitespace_chars - ) + )) + disableMemoization = staticmethod(replaced_by_pep8("disableMemoization", disable_memoization)) + enableLeftRecursion = staticmethod(replaced_by_pep8("enableLeftRecursion", enable_left_recursion)) + enablePackrat = staticmethod(replaced_by_pep8("enablePackrat", enable_packrat)) + resetCache = staticmethod(replaced_by_pep8("resetCache", reset_cache)) + setResultsName = replaced_by_pep8("setResultsName", set_results_name) setBreak = replaced_by_pep8("setBreak", set_break) setParseAction = replaced_by_pep8("setParseAction", set_parse_action) @@ -2275,8 +2294,6 @@ class ParserElement(ABC): addCondition = replaced_by_pep8("addCondition", add_condition) setFailAction = replaced_by_pep8("setFailAction", set_fail_action) tryParse = replaced_by_pep8("tryParse", try_parse) - enableLeftRecursion = replaced_by_pep8("enableLeftRecursion", enable_left_recursion) - enablePackrat = replaced_by_pep8("enablePackrat", enable_packrat) parseString = replaced_by_pep8("parseString", parse_string) scanString = replaced_by_pep8("scanString", scan_string) transformString = replaced_by_pep8("transformString", transform_string) @@ -2290,8 +2307,7 @@ class ParserElement(ABC): setName = replaced_by_pep8("setName", set_name) parseFile = replaced_by_pep8("parseFile", parse_file) runTests = replaced_by_pep8("runTests", run_tests) - canParseNext = can_parse_next - resetCache = reset_cache + canParseNext = replaced_by_pep8("canParseNext", can_parse_next) defaultName = default_name # fmt: on @@ -2331,7 +2347,7 @@ class _PendingSkip(ParserElement): def __repr__(self): return self.defaultName - def parseImpl(self, *args): + def parseImpl(self, *args) -> ParseImplReturnType: raise Exception( "use of `...` expression without following SkipTo target expression" ) @@ -2360,7 +2376,7 @@ class NoMatch(Token): self.mayIndexError = False self.errmsg = "Unmatchable token" - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: raise ParseException(instring, loc, self.errmsg, self) @@ -2409,7 +2425,7 @@ class Literal(Token): def _generateDefaultName(self) -> str: return repr(self.match) - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if instring[loc] == self.firstMatchChar and instring.startswith( self.match, loc ): @@ -2430,12 +2446,12 @@ class Empty(Literal): def _generateDefaultName(self) -> str: return "Empty" - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: return loc, [] class _SingleCharLiteral(Literal): - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if instring[loc] == self.firstMatchChar: return loc + 1, self.match raise ParseException(instring, loc, self.errmsg, self) @@ -2505,7 +2521,7 @@ class Keyword(Token): def _generateDefaultName(self) -> str: return repr(self.match) - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: errmsg = self.errmsg errloc = loc if self.caseless: @@ -2556,7 +2572,10 @@ class Keyword(Token): """ Keyword.DEFAULT_KEYWORD_CHARS = chars - setDefaultKeywordChars = set_default_keyword_chars + # Compatibility synonyms + setDefaultKeywordChars = staticmethod( + replaced_by_pep8("setDefaultKeywordChars", set_default_keyword_chars) + ) class CaselessLiteral(Literal): @@ -2580,7 +2599,7 @@ class CaselessLiteral(Literal): self.returnString = match_string self.errmsg = f"Expected {self.name}" - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if instring[loc : loc + self.matchLen].upper() == self.match: return loc + self.matchLen, self.returnString raise ParseException(instring, loc, self.errmsg, self) @@ -2666,7 +2685,7 @@ class CloseMatch(Token): def _generateDefaultName(self) -> str: return f"{type(self).__name__}:{self.match_string!r}" - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: start = loc instrlen = len(instring) maxloc = start + len(self.match_string) @@ -2911,36 +2930,36 @@ class Word(Token): return base + f"{{{self.minLen},{self.maxLen}}}" return base - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if instring[loc] not in self.initChars: raise ParseException(instring, loc, self.errmsg, self) start = loc loc += 1 instrlen = len(instring) - bodychars = self.bodyChars + body_chars: set[str] = self.bodyChars maxloc = start + self.maxLen maxloc = min(maxloc, instrlen) - while loc < maxloc and instring[loc] in bodychars: + while loc < maxloc and instring[loc] in body_chars: loc += 1 - throwException = False + throw_exception = False if loc - start < self.minLen: - throwException = True - elif self.maxSpecified and loc < instrlen and instring[loc] in bodychars: - throwException = True + throw_exception = True + elif self.maxSpecified and loc < instrlen and instring[loc] in body_chars: + throw_exception = True elif self.asKeyword and ( - (start > 0 and instring[start - 1] in bodychars) - or (loc < instrlen and instring[loc] in bodychars) + (start > 0 and instring[start - 1] in body_chars) + or (loc < instrlen and instring[loc] in body_chars) ): - throwException = True + throw_exception = True - if throwException: + if throw_exception: raise ParseException(instring, loc, self.errmsg, self) return loc, instring[start:loc] - def parseImpl_regex(self, instring, loc, doActions=True): + def parseImpl_regex(self, instring, loc, do_actions=True) -> ParseImplReturnType: result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -3043,7 +3062,7 @@ class Regex(Token): self.parseImpl = self.parseImplAsMatch # type: ignore [assignment] @cached_property - def re(self): + def re(self) -> _RePattern: if self._re: return self._re @@ -3053,17 +3072,18 @@ class Regex(Token): raise ValueError(f"invalid pattern ({self.pattern!r}) passed to Regex") @cached_property - def re_match(self): + def re_match(self) -> Callable[[str], Any]: return self.re.match @cached_property - def mayReturnEmpty(self): + def mayReturnEmpty(self) -> bool: return self.re_match("") is not None def _generateDefaultName(self) -> str: - return "Re:({})".format(repr(self.pattern).replace("\\\\", "\\")) + unescaped = self.pattern.replace("\\\\", "\\") + return f"Re:({unescaped!r})" - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -3077,7 +3097,7 @@ class Regex(Token): return loc, ret - def parseImplAsGroupList(self, instring, loc, doActions=True): + def parseImplAsGroupList(self, instring, loc, do_actions=True): result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -3086,7 +3106,7 @@ class Regex(Token): ret = result.groups() return loc, ret - def parseImplAsMatch(self, instring, loc, doActions=True): + def parseImplAsMatch(self, instring, loc, do_actions=True): result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -3223,7 +3243,7 @@ class QuotedString(Token): # fmt: off # build up re pattern for the content between the quote delimiters - inner_pattern = [] + inner_pattern: List[str] = [] if esc_quote: inner_pattern.append(rf"(?:{re.escape(esc_quote)})") @@ -3245,12 +3265,12 @@ class QuotedString(Token): self.re_flags |= re.MULTILINE | re.DOTALL inner_pattern.append( rf"(?:[^{_escape_regex_range_chars(self.end_quote_char[0])}" - rf"{(_escape_regex_range_chars(esc_char) if self.has_esc_char else '')}])" + rf"{(_escape_regex_range_chars(self.esc_char) if self.has_esc_char else '')}])" ) else: inner_pattern.append( rf"(?:[^{_escape_regex_range_chars(self.end_quote_char[0])}\n\r" - rf"{(_escape_regex_range_chars(esc_char) if self.has_esc_char else '')}])" + rf"{(_escape_regex_range_chars(self.esc_char) if self.has_esc_char else '')}])" ) self.pattern = "".join( @@ -3298,7 +3318,7 @@ class QuotedString(Token): return f"quoted string, starting with {self.quote_char} ending with {self.end_quote_char}" - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: # check first character of opening quote to see if that is a match # before doing the more complicated regex match result = ( @@ -3412,7 +3432,7 @@ class CharsNotIn(Token): else: return f"!W:({self.notChars})" - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: notchars = self.notCharsSet if instring[loc] in notchars: raise ParseException(instring, loc, self.errmsg, self) @@ -3490,7 +3510,7 @@ class White(Token): def _generateDefaultName(self) -> str: return "".join(White.whiteStrs[c] for c in self.matchWhite) - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if instring[loc] not in self.matchWhite: raise ParseException(instring, loc, self.errmsg, self) start = loc @@ -3538,7 +3558,7 @@ class GoToColumn(PositionToken): return loc - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: thiscol = col(loc, instring) if thiscol > self.col: raise ParseException(instring, loc, "Text not in expected column", self) @@ -3576,7 +3596,7 @@ class LineStart(PositionToken): self.orig_whiteChars = set() | self.whiteChars self.whiteChars.discard("\n") self.skipper = Empty().set_whitespace_chars(self.whiteChars) - self.errmsg = "Expected start of line" + self.set_name("start of line") def preParse(self, instring: str, loc: int) -> int: if loc == 0: @@ -3590,7 +3610,7 @@ class LineStart(PositionToken): return ret - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if col(loc, instring) == 1: return loc, [] raise ParseException(instring, loc, self.errmsg, self) @@ -3605,9 +3625,9 @@ class LineEnd(PositionToken): super().__init__() self.whiteChars.discard("\n") self.set_whitespace_chars(self.whiteChars, copy_defaults=False) - self.errmsg = "Expected end of line" + self.set_name("end of line") - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if loc < len(instring): if instring[loc] == "\n": return loc + 1, "\n" @@ -3626,9 +3646,9 @@ class StringStart(PositionToken): def __init__(self): super().__init__() - self.errmsg = "Expected start of text" + self.set_name("start of text") - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: # see if entire string up to here is just whitespace and ignoreables if loc != 0 and loc != self.preParse(instring, 0): raise ParseException(instring, loc, self.errmsg, self) @@ -3643,9 +3663,9 @@ class StringEnd(PositionToken): def __init__(self): super().__init__() - self.errmsg = "Expected end of text" + self.set_name("end of text") - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if loc < len(instring): raise ParseException(instring, loc, self.errmsg, self) if loc == len(instring): @@ -3670,9 +3690,9 @@ class WordStart(PositionToken): wordChars = word_chars if wordChars == printables else wordChars super().__init__() self.wordChars = set(wordChars) - self.errmsg = "Not at the start of a word" + self.set_name("start of a word") - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if loc != 0: if ( instring[loc - 1] in self.wordChars @@ -3696,9 +3716,9 @@ class WordEnd(PositionToken): super().__init__() self.wordChars = set(wordChars) self.skipWhitespace = False - self.errmsg = "Not at the end of a word" + self.set_name("end of a word") - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: instrlen = len(instring) if instrlen > 0 and loc < instrlen: if ( @@ -3709,6 +3729,47 @@ class WordEnd(PositionToken): return loc, [] +class Tag(Token): + """ + A meta-element for inserting a named result into the parsed + tokens that may be checked later in a parse action or while + processing the parsed results. Accepts an optional tag value, + defaulting to `True`. + + Example:: + + end_punc = "." | ("!" + Tag("enthusiastic"))) + greeting = "Hello," + Word(alphas) + end_punc + + result = greeting.parse_string("Hello, World.") + print(result.dump()) + + result = greeting.parse_string("Hello, World!") + print(result.dump()) + + prints:: + + ['Hello,', 'World', '.'] + + ['Hello,', 'World', '!'] + - enthusiastic: True + """ + def __init__(self, tag_name: str, value: Any = True): + super().__init__() + self.mayReturnEmpty = True + self.mayIndexError = False + self.leave_whitespace() + self.tag_name = tag_name + self.tag_value = value + self.add_parse_action(self._add_tag) + + def _add_tag(self, tokens: ParseResults): + tokens[self.tag_name] = self.tag_value + + def _generateDefaultName(self) -> str: + return f"{type(self).__name__}:{self.tag_name}={self.tag_value!r}" + + class ParseExpression(ParserElement): """Abstract subclass of ParserElement, for combining and post-processing parsed tokens. @@ -3846,13 +3907,13 @@ class ParseExpression(ParserElement): ret.exprs = [e.copy() for e in self.exprs] return ret - def _setResultsName(self, name, listAllMatches=False): + def _setResultsName(self, name, list_all_matches=False) -> ParserElement: if not ( __diag__.warn_ungrouped_named_tokens_in_collection and Diagnostics.warn_ungrouped_named_tokens_in_collection not in self.suppress_warnings_ ): - return super()._setResultsName(name, listAllMatches) + return super()._setResultsName(name, list_all_matches) for e in self.exprs: if ( @@ -3871,7 +3932,7 @@ class ParseExpression(ParserElement): warnings.warn(warning, stacklevel=3) break - return super()._setResultsName(name, listAllMatches) + return super()._setResultsName(name, list_all_matches) # Compatibility synonyms # fmt: off @@ -3911,7 +3972,7 @@ class And(ParseExpression): ): exprs: List[ParserElement] = list(exprs_arg) if exprs and Ellipsis in exprs: - tmp = [] + tmp: List[ParserElement] = [] for i, expr in enumerate(exprs): if expr is not Ellipsis: tmp.append(expr) @@ -3991,11 +4052,11 @@ class And(ParseExpression): self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) return self - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True): # pass False as callPreParse arg to _parse for first element, since we already # pre-parsed the string as part of our And pre-parsing loc, resultlist = self.exprs[0]._parse( - instring, loc, doActions, callPreParse=False + instring, loc, do_actions, callPreParse=False ) errorStop = False for e in self.exprs[1:]: @@ -4005,7 +4066,7 @@ class And(ParseExpression): continue if errorStop: try: - loc, exprtokens = e._parse(instring, loc, doActions) + loc, exprtokens = e._parse(instring, loc, do_actions) except ParseSyntaxException: raise except ParseBaseException as pe: @@ -4016,7 +4077,7 @@ class And(ParseExpression): instring, len(instring), self.errmsg, self ) else: - loc, exprtokens = e._parse(instring, loc, doActions) + loc, exprtokens = e._parse(instring, loc, do_actions) resultlist += exprtokens return loc, resultlist @@ -4080,11 +4141,11 @@ class Or(ParseExpression): self.saveAsList = False return self - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: maxExcLoc = -1 maxException = None - matches = [] - fatals = [] + matches: List[Tuple[int, ParserElement]] = [] + fatals: List[ParseFatalException] = [] if all(e.callPreparse for e in self.exprs): loc = self.preParse(instring, loc) for e in self.exprs: @@ -4117,11 +4178,11 @@ class Or(ParseExpression): # might change whether or how much they match of the input. matches.sort(key=itemgetter(0), reverse=True) - if not doActions: + if not do_actions: # no further conditions or parse actions to change the selection of # alternative, so the first match will be the best match best_expr = matches[0][1] - return best_expr._parse(instring, loc, doActions) + return best_expr._parse(instring, loc, do_actions) longest = -1, None for loc1, expr1 in matches: @@ -4130,7 +4191,7 @@ class Or(ParseExpression): return longest try: - loc2, toks = expr1._parse(instring, loc, doActions) + loc2, toks = expr1._parse(instring, loc, do_actions) except ParseException as err: err.__traceback__ = None if err.loc > maxExcLoc: @@ -4173,7 +4234,7 @@ class Or(ParseExpression): def _generateDefaultName(self) -> str: return f"{{{' ^ '.join(str(e) for e in self.exprs)}}}" - def _setResultsName(self, name, listAllMatches=False): + def _setResultsName(self, name, list_all_matches=False) -> ParserElement: if ( __diag__.warn_multiple_tokens_in_named_alternation and Diagnostics.warn_multiple_tokens_in_named_alternation @@ -4194,7 +4255,7 @@ class Or(ParseExpression): ) warnings.warn(warning, stacklevel=3) - return super()._setResultsName(name, listAllMatches) + return super()._setResultsName(name, list_all_matches) class MatchFirst(ParseExpression): @@ -4239,13 +4300,13 @@ class MatchFirst(ParseExpression): self.mayReturnEmpty = True return self - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: maxExcLoc = -1 maxException = None for e in self.exprs: try: - return e._parse(instring, loc, doActions) + return e._parse(instring, loc, do_actions) except ParseFatalException as pfe: pfe.__traceback__ = None pfe.parser_element = e @@ -4280,7 +4341,7 @@ class MatchFirst(ParseExpression): def _generateDefaultName(self) -> str: return f"{{{' | '.join(str(e) for e in self.exprs)}}}" - def _setResultsName(self, name, listAllMatches=False): + def _setResultsName(self, name, list_all_matches=False) -> ParserElement: if ( __diag__.warn_multiple_tokens_in_named_alternation and Diagnostics.warn_multiple_tokens_in_named_alternation @@ -4301,7 +4362,7 @@ class MatchFirst(ParseExpression): ) warnings.warn(warning, stacklevel=3) - return super()._setResultsName(name, listAllMatches) + return super()._setResultsName(name, list_all_matches) class Each(ParseExpression): @@ -4387,7 +4448,7 @@ class Each(ParseExpression): self.mayReturnEmpty = True return self - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if self.initExprGroups: self.opt1map = dict( (id(e.expr), e) for e in self.exprs if isinstance(e, Opt) @@ -4419,11 +4480,11 @@ class Each(ParseExpression): tmpReqd = self.required[:] tmpOpt = self.optionals[:] multis = self.multioptionals[:] - matchOrder = [] + matchOrder: List[ParserElement] = [] keepMatching = True - failed = [] - fatals = [] + failed: List[ParserElement] = [] + fatals: List[ParseFatalException] = [] while keepMatching: tmpExprs = tmpReqd + tmpOpt + multis failed.clear() @@ -4469,7 +4530,7 @@ class Each(ParseExpression): total_results = ParseResults([]) for e in matchOrder: - loc, results = e._parse(instring, loc, doActions) + loc, results = e._parse(instring, loc, do_actions) total_results += results return loc, total_results @@ -4509,12 +4570,14 @@ class ParseElementEnhance(ParserElement): def recurse(self) -> List[ParserElement]: return [self.expr] if self.expr is not None else [] - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True): if self.expr is None: raise ParseException(instring, loc, "No expression defined", self) try: - return self.expr._parse(instring, loc, doActions, callPreParse=False) + return self.expr._parse(instring, loc, do_actions, callPreParse=False) + except ParseSyntaxException: + raise except ParseBaseException as pbe: if not isinstance(self, Forward) or self.customName is not None: if self.errmsg: @@ -4611,14 +4674,14 @@ class IndentedBlock(ParseElementEnhance): self._grouped = grouped self.parent_anchor = 1 - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: # advance parse position to non-whitespace by using an Empty() # this should be the column to be used for all subsequent indented lines anchor_loc = Empty().preParse(instring, loc) # see if self.expr matches at the current location - if not it will raise an exception # and no further work is necessary - self.expr.try_parse(instring, anchor_loc, do_actions=doActions) + self.expr.try_parse(instring, anchor_loc, do_actions=do_actions) indent_col = col(anchor_loc, instring) peer_detect_expr = self._Indent(indent_col) @@ -4643,7 +4706,7 @@ class IndentedBlock(ParseElementEnhance): else: wrapper = lambda expr: expr return (wrapper(block) + Optional(trailing_undent)).parseImpl( - instring, anchor_loc, doActions + instring, anchor_loc, do_actions ) @@ -4662,10 +4725,10 @@ class AtStringStart(ParseElementEnhance): super().__init__(expr) self.callPreparse = False - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if loc != 0: raise ParseException(instring, loc, "not found at string start") - return super().parseImpl(instring, loc, doActions) + return super().parseImpl(instring, loc, do_actions) class AtLineStart(ParseElementEnhance): @@ -4695,10 +4758,10 @@ class AtLineStart(ParseElementEnhance): super().__init__(expr) self.callPreparse = False - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if col(loc, instring) != 1: raise ParseException(instring, loc, "not found at line start") - return super().parseImpl(instring, loc, doActions) + return super().parseImpl(instring, loc, do_actions) class FollowedBy(ParseElementEnhance): @@ -4728,10 +4791,10 @@ class FollowedBy(ParseElementEnhance): super().__init__(expr) self.mayReturnEmpty = True - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: # by using self._expr.parse and deleting the contents of the returned ParseResults list # we keep any named results that were defined in the FollowedBy expression - _, ret = self.expr._parse(instring, loc, doActions=doActions) + _, ret = self.expr._parse(instring, loc, do_actions=do_actions) del ret[:] return loc, ret @@ -4793,7 +4856,7 @@ class PrecededBy(ParseElementEnhance): self.skipWhitespace = False self.parseAction.append(lambda s, l, t: t.__delitem__(slice(None, None))) - def parseImpl(self, instring, loc=0, doActions=True): + def parseImpl(self, instring, loc=0, do_actions=True) -> ParseImplReturnType: if self.exact: if loc < self.retreat: raise ParseException(instring, loc, self.errmsg) @@ -4848,9 +4911,9 @@ class Located(ParseElementEnhance): """ - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: start = loc - loc, tokens = self.expr._parse(instring, start, doActions, callPreParse=False) + loc, tokens = self.expr._parse(instring, start, do_actions, callPreParse=False) ret_tokens = ParseResults([start, tokens, loc]) ret_tokens["locn_start"] = start ret_tokens["value"] = tokens @@ -4896,8 +4959,8 @@ class NotAny(ParseElementEnhance): self.mayReturnEmpty = True self.errmsg = f"Found unwanted token, {self.expr}" - def parseImpl(self, instring, loc, doActions=True): - if self.expr.can_parse_next(instring, loc, do_actions=doActions): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: + if self.expr.can_parse_next(instring, loc, do_actions=do_actions): raise ParseException(instring, loc, self.errmsg, self) return loc, [] @@ -4927,7 +4990,7 @@ class _MultipleMatch(ParseElementEnhance): self.not_ender = ~ender if ender is not None else None return self - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: self_expr_parse = self.expr._parse self_skip_ignorables = self._skipIgnorables check_ender = self.not_ender is not None @@ -4938,7 +5001,7 @@ class _MultipleMatch(ParseElementEnhance): # if so, fail) if check_ender: try_not_ender(instring, loc) - loc, tokens = self_expr_parse(instring, loc, doActions) + loc, tokens = self_expr_parse(instring, loc, do_actions) try: hasIgnoreExprs = not not self.ignoreExprs while 1: @@ -4948,14 +5011,14 @@ class _MultipleMatch(ParseElementEnhance): preloc = self_skip_ignorables(instring, loc) else: preloc = loc - loc, tmptokens = self_expr_parse(instring, preloc, doActions) + loc, tmptokens = self_expr_parse(instring, preloc, do_actions) tokens += tmptokens except (ParseException, IndexError): pass return loc, tokens - def _setResultsName(self, name, listAllMatches=False): + def _setResultsName(self, name, list_all_matches=False) -> ParserElement: if ( __diag__.warn_ungrouped_named_tokens_in_collection and Diagnostics.warn_ungrouped_named_tokens_in_collection @@ -4978,7 +5041,7 @@ class _MultipleMatch(ParseElementEnhance): warnings.warn(warning, stacklevel=3) break - return super()._setResultsName(name, listAllMatches) + return super()._setResultsName(name, list_all_matches) class OneOrMore(_MultipleMatch): @@ -5037,9 +5100,9 @@ class ZeroOrMore(_MultipleMatch): super().__init__(expr, stopOn=stopOn or stop_on) self.mayReturnEmpty = True - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: try: - return super().parseImpl(instring, loc, doActions) + return super().parseImpl(instring, loc, do_actions) except (ParseException, IndexError): return loc, ParseResults([], name=self.resultsName) @@ -5170,10 +5233,10 @@ class Opt(ParseElementEnhance): self.defaultValue = default self.mayReturnEmpty = True - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: self_expr = self.expr try: - loc, tokens = self_expr._parse(instring, loc, doActions, callPreParse=False) + loc, tokens = self_expr._parse(instring, loc, do_actions, callPreParse=False) except (ParseException, IndexError): default_value = self.defaultValue if default_value is not self.__optionalNotMatched: @@ -5279,7 +5342,7 @@ class SkipTo(ParseElementEnhance): self.failOn = self._literalStringClass(failOn) else: self.failOn = failOn - self.errmsg = "No match found for " + str(self.expr) + self.errmsg = f"No match found for {self.expr}" self.ignorer = Empty().leave_whitespace() self._update_ignorer() @@ -5295,7 +5358,7 @@ class SkipTo(ParseElementEnhance): super().ignore(expr) self._update_ignorer() - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True): startloc = loc instrlen = len(instring) self_expr_parse = self.expr._parse @@ -5325,7 +5388,7 @@ class SkipTo(ParseElementEnhance): prev_tmploc = tmploc try: - self_expr_parse(instring, tmploc, doActions=False, callPreParse=False) + self_expr_parse(instring, tmploc, do_actions=False, callPreParse=False) except (ParseException, IndexError): # no match, advance loc in string tmploc += 1 @@ -5343,7 +5406,7 @@ class SkipTo(ParseElementEnhance): skipresult = ParseResults(skiptext) if self.includeMatch: - loc, mat = self_expr_parse(instring, loc, doActions, callPreParse=False) + loc, mat = self_expr_parse(instring, loc, do_actions, callPreParse=False) skipresult += mat return loc, skipresult @@ -5440,7 +5503,7 @@ class Forward(ParseElementEnhance): lineno=self.caller_frame.lineno, ) - def parseImpl(self, instring, loc, doActions=True): + def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if ( self.expr is None and __diag__.warn_on_parse_using_empty_Forward @@ -5466,7 +5529,7 @@ class Forward(ParseElementEnhance): stacklevel=stacklevel, ) if not ParserElement._left_recursion_enabled: - return super().parseImpl(instring, loc, doActions) + return super().parseImpl(instring, loc, do_actions) # ## Bounded Recursion algorithm ## # Recursion only needs to be processed at ``Forward`` elements, since they are # the only ones that can actually refer to themselves. The general idea is @@ -5484,13 +5547,13 @@ class Forward(ParseElementEnhance): # # There is a complication since we not only *parse* but also *transform* via # actions: We do not want to run the actions too often while expanding. Thus, - # we expand using `doActions=False` and only run `doActions=True` if the next + # we expand using `do_actions=False` and only run `do_actions=True` if the next # recursion level is acceptable. with ParserElement.recursion_lock: memo = ParserElement.recursion_memos try: # we are parsing at a specific recursion expansion - use it as-is - prev_loc, prev_result = memo[loc, self, doActions] + prev_loc, prev_result = memo[loc, self, do_actions] if isinstance(prev_result, Exception): raise prev_result return prev_loc, prev_result.copy() @@ -5498,14 +5561,14 @@ class Forward(ParseElementEnhance): act_key = (loc, self, True) peek_key = (loc, self, False) # we are searching for the best recursion expansion - keep on improving - # both `doActions` cases must be tracked separately here! + # both `do_actions` cases must be tracked separately here! prev_loc, prev_peek = memo[peek_key] = ( loc - 1, ParseException( instring, loc, "Forward recursion without base case", self ), ) - if doActions: + if do_actions: memo[act_key] = memo[peek_key] while True: try: @@ -5517,8 +5580,8 @@ class Forward(ParseElementEnhance): new_loc, new_peek = prev_loc, prev_peek # the match did not get better: we are done if new_loc <= prev_loc: - if doActions: - # replace the match for doActions=False as well, + if do_actions: + # replace the match for do_actions=False as well, # in case the action did backtrack prev_loc, prev_result = memo[peek_key] = memo[act_key] del memo[peek_key], memo[act_key] @@ -5526,7 +5589,7 @@ class Forward(ParseElementEnhance): del memo[peek_key] return prev_loc, prev_peek.copy() # the match did get better: see if we can improve further - if doActions: + if do_actions: try: memo[act_key] = super().parseImpl(instring, loc, True) except ParseException as e: @@ -5586,7 +5649,7 @@ class Forward(ParseElementEnhance): ret <<= self return ret - def _setResultsName(self, name, list_all_matches=False): + def _setResultsName(self, name, list_all_matches=False) -> ParserElement: # fmt: off if ( __diag__.warn_name_set_on_empty_Forward @@ -5892,7 +5955,9 @@ def trace_parse_action(f: ParseAction) -> ParseAction: try: ret = f(*paArgs) except Exception as exc: - sys.stderr.write(f"<<leaving {thisFunc} (exception: {exc})\n") + sys.stderr.write( + f"<<leaving {thisFunc} (exception: {type(exc).__name__}: {exc})\n" + ) raise sys.stderr.write(f"<<leaving {thisFunc} (ret: {ret!r})\n") return ret @@ -6070,7 +6135,7 @@ _builtin_exprs: List[ParserElement] = [ v for v in vars().values() if isinstance(v, ParserElement) ] -# backward compatibility names +# Compatibility synonyms # fmt: off sglQuotedString = sgl_quoted_string dblQuotedString = dbl_quoted_string diff --git a/contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py b/contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py index 700d0b561f..3275adafb6 100644 --- a/contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py +++ b/contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py @@ -36,6 +36,7 @@ jinja2_template_source = """\ </head> <body> {% endif %} +<meta charset="UTF-8"/> {{ body | safe }} {% for diagram in diagrams %} <div class="railroad-group"> @@ -89,7 +90,7 @@ class AnnotatedItem(railroad.Group): """ def __init__(self, label: str, item): - super().__init__(item=item, label="[{}]".format(label) if label else label) + super().__init__(item=item, label=f"[{label}]") class EditablePartial(Generic[T]): @@ -145,7 +146,7 @@ def railroad_to_html(diagrams: List[NamedDiagram], embed=False, **kwargs) -> str continue io = StringIO() try: - css = kwargs.get('css') + css = kwargs.get("css") diagram.diagram.writeStandalone(io.write, css=css) except AttributeError: diagram.diagram.writeSvg(io.write) @@ -425,9 +426,11 @@ def _apply_diagram_item_enhancements(fn): element_results_name = element.resultsName if element_results_name: # add "*" to indicate if this is a "list all results" name - element_results_name += "" if element.modalResults else "*" + modal_tag = "" if element.modalResults else "*" ret = EditablePartial.from_call( - railroad.Group, item=ret, label=element_results_name + railroad.Group, + item=ret, + label=f"{repr(element_results_name)}{modal_tag}", ) return ret @@ -534,7 +537,7 @@ def _to_diagram_element( # (all will have the same name, and resultsName) if not exprs: return None - if len(set((e.name, e.resultsName) for e in exprs)) == 1: + if len(set((e.name, e.resultsName) for e in exprs)) == 1 and len(exprs) > 2: ret = EditablePartial.from_call( railroad.OneOrMore, item="", repeat=str(len(exprs)) ) @@ -563,7 +566,7 @@ def _to_diagram_element( if show_groups: ret = EditablePartial.from_call(AnnotatedItem, label="", item="") else: - ret = EditablePartial.from_call(railroad.Group, label="", item="") + ret = EditablePartial.from_call(railroad.Sequence, items=[]) elif isinstance(element, pyparsing.TokenConverter): label = type(element).__name__.lower() if label == "tokenconverter": @@ -573,8 +576,36 @@ def _to_diagram_element( elif isinstance(element, pyparsing.Opt): ret = EditablePartial.from_call(railroad.Optional, item="") elif isinstance(element, pyparsing.OneOrMore): - ret = EditablePartial.from_call(railroad.OneOrMore, item="") + if element.not_ender is not None: + args = [ + parent, + lookup, + vertical, + index, + name_hint, + show_results_names, + show_groups, + ] + return _to_diagram_element( + (~element.not_ender.expr + element.expr)[1, ...].set_name(element.name), + *args, + ) + ret = EditablePartial.from_call(railroad.OneOrMore, item=None) elif isinstance(element, pyparsing.ZeroOrMore): + if element.not_ender is not None: + args = [ + parent, + lookup, + vertical, + index, + name_hint, + show_results_names, + show_groups, + ] + return _to_diagram_element( + (~element.not_ender.expr + element.expr)[...].set_name(element.name), + *args, + ) ret = EditablePartial.from_call(railroad.ZeroOrMore, item="") elif isinstance(element, pyparsing.Group): ret = EditablePartial.from_call( diff --git a/contrib/python/pyparsing/py3/pyparsing/exceptions.py b/contrib/python/pyparsing/py3/pyparsing/exceptions.py index 1aaea56f54..8db34f195a 100644 --- a/contrib/python/pyparsing/py3/pyparsing/exceptions.py +++ b/contrib/python/pyparsing/py3/pyparsing/exceptions.py @@ -85,7 +85,7 @@ class ParseBaseException(Exception): ret = [] if isinstance(exc, ParseBaseException): ret.append(exc.line) - ret.append(" " * (exc.column - 1) + "^") + ret.append(f"{' ' * (exc.column - 1)}^") ret.append(f"{type(exc).__name__}: {exc}") if depth <= 0: @@ -245,6 +245,7 @@ class ParseBaseException(Exception): """ return self.explain_exception(self, depth) + # Compatibility synonyms # fmt: off markInputline = replaced_by_pep8("markInputline", mark_input_line) # fmt: on diff --git a/contrib/python/pyparsing/py3/pyparsing/helpers.py b/contrib/python/pyparsing/py3/pyparsing/helpers.py index dcfdb8fe4b..d5d14a08d6 100644 --- a/contrib/python/pyparsing/py3/pyparsing/helpers.py +++ b/contrib/python/pyparsing/py3/pyparsing/helpers.py @@ -782,9 +782,12 @@ def infix_notation( # if lpar and rpar are not suppressed, wrap in group if not (isinstance(lpar, Suppress) and isinstance(rpar, Suppress)): - lastExpr = base_expr | Group(lpar + ret + rpar) + lastExpr = base_expr | Group(lpar + ret + rpar).set_name( + f"nested_{base_expr.name}" + ) else: - lastExpr = base_expr | (lpar + ret + rpar) + lastExpr = base_expr | (lpar + ret + rpar).set_name(f"nested_{base_expr.name}") + root_expr = lastExpr arity: int rightLeftAssoc: opAssoc @@ -855,6 +858,7 @@ def infix_notation( thisExpr <<= (matchExpr | lastExpr).setName(term_name) lastExpr = thisExpr ret <<= lastExpr + root_expr.set_name("base_expr") return ret @@ -1049,7 +1053,7 @@ def delimited_list( ) -# pre-PEP8 compatible names +# Compatibility synonyms # fmt: off opAssoc = OpAssoc anyOpenTag = any_open_tag diff --git a/contrib/python/pyparsing/py3/pyparsing/results.py b/contrib/python/pyparsing/py3/pyparsing/results.py index 3e5fe2089b..3bb7c948e0 100644 --- a/contrib/python/pyparsing/py3/pyparsing/results.py +++ b/contrib/python/pyparsing/py3/pyparsing/results.py @@ -4,12 +4,14 @@ from collections.abc import ( Mapping, MutableSequence, Iterator, - Sequence, - Container, + Iterable, ) import pprint from typing import Tuple, Any, Dict, Set, List +from .util import replaced_by_pep8 + + str_type: Tuple[type, ...] = (str, bytes) _generator_type = type((_ for _ in ())) @@ -573,20 +575,20 @@ class ParseResults: # replace values with copies if they are of known mutable types for i, obj in enumerate(self._toklist): if isinstance(obj, ParseResults): - self._toklist[i] = obj.deepcopy() + ret._toklist[i] = obj.deepcopy() elif isinstance(obj, (str, bytes)): pass elif isinstance(obj, MutableMapping): - self._toklist[i] = dest = type(obj)() + ret._toklist[i] = dest = type(obj)() for k, v in obj.items(): dest[k] = v.deepcopy() if isinstance(v, ParseResults) else v - elif isinstance(obj, Container): - self._toklist[i] = type(obj)( + elif isinstance(obj, Iterable): + ret._toklist[i] = type(obj)( v.deepcopy() if isinstance(v, ParseResults) else v for v in obj ) return ret - def get_name(self): + def get_name(self) -> str: r""" Returns the results name for this token expression. Useful when several different expressions might match at a particular location. diff --git a/contrib/python/pyparsing/py3/pyparsing/unicode.py b/contrib/python/pyparsing/py3/pyparsing/unicode.py index 426b8b238c..0e3e06572b 100644 --- a/contrib/python/pyparsing/py3/pyparsing/unicode.py +++ b/contrib/python/pyparsing/py3/pyparsing/unicode.py @@ -53,51 +53,51 @@ class unicode_set: _ranges: UnicodeRangeList = [] @_lazyclassproperty - def _chars_for_ranges(cls): - ret = [] + def _chars_for_ranges(cls) -> List[str]: + ret: List[int] = [] for cc in cls.__mro__: if cc is unicode_set: break for rr in getattr(cc, "_ranges", ()): ret.extend(range(rr[0], rr[-1] + 1)) - return [chr(c) for c in sorted(set(ret))] + return sorted(chr(c) for c in set(ret)) @_lazyclassproperty - def printables(cls): + def printables(cls) -> str: """all non-whitespace characters in this range""" return "".join(filterfalse(str.isspace, cls._chars_for_ranges)) @_lazyclassproperty - def alphas(cls): + def alphas(cls) -> str: """all alphabetic characters in this range""" return "".join(filter(str.isalpha, cls._chars_for_ranges)) @_lazyclassproperty - def nums(cls): + def nums(cls) -> str: """all numeric digit characters in this range""" return "".join(filter(str.isdigit, cls._chars_for_ranges)) @_lazyclassproperty - def alphanums(cls): + def alphanums(cls) -> str: """all alphanumeric characters in this range""" return cls.alphas + cls.nums @_lazyclassproperty - def identchars(cls): + def identchars(cls) -> str: """all characters in this range that are valid identifier characters, plus underscore '_'""" return "".join( sorted( - set( - "".join(filter(str.isidentifier, cls._chars_for_ranges)) - + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµº" - + "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ" - + "_" + set(filter(str.isidentifier, cls._chars_for_ranges)) + | set( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzªµº" + "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ" + "_" ) ) ) @_lazyclassproperty - def identbodychars(cls): + def identbodychars(cls) -> str: """ all characters in this range that are valid identifier body characters, plus the digits 0-9, and · (Unicode MIDDLE DOT) @@ -105,7 +105,9 @@ class unicode_set: identifier_chars = set( c for c in cls._chars_for_ranges if ("_" + c).isidentifier() ) - return "".join(sorted(identifier_chars | set(cls.identchars + "0123456789·"))) + return "".join( + sorted(identifier_chars | set(cls.identchars) | set("0123456789·")) + ) @_lazyclassproperty def identifier(cls): diff --git a/contrib/python/pyparsing/py3/pyparsing/util.py b/contrib/python/pyparsing/py3/pyparsing/util.py index 4ae018a963..94837fea0f 100644 --- a/contrib/python/pyparsing/py3/pyparsing/util.py +++ b/contrib/python/pyparsing/py3/pyparsing/util.py @@ -246,7 +246,7 @@ def replaced_by_pep8(compat_name: str, fn: C) -> C: # (Presence of 'self' arg in signature is used by explain_exception() methods, so we take # some extra steps to add it if present in decorated function.) - if "self" == list(inspect.signature(fn).parameters)[0]: + if ["self"] == list(inspect.signature(fn).parameters)[:1]: @wraps(fn) def _inner(self, *args, **kwargs): diff --git a/contrib/python/pyparsing/py3/ya.make b/contrib/python/pyparsing/py3/ya.make index 9df0a0f5fa..c5575db221 100644 --- a/contrib/python/pyparsing/py3/ya.make +++ b/contrib/python/pyparsing/py3/ya.make @@ -4,7 +4,7 @@ PY3_LIBRARY() PROVIDES(pyparsing) -VERSION(3.1.2) +VERSION(3.1.4) LICENSE(MIT) |