diff options
-rw-r--r-- | src/CHANGES | 9 | ||||
-rw-r--r-- | src/pyparsing.py | 24 | ||||
-rw-r--r-- | src/unitTests.py | 16 |
3 files changed, 42 insertions, 7 deletions
diff --git a/src/CHANGES b/src/CHANGES index 5c43a44..1f3624b 100644 --- a/src/CHANGES +++ b/src/CHANGES @@ -4,6 +4,15 @@ Change Log Version 2.0.8 -
---------------------------
+- Modified the internal _trim_arity method to distinguish between
+ TypeError's raised while trying to determine parse action arity and
+ those raised within the parse action itself. This will clear up those
+ confusing "<lambda>() takes exactly 1 argument (0 given)" error
+ messages when there is an actual TypeError in the body of the parse
+ action. Thanks to all who have raised this issue in the past, and
+ most recently to Michael Cohen, who sent in a proposed patch, and got
+ me to finally tackle this problem.
+
- Added expression names for many internal and builtin expressions, to
reduce name and error message overhead during parsing.
diff --git a/src/pyparsing.py b/src/pyparsing.py index d1d5b53..808e640 100644 --- a/src/pyparsing.py +++ b/src/pyparsing.py @@ -58,7 +58,7 @@ The pyparsing module handles some of the problems that are typically vexing when """
__version__ = "2.0.8"
-__versionTime__ = "31 Dec 2015 19:10"
+__versionTime__ = "17 Jan 2016 21:22"
__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
import string
@@ -72,6 +72,7 @@ import collections import pprint
import functools
import itertools
+import traceback
#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
@@ -766,16 +767,28 @@ def _trim_arity(func, maxargs=2): def wrapper(*args):
while 1:
try:
- ret = func(*args[limit[0]:])
+ ret = func(*args[limit[0]:]) #~@$^*)+_(&%#!=-`~;:"[]{}
foundArity[0] = True
return ret
except TypeError:
- if limit[0] <= maxargs and not foundArity[0]:
+ # re-raise TypeErrors if they did not come from our arity testing
+ if foundArity[0]:
+ raise
+ else:
+ try:
+ tb = sys.exc_info()[-1]
+ exc_source_line = traceback.extract_tb(tb)[-1][-1]
+ if not exc_source_line.endswith('#~@$^*)+_(&%#!=-`~;:"[]{}'):
+ raise
+ finally:
+ del tb
+
+ if limit[0] <= maxargs:
limit[0] += 1
continue
raise
return wrapper
-
+
class ParserElement(object):
"""Abstract base level parser element class."""
DEFAULT_WHITE_CHARS = " \n\t\r"
@@ -1715,7 +1728,7 @@ class Word(Token): maximum, and/or exact length. The default value for C{min} is 1 (a
minimum value < 1 is not valid); the default values for C{max} and C{exact}
are 0, meaning no maximum or exact length restriction. An optional
- C{exclude} parameter can list characters that might be found in
+ C{excludeChars} parameter can list characters that might be found in
the input C{bodyChars} string; useful to define a word of all printables
except for one or two characters, for instance.
"""
@@ -3804,4 +3817,3 @@ if __name__ == "__main__": Select
Select ^^^ frox Sys.dual
Select A, B, C from Sys.dual, Table2""")
-
diff --git a/src/unitTests.py b/src/unitTests.py index ab40888..cf840eb 100644 --- a/src/unitTests.py +++ b/src/unitTests.py @@ -2363,6 +2363,19 @@ class SetNameTest(ParseTestCase): tname = str(t)
assert 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)
+ assert exc_msg != invalid_message, "failed to catch TypeError thrown in _trim_arity"
class MiscellaneousParserTests(ParseTestCase):
def runTest(self):
@@ -2577,6 +2590,7 @@ def makeTestSuite(): suite.addTest( EachWithOptionalWithResultsNameTest() )
suite.addTest( UnicodeExpressionTest() )
suite.addTest( SetNameTest() )
+ suite.addTest( TrimArityExceptionMaskingTest() )
suite.addTest( MiscellaneousParserTests() )
if TEST_USING_PACKRAT:
# retest using packrat parsing (disable those tests that aren't compatible)
@@ -2613,7 +2627,7 @@ if console: testRunner = TextTestRunner()
testRunner.run( makeTestSuite() )
- #~ testclass = SetNameTest
+ #~ testclass = TrimArityExceptionMaskingTest
#~ if lp is None:
#~ testRunner.run( makeTestSuiteTemp(testclass) )
#~ else:
|