--- /dev/null +++ b/unitTests.py @@ -0,0 +1,4195 @@ +# -*- coding: utf-8 -*- +# +# unitTests.py +# +# Unit tests for pyparsing module +# +# Copyright 2002-2018, Paul McGuire +# +# +from unittest import TestCase, TestSuite, TextTestRunner +import datetime +from pyparsing import ParseException +import pyparsing as pp + +import sys + +PY_3 = sys.version.startswith('3') +if PY_3: + import builtins + print_ = getattr(builtins, "print") + + # catch calls to builtin print(), should be print_ + def printX(*args, **kwargs): + raise Exception("Test coding error: using print() directly, should use print_()") + globals()['print'] = printX + + from io import StringIO +else: + def _print(*args, **kwargs): + if 'end' in kwargs: + sys.stdout.write(' '.join(map(str,args)) + kwargs['end']) + else: + sys.stdout.write(' '.join(map(str,args)) + '\n') + print_ = _print + from cStringIO import StringIO + + +# see which Python implementation we are running +CPYTHON_ENV = (sys.platform == "win32") +IRON_PYTHON_ENV = (sys.platform == "cli") +JYTHON_ENV = sys.platform.startswith("java") + +TEST_USING_PACKRAT = True +#~ TEST_USING_PACKRAT = False + +VERBOSE = True + +# simple utility for flattening nested lists +def flatten(L): + if type(L) is not list: return [L] + if L == []: return L + return flatten(L[0]) + flatten(L[1:]) + +""" +class ParseTest(TestCase): + def setUp(self): + pass + + def runTest(self): + self.assertTrue(1==1, "we've got bigger problems...") + + def tearDown(self): + pass +""" + +class AutoReset(object): + def __init__(self, *args): + ob = args[0] + attrnames = args[1:] + self.ob = ob + self.save_attrs = attrnames + self.save_values = [getattr(ob, attrname) for attrname in attrnames] + + def __enter__(self): + pass + + def __exit__(self, *args): + for attr, value in zip(self.save_attrs, self.save_values): + setattr(self.ob, attr, value) + +BUFFER_OUTPUT = True + +class ParseTestCase(TestCase): + def __init__(self): + super(ParseTestCase, self).__init__(methodName='_runTest') + + def _runTest(self): + + buffered_stdout = StringIO() + + try: + with AutoReset(sys, 'stdout', 'stderr'): + try: + if BUFFER_OUTPUT: + sys.stdout = buffered_stdout + sys.stderr = buffered_stdout + print_(">>>> Starting test",str(self)) + self.runTest() + + finally: + print_("<<<< End of test",str(self)) + print_() + + except Exception as exc: + if BUFFER_OUTPUT: + print_() + print_(buffered_stdout.getvalue()) + raise + + def runTest(self): + pass + + def __str__(self): + return self.__class__.__name__ + +class PyparsingTestInit(ParseTestCase): + def setUp(self): + from pyparsing import __version__ as pyparsingVersion + print_("Beginning test of pyparsing, version", pyparsingVersion) + print_("Python version", sys.version) + def tearDown(self): + pass + +if 0: + class ParseASMLTest(ParseTestCase): + def runTest(self): + import parseASML + files = [ ("A52759.txt", 2150, True, True, 0.38, 25, "21:47:17", "22:07:32", 235), + ("24141506_P5107RM59_399A1457N1_PHS04", 373,True, True, 0.5, 1, "11:35:25", "11:37:05", 183), + ("24141506_P5107RM59_399A1457N1_PHS04B", 373, True, True, 0.5, 1, "01:02:54", "01:04:49", 186), + ("24157800_P5107RM74_399A1828M1_PHS04", 1141, True, False, 0.5, 13, "00:00:54", "23:59:48", 154) ] + for testFile,numToks,trkInpUsed,trkOutpUsed,maxDelta,numWafers,minProcBeg,maxProcEnd,maxLevStatsIV in files: + print_("Parsing",testFile,"...", end=' ') + #~ text = "\n".join( [ line for line in file(testFile) ] ) + #~ results = parseASML.BNF().parseString( text ) + results = parseASML.BNF().parseFile( testFile ) + #~ pprint.pprint( results.asList() ) + #~ pprint.pprint( results.batchData.asList() ) + #~ print results.batchData.keys() + + allToks = flatten( results.asList() ) + self.assertTrue(len(allToks) == numToks, + "wrong number of tokens parsed (%s), got %d, expected %d" % (testFile, len(allToks),numToks)) + self.assertTrue(results.batchData.trackInputUsed == trkInpUsed, "error evaluating results.batchData.trackInputUsed") + self.assertTrue(results.batchData.trackOutputUsed == trkOutpUsed, "error evaluating results.batchData.trackOutputUsed") + self.assertTrue(results.batchData.maxDelta == maxDelta,"error evaluating results.batchData.maxDelta") + self.assertTrue(len(results.waferData) == numWafers, "did not read correct number of wafers") + self.assertTrue(min([wd.procBegin for wd in results.waferData]) == minProcBeg, "error reading waferData.procBegin") + self.assertTrue(max([results.waferData[k].procEnd for k in range(len(results.waferData))]) == maxProcEnd, "error reading waferData.procEnd") + self.assertTrue(sum(results.levelStatsIV['MAX']) == maxLevStatsIV, "error reading levelStatsIV") + self.assertTrue(sum(results.levelStatsIV.MAX) == maxLevStatsIV, "error reading levelStatsIV") + print_("OK") + print_(testFile,len(allToks)) + #~ print "results.batchData.trackInputUsed =",results.batchData.trackInputUsed + #~ print "results.batchData.trackOutputUsed =",results.batchData.trackOutputUsed + #~ print "results.batchData.maxDelta =",results.batchData.maxDelta + #~ print len(results.waferData)," wafers" + #~ print min([wd.procBegin for wd in results.waferData]) + #~ print max([results.waferData[k].procEnd for k in range(len(results.waferData))]) + #~ print sum(results.levelStatsIV['MAX.']) + + +class ParseFourFnTest(ParseTestCase): + def runTest(self): + import examples.fourFn as fourFn + def test(s,ans): + fourFn.exprStack = [] + results = fourFn.BNF().parseString( s ) + resultValue = fourFn.evaluateStack( fourFn.exprStack ) + self.assertTrue(resultValue == ans, "failed to evaluate %s, got %f" % ( s, resultValue )) + print_(s, "->", resultValue) + + from math import pi,exp + e = exp(1) + + test( "9", 9 ) + test( "9 + 3 + 6", 18 ) + test( "9 + 3 / 11", 9.0+3.0/11.0) + test( "(9 + 3)", 12 ) + test( "(9+3) / 11", (9.0+3.0)/11.0 ) + test( "9 - (12 - 6)", 3) + test( "2*3.14159", 6.28318) + test( "3.1415926535*3.1415926535 / 10", 3.1415926535*3.1415926535/10.0 ) + test( "PI * PI / 10", pi*pi/10.0 ) + test( "PI*PI/10", pi*pi/10.0 ) + test( "6.02E23 * 8.048", 6.02E23 * 8.048 ) + test( "e / 3", e/3.0 ) + test( "sin(PI/2)", 1.0 ) + test( "trunc(E)", 2.0 ) + test( "E^PI", e**pi ) + test( "2^3^2", 2**3**2) + test( "2^3+2", 2**3+2) + test( "2^9", 2**9 ) + test( "sgn(-2)", -1 ) + test( "sgn(0)", 0 ) + test( "sgn(0.1)", 1 ) + +class ParseSQLTest(ParseTestCase): + def runTest(self): + import examples.simpleSQL as simpleSQL + + def test(s, numToks, errloc=-1): + try: + sqlToks = flatten(simpleSQL.simpleSQL.parseString(s).asList()) + print_(s,sqlToks,len(sqlToks)) + self.assertEqual(len(sqlToks), 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 {}, found at {}".format(errloc, e.loc)) + + test( "SELECT * from XYZZY, ABC", 6 ) + test( "select * from SYS.XYZZY", 5 ) + test( "Select A from Sys.dual", 5 ) + test( "Select A,B,C from Sys.dual", 7 ) + test( "Select A, B, C from Sys.dual", 7 ) + test( "Select A, B, C from Sys.dual, Table2 ", 8 ) + test( "Xelect A, B, C from Sys.dual", 0, 0 ) + test( "Select A, B, C frox Sys.dual", 0, 15 ) + test( "Select", 0, 6 ) + test( "Select &&& frox Sys.dual", 0, 7 ) + test( "Select A from Sys.dual where a in ('RED','GREEN','BLUE')", 12 ) + test( "Select A from Sys.dual where a in ('RED','GREEN','BLUE') and b in (10,20,30)", 20 ) + test( "Select A,b from table1,table2 where table1.id eq table2.id -- test out comparison operators", 10 ) + +class ParseConfigFileTest(ParseTestCase): + def runTest(self): + from examples import configParse + + def test(fnam,numToks,resCheckList): + print_("Parsing",fnam,"...", end=' ') + with open(fnam) as infile: + iniFileLines = "\n".join(infile.read().splitlines()) + iniData = configParse.inifile_BNF().parseString( iniFileLines ) + print_(len(flatten(iniData.asList()))) + #~ pprint.pprint( iniData.asList() ) + #~ pprint.pprint( repr(iniData) ) + #~ print len(iniData), len(flatten(iniData.asList())) + print_(list(iniData.keys())) + #~ print iniData.users.keys() + #~ print + self.assertEqual(len(flatten(iniData.asList())), numToks, "file %s not parsed correctly" % fnam) + for chk in resCheckList: + var = iniData + for attr in chk[0].split('.'): + var = getattr(var, attr) + print_(chk[0], var, chk[1]) + self.assertEqual(var, chk[1], + "ParseConfigFileTest: failed to parse ini {!r} as expected {}, found {}".format(chk[0], + chk[1], + var)) + print_("OK") + + test("test/karthik.ini", 23, + [ ("users.K","8"), + ("users.mod_scheme","'QPSK'"), + ("users.Na", "K+2") ] + ) + test("examples/Setup.ini", 125, + [ ("Startup.audioinf", "M3i"), + ("Languages.key1", "0x0003"), + ("test.foo","bar") ] ) + +class ParseJSONDataTest(ParseTestCase): + def runTest(self): + from examples.jsonParser import jsonObject + from test.jsonParserTests import test1,test2,test3,test4,test5 + from test.jsonParserTests import test1,test2,test3,test4,test5 + + expected = [ + [], + [], + [], + [], + [], + ] + + for t,exp in zip((test1,test2,test3,test4,test5),expected): + result = jsonObject.parseString(t) +## print result.dump() + result.pprint() + print_() +## if result.asList() != exp: +## print "Expected %s, parsed results as %s" % (exp, result.asList()) + +class ParseCommaSeparatedValuesTest(ParseTestCase): + def runTest(self): + from pyparsing import commaSeparatedList + + testData = [ + "a,b,c,100.2,,3", + "d, e, j k , m ", + "'Hello, World', f, g , , 5.1,x", + "John Doe, 123 Main St., Cleveland, Ohio", + "Jane Doe, 456 St. James St., Los Angeles , California ", + "", + ] + testVals = [ + [ (3,'100.2'), (4,''), (5, '3') ], + [ (2, 'j k'), (3, 'm') ], + [ (0, "'Hello, World'"), (2, 'g'), (3, '') ], + [ (0,'John Doe'), (1, '123 Main St.'), (2, 'Cleveland'), (3, 'Ohio') ], + [ (0,'Jane Doe'), (1, '456 St. James St.'), (2, 'Los Angeles'), (3, 'California') ] + ] + for line,tests in zip(testData, testVals): + print_("Parsing: \""+line+"\" ->", end=' ') + results = commaSeparatedList.parseString(line) + print_(results.asList()) + for t in tests: + if not(len(results)>t[0] and results[t[0]] == t[1]): + print_("$$$", results.dump()) + print_("$$$", results[0]) + self.assertTrue(len(results)>t[0] and results[t[0]] == t[1], + "failed on %s, item %d s/b '%s', got '%s'" % (line, t[0], t[1], str(results.asList()))) + +class ParseEBNFTest(ParseTestCase): + def runTest(self): + from examples import ebnf + from pyparsing import Word, quotedString, alphas, nums + + print_('Constructing EBNF parser with pyparsing...') + + grammar = ''' + syntax = (syntax_rule), {(syntax_rule)}; + syntax_rule = meta_identifier, '=', definitions_list, ';'; + definitions_list = single_definition, {'|', single_definition}; + single_definition = syntactic_term, {',', syntactic_term}; + syntactic_term = syntactic_factor,['-', syntactic_factor]; + syntactic_factor = [integer, '*'], syntactic_primary; + syntactic_primary = optional_sequence | repeated_sequence | + grouped_sequence | meta_identifier | terminal_string; + optional_sequence = '[', definitions_list, ']'; + repeated_sequence = '{', definitions_list, '}'; + grouped_sequence = '(', definitions_list, ')'; + (* + terminal_string = "'", character - "'", {character - "'"}, "'" | + '"', character - '"', {character - '"'}, '"'; + meta_identifier = letter, {letter | digit}; + integer = digit, {digit}; + *) + ''' + + table = {} + table['terminal_string'] = quotedString + table['meta_identifier'] = Word(alphas+"_", alphas+"_"+nums) + table['integer'] = Word(nums) + + print_('Parsing EBNF grammar with EBNF parser...') + parsers = ebnf.parse(grammar, table) + ebnf_parser = parsers['syntax'] + #~ print ",\n ".join( str(parsers.keys()).split(", ") ) + print_("-","\n- ".join( list(parsers.keys()) )) + self.assertEqual(len(list(parsers.keys())), 13, "failed to construct syntax grammar") + + print_('Parsing EBNF grammar with generated EBNF parser...') + parsed_chars = ebnf_parser.parseString(grammar) + parsed_char_len = len(parsed_chars) + + print_("],\n".join(str( parsed_chars.asList() ).split("],"))) + self.assertEqual(len(flatten(parsed_chars.asList())), 98, "failed to tokenize grammar correctly") + + +class ParseIDLTest(ParseTestCase): + def runTest(self): + from examples import idlParse + + def test( strng, numToks, errloc=0 ): + print_(strng) + try: + bnf = idlParse.CORBA_IDL_BNF() + tokens = bnf.parseString( strng ) + print_("tokens = ") + tokens.pprint() + tokens = flatten( tokens.asList() ) + print_(len(tokens)) + self.assertEqual(len(tokens), numToks, "error matching IDL string, %s -> %s" % (strng, str(tokens))) + except ParseException as err: + print_(err.line) + print_(" "*(err.column-1) + "^") + print_(err) + self.assertEqual(numToks, 0, "unexpected ParseException while parsing %s, %s" % (strng, str(err))) + self.assertEqual(err.loc, errloc, + "expected ParseException at %d, found exception at %d" % (errloc, err.loc)) + + test( + """ + /* + * a block comment * + */ + typedef string[10] tenStrings; + typedef sequence stringSeq; + typedef sequence< sequence > stringSeqSeq; + + interface QoSAdmin { + stringSeq method1( in string arg1, inout long arg2 ); + stringSeqSeq method2( in string arg1, inout long arg2, inout long arg3); + string method3(); + }; + """, 59 + ) + test( + """ + /* + * a block comment * + */ + typedef string[10] tenStrings; + typedef + /** ** *** **** * + * a block comment * + */ + sequence /*comment inside an And */ stringSeq; + /* */ /**/ /***/ /****/ + typedef sequence< sequence > stringSeqSeq; + + interface QoSAdmin { + stringSeq method1( in string arg1, inout long arg2 ); + stringSeqSeq method2( in string arg1, inout long arg2, inout long arg3); + string method3(); + }; + """, 59 + ) + test( + r""" + const string test="Test String\n"; + const long a = 0; + const long b = -100; + const float c = 3.14159; + const long d = 0x007f7f7f; + exception TestException + { + string msg; + sequence dataStrings; + }; + + interface TestInterface + { + void method1( in string arg1, inout long arg2 ); + }; + """, 60 + ) + test( + """ + module Test1 + { + exception TestException + { + string msg; + ]; + + interface TestInterface + { + void method1( in string arg1, inout long arg2 ) + raises ( TestException ); + }; + }; + """, 0, 56 + ) + test( + """ + module Test1 + { + exception TestException + { + string msg; + }; + + }; + """, 13 + ) + +class ParseVerilogTest(ParseTestCase): + def runTest(self): + pass + +class RunExamplesTest(ParseTestCase): + def runTest(self): + pass + +class ScanStringTest(ParseTestCase): + def runTest(self): + from pyparsing import Word, Combine, Suppress, CharsNotIn, nums, StringEnd + testdata = """ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameIP AddressLocation
time-a.nist.gov129.6.15.28NIST, Gaithersburg, Maryland
time-b.nist.gov129.6.15.29NIST, Gaithersburg, Maryland
time-a.timefreq.bldrdoc.gov132.163.4.101NIST, Boulder, Colorado
time-b.timefreq.bldrdoc.gov132.163.4.102NIST, Boulder, Colorado
time-c.timefreq.bldrdoc.gov132.163.4.103NIST, Boulder, Colorado
+ """ + integer = Word(nums) + ipAddress = Combine( integer + "." + integer + "." + integer + "." + integer ) + tdStart = Suppress("") + tdEnd = Suppress("") + timeServerPattern = (tdStart + ipAddress("ipAddr") + tdEnd + + tdStart + CharsNotIn("<")("loc") + tdEnd) + servers = [srvr.ipAddr for srvr,startloc,endloc in timeServerPattern.scanString( testdata )] + + print_(servers) + self.assertEqual(servers, + ['129.6.15.28', '129.6.15.29', '132.163.4.101', '132.163.4.102', '132.163.4.103'], + "failed scanString()") + + # test for stringEnd detection in scanString + foundStringEnds = [ r for r in StringEnd().scanString("xyzzy") ] + print_(foundStringEnds) + self.assertTrue(foundStringEnds, "Failed to find StringEnd in scanString") + +class QuotedStringsTest(ParseTestCase): + def runTest(self): + from pyparsing import sglQuotedString,dblQuotedString,quotedString,QuotedString + testData = \ + """ + 'a valid single quoted string' + 'an invalid single quoted string + because it spans lines' + "a valid double quoted string" + "an invalid double quoted string + because it spans lines" + """ + print_(testData) + + sglStrings = [(t[0],b,e) for (t,b,e) in sglQuotedString.scanString(testData)] + print_(sglStrings) + self.assertTrue(len(sglStrings) == 1 and (sglStrings[0][1] == 17 and sglStrings[0][2] == 47), + "single quoted string failure") + + dblStrings = [(t[0],b,e) for (t,b,e) in dblQuotedString.scanString(testData)] + print_(dblStrings) + self.assertTrue(len(dblStrings) == 1 and (dblStrings[0][1] == 154 and dblStrings[0][2] == 184), + "double quoted string failure") + + allStrings = [(t[0],b,e) for (t,b,e) in quotedString.scanString(testData)] + print_(allStrings) + self.assertTrue(len(allStrings) == 2 + and (allStrings[0][1] == 17 + and allStrings[0][2] == 47) + and (allStrings[1][1] == 154 + and allStrings[1][2] == 184), + "quoted string failure") + + escapedQuoteTest = \ + r""" + 'This string has an escaped (\') quote character' + "This string has an escaped (\") quote character" + """ + + sglStrings = [(t[0],b,e) for (t,b,e) in sglQuotedString.scanString(escapedQuoteTest)] + print_(sglStrings) + self.assertTrue(len(sglStrings) == 1 and (sglStrings[0][1]==17 and sglStrings[0][2]==66), + "single quoted string escaped quote failure (%s)" % str(sglStrings[0])) + + dblStrings = [(t[0],b,e) for (t,b,e) in dblQuotedString.scanString(escapedQuoteTest)] + print_(dblStrings) + self.assertTrue(len(dblStrings) == 1 and (dblStrings[0][1]==83 and dblStrings[0][2]==132), + "double quoted string escaped quote failure (%s)" % str(dblStrings[0])) + + allStrings = [(t[0],b,e) for (t,b,e) in quotedString.scanString(escapedQuoteTest)] + print_(allStrings) + self.assertTrue(len(allStrings) == 2 + and (allStrings[0][1] == 17 + and allStrings[0][2] == 66 + and allStrings[1][1] == 83 + and allStrings[1][2] == 132), + "quoted string escaped quote failure (%s)" % ([str(s[0]) for s in allStrings])) + + dblQuoteTest = \ + r""" + 'This string has an doubled ('') quote character' + "This string has an doubled ("") quote character" + """ + sglStrings = [(t[0],b,e) for (t,b,e) in sglQuotedString.scanString(dblQuoteTest)] + print_(sglStrings) + self.assertTrue(len(sglStrings) == 1 and (sglStrings[0][1]==17 and sglStrings[0][2]==66), + "single quoted string escaped quote failure (%s)" % str(sglStrings[0])) + dblStrings = [(t[0],b,e) for (t,b,e) in dblQuotedString.scanString(dblQuoteTest)] + print_(dblStrings) + self.assertTrue(len(dblStrings) == 1 and (dblStrings[0][1]==83 and dblStrings[0][2]==132), + "double quoted string escaped quote failure (%s)" % str(dblStrings[0])) + allStrings = [(t[0],b,e) for (t,b,e) in quotedString.scanString(dblQuoteTest)] + print_(allStrings) + self.assertTrue(len(allStrings) == 2 + and (allStrings[0][1] == 17 + and allStrings[0][2] == 66 + and allStrings[1][1] == 83 + and allStrings[1][2] == 132), + "quoted string escaped quote failure (%s)" % ([str(s[0]) for s in allStrings])) + + print_("testing catastrophic RE backtracking in implementation of dblQuotedString") + for expr, test_string in [ + (dblQuotedString, '"' + '\\xff' * 500), + (sglQuotedString, "'" + '\\xff' * 500), + (quotedString, '"' + '\\xff' * 500), + (quotedString, "'" + '\\xff' * 500), + (QuotedString('"'), '"' + '\\xff' * 500), + (QuotedString("'"), "'" + '\\xff' * 500), + ]: + expr.parseString(test_string+test_string[0]) + try: + expr.parseString(test_string) + except Exception: + continue + +class CaselessOneOfTest(ParseTestCase): + def runTest(self): + from pyparsing import oneOf,ZeroOrMore + + caseless1 = oneOf("d a b c aA B A C", caseless=True) + caseless1str = str( caseless1 ) + print_(caseless1str) + caseless2 = oneOf("d a b c Aa B A C", caseless=True) + caseless2str = str( caseless2 ) + print_(caseless2str) + self.assertEqual(caseless1str.upper(), caseless2str.upper(), "oneOf not handling caseless option properly") + self.assertNotEqual(caseless1str, caseless2str, "Caseless option properly sorted") + + res = ZeroOrMore(caseless1).parseString("AAaaAaaA") + print_(res) + self.assertEqual(len(res), 4, "caseless1 oneOf failed") + self.assertEqual("".join(res), "aA"*4,"caseless1 CaselessLiteral return failed") + + res = ZeroOrMore(caseless2).parseString("AAaaAaaA") + print_(res) + self.assertEqual(len(res), 4, "caseless2 oneOf failed") + self.assertEqual("".join(res), "Aa"*4,"caseless1 CaselessLiteral return failed") + + +class AsXMLTest(ParseTestCase): + def runTest(self): + + # test asXML() + + aaa = pp.Word("a")("A") + bbb = pp.Group(pp.Word("b"))("B") + ccc = pp.Combine(":" + pp.Word("c"))("C") + g1 = "XXX>&<" + pp.ZeroOrMore( aaa | bbb | ccc ) + teststring = "XXX>&< b b a b b a b :c b a" + #~ print teststring + print_("test including all items") + xml = g1.parseString(teststring).asXML("TEST",namedItemsOnly=False) + assert xml=="\n".join(["", + "", + " XXX>&<", + " ", + " b", + " ", + " ", + " b", + " ", + " a", + " ", + " b", + " ", + " ", + " b", + " ", + " a", + " ", + " b", + " ", + " :c", + " ", + " b", + " ", + " a", + "", + ] ), \ + "failed to generate XML correctly showing all items: \n[" + xml + "]" + print_("test filtering unnamed items") + xml = g1.parseString(teststring).asXML("TEST",namedItemsOnly=True) + assert xml=="\n".join(["", + "", + " ", + " b", + " ", + " ", + " b", + " ", + " a", + " ", + " b", + " ", + " ", + " b", + " ", + " a", + " ", + " b", + " ", + " :c", + " ", + " b", + " ", + " a", + "", + ] ), \ + "failed to generate XML correctly, filtering unnamed items: " + xml + +class AsXMLTest2(ParseTestCase): + def runTest(self): + from pyparsing import Suppress,Optional,CharsNotIn,Combine,ZeroOrMore,Word,\ + Group,Literal,alphas,alphanums,delimitedList,OneOrMore + + EndOfLine = Word("\n").setParseAction(lambda s,l,t: [' ']) + whiteSpace=Word('\t ') + Mexpr = Suppress(Optional(whiteSpace)) + CharsNotIn('\\"\t \n') + Optional(" ") + \ + Suppress(Optional(whiteSpace)) + reducedString = Combine(Mexpr + ZeroOrMore(EndOfLine + Mexpr)) + _bslash = "\\" + _escapables = "tnrfbacdeghijklmopqsuvwxyz" + _bslash + "'" + '"' + _octDigits = "01234567" + _escapedChar = ( Word( _bslash, _escapables, exact=2 ) | + Word( _bslash, _octDigits, min=2, max=4 ) ) + _sglQuote = Literal("'") + _dblQuote = Literal('"') + QuotedReducedString = Combine( Suppress(_dblQuote) + ZeroOrMore( reducedString | + _escapedChar ) + \ + Suppress(_dblQuote )).streamline() + + Manifest_string = QuotedReducedString('manifest_string') + + Identifier = Word( alphas, alphanums+ '_$' )("identifier") + Index_string = CharsNotIn('\\";\n') + Index_string.setName('index_string') + Index_term_list = ( + Group(delimitedList(Manifest_string, delim=',')) | \ + Index_string + )('value') + + IndexKey = Identifier('key') + IndexKey.setName('key') + Index_clause = Group(IndexKey + Suppress(':') + Optional(Index_term_list)) + Index_clause.setName('index_clause') + Index_list = Index_clause('index') + Index_list.setName('index_list') + Index_block = Group('indexing' + Group(OneOrMore(Index_list + Suppress(';'))))('indexes') + + +class CommentParserTest(ParseTestCase): + def runTest(self): + + print_("verify processing of C and HTML comments") + testdata = """ + /* */ + /** **/ + /**/ + /***/ + /****/ + /* /*/ + /** /*/ + /*** /*/ + /* + ablsjdflj + */ + """ + foundLines = [ pp.lineno(s,testdata) + for t,s,e in pp.cStyleComment.scanString(testdata) ] + self.assertEqual(foundLines, list(range(11))[2:],"only found C comments on lines "+str(foundLines)) + testdata = """ + + + + + + + + + + """ + foundLines = [ pp.lineno(s,testdata) + for t,s,e in pp.htmlComment.scanString(testdata) ] + self.assertEqual(foundLines, list(range(11))[2:],"only found HTML comments on lines "+str(foundLines)) + + # test C++ single line comments that have line terminated with '\' (should continue comment to following line) + testSource = r""" + // comment1 + // comment2 \ + still comment 2 + // comment 3 + """ + self.assertEqual(len(pp.cppStyleComment.searchString(testSource)[1][0]), 41, + r"failed to match single-line comment with '\' at EOL") + +class ParseExpressionResultsTest(ParseTestCase): + def runTest(self): + from pyparsing import Word,alphas,OneOrMore,Optional,Group + + a = Word("a",alphas).setName("A") + b = Word("b",alphas).setName("B") + c = Word("c",alphas).setName("C") + ab = (a + b).setName("AB") + abc = (ab + c).setName("ABC") + word = Word(alphas).setName("word") + + #~ words = OneOrMore(word).setName("words") + words = Group(OneOrMore(~a + word)).setName("words") + + #~ phrase = words.setResultsName("Head") + \ + #~ ( abc ^ ab ^ a ).setResultsName("ABC") + \ + #~ words.setResultsName("Tail") + #~ phrase = words.setResultsName("Head") + \ + #~ ( abc | ab | a ).setResultsName("ABC") + \ + #~ words.setResultsName("Tail") + phrase = words("Head") + \ + Group( a + Optional(b + Optional(c)) )("ABC") + \ + words("Tail") + + results = phrase.parseString("xavier yeti alpha beta charlie will beaver") + print_(results,results.Head, results.ABC,results.Tail) + for key,ln in [("Head",2), ("ABC",3), ("Tail",2)]: + self.assertEqual(len(results[key]), ln, + "expected %d elements in %s, found %s" % (ln, key, str(results[key]))) + + +class ParseKeywordTest(ParseTestCase): + def runTest(self): + from pyparsing import Literal,Keyword + + kw = Keyword("if") + lit = Literal("if") + + def test(s,litShouldPass,kwShouldPass): + print_("Test",s) + print_("Match Literal", end=' ') + try: + print_(lit.parseString(s)) + except Exception: + print_("failed") + if litShouldPass: + self.assertTrue(False, "Literal failed to match %s, should have" % s) + else: + if not litShouldPass: + self.assertTrue(False, "Literal matched %s, should not have" % s) + + print_("Match Keyword", end=' ') + try: + print_(kw.parseString(s)) + except Exception: + print_("failed") + if kwShouldPass: + self.assertTrue(False, "Keyword failed to match %s, should have" % s) + else: + if not kwShouldPass: + self.assertTrue(False, "Keyword matched %s, should not have" % s) + + test("ifOnlyIfOnly", True, False) + test("if(OnlyIfOnly)", True, True) + test("if (OnlyIf Only)", True, True) + + kw = Keyword("if",caseless=True) + + test("IFOnlyIfOnly", False, False) + test("If(OnlyIfOnly)", False, True) + test("iF (OnlyIf Only)", False, True) + + + +class ParseExpressionResultsAccumulateTest(ParseTestCase): + def runTest(self): + from pyparsing import Word,delimitedList,Combine,alphas,nums + + num=Word(nums).setName("num")("base10*") + hexnum=Combine("0x"+ Word(nums)).setName("hexnum")("hex*") + name = Word(alphas).setName("word")("word*") + list_of_num=delimitedList( hexnum | num | name, "," ) + + tokens = list_of_num.parseString('1, 0x2, 3, 0x4, aaa') + for k,llen,lst in ( ("base10",2,['1','3']), + ("hex",2,['0x2','0x4']), + ("word",1,['aaa']) ): + print_(k,tokens[k]) + self.assertEqual(len(tokens[k]), llen, "Wrong length for key %s, %s" % (k,str(tokens[k].asList()))) + self.assertEqual(lst, tokens[k].asList(), + "Incorrect list returned for key %s, %s" % (k,str(tokens[k].asList()))) + self.assertEqual(tokens.base10.asList(), ['1','3'], + "Incorrect list for attribute base10, %s" % str(tokens.base10.asList())) + self.assertEqual(tokens.hex.asList(), ['0x2','0x4'], + "Incorrect list for attribute hex, %s" % str(tokens.hex.asList())) + self.assertEqual(tokens.word.asList(), ['aaa'], + "Incorrect list for attribute word, %s" % str(tokens.word.asList())) + + from pyparsing import Literal, Word, nums, Group, Dict, alphas, \ + quotedString, oneOf, delimitedList, removeQuotes, alphanums + + lbrack = Literal("(").suppress() + rbrack = Literal(")").suppress() + integer = Word( nums ).setName("int") + variable = Word( alphas, max=1 ).setName("variable") + relation_body_item = variable | integer | quotedString.copy().setParseAction(removeQuotes) + relation_name = Word( alphas+"_", alphanums+"_" ) + relation_body = lbrack + Group(delimitedList(relation_body_item)) + rbrack + Goal = Dict(Group( relation_name + relation_body )) + Comparison_Predicate = Group(variable + oneOf("< >") + integer)("pred*") + Query = Goal("head") + ":-" + delimitedList(Goal | Comparison_Predicate) + + test="""Q(x,y,z):-Bloo(x,"Mitsis",y),Foo(y,z,1243),y>28,x<12,x>3""" + + queryRes = Query.parseString(test) + print_("pred",queryRes.pred) + self.assertEqual(queryRes.pred.asList(), [['y', '>', '28'], ['x', '<', '12'], ['x', '>', '3']], + "Incorrect list for attribute pred, %s" % str(queryRes.pred.asList())) + print_(queryRes.dump()) + +class ReStringRangeTest(ParseTestCase): + def runTest(self): + testCases = ( + (r"[A-Z]"), + (r"[A-A]"), + (r"[A-Za-z]"), + (r"[A-z]"), + (r"[\ -\~]"), + (r"[\0x20-0]"), + (r"[\0x21-\0x7E]"), + (r"[\0xa1-\0xfe]"), + (r"[\040-0]"), + (r"[A-Za-z0-9]"), + (r"[A-Za-z0-9_]"), + (r"[A-Za-z0-9_$]"), + (r"[A-Za-z0-9_$\-]"), + (r"[^0-9\\]"), + (r"[a-zA-Z]"), + (r"[/\^~]"), + (r"[=\+\-!]"), + (r"[A-]"), + (r"[-A]"), + (r"[\x21]"), + #(r"[а-яА-ЯёЁA-Z$_\041α-ω]".decode('utf-8')), + (u'[\u0430-\u044f\u0410-\u042f\u0451\u0401ABCDEFGHIJKLMNOPQRSTUVWXYZ$_\041\u03b1-\u03c9]'), + ) + expectedResults = ( + "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "A", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz", + " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", + " !\"#$%&'()*+,-./0", + "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~", + #~ "¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ", + u'\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe', + " !\"#$%&'()*+,-./0", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$-", + "0123456789\\", + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + "/^~", + "=+-!", + "A-", + "-A", + "!", + u"абвгдежзийклмнопрстуфхцчшщъыьэюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯёЁABCDEFGHIJKLMNOPQRSTUVWXYZ$_!αβγδεζηθικλμνξοπρςστυφχψω", + ) + for test in zip( testCases, expectedResults ): + t,exp = test + res = pp.srange(t) + #print_(t,"->",res) + self.assertEqual(res, exp, "srange error, srange(%r)->'%r', expected '%r'" % (t, res, exp)) + +class SkipToParserTests(ParseTestCase): + def runTest(self): + + from pyparsing import Literal, SkipTo, cStyleComment, ParseBaseException + + thingToFind = Literal('working') + testExpr = SkipTo(Literal(';'), include=True, ignore=cStyleComment) + thingToFind + + def tryToParse (someText, fail_expected=False): + try: + print_(testExpr.parseString(someText)) + self.assertFalse(fail_expected, "expected failure but no exception raised") + except Exception as e: + print_("Exception %s while parsing string %s" % (e,repr(someText))) + self.assertTrue(fail_expected and isinstance(e,ParseBaseException), + "Exception %s while parsing string %s" % (e,repr(someText))) + + # This first test works, as the SkipTo expression is immediately following the ignore expression (cStyleComment) + tryToParse('some text /* comment with ; in */; working') + # This second test previously failed, as there is text following the ignore expression, and before the SkipTo expression. + tryToParse('some text /* comment with ; in */some other stuff; working') + + # tests for optional failOn argument + testExpr = SkipTo(Literal(';'), include=True, ignore=cStyleComment, failOn='other') + thingToFind + tryToParse('some text /* comment with ; in */; working') + tryToParse('some text /* comment with ; in */some other stuff; working', fail_expected=True) + + # test that we correctly create named results + text = "prefixDATAsuffix" + data = Literal("DATA") + suffix = Literal("suffix") + expr = SkipTo(data + suffix)('prefix') + data + suffix + result = expr.parseString(text) + self.assertTrue(isinstance(result.prefix, str), "SkipTo created with wrong saveAsList attribute") + +class CustomQuotesTest(ParseTestCase): + def runTest(self): + from pyparsing import QuotedString + + testString = r""" + sdlfjs :sdf\:jls::djf: sl:kfsjf + sdlfjs -sdf\:jls::--djf: sl-kfsjf + sdlfjs -sdf\:::jls::--djf: sl:::-kfsjf + sdlfjs ^sdf\:jls^^--djf^ sl-kfsjf + sdlfjs ^^^==sdf\:j=lz::--djf: sl=^^=kfsjf + sdlfjs ==sdf\:j=ls::--djf: sl==kfsjf^^^ + """ + colonQuotes = QuotedString(':','\\','::') + dashQuotes = QuotedString('-','\\', '--') + hatQuotes = QuotedString('^','\\') + hatQuotes1 = QuotedString('^','\\','^^') + dblEqQuotes = QuotedString('==','\\') + + def test(quoteExpr, expected): + print_(quoteExpr.pattern) + print_(quoteExpr.searchString(testString)) + print_(quoteExpr.searchString(testString)[0][0]) + print_(expected) + self.assertEqual(quoteExpr.searchString(testString)[0][0], + expected, + "failed to match %s, expected '%s', got '%s'" % (quoteExpr, expected, + quoteExpr.searchString(testString)[0])) + print_() + + test(colonQuotes, r"sdf:jls:djf") + test(dashQuotes, r"sdf:jls::-djf: sl") + test(hatQuotes, r"sdf:jls") + test(hatQuotes1, r"sdf:jls^--djf") + test(dblEqQuotes, r"sdf:j=ls::--djf: sl") + test(QuotedString(':::'), 'jls::--djf: sl') + test(QuotedString('==',endQuoteChar='--'), r'sdf\:j=lz::') + test(QuotedString('^^^',multiline=True), r"""==sdf\:j=lz::--djf: sl=^^=kfsjf + sdlfjs ==sdf\:j=ls::--djf: sl==kfsjf""") + try: + bad1 = QuotedString('','\\') + except SyntaxError as se: + pass + else: + self.assertTrue(False,"failed to raise SyntaxError with empty quote string") + +class RepeaterTest(ParseTestCase): + def runTest(self): + from pyparsing import matchPreviousLiteral,matchPreviousExpr, Word, nums, ParserElement + + if ParserElement._packratEnabled: + print_("skipping this test, not compatible with packratting") + return + + first = Word("abcdef").setName("word1") + bridge = Word(nums).setName("number") + second = matchPreviousLiteral(first).setName("repeat(word1Literal)") + + seq = first + bridge + second + + tests = [ + ( "abc12abc", True ), + ( "abc12aabc", False ), + ( "abc12cba", True ), + ( "abc12bca", True ), + ] + + for tst,result in tests: + found = False + for tokens,start,end in seq.scanString(tst): + f,b,s = tokens + print_(f,b,s) + found = True + if not found: + print_("No literal match in", tst) + self.assertEqual(found, result, "Failed repeater for test: %s, matching %s" % (tst, str(seq))) + print_() + + # retest using matchPreviousExpr instead of matchPreviousLiteral + second = matchPreviousExpr(first).setName("repeat(word1expr)") + seq = first + bridge + second + + tests = [ + ( "abc12abc", True ), + ( "abc12cba", False ), + ( "abc12abcdef", False ), + ] + + for tst,result in tests: + found = False + for tokens,start,end in seq.scanString(tst): + print_(tokens.asList()) + found = True + if not found: + print_("No expression match in", tst) + self.assertEqual(found, result, "Failed repeater for test: %s, matching %s" % (tst, str(seq))) + + print_() + + first = Word("abcdef").setName("word1") + bridge = Word(nums).setName("number") + second = matchPreviousExpr(first).setName("repeat(word1)") + seq = first + bridge + second + csFirst = seq.setName("word-num-word") + csSecond = matchPreviousExpr(csFirst) + compoundSeq = csFirst + ":" + csSecond + compoundSeq.streamline() + print_(compoundSeq) + + tests = [ + ( "abc12abc:abc12abc", True ), + ( "abc12cba:abc12abc", False ), + ( "abc12abc:abc12abcdef", False ), + ] + + #~ for tst,result in tests: + #~ print tst, + #~ try: + #~ compoundSeq.parseString(tst) + #~ print "MATCH" + #~ assert result, "matched when shouldn't have matched" + #~ except ParseException: + #~ print "NO MATCH" + #~ assert not result, "didnt match but should have" + + #~ for tst,result in tests: + #~ print tst, + #~ if compoundSeq == tst: + #~ print "MATCH" + #~ assert result, "matched when shouldn't have matched" + #~ else: + #~ print "NO MATCH" + #~ assert not result, "didnt match but should have" + + for tst,result in tests: + found = False + for tokens,start,end in compoundSeq.scanString(tst): + print_("match:", tokens.asList()) + found = True + break + if not found: + print_("No expression match in", tst) + self.assertEqual(found, result, "Failed repeater for test: %s, matching %s" % (tst, str(seq))) + + print_() + eFirst = Word(nums) + eSecond = matchPreviousExpr(eFirst) + eSeq = eFirst + ":" + eSecond + + tests = [ + ( "1:1A", True ), + ( "1:10", False ), + ] + + for tst,result in tests: + found = False + for tokens,start,end in eSeq.scanString(tst): + #~ f,b,s = tokens + #~ print f,b,s + print_(tokens.asList()) + found = True + if not found: + print_("No match in", tst) + self.assertEqual(found, result, "Failed repeater for test: %s, matching %s" % (tst, str(seq))) + +class RecursiveCombineTest(ParseTestCase): + def runTest(self): + from pyparsing import Forward,Word,alphas,nums,Optional,Combine + + testInput = "myc(114)r(11)dd" + Stream=Forward() + Stream << Optional(Word(alphas))+Optional("("+Word(nums)+")"+Stream) + expected = Stream.parseString(testInput).asList() + print_(["".join(expected)]) + + Stream=Forward() + Stream << Combine(Optional(Word(alphas))+Optional("("+Word(nums)+")"+Stream)) + testVal = Stream.parseString(testInput).asList() + print_(testVal) + + self.assertEqual("".join(testVal), "".join(expected), "Failed to process Combine with recursive content") + +class InfixNotationGrammarTest1(ParseTestCase): + def runTest(self): + from pyparsing import Word,nums,alphas,Literal,oneOf,infixNotation,opAssoc + import ast + + integer = Word(nums).setParseAction(lambda t:int(t[0])) + variable = Word(alphas,exact=1) + operand = integer | variable + + expop = Literal('^') + signop = oneOf('+ -') + multop = oneOf('* /') + plusop = oneOf('+ -') + factop = Literal('!') + + expr = infixNotation( operand, + [("!", 1, opAssoc.LEFT), + ("^", 2, opAssoc.RIGHT), + (signop, 1, opAssoc.RIGHT), + (multop, 2, opAssoc.LEFT), + (plusop, 2, opAssoc.LEFT),] + ) + + test = ["9 + 2 + 3", + "9 + 2 * 3", + "(9 + 2) * 3", + "(9 + -2) * 3", + "(9 + --2) * 3", + "(9 + -2) * 3^2^2", + "(9! + -2) * 3^2^2", + "M*X + B", + "M*(X + B)", + "1+2*-3^4*5+-+-6", + "3!!"] + expected = """[[9, '+', 2, '+', 3]] + [[9, '+', [2, '*', 3]]] + [[[9, '+', 2], '*', 3]] + [[[9, '+', ['-', 2]], '*', 3]] + [[[9, '+', ['-', ['-', 2]]], '*', 3]] + [[[9, '+', ['-', 2]], '*', [3, '^', [2, '^', 2]]]] + [[[[9, '!'], '+', ['-', 2]], '*', [3, '^', [2, '^', 2]]]] + [[['M', '*', 'X'], '+', 'B']] + [['M', '*', ['X', '+', 'B']]] + [[1, '+', [2, '*', ['-', [3, '^', 4]], '*', 5], '+', ['-', ['+', ['-', 6]]]]] + [[3, '!', '!']]""".split('\n') + expected = [ast.literal_eval(x.strip()) for x in expected] + for t,e in zip(test,expected): + print_(t,"->",e, "got", expr.parseString(t).asList()) + self.assertEqual(expr.parseString(t).asList(), e, + "mismatched results for infixNotation: got %s, expected %s" % (expr.parseString(t).asList(),e)) + +class InfixNotationGrammarTest2(ParseTestCase): + def runTest(self): + + from pyparsing import infixNotation, Word, alphas, oneOf, opAssoc + + boolVars = { "True":True, "False":False } + class BoolOperand(object): + reprsymbol = '' + def __init__(self,t): + self.args = t[0][0::2] + def __str__(self): + sep = " %s " % self.reprsymbol + return "(" + sep.join(map(str,self.args)) + ")" + + class BoolAnd(BoolOperand): + reprsymbol = '&' + def __bool__(self): + for a in self.args: + if isinstance(a,str): + v = boolVars[a] + else: + v = bool(a) + if not v: + return False + return True + + class BoolOr(BoolOperand): + reprsymbol = '|' + def __bool__(self): + for a in self.args: + if isinstance(a,str): + v = boolVars[a] + else: + v = bool(a) + if v: + return True + return False + + class BoolNot(BoolOperand): + def __init__(self,t): + self.arg = t[0][1] + def __str__(self): + return "~" + str(self.arg) + def __bool__(self): + if isinstance(self.arg,str): + v = boolVars[self.arg] + else: + v = bool(self.arg) + return not v + + boolOperand = Word(alphas,max=1) | oneOf("True False") + boolExpr = infixNotation( boolOperand, + [ + ("not", 1, opAssoc.RIGHT, BoolNot), + ("and", 2, opAssoc.LEFT, BoolAnd), + ("or", 2, opAssoc.LEFT, BoolOr), + ]) + test = ["p and not q", + "not not p", + "not(p and q)", + "q or not p and r", + "q or not p or not r", + "q or not (p and r)", + "p or q or r", + "p or q or r and False", + "(p or q or r) and False", + ] + + boolVars["p"] = True + boolVars["q"] = False + boolVars["r"] = True + print_("p =", boolVars["p"]) + print_("q =", boolVars["q"]) + print_("r =", boolVars["r"]) + print_() + for t in test: + res = boolExpr.parseString(t)[0] + print_(t,'\n', res, '=', bool(res),'\n') + + +class InfixNotationGrammarTest3(ParseTestCase): + def runTest(self): + + from pyparsing import infixNotation, Word, alphas, oneOf, opAssoc, nums, Literal + + global count + count = 0 + + def evaluate_int(t): + global count + value = int(t[0]) + print_("evaluate_int", value) + count += 1 + return value + + integer = Word(nums).setParseAction(evaluate_int) + variable = Word(alphas,exact=1) + operand = integer | variable + + expop = Literal('^') + signop = oneOf('+ -') + multop = oneOf('* /') + plusop = oneOf('+ -') + factop = Literal('!') + + expr = infixNotation( operand, + [ + ("!", 1, opAssoc.LEFT), + ("^", 2, opAssoc.LEFT), + (signop, 1, opAssoc.RIGHT), + (multop, 2, opAssoc.LEFT), + (plusop, 2, opAssoc.LEFT), + ]) + + test = ["9"] + for t in test: + count = 0 + print_("%r => %s (count=%d)" % (t, expr.parseString(t), count)) + self.assertEqual(count, 1, "count evaluated too many times!") + +class InfixNotationGrammarTest4(ParseTestCase): + def runTest(self): + + word = pp.Word(pp.alphas) + + def supLiteral(s): + """Returns the suppressed literal s""" + return pp.Literal(s).suppress() + + def booleanExpr(atom): + ops = [ + (supLiteral("!"), 1, pp.opAssoc.RIGHT, lambda s, l, t: ["!", t[0][0]]), + (pp.oneOf("= !="), 2, pp.opAssoc.LEFT, ), + (supLiteral("&"), 2, pp.opAssoc.LEFT, lambda s, l, t: ["&", t[0]]), + (supLiteral("|"), 2, pp.opAssoc.LEFT, lambda s, l, t: ["|", t[0]])] + return pp.infixNotation(atom, ops) + + f = booleanExpr(word) + pp.StringEnd() + + tests = [ + ("bar = foo", "[['bar', '=', 'foo']]"), + ("bar = foo & baz = fee", "['&', [['bar', '=', 'foo'], ['baz', '=', 'fee']]]"), + ] + for test,expected in tests: + print_(test) + results = f.parseString(test) + print_(results) + self.assertEqual(str(results), expected, "failed to match expected results, got '%s'" % str(results)) + print_() + +class InfixNotationGrammarTest5(ParseTestCase): + + def runTest(self): + from pyparsing import infixNotation, opAssoc, pyparsing_common, Literal, oneOf + + expop = Literal('**') + signop = oneOf('+ -') + multop = oneOf('* /') + plusop = oneOf('+ -') + + class ExprNode(object): + def __init__(self, tokens): + self.tokens = tokens[0] + + def eval(self): + return None + + class NumberNode(ExprNode): + def eval(self): + return self.tokens + + class SignOp(ExprNode): + def eval(self): + mult = {'+': 1, '-': -1}[self.tokens[0]] + return mult * self.tokens[1].eval() + + class BinOp(ExprNode): + def eval(self): + ret = self.tokens[0].eval() + for op, operand in zip(self.tokens[1::2], self.tokens[2::2]): + ret = self.opn_map[op](ret, operand.eval()) + return ret + + class ExpOp(BinOp): + opn_map = {'**': lambda a, b: b ** a} + + class MultOp(BinOp): + import operator + opn_map = {'*': operator.mul, '/': operator.truediv} + + class AddOp(BinOp): + import operator + opn_map = {'+': operator.add, '-': operator.sub} + + from pyparsing import pyparsing_common, infixNotation + + operand = pyparsing_common.number().setParseAction(NumberNode) + expr = infixNotation(operand, + [ + (expop, 2, opAssoc.LEFT, (lambda pr: [pr[0][::-1]], ExpOp)), + (signop, 1, opAssoc.RIGHT, SignOp), + (multop, 2, opAssoc.LEFT, MultOp), + (plusop, 2, opAssoc.LEFT, AddOp), + ]) + + tests = """\ + 2+7 + 2**3 + 2**3**2 + 3**9 + 3**3**2 + """ + + for t in tests.splitlines(): + t = t.strip() + if not t: + continue + + parsed = expr.parseString(t) + eval_value = parsed[0].eval() + self.assertEqual(eval_value, eval(t), + "Error evaluating %r, expected %r, got %r" % (t, eval(t), eval_value)) + + +class PickleTest_Greeting(): + def __init__(self, toks): + self.salutation = toks[0] + self.greetee = toks[1] + + def __repr__(self): + return "%s: {%s}" % (self.__class__.__name__, + ', '.join('%r: %r' % (k, getattr(self,k)) for k in sorted(self.__dict__))) + +class ParseResultsPickleTest(ParseTestCase): + def runTest(self): + from pyparsing import makeHTMLTags, ParseResults + import pickle + + # test 1 + body = makeHTMLTags("BODY")[0] + result = body.parseString("") + if VERBOSE: + print_(result.dump()) + print_() + + for protocol in range(pickle.HIGHEST_PROTOCOL+1): + print_("Test pickle dump protocol", protocol) + try: + pickleString = pickle.dumps(result, protocol) + except Exception as e: + print_("dumps exception:", e) + newresult = ParseResults() + else: + newresult = pickle.loads(pickleString) + if VERBOSE: + print_(newresult.dump()) + print_() + + self.assertEqual(result.dump(), newresult.dump(), + "Error pickling ParseResults object (protocol=%d)" % protocol) + + # test 2 + import pyparsing as pp + + word = pp.Word(pp.alphas+"'.") + salutation = pp.OneOrMore(word) + comma = pp.Literal(",") + greetee = pp.OneOrMore(word) + endpunc = pp.oneOf("! ?") + greeting = salutation + pp.Suppress(comma) + greetee + pp.Suppress(endpunc) + greeting.setParseAction(PickleTest_Greeting) + + string = 'Good morning, Miss Crabtree!' + + result = greeting.parseString(string) + + for protocol in range(pickle.HIGHEST_PROTOCOL+1): + print_("Test pickle dump protocol", protocol) + try: + pickleString = pickle.dumps(result, protocol) + except Exception as e: + print_("dumps exception:", e) + newresult = ParseResults() + else: + newresult = pickle.loads(pickleString) + print_(newresult.dump()) + self.assertEqual(newresult.dump(), result.dump(), + "failed to pickle/unpickle ParseResults: expected %r, got %r" % (result, newresult)) + +class ParseResultsWithNamedTupleTest(ParseTestCase): + def runTest(self): + + from pyparsing import Literal,replaceWith + + expr = Literal("A")("Achar") + expr.setParseAction(replaceWith(tuple(["A","Z"]))) + + res = expr.parseString("A") + print_(repr(res)) + print_(res.Achar) + self.assertEqual(res.Achar, ("A","Z"), + "Failed accessing named results containing a tuple, got {!r}".format(res.Achar)) + + +class ParseHTMLTagsTest(ParseTestCase): + def runTest(self): + test = """ + + + + + + + """ + results = [ + ("startBody", False, "", ""), + ("startBody", False, "#00FFCC", ""), + ("startBody", True, "#00FFAA", ""), + ("startBody", False, "#00FFBB", "black"), + ("startBody", True, "", ""), + ("endBody", False, "", ""), + ] + + bodyStart, bodyEnd = pp.makeHTMLTags("BODY") + resIter = iter(results) + for t,s,e in (bodyStart | bodyEnd).scanString( test ): + print_(test[s:e], "->", t.asList()) + (expectedType, expectedEmpty, expectedBG, expectedFG) = next(resIter) + + tType = t.getName() + #~ print tType,"==",expectedType,"?" + self.assertTrue(tType in "startBody endBody".split(), "parsed token of unknown type '%s'" % tType) + self.assertEqual(tType, expectedType, "expected token of type %s, got %s" % (expectedType, tType)) + if tType == "startBody": + self.assertEqual(bool(t.empty), expectedEmpty, + "expected %s token, got %s" % (expectedEmpty and "empty" or "not empty", + t.empty and "empty" or "not empty")) + self.assertEqual(t.bgcolor, expectedBG, + "failed to match BGCOLOR, expected %s, got %s" % (expectedBG, t.bgcolor)) + self.assertEqual(t.fgcolor, expectedFG, + "failed to match FGCOLOR, expected %s, got %s" % (expectedFG, t.bgcolor)) + elif tType == "endBody": + #~ print "end tag" + pass + else: + print_("BAD!!!") + +class UpcaseDowncaseUnicode(ParseTestCase): + def runTest(self): + + import pyparsing as pp + import sys + if PY_3: + unichr = chr + else: + from __builtin__ import unichr + + a = u'\u00bfC\u00f3mo esta usted?' + if not JYTHON_ENV: + ualphas = pp.pyparsing_unicode.alphas + else: + ualphas = "".join( unichr(i) for i in list(range(0xd800)) + list(range(0xe000,sys.maxunicode)) + if unichr(i).isalpha() ) + uword = pp.Word(ualphas).setParseAction(pp.upcaseTokens) + + print_ = lambda *args: None + print_(uword.searchString(a)) + + uword = pp.Word(ualphas).setParseAction(pp.downcaseTokens) + + print_(uword.searchString(a)) + + kw = pp.Keyword('mykey', caseless=True).setParseAction(pp.upcaseTokens)('rname') + ret = kw.parseString('mykey') + print_(ret.rname) + self.assertEqual(ret.rname, 'MYKEY', "failed to upcase with named result") + + kw = pp.Keyword('mykey', caseless=True).setParseAction(pp.pyparsing_common.upcaseTokens)('rname') + ret = kw.parseString('mykey') + print_(ret.rname) + self.assertEqual(ret.rname, 'MYKEY', "failed to upcase with named result (pyparsing_common)") + + kw = pp.Keyword('MYKEY', caseless=True).setParseAction(pp.pyparsing_common.downcaseTokens)('rname') + ret = kw.parseString('mykey') + print_(ret.rname) + self.assertEqual(ret.rname, 'mykey', "failed to upcase with named result") + + if not IRON_PYTHON_ENV: + #test html data + html = u" \ + Производитель, модель \ + BenQ-Siemens CF61 \ + "#.decode('utf-8') + + # u'Manufacturer, model + text_manuf = u'Производитель, модель' + manufacturer = pp.Literal(text_manuf) + + td_start, td_end = pp.makeHTMLTags("td") + manuf_body = td_start.suppress() + manufacturer + pp.SkipTo(td_end)("cells*") + td_end.suppress() + + #~ manuf_body.setDebug() + + #~ for tokens in manuf_body.scanString(html): + #~ print_(tokens) + +class ParseUsingRegex(ParseTestCase): + def runTest(self): + + import re + + signedInt = pp.Regex(r'[-+][0-9]+') + unsignedInt = pp.Regex(r'[0-9]+') + simpleString = pp.Regex(r'("[^\"]*")|(\'[^\']*\')') + namedGrouping = pp.Regex(r'("(?P[^\"]*)")') + compiledRE = pp.Regex(re.compile(r'[A-Z]+')) + + def testMatch (expression, instring, shouldPass, expectedString=None): + if shouldPass: + try: + result = expression.parseString(instring) + print_('%s correctly matched %s' % (repr(expression), repr(instring))) + if expectedString != result[0]: + print_('\tbut failed to match the pattern as expected:') + print_('\tproduced %s instead of %s' % \ + (repr(result[0]), repr(expectedString))) + return True + except pp.ParseException: + print_('%s incorrectly failed to match %s' % \ + (repr(expression), repr(instring))) + else: + try: + result = expression.parseString(instring) + print_('%s incorrectly matched %s' % (repr(expression), repr(instring))) + print_('\tproduced %s as a result' % repr(result[0])) + except pp.ParseException: + print_('%s correctly failed to match %s' % \ + (repr(expression), repr(instring))) + return True + return False + + # These should fail + self.assertTrue(testMatch(signedInt, '1234 foo', False), "Re: (1) passed, expected fail") + self.assertTrue(testMatch(signedInt, ' +foo', False), "Re: (2) passed, expected fail") + self.assertTrue(testMatch(unsignedInt, 'abc', False), "Re: (3) passed, expected fail") + self.assertTrue(testMatch(unsignedInt, '+123 foo', False), "Re: (4) passed, expected fail") + self.assertTrue(testMatch(simpleString, 'foo', False), "Re: (5) passed, expected fail") + self.assertTrue(testMatch(simpleString, '"foo bar\'', False), "Re: (6) passed, expected fail") + self.assertTrue(testMatch(simpleString, '\'foo bar"', False), "Re: (7) passed, expected fail") + + # These should pass + self.assertTrue(testMatch(signedInt, ' +123', True, '+123'), "Re: (8) failed, expected pass") + self.assertTrue(testMatch(signedInt, '+123', True, '+123'), "Re: (9) failed, expected pass") + self.assertTrue(testMatch(signedInt, '+123 foo', True, '+123'), "Re: (10) failed, expected pass") + self.assertTrue(testMatch(signedInt, '-0 foo', True, '-0'), "Re: (11) failed, expected pass") + self.assertTrue(testMatch(unsignedInt, '123 foo', True, '123'), "Re: (12) failed, expected pass") + self.assertTrue(testMatch(unsignedInt, '0 foo', True, '0'), "Re: (13) failed, expected pass") + self.assertTrue(testMatch(simpleString, '"foo"', True, '"foo"'), "Re: (14) failed, expected pass") + self.assertTrue(testMatch(simpleString, "'foo bar' baz", True, "'foo bar'"), "Re: (15) failed, expected pass") + + self.assertTrue(testMatch(compiledRE, 'blah', False), "Re: (16) passed, expected fail") + self.assertTrue(testMatch(compiledRE, 'BLAH', True, 'BLAH'), "Re: (17) failed, expected pass") + + self.assertTrue(testMatch(namedGrouping, '"foo bar" baz', True, '"foo bar"'), "Re: (16) failed, expected pass") + ret = namedGrouping.parseString('"zork" blah') + print_(ret.asList()) + print_(list(ret.items())) + print_(ret.content) + self.assertEqual(ret.content, 'zork', "named group lookup failed") + self.assertEqual(ret[0], simpleString.parseString('"zork" blah')[0], + "Regex not properly returning ParseResults for named vs. unnamed groups") + + try: + #~ print "lets try an invalid RE" + invRe = pp.Regex('("[^\"]*")|(\'[^\']*\'') + except Exception as e: + print_("successfully rejected an invalid RE:", end=' ') + print_(e) + else: + self.assertTrue(False, "failed to reject invalid RE") + + invRe = pp.Regex('') + +class RegexAsTypeTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + test_str = "sldkjfj 123 456 lsdfkj" + + print_("return as list of match groups") + expr = pp.Regex(r"\w+ (\d+) (\d+) (\w+)", asGroupList=True) + expected_group_list = [tuple(test_str.split()[1:])] + result = expr.parseString(test_str) + print_(result.dump()) + print_(expected_group_list) + self.assertEqual(result.asList(), expected_group_list, "incorrect group list returned by Regex)") + + print_("return as re.match instance") + expr = pp.Regex(r"\w+ (?P\d+) (?P\d+) (?P\w+)", asMatch=True) + result = expr.parseString(test_str) + print_(result.dump()) + print_(result[0].groups()) + print_(expected_group_list) + self.assertEqual(result[0].groupdict(), {'num1': '123', 'num2': '456', 'last_word': 'lsdfkj'}, + 'invalid group dict from Regex(asMatch=True)') + self.assertEqual(result[0].groups(), expected_group_list[0], + "incorrect group list returned by Regex(asMatch)") + +class RegexSubTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + print_("test sub with string") + expr = pp.Regex(r"").sub("'Richard III'") + result = expr.transformString("This is the title: <title>") + print_(result) + self.assertEqual(result, "This is the title: 'Richard III'", "incorrect Regex.sub result with simple string") + + print_("test sub with re string") + expr = pp.Regex(r"([Hh]\d):\s*(.*)").sub(r"<\1>\2</\1>") + result = expr.transformString("h1: This is the main heading\nh2: This is the sub-heading") + print_(result) + self.assertEqual(result, '<h1>This is the main heading</h1>\n<h2>This is the sub-heading</h2>', + "incorrect Regex.sub result with re string") + + print_("test sub with re string (Regex returns re.match)") + expr = pp.Regex(r"([Hh]\d):\s*(.*)", asMatch=True).sub(r"<\1>\2</\1>") + result = expr.transformString("h1: This is the main heading\nh2: This is the sub-heading") + print_(result) + self.assertEqual(result, '<h1>This is the main heading</h1>\n<h2>This is the sub-heading</h2>', + "incorrect Regex.sub result with re string") + + print_("test sub with callable that return str") + expr = pp.Regex(r"<(.*?)>").sub(lambda m: m.group(1).upper()) + result = expr.transformString("I want this in upcase: <what? what?>") + print_(result) + self.assertEqual(result, 'I want this in upcase: WHAT? WHAT?', "incorrect Regex.sub result with callable") + + try: + expr = pp.Regex(r"<(.*?)>", asMatch=True).sub(lambda m: m.group(1).upper()) + except SyntaxError: + pass + else: + self.assertTrue(False, "failed to warn using a Regex.sub(callable) with asMatch=True") + + try: + expr = pp.Regex(r"<(.*?)>", asGroupList=True).sub(lambda m: m.group(1).upper()) + except SyntaxError: + pass + else: + self.assertTrue(False, "failed to warn using a Regex.sub() with asGroupList=True") + + try: + expr = pp.Regex(r"<(.*?)>", asGroupList=True).sub("") + except SyntaxError: + pass + else: + self.assertTrue(False, "failed to warn using a Regex.sub() with asGroupList=True") + +class PrecededByTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + num = pp.Word(pp.nums).setParseAction(lambda t: int(t[0])) + interesting_num = pp.PrecededBy(pp.Char("abc")("prefix*")) + num + semi_interesting_num = pp.PrecededBy('_') + num + crazy_num = pp.PrecededBy(pp.Word("^", "$%^")("prefix*"), 10) + num + boring_num = ~pp.PrecededBy(pp.Char("abc_$%^" + pp.nums)) + num + very_boring_num = pp.PrecededBy(pp.WordStart()) + num + finicky_num = pp.PrecededBy(pp.Word("^", "$%^"), retreat=3) + num + + s = "c384 b8324 _9293874 _293 404 $%^$^%$2939" + print_(s) + for expr, expected_list, expected_dict in [ + (interesting_num, [384, 8324], {'prefix': ['c', 'b']}), + (semi_interesting_num, [9293874, 293], {}), + (boring_num, [404], {}), + (crazy_num, [2939], {'prefix': ['^%$']}), + (finicky_num, [2939], {}), + (very_boring_num, [404], {}), + ]: + print_(expr.searchString(s)) + result = sum(expr.searchString(s)) + print_(result) + + self.assertEqual(result.asList(), expected_list, + "Erroneous tokens for {}: expected {}, got {}".format(expr, + expected_list, + result.asList())) + self.assertEqual(result.asDict(), expected_dict, + "Erroneous named results for {}: expected {}, got {}".format(expr, + expected_dict, + result.asDict())) + +class CountedArrayTest(ParseTestCase): + def runTest(self): + from pyparsing import Word,nums,OneOrMore,countedArray + + testString = "2 5 7 6 0 1 2 3 4 5 0 3 5 4 3" + + integer = Word(nums).setParseAction(lambda t: int(t[0])) + countedField = countedArray(integer) + + r = OneOrMore(countedField).parseString( testString ) + print_(testString) + print_(r.asList()) + + self.assertEqual(r.asList(), [[5,7],[0,1,2,3,4,5],[],[5,4,3]], + "Failed matching countedArray, got " + str(r.asList())) + +class CountedArrayTest2(ParseTestCase): + # addresses bug raised by Ralf Vosseler + def runTest(self): + from pyparsing import Word,nums,OneOrMore,countedArray + + testString = "2 5 7 6 0 1 2 3 4 5 0 3 5 4 3" + + integer = Word(nums).setParseAction(lambda t: int(t[0])) + countedField = countedArray(integer) + + dummy = Word("A") + r = OneOrMore(dummy ^ countedField).parseString( testString ) + print_(testString) + print_(r.asList()) + + self.assertEqual(r.asList(), [[5,7],[0,1,2,3,4,5],[],[5,4,3]], + "Failed matching countedArray, got " + str(r.asList())) + +class CountedArrayTest3(ParseTestCase): + # test case where counter is not a decimal integer + def runTest(self): + from pyparsing import Word,nums,OneOrMore,countedArray,alphas + int_chars = "_"+alphas + array_counter = Word(int_chars).setParseAction(lambda t: int_chars.index(t[0])) + + # 123456789012345678901234567890 + testString = "B 5 7 F 0 1 2 3 4 5 _ C 5 4 3" + + integer = Word(nums).setParseAction(lambda t: int(t[0])) + countedField = countedArray(integer, intExpr=array_counter) + + r = OneOrMore(countedField).parseString( testString ) + print_(testString) + print_(r.asList()) + + self.assertEqual(r.asList(), [[5,7],[0,1,2,3,4,5],[],[5,4,3]], + "Failed matching countedArray, got " + str(r.asList())) + +class LineStartTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + pass_tests = [ + """\ + AAA + BBB + """, + """\ + AAA... + BBB + """, + ] + fail_tests = [ + """\ + AAA... + ...BBB + """, + """\ + AAA BBB + """, + ] + + # cleanup test strings + pass_tests = ['\n'.join(s.lstrip() for s in t.splitlines()).replace('.', ' ') for t in pass_tests] + fail_tests = ['\n'.join(s.lstrip() for s in t.splitlines()).replace('.', ' ') for t in fail_tests] + + test_patt = pp.Word('A') - pp.LineStart() + pp.Word('B') + print_(test_patt.streamline()) + success = test_patt.runTests(pass_tests)[0] + self.assertTrue(success, "failed LineStart passing tests (1)") + + success = test_patt.runTests(fail_tests, failureTests=True)[0] + self.assertTrue(success, "failed LineStart failure mode tests (1)") + + with AutoReset(pp.ParserElement, "DEFAULT_WHITE_CHARS"): + print_(r'no \n in default whitespace chars') + pp.ParserElement.setDefaultWhitespaceChars(' ') + + test_patt = pp.Word('A') - pp.LineStart() + pp.Word('B') + print_(test_patt.streamline()) + # should fail the pass tests too, since \n is no longer valid whitespace and we aren't parsing for it + success = test_patt.runTests(pass_tests, failureTests=True)[0] + self.assertTrue(success, "failed LineStart passing tests (2)") + + success = test_patt.runTests(fail_tests, failureTests=True)[0] + self.assertTrue(success, "failed LineStart failure mode tests (2)") + + test_patt = pp.Word('A') - pp.LineEnd().suppress() + pp.LineStart() + pp.Word('B') + pp.LineEnd().suppress() + print_(test_patt.streamline()) + success = test_patt.runTests(pass_tests)[0] + self.assertTrue(success, "failed LineStart passing tests (3)") + + success = test_patt.runTests(fail_tests, failureTests=True)[0] + self.assertTrue(success, "failed LineStart failure mode tests (3)") + + test = """\ + AAA 1 + AAA 2 + + AAA + + B AAA + + """ + + from textwrap import dedent + test = dedent(test) + print_(test) + + for t, s, e in (pp.LineStart() + 'AAA').scanString(test): + print_(s, e, pp.lineno(s, test), pp.line(s, test), ord(test[s])) + print_() + self.assertEqual(test[s], 'A', 'failed LineStart with insignificant newlines') + + with AutoReset(pp.ParserElement, "DEFAULT_WHITE_CHARS"): + pp.ParserElement.setDefaultWhitespaceChars(' ') + for t, s, e in (pp.LineStart() + 'AAA').scanString(test): + print_(s, e, pp.lineno(s, test), pp.line(s, test), ord(test[s])) + print_() + self.assertEqual(test[s], 'A', 'failed LineStart with insignificant newlines') + + +class LineAndStringEndTest(ParseTestCase): + def runTest(self): + from pyparsing import OneOrMore,lineEnd,alphanums,Word,stringEnd,delimitedList,SkipTo + + NLs = OneOrMore(lineEnd) + bnf1 = delimitedList(Word(alphanums).leaveWhitespace(), NLs) + bnf2 = Word(alphanums) + stringEnd + bnf3 = Word(alphanums) + SkipTo(stringEnd) + tests = [ + ("testA\ntestB\ntestC\n", ['testA', 'testB', 'testC']), + ("testD\ntestE\ntestF", ['testD', 'testE', 'testF']), + ("a", ['a']), + ] + + for test,expected in tests: + res1 = bnf1.parseString(test) + print_(res1,'=?',expected) + self.assertEqual(res1.asList(), expected, + "Failed lineEnd/stringEnd test (1): "+repr(test)+ " -> "+str(res1.asList())) + + res2 = bnf2.searchString(test)[0] + print_(res2.asList(),'=?',expected[-1:]) + self.assertEqual(res2.asList(), expected[-1:], + "Failed lineEnd/stringEnd test (2): "+repr(test)+ " -> "+str(res2.asList())) + + res3 = bnf3.parseString(test) + first = res3[0] + rest = res3[1] + #~ print res3.dump() + print_(repr(rest),'=?',repr(test[len(first)+1:])) + self.assertEqual(rest, test[len(first)+1:], + "Failed lineEnd/stringEnd test (3): " +repr(test)+ " -> "+str(res3.asList())) + print_() + + from pyparsing import Regex + import re + + k = Regex(r'a+',flags=re.S+re.M) + k = k.parseWithTabs() + k = k.leaveWhitespace() + + tests = [ + (r'aaa',['aaa']), + (r'\naaa',None), + (r'a\naa',None), + (r'aaa\n',None), + ] + for i,(src,expected) in enumerate(tests): + print_(i, repr(src).replace('\\\\','\\'), end=' ') + try: + res = k.parseString(src, parseAll=True).asList() + except ParseException as pe: + res = None + print_(res) + self.assertEqual(res, expected, "Failed on parseAll=True test %d" % i) + +class VariableParseActionArgsTest(ParseTestCase): + def runTest(self): + + pa3 = lambda s,l,t: t + pa2 = lambda l,t: t + pa1 = lambda t: t + pa0 = lambda : None + class Callable3(object): + def __call__(self,s,l,t): + return t + class Callable2(object): + def __call__(self,l,t): + return t + class Callable1(object): + def __call__(self,t): + return t + class Callable0(object): + def __call__(self): + return + class CallableS3(object): + #~ @staticmethod + def __call__(s,l,t): + return t + __call__=staticmethod(__call__) + class CallableS2(object): + #~ @staticmethod + def __call__(l,t): + return t + __call__=staticmethod(__call__) + class CallableS1(object): + #~ @staticmethod + def __call__(t): + return t + __call__=staticmethod(__call__) + class CallableS0(object): + #~ @staticmethod + def __call__(): + return + __call__=staticmethod(__call__) + class CallableC3(object): + #~ @classmethod + def __call__(cls,s,l,t): + return t + __call__=classmethod(__call__) + class CallableC2(object): + #~ @classmethod + def __call__(cls,l,t): + return t + __call__=classmethod(__call__) + class CallableC1(object): + #~ @classmethod + def __call__(cls,t): + return t + __call__=classmethod(__call__) + class CallableC0(object): + #~ @classmethod + def __call__(cls): + return + __call__=classmethod(__call__) + + class parseActionHolder(object): + #~ @staticmethod + def pa3(s,l,t): + return t + pa3=staticmethod(pa3) + #~ @staticmethod + def pa2(l,t): + return t + pa2=staticmethod(pa2) + #~ @staticmethod + def pa1(t): + return t + pa1=staticmethod(pa1) + #~ @staticmethod + def pa0(): + return + pa0=staticmethod(pa0) + + def paArgs(*args): + print_(args) + return args[2] + + class ClassAsPA0(object): + def __init__(self): + pass + def __str__(self): + return "A" + + class ClassAsPA1(object): + def __init__(self,t): + print_("making a ClassAsPA1") + self.t = t + def __str__(self): + return self.t[0] + + class ClassAsPA2(object): + def __init__(self,l,t): + self.t = t + def __str__(self): + return self.t[0] + + class ClassAsPA3(object): + def __init__(self,s,l,t): + self.t = t + def __str__(self): + return self.t[0] + + class ClassAsPAStarNew(tuple): + def __new__(cls, *args): + print_("make a ClassAsPAStarNew", args) + return tuple.__new__(cls, *args[2].asList()) + def __str__(self): + return ''.join(self) + + #~ def ClassAsPANew(object): + #~ def __new__(cls, t): + #~ return object.__new__(cls, t) + #~ def __init__(self,t): + #~ self.t = t + #~ def __str__(self): + #~ return self.t + + from pyparsing import Literal,OneOrMore + + A = Literal("A").setParseAction(pa0) + B = Literal("B").setParseAction(pa1) + C = Literal("C").setParseAction(pa2) + D = Literal("D").setParseAction(pa3) + E = Literal("E").setParseAction(Callable0()) + F = Literal("F").setParseAction(Callable1()) + G = Literal("G").setParseAction(Callable2()) + H = Literal("H").setParseAction(Callable3()) + I = Literal("I").setParseAction(CallableS0()) + J = Literal("J").setParseAction(CallableS1()) + K = Literal("K").setParseAction(CallableS2()) + L = Literal("L").setParseAction(CallableS3()) + M = Literal("M").setParseAction(CallableC0()) + N = Literal("N").setParseAction(CallableC1()) + O = Literal("O").setParseAction(CallableC2()) + P = Literal("P").setParseAction(CallableC3()) + Q = Literal("Q").setParseAction(paArgs) + R = Literal("R").setParseAction(parseActionHolder.pa3) + S = Literal("S").setParseAction(parseActionHolder.pa2) + T = Literal("T").setParseAction(parseActionHolder.pa1) + U = Literal("U").setParseAction(parseActionHolder.pa0) + V = Literal("V") + + gg = OneOrMore( A | C | D | E | F | G | H | + I | J | K | L | M | N | O | P | Q | R | S | U | V | B | T) + testString = "VUTSRQPONMLKJIHGFEDCBA" + res = gg.parseString(testString) + print_(res.asList()) + self.assertEqual(res.asList(), list(testString), "Failed to parse using variable length parse actions") + + A = Literal("A").setParseAction(ClassAsPA0) + B = Literal("B").setParseAction(ClassAsPA1) + C = Literal("C").setParseAction(ClassAsPA2) + D = Literal("D").setParseAction(ClassAsPA3) + E = Literal("E").setParseAction(ClassAsPAStarNew) + + gg = OneOrMore( A | B | C | D | E | F | G | H | + I | J | K | L | M | N | O | P | Q | R | S | T | U | V) + testString = "VUTSRQPONMLKJIHGFEDCBA" + res = gg.parseString(testString) + print_(list(map(str,res))) + self.assertEqual(list(map(str,res)), list(testString), + "Failed to parse using variable length parse actions " + "using class constructors as parse actions") + +class EnablePackratParsing(ParseTestCase): + def runTest(self): + from pyparsing import ParserElement + ParserElement.enablePackrat() + +class SingleArgExceptionTest(ParseTestCase): + def runTest(self): + from pyparsing import ParseBaseException,ParseFatalException + + msg = "" + raisedMsg = "" + testMessage = "just one arg" + try: + raise ParseFatalException(testMessage) + except ParseBaseException as pbe: + print_("Received expected exception:", pbe) + raisedMsg = pbe.msg + self.assertEqual(raisedMsg, testMessage, "Failed to get correct exception message") + + +class OriginalTextForTest(ParseTestCase): + def runTest(self): + from pyparsing import makeHTMLTags, originalTextFor + + def rfn(t): + return "%s:%d" % (t.src, len("".join(t))) + + makeHTMLStartTag = lambda tag: originalTextFor(makeHTMLTags(tag)[0], asString=False) + + # use the lambda, Luke + #~ start, imge = makeHTMLTags('IMG') + start = makeHTMLStartTag('IMG') + + # don't replace our fancy parse action with rfn, + # append rfn to the list of parse actions + #~ start.setParseAction(rfn) + start.addParseAction(rfn) + + #start.setParseAction(lambda s,l,t:t.src) + text = '''_<img src="images/cal.png" + alt="cal image" width="16" height="15">_''' + s = start.transformString(text) + if VERBOSE: + print_(s) + self.assertTrue(s.startswith("_images/cal.png:"), "failed to preserve input s properly") + self.assertTrue(s.endswith("77_"),"failed to return full original text properly") + + tag_fields = makeHTMLStartTag("IMG").searchString(text)[0] + if VERBOSE: + print_(sorted(tag_fields.keys())) + self.assertEqual(sorted(tag_fields.keys()), + ['alt', 'empty', 'height', 'src', 'startImg', 'tag', 'width'], + 'failed to preserve results names in originalTextFor') + +class PackratParsingCacheCopyTest(ParseTestCase): + def runTest(self): + from pyparsing import Word,nums,delimitedList,Literal,Optional,alphas,alphanums,ZeroOrMore,empty + + integer = Word(nums).setName("integer") + id = Word(alphas+'_',alphanums+'_') + simpleType = Literal('int'); + arrayType= simpleType+ZeroOrMore('['+delimitedList(integer)+']') + varType = arrayType | simpleType + varDec = varType + delimitedList(id + Optional('='+integer))+';' + + codeBlock = Literal('{}') + + funcDef = Optional(varType | 'void')+id+'('+(delimitedList(varType+id)|'void'|empty)+')'+codeBlock + + program = varDec | funcDef + input = 'int f(){}' + results = program.parseString(input) + print_("Parsed '%s' as %s" % (input, results.asList())) + self.assertEqual(results.asList(), ['int', 'f', '(', ')', '{}'], "Error in packrat parsing") + +class PackratParsingCacheCopyTest2(ParseTestCase): + def runTest(self): + from pyparsing import Keyword,Word,Suppress,Forward,Optional,delimitedList,Group + + DO,AA = list(map(Keyword, "DO AA".split())) + LPAR,RPAR = list(map(Suppress,"()")) + identifier = ~AA + Word("Z") + + function_name = identifier.copy() + #~ function_name = ~AA + Word("Z") #identifier.copy() + expr = Forward().setName("expr") + expr << (Group(function_name + LPAR + Optional(delimitedList(expr)) + RPAR).setName("functionCall") | + identifier.setName("ident")#.setDebug()#.setBreak() + ) + + stmt = DO + Group(delimitedList(identifier + ".*" | expr)) + result = stmt.parseString("DO Z") + print_(result.asList()) + self.assertEqual(len(result[1]), 1, "packrat parsing is duplicating And term exprs") + +class ParseResultsDelTest(ParseTestCase): + def runTest(self): + from pyparsing import OneOrMore, Word, alphas, nums + + grammar = OneOrMore(Word(nums))("ints") + OneOrMore(Word(alphas))("words") + res = grammar.parseString("123 456 ABC DEF") + print_(res.dump()) + origInts = res.ints.asList() + origWords = res.words.asList() + del res[1] + del res["words"] + print_(res.dump()) + self.assertEqual(res[1], 'ABC',"failed to delete 0'th element correctly") + self.assertEqual(res.ints.asList(), origInts, "updated named attributes, should have updated list only") + self.assertEqual(res.words, "", "failed to update named attribute correctly") + self.assertEqual(res[-1], 'DEF', "updated list, should have updated named attributes only") + +class WithAttributeParseActionTest(ParseTestCase): + def runTest(self): + """ + This unit test checks withAttribute in these ways: + + * Argument forms as keywords and tuples + * Selecting matching tags by attribute + * Case-insensitive attribute matching + * Correctly matching tags having the attribute, and rejecting tags not having the attribute + + (Unit test written by voigts as part of the Google Highly Open Participation Contest) + """ + + from pyparsing import makeHTMLTags, Word, withAttribute, withClass, nums + + data = """ + <a>1</a> + <a b="x">2</a> + <a B="x">3</a> + <a b="X">4</a> + <a b="y">5</a> + <a class="boo">8</a> + """ + tagStart, tagEnd = makeHTMLTags("a") + + expr = tagStart + Word(nums)("value") + tagEnd + + expected = ([['a', ['b', 'x'], False, '2', '</a>'], + ['a', ['b', 'x'], False, '3', '</a>']], + [['a', ['b', 'x'], False, '2', '</a>'], + ['a', ['b', 'x'], False, '3', '</a>']], + [['a', ['class', 'boo'], False, '8', '</a>']], + ) + + for attrib, exp in zip([ + withAttribute(b="x"), + #withAttribute(B="x"), + withAttribute(("b","x")), + #withAttribute(("B","x")), + withClass("boo"), + ], expected): + + tagStart.setParseAction(attrib) + result = expr.searchString(data) + + print_(result.dump()) + self.assertEqual(result.asList(), exp, "Failed test, expected %s, got %s" % (expected, result.asList())) + +class NestedExpressionsTest(ParseTestCase): + def runTest(self): + """ + This unit test checks nestedExpr in these ways: + - use of default arguments + - use of non-default arguments (such as a pyparsing-defined comment + expression in place of quotedString) + - use of a custom content expression + - use of a pyparsing expression for opener and closer is *OPTIONAL* + - use of input data containing nesting delimiters + - correct grouping of parsed tokens according to nesting of opening + and closing delimiters in the input string + + (Unit test written by christoph... as part of the Google Highly Open Participation Contest) + """ + from pyparsing import nestedExpr, Literal, Regex, restOfLine, quotedString + + #All defaults. Straight out of the example script. Also, qualifies for + #the bonus: note the fact that (Z | (E^F) & D) is not parsed :-). + # Tests for bug fixed in 1.4.10 + print_("Test defaults:") + teststring = "(( ax + by)*C) (Z | (E^F) & D)" + + expr = nestedExpr() + + expected = [[['ax', '+', 'by'], '*C']] + result = expr.parseString(teststring) + print_(result.dump()) + self.assertEqual(result.asList(), expected, "Defaults didn't work. That's a bad sign. Expected: %s, got: %s" % (expected, result)) + + #Going through non-defaults, one by one; trying to think of anything + #odd that might not be properly handled. + + #Change opener + print_("\nNon-default opener") + opener = "[" + teststring = test_string = "[[ ax + by)*C)" + expected = [[['ax', '+', 'by'], '*C']] + expr = nestedExpr("[") + result = expr.parseString(teststring) + print_(result.dump()) + self.assertEqual(result.asList(), expected, "Non-default opener didn't work. Expected: %s, got: %s" % (expected, result)) + + #Change closer + print_("\nNon-default closer") + + teststring = test_string = "(( ax + by]*C]" + expected = [[['ax', '+', 'by'], '*C']] + expr = nestedExpr(closer="]") + result = expr.parseString(teststring) + print_(result.dump()) + self.assertEqual(result.asList(), expected, "Non-default closer didn't work. Expected: %s, got: %s" % (expected, result)) + + # #Multicharacter opener, closer + # opener = "bar" + # closer = "baz" + print_("\nLiteral expressions for opener and closer") + + opener,closer = list(map(Literal, "bar baz".split())) + expr = nestedExpr(opener, closer, + content=Regex(r"([^b ]|b(?!a)|ba(?![rz]))+")) + + teststring = "barbar ax + bybaz*Cbaz" + expected = [[['ax', '+', 'by'], '*C']] + # expr = nestedExpr(opener, closer) + result = expr.parseString(teststring) + print_(result.dump()) + self.assertEqual(result.asList(), expected, "Multicharacter opener and closer didn't work. Expected: %s, got: %s" % (expected, result)) + + #Lisp-ish comments + print_("\nUse ignore expression (1)") + comment = Regex(r";;.*") + teststring = \ + """ + (let ((greeting "Hello, world!")) ;;(foo bar + (display greeting)) + """ + + expected = [['let', [['greeting', '"Hello,', 'world!"']], ';;(foo bar',\ + ['display', 'greeting']]] + expr = nestedExpr(ignoreExpr=comment) + result = expr.parseString(teststring) + print_(result.dump()) + self.assertEqual(result.asList(), expected , "Lisp-ish comments (\";; <...> $\") didn't work. Expected: %s, got: %s" % (expected, result)) + + + #Lisp-ish comments, using a standard bit of pyparsing, and an Or. + print_("\nUse ignore expression (2)") + comment = ';;' + restOfLine + + teststring = \ + """ + (let ((greeting "Hello, )world!")) ;;(foo bar + (display greeting)) + """ + + expected = [['let', [['greeting', '"Hello, )world!"']], ';;', '(foo bar', + ['display', 'greeting']]] + expr = nestedExpr(ignoreExpr=(comment ^ quotedString)) + result = expr.parseString(teststring) + print_(result.dump()) + self.assertEqual(result.asList(), expected , + "Lisp-ish comments (\";; <...> $\") and quoted strings didn't work. Expected: %s, got: %s" % (expected, result)) + +class WordExcludeTest(ParseTestCase): + def runTest(self): + from pyparsing import Word, printables + allButPunc = Word(printables, excludeChars=".,:;-_!?") + + test = "Hello, Mr. Ed, it's Wilbur!" + result = allButPunc.searchString(test).asList() + print_(result) + self.assertEqual(result, [['Hello'], ['Mr'], ['Ed'], ["it's"], ['Wilbur']], "failed WordExcludeTest") + +class ParseAllTest(ParseTestCase): + def runTest(self): + from pyparsing import Word, cppStyleComment + + testExpr = Word("A") + + tests = [ + ("AAAAA", False, True), + ("AAAAA", True, True), + ("AAABB", False, True), + ("AAABB", True, False), + ] + for s,parseAllFlag,shouldSucceed in tests: + try: + print_("'%s' parseAll=%s (shouldSuceed=%s)" % (s, parseAllFlag, shouldSucceed)) + testExpr.parseString(s,parseAllFlag) + self.assertTrue(shouldSucceed, "successfully parsed when should have failed") + except ParseException as pe: + self.assertFalse(shouldSucceed, "failed to parse when should have succeeded") + + # add test for trailing comments + testExpr.ignore(cppStyleComment) + + tests = [ + ("AAAAA //blah", False, True), + ("AAAAA //blah", True, True), + ("AAABB //blah", False, True), + ("AAABB //blah", True, False), + ] + for s,parseAllFlag,shouldSucceed in tests: + try: + print_("'%s' parseAll=%s (shouldSucceed=%s)" % (s, parseAllFlag, shouldSucceed)) + testExpr.parseString(s,parseAllFlag) + self.assertTrue(shouldSucceed, "successfully parsed when should have failed") + except ParseException as 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 + + src = """\ + "string1", "strin""g2" + 'string1', 'string2' + ^string1^, ^string2^ + <string1>, <string2>""" + + testExprs = (sglQuotedString, dblQuotedString, quotedString, + QuotedString('"', escQuote='""'), QuotedString("'", escQuote="''"), + QuotedString("^"), QuotedString("<",endQuoteChar=">")) + for expr in testExprs: + strs = delimitedList(expr).searchString(src) + print_(strs) + self.assertTrue(bool(strs), "no matches found for test expression '%s'" % expr) + for lst in strs: + self.assertEqual(len(lst), 2, "invalid match found for test expression '%s'" % expr) + + from pyparsing import alphas, nums, Word + src = """'ms1',1,0,'2009-12-22','2009-12-22 10:41:22') ON DUPLICATE KEY UPDATE sent_count = sent_count + 1, mtime = '2009-12-22 10:41:22';""" + tok_sql_quoted_value = ( + QuotedString("'", "\\", "''", True, False) ^ + QuotedString('"', "\\", '""', True, False)) + tok_sql_computed_value = Word(nums) + tok_sql_identifier = Word(alphas) + + val = tok_sql_quoted_value | tok_sql_computed_value | tok_sql_identifier + vals = delimitedList(val) + print_(vals.parseString(src)) + self.assertEqual(len(vals.parseString(src)), 5, "error in greedy quote escaping") + + +class WordBoundaryExpressionsTest(ParseTestCase): + def runTest(self): + from pyparsing import WordEnd, WordStart, oneOf + + ws = WordStart() + we = WordEnd() + vowel = oneOf(list("AEIOUY")) + consonant = oneOf(list("BCDFGHJKLMNPQRSTVWXZ")) + + leadingVowel = ws + vowel + trailingVowel = vowel + we + leadingConsonant = ws + consonant + trailingConsonant = consonant + we + internalVowel = ~ws + vowel + ~we + + bnf = leadingVowel | trailingVowel + + tests = """\ + ABC DEF GHI + JKL MNO PQR + STU VWX YZ """.splitlines() + tests.append( "\n".join(tests) ) + + expectedResult = [ + [['D', 'G'], ['A'], ['C', 'F'], ['I'], ['E'], ['A', 'I']], + [['J', 'M', 'P'], [], ['L', 'R'], ['O'], [], ['O']], + [['S', 'V'], ['Y'], ['X', 'Z'], ['U'], [], ['U', 'Y']], + [['D', 'G', 'J', 'M', 'P', 'S', 'V'], + ['A', 'Y'], + ['C', 'F', 'L', 'R', 'X', 'Z'], + ['I', 'O', 'U'], + ['E'], + ['A', 'I', 'O', 'U', 'Y']], + ] + + for t,expected in zip(tests, expectedResult): + print_(t) + results = [flatten(e.searchString(t).asList()) for e in [ + leadingConsonant, + leadingVowel, + trailingConsonant, + trailingVowel, + internalVowel, + bnf, + ]] + print_(results) + print_() + self.assertEqual(results, expected,"Failed WordBoundaryTest, expected %s, got %s" % (expected,results)) + +class RequiredEachTest(ParseTestCase): + def runTest(self): + from pyparsing import Keyword + + parser = Keyword('bam') & Keyword('boo') + try: + res1 = parser.parseString('bam boo') + print_(res1.asList()) + res2 = parser.parseString('boo bam') + print_(res2.asList()) + except ParseException: + failed = True + else: + failed = False + self.assertFalse(failed, "invalid logic in Each") + + self.assertEqual(set(res1), set(res2), "Failed RequiredEachTest, expected " + + str(res1.asList()) + " and " + str(res2.asList()) + + "to contain same words in any order" ) + +class OptionalEachTest(ParseTestCase): + def runTest1(self): + from pyparsing import Optional, Keyword + + the_input = "Major Tal Weiss" + parser1 = (Optional('Tal') + Optional('Weiss')) & Keyword('Major') + parser2 = Optional(Optional('Tal') + Optional('Weiss')) & Keyword('Major') + p1res = parser1.parseString( the_input) + p2res = parser2.parseString( the_input) + self.assertEqual(p1res.asList(), p2res.asList(), + "Each failed to match with nested Optionals, " + + str(p1res.asList()) + " should match " + str(p2res.asList())) + + def runTest2(self): + from pyparsing import Word, alphanums, OneOrMore, Group, Regex, Optional + + word = Word(alphanums + '_').setName("word") + with_stmt = 'with' + OneOrMore(Group(word('key') + '=' + word('value')))('overrides') + using_stmt = 'using' + Regex('id-[0-9a-f]{8}')('id') + modifiers = Optional(with_stmt('with_stmt')) & Optional(using_stmt('using_stmt')) + + self.assertEqual(modifiers, "with foo=bar bing=baz using id-deadbeef") + self.assertNotEqual(modifiers, "with foo=bar bing=baz using id-deadbeef using id-feedfeed") + + def runTest3(self): + from pyparsing import Literal,Suppress,ZeroOrMore,OneOrMore + + foo = Literal('foo') + bar = Literal('bar') + + openBrace = Suppress(Literal("{")) + closeBrace = Suppress(Literal("}")) + + exp = openBrace + (OneOrMore(foo)("foo") & ZeroOrMore(bar)("bar")) + closeBrace + + tests = """\ + {foo} + {bar foo bar foo bar foo} + """.splitlines() + for test in tests: + test = test.strip() + if not test: + continue + result = exp.parseString(test) + print_(test, '->', result.asList()) + self.assertEqual(result.asList(), test.strip("{}").split(), "failed to parse Each expression %r" % test) + print_(result.dump()) + + try: + result = exp.parseString("{bar}") + self.assertTrue(False, "failed to raise exception when required element is missing") + except ParseException as pe: + pass + + def runTest4(self): + from pyparsing import pyparsing_common, ZeroOrMore, Group + + expr = ((~pyparsing_common.iso8601_date + pyparsing_common.integer("id")) + & ZeroOrMore(Group(pyparsing_common.iso8601_date)("date*"))) + + expr.runTests(""" + 1999-12-31 100 2001-01-01 + 42 + """) + + + def runTest(self): + self.runTest1() + self.runTest2() + self.runTest3() + self.runTest4() + +class SumParseResultsTest(ParseTestCase): + def runTest(self): + + samplestr1 = "garbage;DOB 10-10-2010;more garbage\nID PARI12345678;more garbage" + samplestr2 = "garbage;ID PARI12345678;more garbage\nDOB 10-10-2010;more garbage" + samplestr3 = "garbage;DOB 10-10-2010" + samplestr4 = "garbage;ID PARI12345678;more garbage- I am cool" + + res1 = "ID:PARI12345678 DOB:10-10-2010 INFO:" + res2 = "ID:PARI12345678 DOB:10-10-2010 INFO:" + res3 = "ID: DOB:10-10-2010 INFO:" + res4 = "ID:PARI12345678 DOB: INFO: I am cool" + + from pyparsing import Regex, Word, alphanums, restOfLine + dob_ref = "DOB" + Regex(r"\d{2}-\d{2}-\d{4}")("dob") + id_ref = "ID" + Word(alphanums,exact=12)("id") + info_ref = "-" + restOfLine("info") + + person_data = dob_ref | id_ref | info_ref + + tests = (samplestr1,samplestr2,samplestr3,samplestr4,) + results = (res1, res2, res3, res4,) + for test,expected in zip(tests, results): + person = sum(person_data.searchString(test)) + result = "ID:%s DOB:%s INFO:%s" % (person.id, person.dob, person.info) + print_(test) + print_(expected) + print_(result) + for pd in person_data.searchString(test): + print_(pd.dump()) + print_() + self.assertEqual(expected, result, + "Failed to parse '%s' correctly, \nexpected '%s', got '%s'" % (test,expected,result)) + +class MarkInputLineTest(ParseTestCase): + def runTest(self): + + samplestr1 = "DOB 100-10-2010;more garbage\nID PARI12345678;more garbage" + + from pyparsing import Regex + dob_ref = "DOB" + Regex(r"\d{2}-\d{2}-\d{4}")("dob") + + try: + res = dob_ref.parseString(samplestr1) + except ParseException as pe: + outstr = pe.markInputline() + print_(outstr) + self.assertEqual(outstr, "DOB >!<100-10-2010;more garbage", "did not properly create marked input line") + else: + self.assertEqual(False, "test construction failed - should have raised an exception") + +class LocatedExprTest(ParseTestCase): + def runTest(self): + + # 012345678901234567890123456789012345678901234567890 + samplestr1 = "DOB 10-10-2010;more garbage;ID PARI12345678 ;more garbage" + + from pyparsing import Word, alphanums, locatedExpr + id_ref = locatedExpr("ID" + Word(alphanums,exact=12)("id")) + + res = id_ref.searchString(samplestr1)[0][0] + print_(res.dump()) + self.assertEqual(samplestr1[res.locn_start:res.locn_end], 'ID PARI12345678', "incorrect location calculation") + + +class PopTest(ParseTestCase): + def runTest(self): + from pyparsing import Word, alphas, nums + + source = "AAA 123 456 789 234" + patt = Word(alphas)("name") + Word(nums)*(1,) + + result = patt.parseString(source) + tests = [ + (0, 'AAA', ['123', '456', '789', '234']), + (None, '234', ['123', '456', '789']), + ('name', 'AAA', ['123', '456', '789']), + (-1, '789', ['123', '456']), + ] + for test in tests: + idx, val, remaining = test + if idx is not None: + ret = result.pop(idx) + else: + ret = result.pop() + print_("EXP:", val, remaining) + print_("GOT:", ret, result.asList()) + print_(ret, result.asList()) + self.assertEqual(ret, val, "wrong value returned, got %r, expected %r" % (ret, val)) + self.assertEqual(remaining, result.asList(), + "list is in wrong state after pop, got %r, expected %r" % (result.asList(), remaining)) + print_() + + prevlist = result.asList() + ret = result.pop('name', default="noname") + print_(ret) + print_(result.asList()) + self.assertEqual(ret, "noname", + "default value not successfully returned, got %r, expected %r" % (ret, "noname")) + self.assertEqual(result.asList(), prevlist, + "list is in wrong state after pop, got %r, expected %r" % (result.asList(), remaining)) + + +class AddConditionTest(ParseTestCase): + def runTest(self): + from pyparsing import Word, nums, Suppress, ParseFatalException + + numParser = Word(nums) + numParser.addParseAction(lambda s,l,t: int(t[0])) + numParser.addCondition(lambda s,l,t: t[0] % 2) + numParser.addCondition(lambda s,l,t: t[0] >= 7) + + result = numParser.searchString("1 2 3 4 5 6 7 8 9 10") + print_(result.asList()) + self.assertEqual(result.asList(), [[7],[9]], "failed to properly process conditions") + + numParser = Word(nums) + numParser.addParseAction(lambda s,l,t: int(t[0])) + rangeParser = (numParser("from_") + Suppress('-') + numParser("to")) + + result = rangeParser.searchString("1-4 2-4 4-3 5 6 7 8 9 10") + print_(result.asList()) + self.assertEqual(result.asList(), [[1, 4], [2, 4], [4, 3]], "failed to properly process conditions") + + rangeParser.addCondition(lambda t: t.to > t.from_, message="from must be <= to", fatal=False) + result = rangeParser.searchString("1-4 2-4 4-3 5 6 7 8 9 10") + print_(result.asList()) + self.assertEqual(result.asList(), [[1, 4], [2, 4]], "failed to properly process conditions") + + rangeParser = (numParser("from_") + Suppress('-') + numParser("to")) + rangeParser.addCondition(lambda t: t.to > t.from_, message="from must be <= to", fatal=True) + try: + result = rangeParser.searchString("1-4 2-4 4-3 5 6 7 8 9 10") + self.assertTrue(False, "failed to interrupt parsing on fatal condition failure") + except ParseFatalException: + print_("detected fatal condition") + +class PatientOrTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + # Two expressions and a input string which could - syntactically - be matched against + # both expressions. The "Literal" expression is considered invalid though, so this PE + # should always detect the "Word" expression. + def validate(token): + if token[0] == "def": + raise pp.ParseException("signalling invalid token") + return token + + a = pp.Word("de").setName("Word")#.setDebug() + b = pp.Literal("def").setName("Literal").setParseAction(validate)#.setDebug() + c = pp.Literal("d").setName("d")#.setDebug() + + # The "Literal" expressions's ParseAction is not executed directly after syntactically + # detecting the "Literal" Expression but only after the Or-decision has been made + # (which is too late)... + try: + result = (a ^ b ^ c).parseString("def") + self.assertEqual(result.asList(), ['de'], "failed to select longest match, chose %s" % result) + except ParseException: + failed = True + else: + failed = False + self.assertFalse(failed, "invalid logic in Or, fails on longest match with exception in parse action") + +class EachWithOptionalWithResultsNameTest(ParseTestCase): + def runTest(self): + from pyparsing import Optional + + result = (Optional('foo')('one') & Optional('bar')('two')).parseString('bar foo') + print_(result.dump()) + self.assertEqual(sorted(result.keys()), ['one','two']) + +class UnicodeExpressionTest(ParseTestCase): + def runTest(self): + from pyparsing import Literal, ParseException + + z = 'a' | Literal(u'\u1111') + z.streamline() + try: + z.parseString('b') + except ParseException as pe: + if not PY_3: + self.assertEqual(pe.msg, r'''Expected {"a" | "\u1111"}''', + "Invalid error message raised, got %r" % pe.msg) + else: + self.assertEqual(pe.msg, r'''Expected {"a" | "ᄑ"}''', + "Invalid error message raised, got %r" % pe.msg) + +class SetNameTest(ParseTestCase): + def runTest(self): + from pyparsing import (oneOf,infixNotation,Word,nums,opAssoc,delimitedList,countedArray, + nestedExpr,makeHTMLTags,anyOpenTag,anyCloseTag,commonHTMLEntity,replaceHTMLEntity) + + a = oneOf("a b c") + b = oneOf("d e f") + arith_expr = infixNotation(Word(nums), + [ + (oneOf('* /'),2,opAssoc.LEFT), + (oneOf('+ -'),2,opAssoc.LEFT), + ]) + arith_expr2 = infixNotation(Word(nums), + [ + (('?',':'),3,opAssoc.LEFT), + ]) + + tests = [ + a, + b, + (a | b), + arith_expr, + arith_expr.expr, + arith_expr2, + arith_expr2.expr, + delimitedList(Word(nums).setName("int")), + countedArray(Word(nums).setName("int")), + nestedExpr(), + makeHTMLTags('Z'), + (anyOpenTag,anyCloseTag), + commonHTMLEntity, + commonHTMLEntity.setParseAction(replaceHTMLEntity).transformString("lsdjkf <lsdjkf>&'"&xyzzy;"), + ] + + expected = map(str.strip, """\ + a | b | c + d | e | f + {a | b | c | d | e | f} + Forward: ... + + | - term + Forward: ... + ?: term + int [, int]... + (len) int... + nested () expression + (<Z>, </Z>) + (<any tag>, </any tag>) + common HTML entity + lsdjkf <lsdjkf>&'"&xyzzy;""".splitlines()) + + for t,e in zip(tests, expected): + tname = str(t) + self.assertEqual(tname, e, "expression name mismatch, expected {} got {}".format(e, tname)) + +class TrimArityExceptionMaskingTest(ParseTestCase): + def runTest(self): + from pyparsing import Word + + invalid_message = [ + "<lambda>() takes exactly 1 argument (0 given)", + "<lambda>() missing 1 required positional argument: 't'" + ][PY_3] + try: + Word('a').setParseAction(lambda t: t[0]+1).parseString('aaa') + except Exception as e: + exc_msg = str(e) + self.assertNotEqual(exc_msg, invalid_message, "failed to catch TypeError thrown in _trim_arity") + +class TrimArityExceptionMaskingTest2(ParseTestCase): + def runTest(self): + # construct deep call tree + def A(): + import traceback + + traceback.print_stack(limit=2) + + from pyparsing import Word + + invalid_message = [ + "<lambda>() takes exactly 1 argument (0 given)", + "<lambda>() missing 1 required positional argument: 't'" + ][PY_3] + try: + Word('a').setParseAction(lambda t: t[0]+1).parseString('aaa') + except Exception as e: + exc_msg = str(e) + self.assertNotEqual(exc_msg, invalid_message, "failed to catch TypeError thrown in _trim_arity") + + + def B(): + A() + + def C(): + B() + + def D(): + C() + + def E(): + D() + + def F(): + E() + + def G(): + F() + + def H(): + G() + + def J(): + H() + + def K(): + J() + + K() + +class OneOrMoreStopTest(ParseTestCase): + def runTest(self): + from pyparsing import (Word, OneOrMore, alphas, Keyword, CaselessKeyword, + nums, alphanums) + + test = "BEGIN aaa bbb ccc END" + BEGIN,END = map(Keyword, "BEGIN,END".split(',')) + body_word = Word(alphas).setName("word") + for ender in (END, "END", CaselessKeyword("END")): + expr = BEGIN + OneOrMore(body_word, stopOn=ender) + END + self.assertEqual(test, expr, "Did not successfully stop on ending expression %r" % ender) + + number = Word(nums+',.()').setName("number with optional commas") + parser= (OneOrMore(Word(alphanums+'-/.'), stopOn=number)('id').setParseAction(' '.join) + + number('data')) + result = parser.parseString(' XXX Y/123 1,234.567890') + self.assertEqual(result.asList(), ['XXX Y/123', '1,234.567890'], + "Did not successfully stop on ending expression %r" % number) + +class ZeroOrMoreStopTest(ParseTestCase): + def runTest(self): + from pyparsing import (Word, ZeroOrMore, alphas, Keyword, CaselessKeyword) + + test = "BEGIN END" + BEGIN,END = map(Keyword, "BEGIN,END".split(',')) + body_word = Word(alphas).setName("word") + for ender in (END, "END", CaselessKeyword("END")): + expr = BEGIN + ZeroOrMore(body_word, stopOn=ender) + END + self.assertEqual(test, expr, "Did not successfully stop on ending expression %r" % ender) + +class NestedAsDictTest(ParseTestCase): + def runTest(self): + from pyparsing import Literal, Forward, alphanums, Group, delimitedList, Dict, Word, Optional + + equals = Literal("=").suppress() + lbracket = Literal("[").suppress() + rbracket = Literal("]").suppress() + lbrace = Literal("{").suppress() + rbrace = Literal("}").suppress() + + value_dict = Forward() + value_list = Forward() + value_string = Word(alphanums + "@. ") + + value = value_list ^ value_dict ^ value_string + values = Group(delimitedList(value, ",")) + #~ values = delimitedList(value, ",").setParseAction(lambda toks: [toks.asList()]) + + value_list << lbracket + values + rbracket + + identifier = Word(alphanums + "_.") + + assignment = Group(identifier + equals + Optional(value)) + assignments = Dict(delimitedList(assignment, ';')) + value_dict << lbrace + assignments + rbrace + + response = assignments + + rsp = 'username=goat; errors={username=[already taken, too short]}; empty_field=' + result_dict = response.parseString(rsp).asDict() + print_(result_dict) + self.assertEqual(result_dict['username'], 'goat', "failed to process string in ParseResults correctly") + self.assertEqual(result_dict['errors']['username'], ['already taken', 'too short'], + "failed to process nested ParseResults correctly") + +class TraceParseActionDecoratorTest(ParseTestCase): + def runTest(self): + from pyparsing import traceParseAction, Word, nums + + @traceParseAction + def convert_to_int(t): + return int(t[0]) + + class Z(object): + def __call__(self, other): + return other[0] * 1000 + + integer = Word(nums).addParseAction(convert_to_int) + integer.addParseAction(traceParseAction(lambda t: t[0]*10)) + integer.addParseAction(traceParseAction(Z())) + integer.parseString("132") + +class RunTestsTest(ParseTestCase): + def runTest(self): + from pyparsing import Word, nums, delimitedList + + integer = Word(nums).setParseAction(lambda t : int(t[0])) + intrange = integer("start") + '-' + integer("end") + intrange.addCondition(lambda t: t.end > t.start, message="invalid range, start must be <= end", fatal=True) + intrange.addParseAction(lambda t: list(range(t.start, t.end+1))) + + indices = delimitedList(intrange | integer) + indices.addParseAction(lambda t: sorted(set(t))) + + tests = """\ + # normal data + 1-3,2-4,6,8-10,16 + + # lone integer + 11""" + results = indices.runTests(tests, printResults=False)[1] + + expectedResults = [ + [1, 2, 3, 4, 6, 8, 9, 10, 16], + [11], + ] + for res, expected in zip(results, expectedResults): + print_(res[1].asList()) + print_(expected) + self.assertEqual(res[1].asList(), expected, "failed test: " + str(expected)) + + tests = """\ + # invalid range + 1-2, 3-1, 4-6, 7, 12 + """ + success = indices.runTests(tests, printResults=False, failureTests=True)[0] + self.assertTrue(success, "failed to raise exception on improper range test") + +class RunTestsPostParseTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + integer = pp.pyparsing_common.integer + fraction = integer('numerator') + '/' + integer('denominator') + + accum = [] + def eval_fraction(test, result): + accum.append((test, result.asList())) + return "eval: {}".format(result.numerator / result.denominator) + + success = fraction.runTests("""\ + 1/2 + 1/0 + """, postParse=eval_fraction)[0] + print_(success) + + self.assertTrue(success, "failed to parse fractions in RunTestsPostParse") + + expected_accum = [('1/2', [1, '/', 2]), ('1/0', [1, '/', 0])] + self.assertEqual(accum, expected_accum, "failed to call postParse method during runTests") + +class CommonExpressionsTest(ParseTestCase): + def runTest(self): + from pyparsing import pyparsing_common + import ast + + success = pyparsing_common.mac_address.runTests(""" + AA:BB:CC:DD:EE:FF + AA.BB.CC.DD.EE.FF + AA-BB-CC-DD-EE-FF + """)[0] + self.assertTrue(success, "error in parsing valid MAC address") + + success = pyparsing_common.mac_address.runTests(""" + # mixed delimiters + AA.BB:CC:DD:EE:FF + """, failureTests=True)[0] + self.assertTrue( success, "error in detecting invalid mac address") + + success = pyparsing_common.ipv4_address.runTests(""" + 0.0.0.0 + 1.1.1.1 + 127.0.0.1 + 1.10.100.199 + 255.255.255.255 + """)[0] + self.assertTrue(success, "error in parsing valid IPv4 address") + + success = pyparsing_common.ipv4_address.runTests(""" + # out of range value + 256.255.255.255 + """, failureTests=True)[0] + self.assertTrue(success, "error in detecting invalid IPv4 address") + + success = pyparsing_common.ipv6_address.runTests(""" + 2001:0db8:85a3:0000:0000:8a2e:0370:7334 + 2134::1234:4567:2468:1236:2444:2106 + 0:0:0:0:0:0:A00:1 + 1080::8:800:200C:417A + ::A00:1 + + # loopback address + ::1 + + # the null address + :: + + # ipv4 compatibility form + ::ffff:192.168.0.1 + """)[0] + self.assertTrue(success, "error in parsing valid IPv6 address") + + success = pyparsing_common.ipv6_address.runTests(""" + # too few values + 1080:0:0:0:8:800:200C + + # too many ::'s, only 1 allowed + 2134::1234:4567::2444:2106 + """, failureTests=True)[0] + self.assertTrue(success, "error in detecting invalid IPv6 address") + + success = pyparsing_common.number.runTests(""" + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + """)[0] + self.assertTrue(success, "error in parsing valid numerics") + + success = pyparsing_common.sci_real.runTests(""" + 1e12 + -1e12 + 3.14159 + 6.02e23 + """)[0] + self.assertTrue(success, "error in parsing valid scientific notation reals") + + # any int or real number, returned as float + success = pyparsing_common.fnumber.runTests(""" + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + """)[0] + self.assertTrue(success, "error in parsing valid numerics") + + success, results = pyparsing_common.iso8601_date.runTests(""" + 1997 + 1997-07 + 1997-07-16 + """) + self.assertTrue(success, "error in parsing valid iso8601_date") + expected = [ + ('1997', None, None), + ('1997', '07', None), + ('1997', '07', '16'), + ] + for r,exp in zip(results, expected): + self.assertTrue((r[1].year,r[1].month,r[1].day,) == exp, "failed to parse date into fields") + + success, results = pyparsing_common.iso8601_date().addParseAction(pyparsing_common.convertToDate()).runTests(""" + 1997-07-16 + """) + self.assertTrue(success, "error in parsing valid iso8601_date with parse action") + self.assertTrue(results[0][1][0] == datetime.date(1997, 7, 16)) + + success, results = pyparsing_common.iso8601_datetime.runTests(""" + 1997-07-16T19:20+01:00 + 1997-07-16T19:20:30+01:00 + 1997-07-16T19:20:30.45Z + 1997-07-16 19:20:30.45 + """) + self.assertTrue(success, "error in parsing valid iso8601_datetime") + + success, results = pyparsing_common.iso8601_datetime().addParseAction(pyparsing_common.convertToDatetime()).runTests(""" + 1997-07-16T19:20:30.45 + """) + self.assertTrue(success, "error in parsing valid iso8601_datetime") + self.assertTrue(results[0][1][0] == datetime.datetime(1997, 7, 16, 19, 20, 30, 450000)) + + success = pyparsing_common.uuid.runTests(""" + 123e4567-e89b-12d3-a456-426655440000 + """)[0] + self.assertTrue(success, "failed to parse valid uuid") + + success = pyparsing_common.fraction.runTests(""" + 1/2 + -15/16 + -3/-4 + """)[0] + self.assertTrue(success, "failed to parse valid fraction") + + success = pyparsing_common.mixed_integer.runTests(""" + 1/2 + -15/16 + -3/-4 + 1 1/2 + 2 -15/16 + 0 -3/-4 + 12 + """)[0] + self.assertTrue(success, "failed to parse valid mixed integer") + + success, results = pyparsing_common.number.runTests(""" + 100 + -3 + 1.732 + -3.14159 + 6.02e23""") + self.assertTrue(success, "failed to parse numerics") + + for test,result in results: + expected = ast.literal_eval(test) + self.assertEqual(result[0], expected, "numeric parse failed (wrong value) (%s should be %s)" % (result[0], expected)) + self.assertEqual(type(result[0]), type(expected), "numeric parse failed (wrong type) (%s should be %s)" % (type(result[0]), type(expected))) + + +class TokenMapTest(ParseTestCase): + def runTest(self): + from pyparsing import tokenMap, Word, hexnums, OneOrMore + + parser = OneOrMore(Word(hexnums)).setParseAction(tokenMap(int, 16)) + success, results = parser.runTests(""" + 00 11 22 aa FF 0a 0d 1a + """, printResults=False) + self.assertTrue(success, "failed to parse hex integers") + print_(results) + self.assertEqual(results[0][-1].asList(), [0, 17, 34, 170, 255, 10, 13, 26], "tokenMap parse action failed") + + +class ParseFileTest(ParseTestCase): + def runTest(self): + from pyparsing import pyparsing_common, OneOrMore + s = """ + 123 456 789 + """ + input_file = StringIO(s) + integer = pyparsing_common.integer + + results = OneOrMore(integer).parseFile(input_file) + print_(results) + + results = OneOrMore(integer).parseFile('test/parsefiletest_input_file.txt') + print_(results) + + +class HTMLStripperTest(ParseTestCase): + def runTest(self): + from pyparsing import pyparsing_common, originalTextFor, OneOrMore, Word, printables + + sample = """ + <html> + Here is some sample <i>HTML</i> text. + </html> + """ + read_everything = originalTextFor(OneOrMore(Word(printables))) + read_everything.addParseAction(pyparsing_common.stripHTMLTags) + + result = read_everything.parseString(sample) + self.assertEqual(result[0].strip(), 'Here is some sample HTML text.') + +class ExprSplitterTest(ParseTestCase): + def runTest(self): + + from pyparsing import Literal, quotedString, pythonStyleComment, Empty + + expr = Literal(';') + Empty() + expr.ignore(quotedString) + expr.ignore(pythonStyleComment) + + + sample = """ + def main(): + this_semi_does_nothing(); + neither_does_this_but_there_are_spaces_afterward(); + a = "a;b"; return a # this is a comment; it has a semicolon! + + def b(): + if False: + z=1000;b("; in quotes"); c=200;return z + return ';' + + class Foo(object): + def bar(self): + '''a docstring; with a semicolon''' + a = 10; b = 11; c = 12 + + # this comment; has several; semicolons + if self.spam: + x = 12; return x # so; does; this; one + x = 15;;; y += x; return y + + def baz(self): + return self.bar + """ + expected = [ + [' this_semi_does_nothing()', ''], + [' neither_does_this_but_there_are_spaces_afterward()', ''], + [' a = "a;b"', 'return a # this is a comment; it has a semicolon!'], + [' z=1000', 'b("; in quotes")', 'c=200', 'return z'], + [" return ';'"], + [" '''a docstring; with a semicolon'''"], + [' a = 10', 'b = 11', 'c = 12'], + [' # this comment; has several; semicolons'], + [' x = 12', 'return x # so; does; this; one'], + [' x = 15', '', '', 'y += x', 'return y'], + ] + + exp_iter = iter(expected) + for line in filter(lambda ll: ';' in ll, sample.splitlines()): + print_(str(list(expr.split(line)))+',') + self.assertEqual(list(expr.split(line)), next(exp_iter), "invalid split on expression") + + print_() + + expected = [ + [' this_semi_does_nothing()', ';', ''], + [' neither_does_this_but_there_are_spaces_afterward()', ';', ''], + [' a = "a;b"', ';', 'return a # this is a comment; it has a semicolon!'], + [' z=1000', ';', 'b("; in quotes")', ';', 'c=200', ';', 'return z'], + [" return ';'"], + [" '''a docstring; with a semicolon'''"], + [' a = 10', ';', 'b = 11', ';', 'c = 12'], + [' # this comment; has several; semicolons'], + [' x = 12', ';', 'return x # so; does; this; one'], + [' x = 15', ';', '', ';', '', ';', 'y += x', ';', 'return y'], + ] + exp_iter = iter(expected) + for line in filter(lambda ll: ';' in ll, sample.splitlines()): + print_(str(list(expr.split(line, includeSeparators=True)))+',') + self.assertEqual(list(expr.split(line, includeSeparators=True)), next(exp_iter), + "invalid split on expression") + + print_() + + + expected = [ + [' this_semi_does_nothing()', ''], + [' neither_does_this_but_there_are_spaces_afterward()', ''], + [' a = "a;b"', 'return a # this is a comment; it has a semicolon!'], + [' z=1000', 'b("; in quotes"); c=200;return z'], + [' a = 10', 'b = 11; c = 12'], + [' x = 12', 'return x # so; does; this; one'], + [' x = 15', ';; y += x; return y'], + ] + exp_iter = iter(expected) + for line in sample.splitlines(): + pieces = list(expr.split(line, maxsplit=1)) + print_(str(pieces)+',') + if len(pieces) == 2: + exp = next(exp_iter) + self.assertEqual(pieces, exp, "invalid split on expression with maxSplits=1") + elif len(pieces) == 1: + self.assertEqual(len(expr.searchString(line)), 0, "invalid split with maxSplits=1 when expr not present") + else: + print_("\n>>> " + line) + self.assertTrue(False, "invalid split on expression with maxSplits=1, corner case") + +class ParseFatalExceptionTest(ParseTestCase): + def runTest(self): + + from pyparsing import Word, nums, ParseFatalException + + success = False + try: + expr = "ZZZ" - Word(nums) + expr.parseString("ZZZ bad") + except ParseFatalException as pfe: + print_('ParseFatalException raised correctly') + success = True + except Exception as e: + print_(type(e)) + print_(e) + + self.assertTrue(success, "bad handling of syntax error") + +class InlineLiteralsUsingTest(ParseTestCase): + def runTest(self): + + from pyparsing import ParserElement, Suppress, Literal, CaselessLiteral, Word, alphas, oneOf, CaselessKeyword, nums + + with AutoReset(ParserElement, "_literalStringClass"): + ParserElement.inlineLiteralsUsing(Suppress) + wd = Word(alphas) + result = (wd + ',' + wd + oneOf("! . ?")).parseString("Hello, World!") + self.assertEqual(len(result), 3, "inlineLiteralsUsing(Suppress) failed!") + + ParserElement.inlineLiteralsUsing(Literal) + result = (wd + ',' + wd + oneOf("! . ?")).parseString("Hello, World!") + self.assertEqual(len(result), 4, "inlineLiteralsUsing(Literal) failed!") + + ParserElement.inlineLiteralsUsing(CaselessKeyword) + result = ("SELECT" + wd + "FROM" + wd).parseString("select color from colors") + self.assertEqual(result.asList(), "SELECT color FROM colors".split(), + "inlineLiteralsUsing(CaselessKeyword) failed!") + + ParserElement.inlineLiteralsUsing(CaselessLiteral) + result = ("SELECT" + wd + "FROM" + wd).parseString("select color from colors") + self.assertEqual(result.asList(), "SELECT color FROM colors".split(), + "inlineLiteralsUsing(CaselessLiteral) failed!") + + integer = Word(nums) + ParserElement.inlineLiteralsUsing(Literal) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + result = date_str.parseString("1999/12/31") + self.assertEqual(result.asList(), ['1999', '/', '12', '/', '31'], "inlineLiteralsUsing(example 1) failed!") + + # change to Suppress + ParserElement.inlineLiteralsUsing(Suppress) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parseString("1999/12/31") # -> ['1999', '12', '31'] + self.assertEqual(result.asList(), ['1999', '12', '31'], "inlineLiteralsUsing(example 2) failed!") + +class CloseMatchTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + searchseq = pp.CloseMatch("ATCATCGAATGGA", 2) + + _, results = searchseq.runTests(""" + ATCATCGAATGGA + XTCATCGAATGGX + ATCATCGAAXGGA + ATCAXXGAATGGA + ATCAXXGAATGXA + ATCAXXGAATGG + """) + expected = ( + [], + [0,12], + [9], + [4,5], + None, + None + ) + + for r, exp in zip(results, expected): + if exp is not None: + self.assertEquals(r[1].mismatches, exp, + "fail CloseMatch between %r and %r" % (searchseq.match_string, r[0])) + print_(r[0], 'exc: %s' % r[1] if exp is None and isinstance(r[1], Exception) + else ("no match", "match")[r[1].mismatches == exp]) + +class DefaultKeywordCharsTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + try: + pp.Keyword("start").parseString("start1000") + except pp.ParseException: + pass + else: + self.assertTrue(False, "failed to fail on default keyword chars") + + try: + pp.Keyword("start", identChars=pp.alphas).parseString("start1000") + except pp.ParseException: + self.assertTrue(False, "failed to match keyword using updated keyword chars") + else: + pass + + with AutoReset(pp.Keyword, "DEFAULT_KEYWORD_CHARS"): + pp.Keyword.setDefaultKeywordChars(pp.alphas) + try: + pp.Keyword("start").parseString("start1000") + except pp.ParseException: + self.assertTrue(False, "failed to match keyword using updated keyword chars") + else: + pass + + try: + pp.CaselessKeyword("START").parseString("start1000") + except pp.ParseException: + pass + else: + self.assertTrue(False, "failed to fail on default keyword chars") + + try: + pp.CaselessKeyword("START", identChars=pp.alphas).parseString("start1000") + except pp.ParseException: + self.assertTrue(False, "failed to match keyword using updated keyword chars") + else: + pass + + with AutoReset(pp.Keyword, "DEFAULT_KEYWORD_CHARS"): + pp.Keyword.setDefaultKeywordChars(pp.alphas) + try: + pp.CaselessKeyword("START").parseString("start1000") + except pp.ParseException: + self.assertTrue(False, "failed to match keyword using updated keyword chars") + else: + pass + +class ColTest(ParseTestCase): + def runTest(self): + + test = "*\n* \n* ALF\n*\n" + initials = [c for i, c in enumerate(test) if pp.col(i, test) == 1] + print_(initials) + self.assertTrue(len(initials) == 4 and all(c=='*' for c in initials), 'fail col test') + +class LiteralExceptionTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + for cls in (pp.Literal, pp.CaselessLiteral, pp.Keyword, pp.CaselessKeyword, + pp.Word, pp.Regex): + 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 {} raised wrong exception type {}".format(cls.__name__, type(e).__name__)) + +class ParseActionExceptionTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + import traceback + + number = pp.Word(pp.nums) + def number_action(): + raise IndexError # this is the important line! + + number.setParseAction(number_action) + symbol = pp.Word('abcd', max=1) + expr = number | symbol + + try: + expr.parseString('1 + 2') + except Exception as e: + self.assertTrue(hasattr(e, '__cause__'), "no __cause__ attribute in the raised exception") + self.assertTrue(e.__cause__ is not None, "__cause__ not propagated to outer exception") + self.assertTrue(type(e.__cause__) == IndexError, "__cause__ references wrong exception") + traceback.print_exc() + else: + self.assertTrue(False, "Expected ParseException not raised") + +class ParseActionNestingTest(ParseTestCase): + # tests Issue #22 + def runTest(self): + + vals = pp.OneOrMore(pp.pyparsing_common.integer)("int_values") + def add_total(tokens): + tokens['total'] = sum(tokens) + return tokens + vals.addParseAction(add_total) + results = vals.parseString("244 23 13 2343") + print_(results.dump()) + self.assertEqual(results.int_values.asDict(), {}, "noop parse action changed ParseResults structure") + + name = pp.Word(pp.alphas)('name') + score = pp.Word(pp.nums + '.')('score') + nameScore = pp.Group(name + score) + line1 = nameScore('Rider') + + result1 = line1.parseString('Mauney 46.5') + + print_("### before parse action is added ###") + print_("result1.dump():\n" + result1.dump() + "\n") + before_pa_dict = result1.asDict() + + line1.setParseAction(lambda t: t) + + result1 = line1.parseString('Mauney 46.5') + after_pa_dict = result1.asDict() + + print_("### after parse action was added ###") + print_("result1.dump():\n" + result1.dump() + "\n") + self.assertEqual(before_pa_dict, after_pa_dict, "noop parse action changed ParseResults structure") + +class ParseResultsNameBelowUngroupedNameTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + rule_num = pp.Regex("[0-9]+")("LIT_NUM*") + list_num = pp.Group(pp.Literal("[")("START_LIST") + + pp.delimitedList(rule_num)("LIST_VALUES") + + pp.Literal("]")("END_LIST"))("LIST") + + test_string = "[ 1,2,3,4,5,6 ]" + list_num.runTests(test_string) + + U = list_num.parseString(test_string) + self.assertTrue("LIT_NUM" not in U.LIST.LIST_VALUES, "results name retained as sub in ungrouped named result") + +class ParseResultsNamesInGroupWithDictTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + key = pp.pyparsing_common.identifier() + value = pp.pyparsing_common.integer() + lat = pp.pyparsing_common.real() + long = pp.pyparsing_common.real() + EQ = pp.Suppress('=') + + data = lat("lat") + long("long") + pp.Dict(pp.OneOrMore(pp.Group(key + EQ + value))) + site = pp.QuotedString('"')("name") + pp.Group(data)("data") + + test_string = '"Golden Gate Bridge" 37.819722 -122.478611 height=746 span=4200' + site.runTests(test_string) + + # U = list_num.parseString(test_string) + # self.assertTrue("LIT_NUM" not in U.LIST.LIST_VALUES, "results name retained as sub in ungrouped named result") + +class FollowedByTest(ParseTestCase): + def runTest(self): + expr = pp.Word(pp.alphas)("item") + pp.FollowedBy(pp.pyparsing_common.integer("qty")) + result = expr.parseString("balloon 99") + print_(result.dump()) + self.assertTrue('qty' in result, "failed to capture results name in FollowedBy") + self.assertEqual(result.asDict(), {'item': 'balloon', 'qty': 99}, + "invalid results name structure from FollowedBy") + +class SetBreakTest(ParseTestCase): + """ + Test behavior of ParserElement.setBreak(), to invoke the debugger before parsing that element is attempted. + + Temporarily monkeypatches pdb.set_trace. + """ + def runTest(self): + was_called = [] + def mock_set_trace(): + was_called.append(True) + + import pyparsing as pp + wd = pp.Word(pp.alphas) + wd.setBreak() + + print_("Before parsing with setBreak:", was_called) + import pdb + with AutoReset(pdb, "set_trace"): + pdb.set_trace = mock_set_trace + wd.parseString("ABC") + + print_("After parsing with setBreak:", was_called) + self.assertTrue(bool(was_called), "set_trace wasn't called by setBreak") + +class UnicodeTests(ParseTestCase): + def runTest(self): + import pyparsing as pp + p_u = pp.pyparsing_unicode + + # verify proper merging of ranges by addition + kanji_printables = p_u.Japanese.Kanji.printables + katakana_printables = p_u.Japanese.Katakana.printables + hiragana_printables = p_u.Japanese.Hiragana.printables + japanese_printables = p_u.Japanese.printables + self.assertEqual(set(japanese_printables), set(kanji_printables + + katakana_printables + + hiragana_printables), + "failed to construct ranges by merging Japanese types") + + # verify proper merging of ranges using multiple inheritance + cjk_printables = p_u.CJK.printables + self.assertEqual(len(cjk_printables), len(set(cjk_printables)), + "CJK contains duplicate characters - all should be unique") + + chinese_printables = p_u.Chinese.printables + korean_printables = p_u.Korean.printables + print_(len(cjk_printables), len(set(chinese_printables + + korean_printables + + japanese_printables))) + + self.assertEqual(len(cjk_printables), len(set(chinese_printables + + korean_printables + + japanese_printables)), + "failed to construct ranges by merging Chinese, Japanese and Korean") + + alphas = pp.pyparsing_unicode.Greek.alphas + greet = pp.Word(alphas) + ',' + pp.Word(alphas) + '!' + + # input string + hello = u"Καλημέρα, κόσμε!" + result = greet.parseString(hello) + print_(result) + self.assertTrue(result.asList() == [u'Καλημέρα', ',', u'κόσμε', '!'], + "Failed to parse Greek 'Hello, World!' using pyparsing_unicode.Greek.alphas") + + # define a custom unicode range using multiple inheritance + class Turkish_set(pp.pyparsing_unicode.Latin1, pp.pyparsing_unicode.LatinA): + pass + + self.assertEqual(set(Turkish_set.printables), + set(pp.pyparsing_unicode.Latin1.printables + + pp.pyparsing_unicode.LatinA.printables), + "failed to construct ranges by merging Latin1 and LatinA (printables)") + + self.assertEqual(set(Turkish_set.alphas), + set(pp.pyparsing_unicode.Latin1.alphas + + pp.pyparsing_unicode.LatinA.alphas), + "failed to construct ranges by merging Latin1 and LatinA (alphas)") + + self.assertEqual(set(Turkish_set.nums), + set(pp.pyparsing_unicode.Latin1.nums + + pp.pyparsing_unicode.LatinA.nums), + "failed to construct ranges by merging Latin1 and LatinA (nums)") + + key = pp.Word(Turkish_set.alphas) + value = pp.pyparsing_common.integer | pp.Word(Turkish_set.alphas, Turkish_set.alphanums) + EQ = pp.Suppress('=') + key_value = key + EQ + value + + sample = u"""\ + şehir=İzmir + ülke=Türkiye + nüfus=4279677""" + result = pp.Dict(pp.OneOrMore(pp.Group(key_value))).parseString(sample) + + print_(result.asDict()) + self.assertEqual(result.asDict(), {u'şehir': u'İzmir', u'ülke': u'Türkiye', u'nüfus': 4279677}, + "Failed to parse Turkish key-value pairs") + +class IndentedBlockTest(ParseTestCase): + # parse pseudo-yaml indented text + def runTest(self): + if pp.ParserElement.packrat_cache: + print_("cannot test indentedBlock with packrat enabled") + return + import textwrap + + EQ = pp.Suppress('=') + stack = [1] + key = pp.pyparsing_common.identifier + value = pp.Forward() + key_value = key + EQ + value + compound_value = pp.Dict(pp.ungroup(pp.indentedBlock(key_value, stack))) + value <<= pp.pyparsing_common.integer | pp.QuotedString("'") | compound_value + parser = pp.Dict(pp.OneOrMore(pp.Group(key_value))) + + text = """\ + a = 100 + b = 101 + c = + c1 = 200 + c2 = + c21 = 999 + c3 = 'A horse, a horse, my kingdom for a horse' + d = 505 + """ + text = textwrap.dedent(text) + print_(text) + + result = parser.parseString(text) + print_(result.dump()) + self.assertEqual(result.a, 100, "invalid indented block result") + self.assertEqual(result.c.c1, 200, "invalid indented block result") + self.assertEqual(result.c.c2.c21, 999, "invalid indented block result") + +class ParseResultsWithNameMatchFirst(ParseTestCase): + def runTest(self): + import pyparsing as pp + expr_a = pp.Literal('not') + pp.Literal('the') + pp.Literal('bird') + expr_b = pp.Literal('the') + pp.Literal('bird') + expr = (expr_a | expr_b)('rexp') + expr.runTests("""\ + not the bird + the bird + """) + self.assertEqual(list(expr.parseString('not the bird')['rexp']), 'not the bird'.split()) + self.assertEqual(list(expr.parseString('the bird')['rexp']), 'the bird'.split()) + +class ParseResultsWithNameOr(ParseTestCase): + def runTest(self): + import pyparsing as pp + expr_a = pp.Literal('not') + pp.Literal('the') + pp.Literal('bird') + expr_b = pp.Literal('the') + pp.Literal('bird') + expr = (expr_a ^ expr_b)('rexp') + expr.runTests("""\ + not the bird + the bird + """) + self.assertEqual(list(expr.parseString('not the bird')['rexp']), 'not the bird'.split()) + self.assertEqual(list(expr.parseString('the bird')['rexp']), 'the bird'.split()) + +class EmptyDictDoesNotRaiseException(ParseTestCase): + def runTest(self): + import pyparsing as pp + + key = pp.Word(pp.alphas) + value = pp.Word(pp.nums) + EQ = pp.Suppress('=') + key_value_dict = pp.dictOf(key, EQ + value) + + print_(key_value_dict.parseString("""\ + a = 10 + b = 20 + """).dump()) + + try: + print_(key_value_dict.parseString("").dump()) + except pp.ParseException as pe: + print_(pp.ParseException.explain(pe)) + else: + self.assertTrue(False, "failed to raise exception when matching empty string") + +class ExplainExceptionTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + expr = pp.Word(pp.nums).setName("int") + pp.Word(pp.alphas).setName("word") + try: + expr.parseString("123 355") + except pp.ParseException as pe: + print_(pp.ParseException.explain(pe, depth=0)) + + expr = pp.Word(pp.nums).setName("int") - pp.Word(pp.alphas).setName("word") + try: + expr.parseString("123 355 (test using ErrorStop)") + except pp.ParseSyntaxException as pe: + print_(pp.ParseException.explain(pe)) + + integer = pp.Word(pp.nums).setName("int").addParseAction(lambda t: int(t[0])) + expr = integer + integer + + def divide_args(t): + integer.parseString("A") + return t[0] / t[1] + + expr.addParseAction(divide_args) + pp.ParserElement.enablePackrat() + print_() + # ~ print(expr.parseString("125 25")) + + try: + expr.parseString("123 0") + except pp.ParseException as pe: + print_(pp.ParseException.explain(pe)) + except Exception as exc: + print_(pp.ParseException.explain(exc)) + raise + + +class CaselessKeywordVsKeywordCaselessTest(ParseTestCase): + def runTest(self): + import pyparsing as pp + + frule = pp.Keyword('t', caseless=True) + pp.Keyword('yes', caseless=True) + crule = pp.CaselessKeyword('t') + pp.CaselessKeyword('yes') + + flist = frule.searchString('not yes').asList() + print_(flist) + clist = crule.searchString('not yes').asList() + print_(clist) + self.assertEqual(flist, clist, "CaselessKeyword not working the same as Keyword(caseless=True)") + + +class MiscellaneousParserTests(ParseTestCase): + def runTest(self): + + runtests = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + if IRON_PYTHON_ENV: + runtests = "ABCDEGHIJKLMNOPQRSTUVWXYZ" + + # test making oneOf with duplicate symbols + if "A" in runtests: + print_("verify oneOf handles duplicate symbols") + try: + test1 = pp.oneOf("a b c d a") + except RuntimeError: + self.assertTrue(False,"still have infinite loop in oneOf with duplicate symbols (string input)") + + print_("verify oneOf handles generator input") + try: + test1 = pp.oneOf(c for c in "a b c d a" if not c.isspace()) + except RuntimeError: + self.assertTrue(False,"still have infinite loop in oneOf with duplicate symbols (generator input)") + + print_("verify oneOf handles list input") + try: + test1 = pp.oneOf("a b c d a".split()) + except RuntimeError: + self.assertTrue(False,"still have infinite loop in oneOf with duplicate symbols (list input)") + + print_("verify oneOf handles set input") + try: + test1 = pp.oneOf(set("a b c d a")) + except RuntimeError: + self.assertTrue(False,"still have infinite loop in oneOf with duplicate symbols (set input)") + + # test MatchFirst bugfix + if "B" in runtests: + print_("verify MatchFirst iterates properly") + results = pp.quotedString.parseString("'this is a single quoted string'") + self.assertTrue(len(results) > 0, "MatchFirst error - not iterating over all choices") + + # verify streamline of subexpressions + if "C" in runtests: + print_("verify proper streamline logic") + compound = pp.Literal("A") + "B" + "C" + "D" + self.assertEqual(len(compound.exprs), 2,"bad test setup") + print_(compound) + compound.streamline() + print_(compound) + self.assertEqual(len(compound.exprs), 4,"streamline not working") + + # test for Optional with results name and no match + if "D" in runtests: + print_("verify Optional's do not cause match failure if have results name") + testGrammar = pp.Literal("A") + pp.Optional("B")("gotB") + pp.Literal("C") + try: + testGrammar.parseString("ABC") + testGrammar.parseString("AC") + except pp.ParseException as pe: + print_(pe.pstr,"->",pe) + self.assertTrue(False, "error in Optional matching of string %s" % pe.pstr) + + # test return of furthest exception + if "E" in runtests: + testGrammar = ( pp.Literal("A") | + ( pp.Optional("B") + pp.Literal("C") ) | + pp.Literal("D") ) + try: + testGrammar.parseString("BC") + testGrammar.parseString("BD") + except pp.ParseException as pe: + print_(pe.pstr,"->",pe) + self.assertEqual(pe.pstr, "BD", "wrong test string failed to parse") + self.assertEqual(pe.loc, 1, "error in Optional matching, pe.loc="+str(pe.loc)) + + # test validate + if "F" in runtests: + print_("verify behavior of validate()") + def testValidation( grmr, gnam, isValid ): + try: + grmr.streamline() + grmr.validate() + self.assertTrue(isValid,"validate() accepted invalid grammar " + gnam) + except pp.RecursiveGrammarException as e: + print_(grmr) + self.assertFalse(isValid, "validate() rejected valid grammar " + gnam) + + fwd = pp.Forward() + g1 = pp.OneOrMore( ( pp.Literal("A") + "B" + "C" ) | fwd ) + g2 = pp.ZeroOrMore("C" + g1) + fwd << pp.Group(g2) + testValidation( fwd, "fwd", isValid=True ) + + fwd2 = pp.Forward() + fwd2 << pp.Group("A" | fwd2) + testValidation( fwd2, "fwd2", isValid=False ) + + fwd3 = pp.Forward() + fwd3 << pp.Optional("A") + fwd3 + testValidation( fwd3, "fwd3", isValid=False ) + + # test getName + if "G" in runtests: + print_("verify behavior of getName()") + aaa = pp.Group(pp.Word("a")("A")) + bbb = pp.Group(pp.Word("b")("B")) + ccc = pp.Group(":" + pp.Word("c")("C")) + g1 = "XXX" + pp.ZeroOrMore( aaa | bbb | ccc ) + teststring = "XXX b bb a bbb bbbb aa bbbbb :c bbbbbb aaa" + names = [] + print_(g1.parseString(teststring).dump()) + for t in g1.parseString(teststring): + print_(t, repr(t)) + try: + names.append( t[0].getName() ) + except Exception: + try: + names.append( t.getName() ) + except Exception: + names.append( None ) + print_(teststring) + print_(names) + self.assertEqual(names, [None, 'B', 'B', 'A', 'B', 'B', 'A', 'B', None, 'B', 'A'], + "failure in getting names for tokens") + + from pyparsing import Keyword, Word, alphas, OneOrMore + IF,AND,BUT = map(Keyword, "if and but".split()) + ident = ~(IF | AND | BUT) + Word(alphas)("non-key") + scanner = OneOrMore(IF | AND | BUT | ident) + def getNameTester(s,l,t): + print_(t, t.getName()) + ident.addParseAction(getNameTester) + scanner.parseString("lsjd sldkjf IF Saslkj AND lsdjf") + + # test ParseResults.get() method + if "H" in runtests: + print_("verify behavior of ParseResults.get()") + # use sum() to merge separate groups into single ParseResults + res = sum(g1.parseString(teststring)[1:]) + print_(res.dump()) + print_(res.get("A","A not found")) + print_(res.get("D","!D")) + self.assertEqual(res.get("A","A not found"), "aaa", "get on existing key failed") + self.assertEqual(res.get("D","!D"), "!D", "get on missing key failed") + + if "I" in runtests: + print_("verify handling of Optional's beyond the end of string") + testGrammar = "A" + pp.Optional("B") + pp.Optional("C") + pp.Optional("D") + testGrammar.parseString("A") + testGrammar.parseString("AB") + + # test creating Literal with empty string + if "J" in runtests: + print_('verify non-fatal usage of Literal("")') + e = pp.Literal("") + try: + e.parseString("SLJFD") + except Exception as e: + self.assertTrue(False, "Failed to handle empty Literal") + + # test line() behavior when starting at 0 and the opening line is an \n + if "K" in runtests: + print_('verify correct line() behavior when first line is empty string') + self.assertEqual(pp.line(0, "\nabc\ndef\n"), '', "Error in line() with empty first line in text") + txt = "\nabc\ndef\n" + results = [ pp.line(i,txt) for i in range(len(txt)) ] + self.assertEqual(results, ['', 'abc', 'abc', 'abc', 'abc', 'def', 'def', 'def', 'def'], + "Error in line() with empty first line in text") + txt = "abc\ndef\n" + results = [ pp.line(i,txt) for i in range(len(txt)) ] + self.assertEqual(results, ['abc', 'abc', 'abc', 'abc', 'def', 'def', 'def', 'def'], + "Error in line() with non-empty first line in text") + + # test bugfix with repeated tokens when packrat parsing enabled + if "L" in runtests: + print_('verify behavior with repeated tokens when packrat parsing is enabled') + a = pp.Literal("a") + b = pp.Literal("b") + c = pp.Literal("c") + + abb = a + b + b + abc = a + b + c + aba = a + b + a + grammar = abb | abc | aba + + self.assertEqual(''.join(grammar.parseString( "aba" )), 'aba', "Packrat ABA failure!") + + if "M" in runtests: + print_('verify behavior of setResultsName with OneOrMore and ZeroOrMore') + + stmt = pp.Keyword('test') + print_(pp.ZeroOrMore(stmt)('tests').parseString('test test').tests) + print_(pp.OneOrMore(stmt)('tests').parseString('test test').tests) + print_(pp.Optional(pp.OneOrMore(stmt)('tests')).parseString('test test').tests) + print_(pp.Optional(pp.OneOrMore(stmt))('tests').parseString('test test').tests) + print_(pp.Optional(pp.delimitedList(stmt))('tests').parseString('test,test').tests) + self.assertEqual(len(pp.ZeroOrMore(stmt)('tests').parseString('test test').tests), 2, "ZeroOrMore failure with setResultsName") + self.assertEqual(len(pp.OneOrMore(stmt)('tests').parseString('test test').tests), 2, "OneOrMore failure with setResultsName") + self.assertEqual(len(pp.Optional(pp.OneOrMore(stmt)('tests')).parseString('test test').tests), 2, "OneOrMore failure with setResultsName") + self.assertEqual(len(pp.Optional(pp.delimitedList(stmt))('tests').parseString('test,test').tests), 2, "delimitedList failure with setResultsName") + self.assertEqual(len((stmt*2)('tests').parseString('test test').tests), 2, "multiplied(1) failure with setResultsName") + self.assertEqual(len((stmt*(None,2))('tests').parseString('test test').tests), 2, "multiplied(2) failure with setResultsName") + self.assertEqual(len((stmt*(1,))('tests').parseString('test test').tests), 2, "multipled(3) failure with setResultsName") + self.assertEqual(len((stmt*(2,))('tests').parseString('test test').tests), 2, "multipled(3) failure with setResultsName") + +def makeTestSuite(): + import inspect + suite = TestSuite() + suite.addTest( PyparsingTestInit() ) + + test_case_classes = ParseTestCase.__subclasses__() + # put classes in order as they are listed in the source code + test_case_classes.sort(key=lambda cls: inspect.getsourcelines(cls)[1]) + + test_case_classes.remove(PyparsingTestInit) + # test_case_classes.remove(ParseASMLTest) + test_case_classes.remove(EnablePackratParsing) + if IRON_PYTHON_ENV: + test_case_classes.remove(OriginalTextForTest) + + suite.addTests(T() for T in test_case_classes) + + if TEST_USING_PACKRAT: + # retest using packrat parsing (disable those tests that aren't compatible) + suite.addTest( EnablePackratParsing() ) + + unpackrattables = [ PyparsingTestInit, EnablePackratParsing, RepeaterTest, ] + + # add tests to test suite a second time, to run with packrat parsing + # (leaving out those that we know wont work with packrat) + packratTests = [t.__class__() for t in suite._tests + if t.__class__ not in unpackrattables] + suite.addTests( packratTests ) + + return suite + +def makeTestSuiteTemp(classes): + suite = TestSuite() + suite.addTest(PyparsingTestInit()) + for cls in classes: + suite.addTest(cls()) + return suite + +if __name__ == '__main__': + + testRunner = TextTestRunner() + + # run specific tests by including them in this list, otherwise + # all tests will be run + testclasses = [ + ] + + if not testclasses: + testRunner.run(makeTestSuite()) + else: + BUFFER_OUTPUT = False + testRunner.run(makeTestSuiteTemp(testclasses))