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:
Benjamin Peterson 2009-08-28 20:13:49 -05:00
parent 130046d245
commit e596d9df13
6 changed files with 92 additions and 81 deletions

View File

@ -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__'),

View File

@ -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:

View File

@ -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():

76
py/code/assertion.py Normal file
View File

@ -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

View File

@ -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)

View File

@ -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]