diff options
-rw-r--r-- | CHANGES | 14 | ||||
-rw-r--r-- | pyparsing.py | 20 | ||||
-rw-r--r-- | unitTests.py | 22 |
3 files changed, 52 insertions, 4 deletions
@@ -2,6 +2,20 @@ Change Log
==========
+Version 2.3.0 - TBD
+-------------------
+- IndexError's raised in parse actions will get explicitly reraised
+ as ParseExceptions that wrap the original IndexError. Since
+ IndexError sometimes occurs as part of pyparsing's normal parsing
+ logic, IndexErrors that are raised during a parse action may have
+ gotten silently reinterpreted as parsing errors. To retain the
+ information from the IndexError, these exceptions will now be
+ raised as ParseExceptions that reference the original IndexError.
+ This wrapping will only be visible when run under Python3, since it
+ emulates "raise ... from ..." syntax. Addresses Issue#4, reported
+ by guswns0528.
+
+
Version 2.2.2 - September, 2018
-------------------------------
- Fixed bug in SkipTo, if a SkipTo expression that was skipping to
diff --git a/pyparsing.py b/pyparsing.py index 3ea7660..1df31c3 100644 --- a/pyparsing.py +++ b/pyparsing.py @@ -74,8 +74,8 @@ classes inherit from. Use the docstrings for examples of how to: - find more useful common expressions in the L{pyparsing_common} namespace class
"""
-__version__ = "2.2.2"
-__versionTime__ = "29 Sep 2018 15:58 UTC"
+__version__ = "2.3.0"
+__versionTime__ = "01 Oct 2018 04:14 UTC"
__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
import string
@@ -1412,7 +1412,13 @@ class ParserElement(object): if debugging:
try:
for fn in self.parseAction:
- tokens = fn( instring, tokensStart, retTokens )
+ try:
+ tokens = fn( instring, tokensStart, retTokens )
+ except IndexError as parse_action_exc:
+ exc = ParseException("exception raised in parse action")
+ exc.__cause__ = parse_action_exc
+ raise exc
+
if tokens is not None:
retTokens = ParseResults( tokens,
self.resultsName,
@@ -1425,7 +1431,13 @@ class ParserElement(object): raise
else:
for fn in self.parseAction:
- tokens = fn( instring, tokensStart, retTokens )
+ try:
+ tokens = fn( instring, tokensStart, retTokens )
+ except IndexError as parse_action_exc:
+ exc = ParseException("exception raised in parse action")
+ exc.__cause__ = parse_action_exc
+ raise exc
+
if tokens is not None:
retTokens = ParseResults( tokens,
self.resultsName,
diff --git a/unitTests.py b/unitTests.py index 9966012..ba84898 100644 --- a/unitTests.py +++ b/unitTests.py @@ -3489,6 +3489,28 @@ class LiteralExceptionTest(ParseTestCase): print(cls.__name__, str(e))
assert 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
+ with self.assertRaises(pp.ParseException):
+ try:
+ expr.parseString('1 + 2')
+ except Exception as e:
+ assert hasattr(e, '__cause__'), "no __cause__ attribute in the raised exception"
+ assert e.__cause__ is not None, "__cause__ not propagated to outer exception"
+ assert type(e.__cause__) == IndexError, "__cause__ references wrong exception"
+ traceback.print_exc()
+ raise
+
class MiscellaneousParserTests(ParseTestCase):
def runTest(self):
import pyparsing
|