python-pyparsing/pass_unitTests.patch
Matej Cepl 046202169a - Repackage back to plain 2.3.0 tarball with appropriate patches:
* docs_to_tarball_tests_pass_py2k.patch (gh#pyparsing/pyparsing#47)
    * pass_unitTests.patch (gh#pyparsing/pyparsing#63)

OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-pyparsing?expand=0&rev=54
2019-01-08 14:07:22 +00:00

4199 lines
168 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

--- /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))