summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorptmcg <ptmcg@9bf210a0-9d2d-494c-87cf-cfb32e7dff7b>2016-08-12 14:48:18 +0000
committerptmcg <ptmcg@9bf210a0-9d2d-494c-87cf-cfb32e7dff7b>2016-08-12 14:48:18 +0000
commit2b48ff26f8e3108d3a6859c3702cd3fd38fcede5 (patch)
treeb95bfa4963a21dfbd354bc3a7df38240f73fea2a
parent1d9341fd0783421f1615683b6fd7f808b7907301 (diff)
downloadpyparsing-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/CHANGES5
-rw-r--r--src/pyparsing.py14
-rw-r--r--src/unitTests.py52
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,