summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorptmcg <ptmcg@9bf210a0-9d2d-494c-87cf-cfb32e7dff7b>2015-10-31 17:58:32 +0000
committerptmcg <ptmcg@9bf210a0-9d2d-494c-87cf-cfb32e7dff7b>2015-10-31 17:58:32 +0000
commite9d3d92b2c1ae540479ab5397adf1b95d16871d8 (patch)
tree1a5e7380827ef586b12f54b3764429d7e40fb033
parent7000d600e5e7a29acc60c3ad8e13d3751e5cc8b4 (diff)
downloadpyparsing-e9d3d92b2c1ae540479ab5397adf1b95d16871d8.tar.gz
Fixed bug in Each with multiple Optionals; added parseAll and output cleanup to runTests; improved exception messages for MatchFirst and Or exceptions.
git-svn-id: svn://svn.code.sf.net/p/pyparsing/code/trunk@296 9bf210a0-9d2d-494c-87cf-cfb32e7dff7b
-rw-r--r--src/CHANGES18
-rw-r--r--src/pyparsing.py35
-rw-r--r--src/unitTests.py18
3 files changed, 57 insertions, 14 deletions
diff --git a/src/CHANGES b/src/CHANGES
index 7c51766..7332ce7 100644
--- a/src/CHANGES
+++ b/src/CHANGES
@@ -2,6 +2,24 @@
Change Log
==========
+Version 2.0.6 -
+---------------------------
+- Fixed a bug in Each when multiple Optional elements are present.
+ Thanks for reporting this, whereswalden on SO.
+
+- Added optional parseAll argument to runTests, whether tests should
+ require the entire input string to be parsed or not (similar to
+ parseAll argument to parseString). Plus a little neaten-up of the
+ output on Python 2 (no stray ()'s).
+
+- Modified exception messages from MatchFirst and Or expressions. These
+ were formerly misleading as they would only give the first or longest
+ exception mismatch error message. Now the error message includes all
+ the alternatives that were possible matches. Originally proposed by
+ a pyparsing user, but I've lost the email thread - finally figured out
+ a fairly clean way to do this.
+
+
Version 2.0.5 -
---------------------------
- (&$(@#&$(@!!!! Some "print" statements snuck into pyparsing v2.0.4,
diff --git a/src/pyparsing.py b/src/pyparsing.py
index ef429db..d239524 100644
--- a/src/pyparsing.py
+++ b/src/pyparsing.py
@@ -57,8 +57,8 @@ The pyparsing module handles some of the problems that are typically vexing when
- embedded comments
"""
-__version__ = "2.0.5"
-__versionTime__ = "29 Oct 2015 08:08"
+__version__ = "2.0.6"
+__versionTime__ = "31 Oct 2015 12:41"
__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
import string
@@ -1548,25 +1548,30 @@ class ParserElement(object):
def __rne__(self,other):
return not (self == other)
- def runTests(self, tests):
+ def runTests(self, tests, parseAll=False):
"""Execute the parse expression on a series of test strings, showing each
test, the parsed results or where the parse failed. Quick and easy way to
run a parse expression against a list of sample strings.
+
+ Parameters:
+ - tests - a list of separate test strings, or a multiline string of test strings
+ - parseAll - (default=False) - flag to pass to C{L{parseString}} when running tests
"""
if isinstance(tests, basestring):
tests = map(str.strip, tests.splitlines())
for t in tests:
- print (t)
+ out = [t]
try:
- print (self.parseString(t).dump())
+ out.append(self.parseString(t, parseAll=parseAll).dump())
except ParseException as pe:
if '\n' in t:
- print (line(pe.loc, t))
- print (' '*(col(pe.loc,t)-1) + '^')
+ out.append(line(pe.loc, t))
+ out.append(' '*(col(pe.loc,t)-1) + '^')
else:
- print (' '*pe.loc + '^')
- print (pe)
- print()
+ out.append(' '*pe.loc + '^')
+ out.append(str(pe))
+ out.append('')
+ print('\n'.join(out))
class Token(ParserElement):
@@ -2348,6 +2353,8 @@ class ParseExpression(ParserElement):
self.mayReturnEmpty |= other.mayReturnEmpty
self.mayIndexError |= other.mayIndexError
+ self.errmsg = "Expected " + str(self)
+
return self
def setResultsName( self, name, listAllMatches=False ):
@@ -2466,6 +2473,7 @@ class Or(ParseExpression):
if maxMatchLoc < 0:
if maxException is not None:
+ maxException.msg = self.errmsg
raise maxException
else:
raise ParseException(instring, loc, "no defined alternatives to match", self)
@@ -2523,6 +2531,7 @@ class MatchFirst(ParseExpression):
# only got here if no expression matched, raise exception for match that made it the furthest
else:
if maxException is not None:
+ maxException.msg = self.errmsg
raise maxException
else:
raise ParseException(instring, loc, "no defined alternatives to match", self)
@@ -2561,7 +2570,7 @@ class Each(ParseExpression):
def parseImpl( self, instring, loc, doActions=True ):
if self.initExprGroups:
opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ]
- opt2 = [ e for e in self.exprs if e.mayReturnEmpty and e not in opt1 ]
+ opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)]
self.optionals = opt1 + opt2
self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ]
self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ]
@@ -3766,9 +3775,9 @@ if __name__ == "__main__":
ident = Word( alphas, alphanums + "_$" )
columnName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
- columnNameList = Group( delimitedList( columnName ) )#.setName("columns")
+ columnNameList = Group( delimitedList( columnName ) ).setName("columns")
tableName = delimitedList( ident, ".", combine=True ).setParseAction( upcaseTokens )
- tableNameList = Group( delimitedList( tableName ) )#.setName("tables")
+ tableNameList = Group( delimitedList( tableName ) ).setName("tables")
simpleSQL = ( selectToken + \
( '*' | columnNameList ).setResultsName( "columns" ) + \
fromToken + \
diff --git a/src/unitTests.py b/src/unitTests.py
index a675ffe..422ceb3 100644
--- a/src/unitTests.py
+++ b/src/unitTests.py
@@ -2120,7 +2120,7 @@ class WordBoundaryExpressionsTest(ParseTestCase):
print_()
class OptionalEachTest(ParseTestCase):
- def runTest(self):
+ def runTest1(self):
from pyparsing import Optional, Keyword
the_input = "Major Tal Weiss"
@@ -2131,6 +2131,22 @@ class OptionalEachTest(ParseTestCase):
assert 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, Suppress, 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'))
+
+ assert modifiers == "with foo=bar bing=baz using id-deadbeef"
+ assert not modifiers == "with foo=bar bing=baz using id-deadbeef using id-feedfeed"
+
+ def runTest(self):
+ self.runTest1()
+ self.runTest2()
+
class SumParseResultsTest(ParseTestCase):
def runTest(self):