move the old assertion reinterpreting implementation to _assertionold.py
Also, seperate out some common code from the two. --HG-- branch : trunk
This commit is contained in:
parent
130046d245
commit
e596d9df13
|
@ -133,7 +133,7 @@ initpkg(__name__,
|
||||||
'code.getrawcode' : ('./code/code.py', 'getrawcode'),
|
'code.getrawcode' : ('./code/code.py', 'getrawcode'),
|
||||||
'code.patch_builtins' : ('./code/code.py', 'patch_builtins'),
|
'code.patch_builtins' : ('./code/code.py', 'patch_builtins'),
|
||||||
'code.unpatch_builtins' : ('./code/code.py', 'unpatch_builtins'),
|
'code.unpatch_builtins' : ('./code/code.py', 'unpatch_builtins'),
|
||||||
'code._AssertionError' : ('./code/_assertion.py', 'AssertionError'),
|
'code._AssertionError' : ('./code/assertion.py', 'AssertionError'),
|
||||||
|
|
||||||
# backports and additions of builtins
|
# backports and additions of builtins
|
||||||
'builtin.__doc__' : ('./builtin/__init__.py', '__doc__'),
|
'builtin.__doc__' : ('./builtin/__init__.py', '__doc__'),
|
||||||
|
|
|
@ -7,7 +7,7 @@ import sys
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
import py
|
import py
|
||||||
from py.__.code._assertion import _format_explanation, BuiltinAssertionError
|
from py.__.code.assertion import _format_explanation, BuiltinAssertionError
|
||||||
|
|
||||||
|
|
||||||
class Failure(Exception):
|
class Failure(Exception):
|
||||||
|
@ -40,6 +40,8 @@ def getfailure(failure):
|
||||||
value = failure.cause[1]
|
value = failure.cause[1]
|
||||||
if str(value):
|
if str(value):
|
||||||
lines = explanation.splitlines()
|
lines = explanation.splitlines()
|
||||||
|
if not lines:
|
||||||
|
lines.append("")
|
||||||
lines[0] += " << {0}".format(value)
|
lines[0] += " << {0}".format(value)
|
||||||
explanation = "\n".join(lines)
|
explanation = "\n".join(lines)
|
||||||
text = "{0}: {1}".format(failure.cause[0].__name__, explanation)
|
text = "{0}: {1}".format(failure.cause[0].__name__, explanation)
|
||||||
|
@ -97,7 +99,7 @@ class DebugInterpreter(ast.NodeVisitor):
|
||||||
mod = ast.Module([node])
|
mod = ast.Module([node])
|
||||||
co = self._compile(mod, "exec")
|
co = self._compile(mod, "exec")
|
||||||
try:
|
try:
|
||||||
frame.exec_(co)
|
self.frame.exec_(co)
|
||||||
except Exception:
|
except Exception:
|
||||||
raise Failure()
|
raise Failure()
|
||||||
return None, None
|
return None, None
|
||||||
|
@ -107,6 +109,9 @@ class DebugInterpreter(ast.NodeVisitor):
|
||||||
def _compile(self, source, mode="eval"):
|
def _compile(self, source, mode="eval"):
|
||||||
return compile(source, "<assertion interpretation>", mode)
|
return compile(source, "<assertion interpretation>", mode)
|
||||||
|
|
||||||
|
def visit_Expr(self, expr):
|
||||||
|
return self.visit(expr.value)
|
||||||
|
|
||||||
def visit_Module(self, mod):
|
def visit_Module(self, mod):
|
||||||
for stmt in mod.body:
|
for stmt in mod.body:
|
||||||
self.visit(stmt)
|
self.visit(stmt)
|
||||||
|
@ -175,8 +180,8 @@ class DebugInterpreter(ast.NodeVisitor):
|
||||||
left_explanation, left_result = self.visit(binop.left)
|
left_explanation, left_result = self.visit(binop.left)
|
||||||
right_explanation, right_result = self.visit(binop.right)
|
right_explanation, right_result = self.visit(binop.right)
|
||||||
symbol = operator_map[binop.op.__class__]
|
symbol = operator_map[binop.op.__class__]
|
||||||
explanation = "{0} {1} {2}".format(left_explanation, symbol,
|
explanation = "({0} {1} {2})".format(left_explanation, symbol,
|
||||||
right_explanation)
|
right_explanation)
|
||||||
source = "__exprinfo_left {0} __exprinfo_right".format(symbol)
|
source = "__exprinfo_left {0} __exprinfo_right".format(symbol)
|
||||||
co = self._compile(source)
|
co = self._compile(source)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import py
|
import py
|
||||||
import sys, inspect
|
import sys, inspect
|
||||||
from compiler import parse, ast, pycodegen
|
from compiler import parse, ast, pycodegen
|
||||||
import __builtin__ as cpy_builtin
|
from py.__.code.assertion import BuiltinAssertionError, _format_explanation
|
||||||
BuiltinAssertionError = cpy_builtin.AssertionError
|
|
||||||
|
|
||||||
passthroughex = (KeyboardInterrupt, SystemExit, MemoryError)
|
passthroughex = (KeyboardInterrupt, SystemExit, MemoryError)
|
||||||
|
|
||||||
|
@ -97,42 +96,6 @@ def enumsubclasses(cls):
|
||||||
yield cls
|
yield cls
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _format_explanation(explanation):
|
|
||||||
# uck! See CallFunc for where \n{ and \n} escape sequences are used
|
|
||||||
raw_lines = (explanation or '').split('\n')
|
|
||||||
# escape newlines not followed by { and }
|
|
||||||
lines = [raw_lines[0]]
|
|
||||||
for l in raw_lines[1:]:
|
|
||||||
if l.startswith('{') or l.startswith('}'):
|
|
||||||
lines.append(l)
|
|
||||||
else:
|
|
||||||
lines[-1] += '\\n' + l
|
|
||||||
|
|
||||||
result = lines[:1]
|
|
||||||
stack = [0]
|
|
||||||
stackcnt = [0]
|
|
||||||
for line in lines[1:]:
|
|
||||||
if line.startswith('{'):
|
|
||||||
if stackcnt[-1]:
|
|
||||||
s = 'and '
|
|
||||||
else:
|
|
||||||
s = 'where '
|
|
||||||
stack.append(len(result))
|
|
||||||
stackcnt[-1] += 1
|
|
||||||
stackcnt.append(0)
|
|
||||||
result.append(' +' + ' '*(len(stack)-1) + s + line[1:])
|
|
||||||
else:
|
|
||||||
assert line.startswith('}')
|
|
||||||
stack.pop()
|
|
||||||
stackcnt.pop()
|
|
||||||
result[stack[-1]] += line[1:]
|
|
||||||
assert len(stack) == 1
|
|
||||||
return '\n'.join(result)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Interpretable(View):
|
class Interpretable(View):
|
||||||
"""A parse tree node with a few extra methods."""
|
"""A parse tree node with a few extra methods."""
|
||||||
explanation = None
|
explanation = None
|
||||||
|
@ -566,39 +529,6 @@ def run(s, frame=None):
|
||||||
report_failure(e)
|
report_failure(e)
|
||||||
|
|
||||||
|
|
||||||
class AssertionError(BuiltinAssertionError):
|
|
||||||
def __init__(self, *args):
|
|
||||||
BuiltinAssertionError.__init__(self, *args)
|
|
||||||
if args:
|
|
||||||
try:
|
|
||||||
self.msg = str(args[0])
|
|
||||||
except (KeyboardInterrupt, SystemExit):
|
|
||||||
raise
|
|
||||||
except:
|
|
||||||
self.msg = "<[broken __repr__] %s at %0xd>" %(
|
|
||||||
args[0].__class__, id(args[0]))
|
|
||||||
|
|
||||||
else:
|
|
||||||
f = py.code.Frame(sys._getframe(1))
|
|
||||||
try:
|
|
||||||
source = f.statement
|
|
||||||
source = str(source.deindent()).strip()
|
|
||||||
except py.error.ENOENT:
|
|
||||||
source = None
|
|
||||||
# this can also occur during reinterpretation, when the
|
|
||||||
# co_filename is set to "<run>".
|
|
||||||
if source:
|
|
||||||
if sys.version_info >= (2, 6):
|
|
||||||
from py.__.code._assertionnew import interpret as do_interp
|
|
||||||
else:
|
|
||||||
do_interp = interpret
|
|
||||||
self.msg = do_interp(source, f, should_fail=True)
|
|
||||||
if not self.args:
|
|
||||||
self.args = (self.msg,)
|
|
||||||
else:
|
|
||||||
self.msg = None
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# example:
|
# example:
|
||||||
def f():
|
def f():
|
|
@ -0,0 +1,76 @@
|
||||||
|
try:
|
||||||
|
import __builtin__ as builtins
|
||||||
|
except ImportError:
|
||||||
|
import builtins
|
||||||
|
import sys
|
||||||
|
import py
|
||||||
|
|
||||||
|
BuiltinAssertionError = builtins.AssertionError
|
||||||
|
|
||||||
|
|
||||||
|
def _format_explanation(explanation):
|
||||||
|
# uck! See CallFunc for where \n{ and \n} escape sequences are used
|
||||||
|
raw_lines = (explanation or '').split('\n')
|
||||||
|
# escape newlines not followed by { and }
|
||||||
|
lines = [raw_lines[0]]
|
||||||
|
for l in raw_lines[1:]:
|
||||||
|
if l.startswith('{') or l.startswith('}'):
|
||||||
|
lines.append(l)
|
||||||
|
else:
|
||||||
|
lines[-1] += '\\n' + l
|
||||||
|
|
||||||
|
result = lines[:1]
|
||||||
|
stack = [0]
|
||||||
|
stackcnt = [0]
|
||||||
|
for line in lines[1:]:
|
||||||
|
if line.startswith('{'):
|
||||||
|
if stackcnt[-1]:
|
||||||
|
s = 'and '
|
||||||
|
else:
|
||||||
|
s = 'where '
|
||||||
|
stack.append(len(result))
|
||||||
|
stackcnt[-1] += 1
|
||||||
|
stackcnt.append(0)
|
||||||
|
result.append(' +' + ' '*(len(stack)-1) + s + line[1:])
|
||||||
|
else:
|
||||||
|
assert line.startswith('}')
|
||||||
|
stack.pop()
|
||||||
|
stackcnt.pop()
|
||||||
|
result[stack[-1]] += line[1:]
|
||||||
|
assert len(stack) == 1
|
||||||
|
return '\n'.join(result)
|
||||||
|
|
||||||
|
|
||||||
|
if sys.version_info >= (2, 6):
|
||||||
|
from py.__.code._assertionnew import interpret
|
||||||
|
else:
|
||||||
|
from py.__.code._assertionold import interpret
|
||||||
|
|
||||||
|
|
||||||
|
class AssertionError(BuiltinAssertionError):
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
BuiltinAssertionError.__init__(self, *args)
|
||||||
|
if args:
|
||||||
|
try:
|
||||||
|
self.msg = str(args[0])
|
||||||
|
except (KeyboardInterrupt, SystemExit):
|
||||||
|
raise
|
||||||
|
except:
|
||||||
|
self.msg = "<[broken __repr__] %s at %0xd>" %(
|
||||||
|
args[0].__class__, id(args[0]))
|
||||||
|
else:
|
||||||
|
f = py.code.Frame(sys._getframe(1))
|
||||||
|
try:
|
||||||
|
source = f.statement
|
||||||
|
source = str(source.deindent()).strip()
|
||||||
|
except py.error.ENOENT:
|
||||||
|
source = None
|
||||||
|
# this can also occur during reinterpretation, when the
|
||||||
|
# co_filename is set to "<run>".
|
||||||
|
if source:
|
||||||
|
self.msg = interpret(source, f, should_fail=True)
|
||||||
|
if not self.args:
|
||||||
|
self.args = (self.msg,)
|
||||||
|
else:
|
||||||
|
self.msg = None
|
|
@ -197,9 +197,9 @@ class TracebackEntry(object):
|
||||||
"""Reinterpret the failing statement and returns a detailed information
|
"""Reinterpret the failing statement and returns a detailed information
|
||||||
about what operations are performed."""
|
about what operations are performed."""
|
||||||
if self.exprinfo is None:
|
if self.exprinfo is None:
|
||||||
from py.__.code import _assertion
|
from py.__.code import assertion
|
||||||
source = str(self.statement).strip()
|
source = str(self.statement).strip()
|
||||||
x = _assertion.interpret(source, self.frame, should_fail=True)
|
x = assertion.interpret(source, self.frame, should_fail=True)
|
||||||
if not isinstance(x, str):
|
if not isinstance(x, str):
|
||||||
raise TypeError("interpret returned non-string %r" % (x,))
|
raise TypeError("interpret returned non-string %r" % (x,))
|
||||||
self.exprinfo = x
|
self.exprinfo = x
|
||||||
|
@ -739,10 +739,10 @@ oldbuiltins = {}
|
||||||
def patch_builtins(assertion=True, compile=True):
|
def patch_builtins(assertion=True, compile=True):
|
||||||
""" put compile and AssertionError builtins to Python's builtins. """
|
""" put compile and AssertionError builtins to Python's builtins. """
|
||||||
if assertion:
|
if assertion:
|
||||||
from py.__.code import _assertion
|
from py.__.code import assertion
|
||||||
l = oldbuiltins.setdefault('AssertionError', [])
|
l = oldbuiltins.setdefault('AssertionError', [])
|
||||||
l.append(py.builtin.builtins.AssertionError)
|
l.append(py.builtin.builtins.AssertionError)
|
||||||
py.builtin.builtins.AssertionError = _assertion.AssertionError
|
py.builtin.builtins.AssertionError = assertion.AssertionError
|
||||||
if compile:
|
if compile:
|
||||||
l = oldbuiltins.setdefault('compile', [])
|
l = oldbuiltins.setdefault('compile', [])
|
||||||
l.append(py.builtin.builtins.compile)
|
l.append(py.builtin.builtins.compile)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import py
|
import py
|
||||||
from py.__.code._assertion import View
|
from py.__.code._assertionold import View
|
||||||
def exvalue():
|
def exvalue():
|
||||||
return py.std.sys.exc_info()[1]
|
return py.std.sys.exc_info()[1]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue