python-pyparsing/pass_unitTests.patch

4199 lines
168 KiB
Diff
Raw Normal View History

--- /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<string> stringSeq;
+ typedef sequence< sequence<string> > 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<string> /*comment inside an And */ stringSeq;
+ /* */ /**/ /***/ /****/
+ typedef sequence< sequence<string> > 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<string> 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 = """
+ <table border="0" cellpadding="3" cellspacing="3" frame="" width="90%">
+ <tr align="left" valign="top">
+ <td><b>Name</b></td>
+ <td><b>IP Address</b></td>
+ <td><b>Location</b></td>
+ </tr>
+ <tr align="left" valign="top" bgcolor="#c7efce">
+ <td>time-a.nist.gov</td>
+ <td>129.6.15.28</td>
+ <td>NIST, Gaithersburg, Maryland</td>
+ </tr>
+ <tr align="left" valign="top">
+ <td>time-b.nist.gov</td>
+ <td>129.6.15.29</td>
+ <td>NIST, Gaithersburg, Maryland</td>
+ </tr>
+ <tr align="left" valign="top" bgcolor="#c7efce">
+ <td>time-a.timefreq.bldrdoc.gov</td>
+ <td>132.163.4.101</td>
+ <td>NIST, Boulder, Colorado</td>
+ </tr>
+ <tr align="left" valign="top">
+ <td>time-b.timefreq.bldrdoc.gov</td>
+ <td>132.163.4.102</td>
+ <td>NIST, Boulder, Colorado</td>
+ </tr>
+ <tr align="left" valign="top" bgcolor="#c7efce">
+ <td>time-c.timefreq.bldrdoc.gov</td>
+ <td>132.163.4.103</td>
+ <td>NIST, Boulder, Colorado</td>
+ </tr>
+ </table>
+ """
+ integer = Word(nums)
+ ipAddress = Combine( integer + "." + integer + "." + integer + "." + integer )
+ tdStart = Suppress("<td>")
+ tdEnd = Suppress("</td>")
+ 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(["",
+ "<TEST>",
+ " <ITEM>XXX&gt;&amp;&lt;</ITEM>",
+ " <B>",
+ " <ITEM>b</ITEM>",
+ " </B>",
+ " <B>",
+ " <ITEM>b</ITEM>",
+ " </B>",
+ " <A>a</A>",
+ " <B>",
+ " <ITEM>b</ITEM>",
+ " </B>",
+ " <B>",
+ " <ITEM>b</ITEM>",
+ " </B>",
+ " <A>a</A>",
+ " <B>",
+ " <ITEM>b</ITEM>",
+ " </B>",
+ " <C>:c</C>",
+ " <B>",
+ " <ITEM>b</ITEM>",
+ " </B>",
+ " <A>a</A>",
+ "</TEST>",
+ ] ), \
+ "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(["",
+ "<TEST>",
+ " <B>",
+ " <ITEM>b</ITEM>",
+ " </B>",
+ " <B>",
+ " <ITEM>b</ITEM>",
+ " </B>",
+ " <A>a</A>",
+ " <B>",
+ " <ITEM>b</ITEM>",
+ " </B>",
+ " <B>",
+ " <ITEM>b</ITEM>",
+ " </B>",
+ " <A>a</A>",
+ " <B>",
+ " <ITEM>b</ITEM>",
+ " </B>",
+ " <C>:c</C>",
+ " <B>",
+ " <ITEM>b</ITEM>",
+ " </B>",
+ " <A>a</A>",
+ "</TEST>",
+ ] ), \
+ "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 = """
+ <!-- -->
+ <!--- --->
+ <!---->
+ <!----->
+ <!------>
+ <!-- /-->
+ <!--- /-->
+ <!---- /-->
+ <!---- /- ->
+ <!---- / -- >
+ <!--
+ ablsjdflj
+ -->
+ """
+ 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("<BODY BGCOLOR='#00FFBB' FGCOLOR=black>")
+ 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 = """
+ <BODY>
+ <BODY BGCOLOR="#00FFCC">
+ <BODY BGCOLOR="#00FFAA"/>
+ <BODY BGCOLOR='#00FFBB' FGCOLOR=black>
+ <BODY/>
+ </BODY>
+ """
+ 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"<TR class=maintxt bgColor=#ffffff> \
+ <TD vAlign=top>Производитель, модель</TD> \
+ <TD vAlign=top><STRONG>BenQ-Siemens CF61</STRONG></TD> \
+ "#.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<content>[^\"]*)")')
+ 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<num1>\d+) (?P<num2>\d+) (?P<last_word>\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"<title>").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 &lt;lsdjkf&gt;&amp;&apos;&quot;&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))