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