diff options
author | ptmcg <ptmcg@9bf210a0-9d2d-494c-87cf-cfb32e7dff7b> | 2016-08-12 14:48:18 +0000 |
---|---|---|
committer | ptmcg <ptmcg@9bf210a0-9d2d-494c-87cf-cfb32e7dff7b> | 2016-08-12 14:48:18 +0000 |
commit | 2b48ff26f8e3108d3a6859c3702cd3fd38fcede5 (patch) | |
tree | b95bfa4963a21dfbd354bc3a7df38240f73fea2a | |
parent | 1d9341fd0783421f1615683b6fd7f808b7907301 (diff) | |
download | pyparsing-2b48ff26f8e3108d3a6859c3702cd3fd38fcede5.tar.gz |
Add limit=n args to extract_stack and extract_tb calls, to minimize scanning through full call stack - trying to address UnicodeDecodeError exceptions from loading in more code than we need.
git-svn-id: svn://svn.code.sf.net/p/pyparsing/code/trunk@415 9bf210a0-9d2d-494c-87cf-cfb32e7dff7b
-rw-r--r-- | src/CHANGES | 5 | ||||
-rw-r--r-- | src/pyparsing.py | 14 | ||||
-rw-r--r-- | src/unitTests.py | 52 |
3 files changed, 64 insertions, 7 deletions
diff --git a/src/CHANGES b/src/CHANGES index 6971d81..b73b7bb 100644 --- a/src/CHANGES +++ b/src/CHANGES @@ -4,6 +4,11 @@ Change Log Version 2.1.8 -
------------------------------
+- Fixed issue in the optimization to _trim_arity, when the full
+ stacktrace is retrieved to determine if a TypeError is raised in
+ pyparsing or in the caller's parse action. Code was traversing
+ the full stacktrace, and potentially encountering UnicodeDecodeError.
+
- Fixed bug in ParserElement.inlineLiteralsUsing, causing infinite
loop with Suppress.
diff --git a/src/pyparsing.py b/src/pyparsing.py index e101ab4..9191426 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.1.8"
-__versionTime__ = "11 Aug 2016 20:00 UTC"
+__versionTime__ = "12 Aug 2016 14:46 UTC"
__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>"
import string
@@ -1017,13 +1017,13 @@ def _trim_arity(func, maxargs=2): # traceback return data structure changed in Py3.5 - normalize back to plain tuples
if system_version[:2] >= (3,5):
- def extract_stack():
+ def extract_stack(limit=0):
# special handling for Python 3.5.0 - extra deep call stack by 1
offset = -3 if system_version == (3,5,0) else -2
- frame_summary = traceback.extract_stack()[offset]
+ frame_summary = traceback.extract_stack(limit=-offset+limit-1)[offset]
return [(frame_summary.filename, frame_summary.lineno)]
- def extract_tb(tb):
- frames = traceback.extract_tb(tb)
+ def extract_tb(tb, limit=0):
+ frames = traceback.extract_tb(tb, limit=limit)
frame_summary = frames[-1]
return [(frame_summary.filename, frame_summary.lineno)]
else:
@@ -1036,7 +1036,7 @@ def _trim_arity(func, maxargs=2): LINE_DIFF = 6
# IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND
# THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!!
- this_line = extract_stack()[-1]
+ this_line = extract_stack(limit=2)[-1]
pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF)
def wrapper(*args):
@@ -1052,7 +1052,7 @@ def _trim_arity(func, maxargs=2): else:
try:
tb = sys.exc_info()[-1]
- if not extract_tb(tb)[-1][:2] == pa_call_line_synth:
+ if not extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth:
raise
finally:
del tb
diff --git a/src/unitTests.py b/src/unitTests.py index 87b4beb..1f7964e 100644 --- a/src/unitTests.py +++ b/src/unitTests.py @@ -2529,6 +2529,58 @@ class TrimArityExceptionMaskingTest(ParseTestCase): exc_msg = str(e)
assert 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)
+ assert 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,
|