diff options
author | ptmcg <ptmcg@austin.rr.com> | 2019-09-25 18:31:22 -0500 |
---|---|---|
committer | ptmcg <ptmcg@austin.rr.com> | 2019-09-25 18:31:22 -0500 |
commit | a3c11d6054c2b84492e8551bd95b9eb936ae4aa2 (patch) | |
tree | 00daeda8b60126e3518844733360163928714b0a /pyparsing.py | |
parent | 87016995f05a0b4927eef22f767a349d85e6afd2 (diff) | |
download | pyparsing-git-a3c11d6054c2b84492e8551bd95b9eb936ae4aa2.tar.gz |
More Py2->Py3 cleanup, roll forward fix to ParserElement.__eq__
Diffstat (limited to 'pyparsing.py')
-rw-r--r-- | pyparsing.py | 141 |
1 files changed, 62 insertions, 79 deletions
diff --git a/pyparsing.py b/pyparsing.py index e47aa54..5f93a1f 100644 --- a/pyparsing.py +++ b/pyparsing.py @@ -47,7 +47,7 @@ and the strings are auto-converted to :class:`Literal` expressions):: greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" - print (hello, "->", greet.parseString(hello)) + print(hello, "->", greet.parseString(hello)) The program outputs the following:: @@ -96,7 +96,7 @@ classes inherit from. Use the docstrings for examples of how to: """ __version__ = "3.0.0a1" -__versionTime__ = "02 Sep 2019 16:36 UTC" +__versionTime__ = "25 Sep 2019 22:27 UTC" __author__ = "Paul McGuire <ptmcg@users.sourceforge.net>" import string @@ -107,6 +107,7 @@ import warnings import re import sre_constants import collections +from collections.abc import Iterable, MutableMapping, Mapping import pprint import traceback import types @@ -114,18 +115,8 @@ from datetime import datetime from operator import itemgetter, attrgetter import itertools from functools import wraps - from itertools import filterfalse - -try: - from _thread import RLock -except ImportError: - from threading import RLock - -from collections.abc import Iterable -from collections.abc import MutableMapping, Mapping -from collections import OrderedDict -from types import SimpleNamespace +from threading import RLock class __config_flags: @@ -137,10 +128,8 @@ class __config_flags: @classmethod def _set(cls, dname, value): if dname in cls._fixed_names: - warnings.warn("{}.{} {} is {} and cannot be overridden".format(cls.__name__, - dname, - cls._type_desc, - str(getattr(cls, dname)).upper())) + warnings.warn("{}.{} {} is {} and cannot be overridden".format(cls.__name__, dname, cls._type_desc, + str(getattr(cls, dname)).upper())) return if dname in cls._all_names: setattr(cls, dname, value) @@ -238,7 +227,7 @@ str_type = (str, bytes) # build list of single arg builtins, that can be used as parse actions singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max] -_generatorType = type((y for y in range(1))) +_generatorType = types.GeneratorType alphas = string.ascii_uppercase + string.ascii_lowercase nums = "0123456789" @@ -249,6 +238,16 @@ printables = "".join(c for c in string.printable if c not in string.whitespace) def conditionAsParseAction(fn, message=None, fatal=False): + """ + Function to convert a simple predicate function that returns True or False + into a parse action. Can be used in places when a parse action is required + and ParserElement.addCondition cannot be used (such as when adding a condition + to an operator level in infixNotation). + + Optional keyword arguments: + - message = define a custom message to be used in the raised exception + - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException + """ msg = message if message is not None else "failed user-defined condition" exc_type = ParseFatalException if fatal else ParseException fn = _trim_arity(fn) @@ -378,7 +377,7 @@ class ParseException(ParseBaseException): if isinstance(exc, ParseBaseException): ret.append(exc.line) ret.append(' ' * (exc.col - 1) + '^') - ret.append("{0}: {1}".format(type(exc).__name__, exc)) + ret.append("{}: {}".format(type(exc).__name__, exc)) if depth > 0: callers = inspect.getinnerframes(exc.__traceback__, context=depth) @@ -395,19 +394,18 @@ class ParseException(ParseBaseException): seen.add(f_self) self_type = type(f_self) - ret.append("{0}.{1} - {2}".format(self_type.__module__, - self_type.__name__, - f_self)) + ret.append("{}.{} - {}".format(self_type.__module__, self_type.__name__, f_self)) + elif f_self is not None: self_type = type(f_self) - ret.append("{0}.{1}".format(self_type.__module__, - self_type.__name__)) + ret.append("{}.{}".format(self_type.__module__, self_type.__name__)) + else: code = frm.f_code if code.co_name in ('wrapper', '<module>'): continue - ret.append("{0}".format(code.co_name)) + ret.append("{}".format(code.co_name)) depth -= 1 if not depth: @@ -506,7 +504,7 @@ class ParseResults(object): - year: 1999 """ def __new__(cls, toklist=None, name=None, asList=True, modal=True): - if isinstance(toklist, cls): + if isinstance(toklist, ParseResults): return toklist retobj = object.__new__(cls) retobj.__doinit = True @@ -854,18 +852,13 @@ class ParseResults(object): print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable print(json.dumps(result.asDict())) # -> {"month": "31", "day": "1999", "year": "12"} """ - item_fn = self.items - - def toItem(obj): + def to_item(obj): if isinstance(obj, ParseResults): - if obj.haskeys(): - return obj.asDict() - else: - return [toItem(v) for v in obj] + return obj.asDict() if obj.haskeys() else [to_item(v) for v in obj] else: return obj - return dict((k, toItem(v)) for k, v in item_fn()) + return dict((k, to_item(v)) for k, v in self.items()) def copy(self): """ @@ -878,13 +871,6 @@ class ParseResults(object): ret.__name = self.__name return ret - def __lookup(self, sub): - for k, vlist in self.__tokdict.items(): - for v, loc in vlist: - if sub is v: - return k - return None - def getName(self): r""" Returns the results name for this token expression. Useful when several @@ -914,10 +900,9 @@ class ParseResults(object): return self.__name elif self.__parent: par = self.__parent() - if par: - return par.__lookup(self) - else: - return None + def lookup(self, sub): + return next((k for k, vlist in par.__tokdict.items() for v, loc in vlist if sub is v), None) + return lookup(self) if par else None elif (len(self) == 1 and len(self.__tokdict) == 1 and next(iter(self.__tokdict.values()))[0][1] in (0, -1)): @@ -948,10 +933,7 @@ class ParseResults(object): """ out = [] NL = '\n' - if include_list: - out.append(indent + str(self.asList())) - else: - out.append('') + out.append(indent + str(self.asList()) if include_list else '') if full: if self.haskeys(): @@ -1099,10 +1081,7 @@ def line(loc, strg): """ lastCR = strg.rfind("\n", 0, loc) nextCR = strg.find("\n", loc) - if nextCR >= 0: - return strg[lastCR + 1:nextCR] - else: - return strg[lastCR + 1:] + return strg[lastCR + 1:nextCR] if nextCR >= 0 else strg[lastCR + 1:] def _defaultStartDebugAction(instring, loc, expr): print(("Match " + str(expr) + " at loc " + str(loc) + "(%d,%d)" % (lineno(loc, instring), col(loc, instring)))) @@ -1417,7 +1396,10 @@ class ParserElement(object): Optional keyword arguments: - message = define a custom message to be used in the raised exception - - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException + - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise + ParseException + - callDuringTry = boolean to indicate if this method should be called during internal tryParse calls, + default=False Example:: @@ -1426,7 +1408,8 @@ class ParserElement(object): year_int.addCondition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later") date_str = year_int + '/' + integer + '/' + integer - result = date_str.parseString("1999/12/31") # -> Exception: Only support years 2000 and later (at char 0), (line:1, col:1) + result = date_str.parseString("1999/12/31") # -> Exception: Only support years 2000 and later (at char 0), + (line:1, col:1) """ for fn in fns: self.parseAction.append(conditionAsParseAction(fn, message=kwargs.get('message'), @@ -1485,7 +1468,7 @@ class ParserElement(object): debugging = (self.debug) # and doActions) if debugging or self.failAction: - # ~ print ("Match", self, "at loc", loc, "(%d, %d)" % (lineno(loc, instring), col(loc, instring))) + # ~ print("Match", self, "at loc", loc, "(%d, %d)" % (lineno(loc, instring), col(loc, instring))) if self.debugActions[TRY]: self.debugActions[TRY](instring, loc, self) try: @@ -1502,7 +1485,7 @@ class ParserElement(object): else: loc, tokens = self.parseImpl(instring, preloc, doActions) except Exception as err: - # ~ print ("Exception raised:", err) + # ~ print("Exception raised:", err) if self.debugActions[FAIL]: self.debugActions[FAIL](instring, tokensStart, self, err) if self.failAction: @@ -1561,7 +1544,7 @@ class ParserElement(object): asList=self.saveAsList and isinstance(tokens, (ParseResults, list)), modal=self.modalResults) if debugging: - # ~ print ("Matched", self, "->", retTokens.asList()) + # ~ print("Matched", self, "->", retTokens.asList()) if self.debugActions[MATCH]: self.debugActions[MATCH](instring, tokensStart, loc, self, retTokens) @@ -1608,8 +1591,7 @@ class ParserElement(object): class _FifoCache(object): def __init__(self, size): self.not_in_cache = not_in_cache = object() - - cache = OrderedDict() + cache = collections.OrderedDict() def get(self, key): return cache.get(key, not_in_cache) @@ -1954,7 +1936,7 @@ class ParserElement(object): greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" - print (hello, "->", greet.parseString(hello)) + print(hello, "->", greet.parseString(hello)) prints:: @@ -2206,15 +2188,15 @@ class ParserElement(object): # convert single arg keys to tuples try: - if isinstance(key, str): + if isinstance(key, str_type): key = (key,) iter(key) except TypeError: key = (key, key) if len(key) > 2: - warnings.warn("only 1 or 2 index arguments supported ({0}{1})".format(key[:5], - '... [{0}]'.format(len(key)) + warnings.warn("only 1 or 2 index arguments supported ({}{})".format(key[:5], + '... [{}]'.format(len(key)) if len(key) > 5 else '')) # clip to 2 elements @@ -2393,12 +2375,13 @@ class ParserElement(object): raise exc def __eq__(self, other): - if isinstance(other, ParserElement): - return self is other or super().__eq__(other) + if self is other: + return True elif isinstance(other, str_type): return self.matches(other) - else: - return super().__eq__(other) + elif isinstance(other, ParserElement): + return vars(self) == vars(other) + return False def __ne__(self, other): return not (self == other) @@ -2581,7 +2564,7 @@ class ParserElement(object): out.append(result.dump()) except Exception as e: out.append(result.dump(full=fullDump)) - out.append("{0} failed: {1}: {2}".format(postParse.__name__, type(e).__name__, e)) + out.append("{} failed: {}: {}".format(postParse.__name__, type(e).__name__, e)) else: out.append(result.dump(full=fullDump)) out.append('') @@ -3773,8 +3756,8 @@ class ParseExpression(ParserElement): if __diag__.warn_ungrouped_named_tokens_in_collection: for e in self.exprs: if isinstance(e, ParserElement) and e.resultsName: - warnings.warn("{0}: setting results name {1!r} on {2} expression " - "collides with {3!r} on contained expression".format("warn_ungrouped_named_tokens_in_collection", + warnings.warn("{}: setting results name {!r} on {} expression " + "collides with {!r} on contained expression".format("warn_ungrouped_named_tokens_in_collection", name, type(self).__name__, e.resultsName), @@ -4020,7 +4003,7 @@ class Or(ParseExpression): def _setResultsName(self, name, listAllMatches=False): if __diag__.warn_multiple_tokens_in_named_alternation: if any(isinstance(e, And) for e in self.exprs): - warnings.warn("{0}: setting results name {1!r} on {2} expression " + warnings.warn("{}: setting results name {!r} on {} expression " "will return a list of all parsed tokens in an And alternative, " "in prior versions only the first token was returned".format( "warn_multiple_tokens_in_named_alternation", name, type(self).__name__), @@ -4117,7 +4100,7 @@ class MatchFirst(ParseExpression): def _setResultsName(self, name, listAllMatches=False): if __diag__.warn_multiple_tokens_in_named_alternation: if any(isinstance(e, And) for e in self.exprs): - warnings.warn("{0}: setting results name {1!r} on {2} expression " + warnings.warn("{}: setting results name {!r} on {} expression " "may only return a single token for an And alternative, " "in future will return the full list of tokens".format( "warn_multiple_tokens_in_named_alternation", name, type(self).__name__), @@ -4426,7 +4409,7 @@ class PrecededBy(ParseElementEnhance): self.mayReturnEmpty = True self.mayIndexError = False self.exact = False - if isinstance(expr, str): + if isinstance(expr, str_type): retreat = len(expr) self.exact = True elif isinstance(expr, (Literal, Keyword)): @@ -4559,8 +4542,8 @@ class _MultipleMatch(ParseElementEnhance): if __diag__.warn_ungrouped_named_tokens_in_collection: for e in [self.expr] + getattr(self.expr, 'exprs', []): if isinstance(e, ParserElement) and e.resultsName: - warnings.warn("{0}: setting results name {1!r} on {2} expression " - "collides with {3!r} on contained expression".format("warn_ungrouped_named_tokens_in_collection", + warnings.warn("{}: setting results name {!r} on {} expression " + "collides with {!r} on contained expression".format("warn_ungrouped_named_tokens_in_collection", name, type(self).__name__, e.resultsName), @@ -4925,7 +4908,7 @@ class Forward(ParseElementEnhance): def _setResultsName(self, name, listAllMatches=False): if __diag__.warn_name_set_on_empty_Forward: if self.expr is None: - warnings.warn("{0}: setting results name {0!r} on {1} expression " + warnings.warn("{}: setting results name {!r} on {} expression " "that has no contained expression".format("warn_name_set_on_empty_Forward", name, type(self).__name__), @@ -5403,7 +5386,7 @@ def oneOf(strs, caseless=False, useRegex=True, asKeyword=False): i += 1 if not (caseless or asKeyword) and useRegex: - # ~ print (strs, "->", "|".join([_escapeRegexChars(sym) for sym in symbols])) + # ~ print(strs, "->", "|".join([_escapeRegexChars(sym) for sym in symbols])) try: if len(symbols) == len("".join(symbols)): return Regex("[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols)).setName(' | '.join(symbols)) @@ -5843,7 +5826,7 @@ def withClass(classname, namespace=''): classattr = "%s:class" % namespace if namespace else "class" return withAttribute(**{classattr: classname}) -opAssoc = SimpleNamespace() +opAssoc = types.SimpleNamespace() opAssoc.LEFT = object() opAssoc.RIGHT = object() |