diff options
author | Paul McGuire <ptmcg@austin.rr.com> | 2019-09-26 23:11:37 -0500 |
---|---|---|
committer | Paul McGuire <ptmcg@austin.rr.com> | 2019-09-26 23:11:37 -0500 |
commit | 30a41524ed347662e7e050cc4fd0a873932c4feb (patch) | |
tree | e23f33338ee2ca1571e62538b16c1ff89c2cf2b3 | |
parent | 76d9748718eb3fbf16b2e352fd524ae123dd9f47 (diff) | |
download | pyparsing-git-30a41524ed347662e7e050cc4fd0a873932c4feb.tar.gz |
Merge changes from master
-rw-r--r-- | examples/bigquery_view_parser.py | 19 | ||||
-rw-r--r-- | pyparsing.py | 147 | ||||
-rw-r--r-- | unitTests.py | 61 |
3 files changed, 123 insertions, 104 deletions
diff --git a/examples/bigquery_view_parser.py b/examples/bigquery_view_parser.py index 6172481..86e01e5 100644 --- a/examples/bigquery_view_parser.py +++ b/examples/bigquery_view_parser.py @@ -566,6 +566,8 @@ class BigQueryViewParser: ) ) + window_select_clause = WINDOW + identifier + AS + LPAR + window_specification + RPAR + select_core = ( SELECT + Optional(DISTINCT | ALL) @@ -581,6 +583,9 @@ class BigQueryViewParser: ORDER + BY + Group(delimitedList(ordering_term))("order_by_terms") ) + + Optional( + delimitedList(window_select_clause) + ) ) grouped_select_core = select_core | (LPAR + select_core + RPAR) @@ -1492,6 +1497,20 @@ class BigQueryViewParser: [ (None, None, 'x'), ] + ], + [ + """ + WITH x AS ( + SELECT a + FROM b + WINDOW w as (PARTITION BY a) + ) + SELECT y FROM z + """, + [ + (None, None, 'b'), + (None, None, 'z') + ] ] ] diff --git a/pyparsing.py b/pyparsing.py index 0e41493..4f0c829 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:: @@ -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 @@ -115,19 +116,10 @@ from operator import itemgetter, attrgetter import itertools from functools import wraps from itertools import filterfalse +from threading import RLock from contextlib import contextmanager import unittest -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 - class __config_flags: """Internal class for defining compatibility and debugging flags""" @@ -138,10 +130,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) @@ -229,7 +219,7 @@ __all__ = ['__version__', '__versionTime__', '__author__', '__compat__', '__diag 'stringStart', 'traceParseAction', 'unicodeString', 'withAttribute', 'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation', 'locatedExpr', 'withClass', 'CloseMatch', 'tokenMap', 'pyparsing_common', 'pyparsing_unicode', 'unicode_set', - 'conditionAsParseAction', + 'conditionAsParseAction', 'pyparsing_test', ] system_version = tuple(sys.version_info)[:3] @@ -239,7 +229,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" @@ -250,6 +240,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) @@ -379,7 +379,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) @@ -396,19 +396,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: @@ -507,7 +506,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 @@ -855,18 +854,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): """ @@ -879,13 +873,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 @@ -915,10 +902,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)): @@ -949,10 +935,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(): @@ -1100,10 +1083,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)))) @@ -1418,7 +1398,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:: @@ -1427,7 +1410,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'), @@ -1486,7 +1470,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: @@ -1503,7 +1487,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: @@ -1562,7 +1546,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) @@ -1609,8 +1593,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) @@ -1955,7 +1938,7 @@ class ParserElement(object): greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" - print (hello, "->", greet.parseString(hello)) + print(hello, "->", greet.parseString(hello)) prints:: @@ -2207,15 +2190,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 @@ -2394,12 +2377,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) @@ -2582,7 +2566,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('') @@ -3774,8 +3758,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), @@ -4021,7 +4005,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__), @@ -4118,7 +4102,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__), @@ -4427,7 +4411,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)): @@ -4560,8 +4544,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), @@ -4926,7 +4910,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__), @@ -5404,7 +5388,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)) @@ -5844,7 +5828,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() @@ -6737,11 +6721,6 @@ class pyparsing_test: """ Unit test assertion to compare a ParseResults object with an optional expected_list, and compare any defined results names with an optional expected_dict. - :param result: - :param expected_list: - :param expected_dict: - :param msg: - :return: """ if expected_list is not None: self.assertEqual(expected_list, result.asList(), msg=msg) @@ -6757,8 +6736,6 @@ class pyparsing_test: :param run_tests_report: tuple(bool, [tuple(str, ParseResults or Exception)]) returned from runTests :param expected_parse_results (optional): [tuple(str, list, dict, Exception)] - :param msg: - :return: None """ run_test_success, run_test_results = run_tests_report diff --git a/unitTests.py b/unitTests.py index fb39e08..6fb8fdd 100644 --- a/unitTests.py +++ b/unitTests.py @@ -216,7 +216,7 @@ class ParseFourFnTest(ParseTestCase): try: resultValue = fourFn.evaluate_stack(fourFn.exprStack) except Exception: - self.assertIsNone(ans, "exception raised for expression {0!r}".format(s)) + self.assertIsNone(ans, "exception raised for expression {!r}".format(s)) else: self.assertTrue(resultValue == ans, "failed to evaluate %s, got %f" % (s, resultValue)) print(s, "->", resultValue) @@ -274,12 +274,12 @@ class ParseSQLTest(ParseTestCase): sqlToks = flatten(simpleSQL.simpleSQL.parseString(s).asList()) print(s, sqlToks, len(sqlToks)) self.assertEqual(len(sqlToks), numToks, - "invalid parsed tokens, expected {0}, found {1} ({2})".format(numToks, + "invalid parsed tokens, expected {}, found {} ({})".format(numToks, len(sqlToks), sqlToks)) except ParseException as e: if errloc >= 0: - self.assertEqual(e.loc, errloc, "expected error at {0}, found at {1}".format(errloc, e.loc)) + self.assertEqual(e.loc, errloc, "expected error at {}, found at {}".format(errloc, e.loc)) test("SELECT * from XYZZY, ABC", 6) test("select * from SYS.XYZZY", 5) @@ -313,7 +313,7 @@ class ParseConfigFileTest(ParseTestCase): var = getattr(var, attr) print(chk[0], var, chk[1]) self.assertEqual(var, chk[1], - "ParseConfigFileTest: failed to parse ini {0!r} as expected {1}, found {2}".format(chk[0], + "ParseConfigFileTest: failed to parse ini {!r} as expected {}, found {}".format(chk[0], chk[1], var)) print("OK") @@ -503,7 +503,7 @@ class ParseJSONDataTest(ParseTestCase): for t, exp in zip((test1, test2, test3, test4, test5), expected): result = jsonObject.parseString(t) result.pprint() - self.assertEqual(result.asList(), exp, "failed test {0}".format(t)) + self.assertEqual(result.asList(), exp, "failed test {}".format(t)) class ParseCommaSeparatedValuesTest(ParseTestCase): def runTest(self): @@ -1797,7 +1797,7 @@ class ParseResultsWithNamedTupleTest(ParseTestCase): print(res.Achar) self.assertParseResultsEquals(res, expected_dict={'Achar': ('A', 'Z')}, msg="Failed accessing named results containing a tuple, " - "got {0!r}".format(res.Achar)) + "got {!r}".format(res.Achar)) class ParseHTMLTagsTest(ParseTestCase): @@ -2433,7 +2433,7 @@ class VariableParseActionArgsTest(ParseTestCase): "Failed to parse using variable length parse actions " "using class constructors as parse actions") -class EnablePackratParsing(TestCase): +class EnablePackratParsing(ParseTestCase): def runTest(self): from pyparsing import ParserElement ParserElement.enablePackrat() @@ -2718,10 +2718,11 @@ class ParseAllTest(ParseTestCase): ] for s, parseAllFlag, shouldSucceed in tests: try: - print("'%s' parseAll=%s (shouldSuceed=%s)" % (s, parseAllFlag, shouldSucceed)) - testExpr.parseString(s, parseAllFlag) + print("'%s' parseAll=%s (shouldSucceed=%s)" % (s, parseAllFlag, shouldSucceed)) + testExpr.parseString(s, parseAll=parseAllFlag) self.assertTrue(shouldSucceed, "successfully parsed when should have failed") except ParseException as pe: + print(pe.explain(pe)) self.assertFalse(shouldSucceed, "failed to parse when should have succeeded") # add test for trailing comments @@ -2736,11 +2737,33 @@ class ParseAllTest(ParseTestCase): for s, parseAllFlag, shouldSucceed in tests: try: print("'%s' parseAll=%s (shouldSucceed=%s)" % (s, parseAllFlag, shouldSucceed)) - testExpr.parseString(s, parseAllFlag) + testExpr.parseString(s, parseAll=parseAllFlag) + self.assertTrue(shouldSucceed, "successfully parsed when should have failed") + except ParseException as pe: + print(pe.explain(pe)) + self.assertFalse(shouldSucceed, "failed to parse when should have succeeded") + + # add test with very long expression string + # testExpr = pp.MatchFirst([pp.Literal(c) for c in pp.printables if c != 'B'])[1, ...] + anything_but_an_f = pp.OneOrMore(pp.MatchFirst([pp.Literal(c) for c in pp.printables if c != 'f'])) + testExpr = pp.Word('012') + anything_but_an_f + + tests = [ + ("00aab", False, True), + ("00aab", True, True), + ("00aaf", False, True), + ("00aaf", True, False), + ] + for s, parseAllFlag, shouldSucceed in tests: + try: + print("'%s' parseAll=%s (shouldSucceed=%s)" % (s, parseAllFlag, shouldSucceed)) + testExpr.parseString(s, parseAll=parseAllFlag) self.assertTrue(shouldSucceed, "successfully parsed when should have failed") except ParseException as pe: + print(pe.explain(pe)) self.assertFalse(shouldSucceed, "failed to parse when should have succeeded") + class GreedyQuotedStringsTest(ParseTestCase): def runTest(self): from pyparsing import QuotedString, sglQuotedString, dblQuotedString, quotedString, delimitedList @@ -2939,7 +2962,7 @@ class EachWithParseFatalExceptionTest(ParseTestCase): success, output = parser.runTests((t[0] for t in tests), failureTests=True) for test_str, result in output: self.assertEqual(test_lookup[test_str], str(result), - "incorrect exception raised for test string {0!r}".format(test_str)) + "incorrect exception raised for test string {!r}".format(test_str)) class SumParseResultsTest(ParseTestCase): def runTest(self): @@ -3200,7 +3223,7 @@ class SetNameTest(ParseTestCase): for t, e in zip(tests, expected): tname = str(t) print(tname) - self.assertEqual(tname, e, "expression name mismatch, expected {0} got {1}".format(e, tname)) + self.assertEqual(tname, e, "expression name mismatch, expected {} got {}".format(e, tname)) class TrimArityExceptionMaskingTest(ParseTestCase): def runTest(self): @@ -3412,7 +3435,7 @@ class RunTestsPostParseTest(ParseTestCase): accum = [] def eval_fraction(test, result): accum.append((test, result.asList())) - return "eval: {0}".format(result.numerator / result.denominator) + return "eval: {}".format(result.numerator / result.denominator) success = fraction.runTests("""\ 1/2 @@ -3661,7 +3684,7 @@ class NumericExpressionsTest(ParseTestCase): # success, test_results = expr.runTests(sorted(tests, key=len), failureTests=is_fail, **suppress_results) # filter_result_fn = (lambda r: isinstance(r, Exception), # lambda r: not isinstance(r, Exception))[is_fail] - # print(expr, ('FAIL', 'PASS')[success], "{1}valid tests ({0})".format(len(tests), + # print(expr, ('FAIL', 'PASS')[success], "{}valid tests ({})".format(len(tests), # 'in' if is_fail else '')) # if not success: # all_pass = False @@ -3671,7 +3694,7 @@ class NumericExpressionsTest(ParseTestCase): # test_value = fn(test_string) # except ValueError as ve: # test_value = str(ve) - # print("{0!r}: {1} {2} {3}".format(test_string, result, + # print("{!r}: {} {} {}".format(test_string, result, # expr.matches(test_string, parseAll=True), test_value)) success = True @@ -3684,8 +3707,8 @@ class NumericExpressionsTest(ParseTestCase): if not is_fail: print(t, "should not fail but did") success = False - print(expr, ('FAIL', 'PASS')[success], "{1}valid tests ({0})".format(len(tests), - 'in' if is_fail else '')) + print(expr, ('FAIL', 'PASS')[success], "{}valid tests ({})".format('in' if is_fail else '', + len(tests),)) all_pass = all_pass and success self.assertTrue(all_pass, "failed one or more numeric tests") @@ -3994,14 +4017,14 @@ class LiteralExceptionTest(ParseTestCase): for cls in (pp.Literal, pp.CaselessLiteral, pp.Keyword, pp.CaselessKeyword, pp.Word, pp.Regex): - expr = cls('xyz')#.setName('{0}_expr'.format(cls.__name__.lower())) + expr = cls('xyz')#.setName('{}_expr'.format(cls.__name__.lower())) try: expr.parseString(' ') except Exception as e: print(cls.__name__, str(e)) self.assertTrue(isinstance(e, pp.ParseBaseException), - "class {0} raised wrong exception type {1}".format(cls.__name__, type(e).__name__)) + "class {} raised wrong exception type {}".format(cls.__name__, type(e).__name__)) class ParseActionExceptionTest(ParseTestCase): def runTest(self): |