Drop assertionnew and assertionold from _pytest._code
This commit is contained in:
		
							parent
							
								
									a912d3745b
								
							
						
					
					
						commit
						7a6f902f6f
					
				| 
						 | 
				
			
			@ -1,9 +1,4 @@
 | 
			
		|||
""" python inspection/code generation API """
 | 
			
		||||
from .assertion import AssertionError as _AssertionError  # noqa
 | 
			
		||||
from .assertion import _format_explanation  # noqa
 | 
			
		||||
from .assertion import _reprcompare  # noqa
 | 
			
		||||
from .assertion import reinterpret as _reinterpret  # noqa
 | 
			
		||||
from .assertion import reinterpret_old as _reinterpret_old  # noqa
 | 
			
		||||
from .code import Code  # noqa
 | 
			
		||||
from .code import ExceptionInfo  # noqa
 | 
			
		||||
from .code import Frame  # noqa
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,339 +0,0 @@
 | 
			
		|||
"""
 | 
			
		||||
Find intermediate evalutation results in assert statements through builtin AST.
 | 
			
		||||
This should replace _assertionold.py eventually.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import ast
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
from .assertion import _format_explanation, BuiltinAssertionError
 | 
			
		||||
 | 
			
		||||
if sys.platform.startswith("java") and sys.version_info < (2, 5, 2):
 | 
			
		||||
    # See http://bugs.jython.org/issue1497
 | 
			
		||||
    _exprs = ("BoolOp", "BinOp", "UnaryOp", "Lambda", "IfExp", "Dict",
 | 
			
		||||
              "ListComp", "GeneratorExp", "Yield", "Compare", "Call",
 | 
			
		||||
              "Repr", "Num", "Str", "Attribute", "Subscript", "Name",
 | 
			
		||||
              "List", "Tuple")
 | 
			
		||||
    _stmts = ("FunctionDef", "ClassDef", "Return", "Delete", "Assign",
 | 
			
		||||
              "AugAssign", "Print", "For", "While", "If", "With", "Raise",
 | 
			
		||||
              "TryExcept", "TryFinally", "Assert", "Import", "ImportFrom",
 | 
			
		||||
              "Exec", "Global", "Expr", "Pass", "Break", "Continue")
 | 
			
		||||
    _expr_nodes = set(getattr(ast, name) for name in _exprs)
 | 
			
		||||
    _stmt_nodes = set(getattr(ast, name) for name in _stmts)
 | 
			
		||||
    def _is_ast_expr(node):
 | 
			
		||||
        return node.__class__ in _expr_nodes
 | 
			
		||||
    def _is_ast_stmt(node):
 | 
			
		||||
        return node.__class__ in _stmt_nodes
 | 
			
		||||
else:
 | 
			
		||||
    def _is_ast_expr(node):
 | 
			
		||||
        return isinstance(node, ast.expr)
 | 
			
		||||
    def _is_ast_stmt(node):
 | 
			
		||||
        return isinstance(node, ast.stmt)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Failure(Exception):
 | 
			
		||||
    """Error found while interpreting AST."""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, explanation=""):
 | 
			
		||||
        self.cause = sys.exc_info()
 | 
			
		||||
        self.explanation = explanation
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def interpret(source, frame, should_fail=False):
 | 
			
		||||
    mod = ast.parse(source)
 | 
			
		||||
    visitor = DebugInterpreter(frame)
 | 
			
		||||
    try:
 | 
			
		||||
        visitor.visit(mod)
 | 
			
		||||
    except Failure:
 | 
			
		||||
        failure = sys.exc_info()[1]
 | 
			
		||||
        return getfailure(failure)
 | 
			
		||||
    if should_fail:
 | 
			
		||||
        return ("(assertion failed, but when it was re-run for "
 | 
			
		||||
                "printing intermediate values, it did not fail.  Suggestions: "
 | 
			
		||||
                "compute assert expression before the assert or use --no-assert)")
 | 
			
		||||
 | 
			
		||||
def run(offending_line, frame=None):
 | 
			
		||||
    from .code import Frame
 | 
			
		||||
    if frame is None:
 | 
			
		||||
        frame = Frame(sys._getframe(1))
 | 
			
		||||
    return interpret(offending_line, frame)
 | 
			
		||||
 | 
			
		||||
def getfailure(failure):
 | 
			
		||||
    explanation = _format_explanation(failure.explanation)
 | 
			
		||||
    value = failure.cause[1]
 | 
			
		||||
    if str(value):
 | 
			
		||||
        lines = explanation.splitlines()
 | 
			
		||||
        if not lines:
 | 
			
		||||
            lines.append("")
 | 
			
		||||
        lines[0] += " << %s" % (value,)
 | 
			
		||||
        explanation = "\n".join(lines)
 | 
			
		||||
    text = "%s: %s" % (failure.cause[0].__name__, explanation)
 | 
			
		||||
    if text.startswith("AssertionError: assert "):
 | 
			
		||||
        text = text[16:]
 | 
			
		||||
    return text
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
operator_map = {
 | 
			
		||||
    ast.BitOr : "|",
 | 
			
		||||
    ast.BitXor : "^",
 | 
			
		||||
    ast.BitAnd : "&",
 | 
			
		||||
    ast.LShift : "<<",
 | 
			
		||||
    ast.RShift : ">>",
 | 
			
		||||
    ast.Add : "+",
 | 
			
		||||
    ast.Sub : "-",
 | 
			
		||||
    ast.Mult : "*",
 | 
			
		||||
    ast.Div : "/",
 | 
			
		||||
    ast.FloorDiv : "//",
 | 
			
		||||
    ast.Mod : "%",
 | 
			
		||||
    ast.Eq : "==",
 | 
			
		||||
    ast.NotEq : "!=",
 | 
			
		||||
    ast.Lt : "<",
 | 
			
		||||
    ast.LtE : "<=",
 | 
			
		||||
    ast.Gt : ">",
 | 
			
		||||
    ast.GtE : ">=",
 | 
			
		||||
    ast.Pow : "**",
 | 
			
		||||
    ast.Is : "is",
 | 
			
		||||
    ast.IsNot : "is not",
 | 
			
		||||
    ast.In : "in",
 | 
			
		||||
    ast.NotIn : "not in"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unary_map = {
 | 
			
		||||
    ast.Not : "not %s",
 | 
			
		||||
    ast.Invert : "~%s",
 | 
			
		||||
    ast.USub : "-%s",
 | 
			
		||||
    ast.UAdd : "+%s"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DebugInterpreter(ast.NodeVisitor):
 | 
			
		||||
    """Interpret AST nodes to gleam useful debugging information. """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, frame):
 | 
			
		||||
        self.frame = frame
 | 
			
		||||
 | 
			
		||||
    def generic_visit(self, node):
 | 
			
		||||
        # Fallback when we don't have a special implementation.
 | 
			
		||||
        if _is_ast_expr(node):
 | 
			
		||||
            mod = ast.Expression(node)
 | 
			
		||||
            co = self._compile(mod)
 | 
			
		||||
            try:
 | 
			
		||||
                result = self.frame.eval(co)
 | 
			
		||||
            except Exception:
 | 
			
		||||
                raise Failure()
 | 
			
		||||
            explanation = self.frame.repr(result)
 | 
			
		||||
            return explanation, result
 | 
			
		||||
        elif _is_ast_stmt(node):
 | 
			
		||||
            mod = ast.Module([node])
 | 
			
		||||
            co = self._compile(mod, "exec")
 | 
			
		||||
            try:
 | 
			
		||||
                self.frame.exec_(co)
 | 
			
		||||
            except Exception:
 | 
			
		||||
                raise Failure()
 | 
			
		||||
            return None, None
 | 
			
		||||
        else:
 | 
			
		||||
            raise AssertionError("can't handle %s" %(node,))
 | 
			
		||||
 | 
			
		||||
    def _compile(self, source, mode="eval"):
 | 
			
		||||
        return compile(source, "<assertion interpretation>", mode)
 | 
			
		||||
 | 
			
		||||
    def visit_Expr(self, expr):
 | 
			
		||||
        return self.visit(expr.value)
 | 
			
		||||
 | 
			
		||||
    def visit_Module(self, mod):
 | 
			
		||||
        for stmt in mod.body:
 | 
			
		||||
            self.visit(stmt)
 | 
			
		||||
 | 
			
		||||
    def visit_Name(self, name):
 | 
			
		||||
        explanation, result = self.generic_visit(name)
 | 
			
		||||
        # See if the name is local.
 | 
			
		||||
        source = "%r in locals() is not globals()" % (name.id,)
 | 
			
		||||
        co = self._compile(source)
 | 
			
		||||
        try:
 | 
			
		||||
            local = self.frame.eval(co)
 | 
			
		||||
        except Exception:
 | 
			
		||||
            # have to assume it isn't
 | 
			
		||||
            local = False
 | 
			
		||||
        if not local:
 | 
			
		||||
            return name.id, result
 | 
			
		||||
        return explanation, result
 | 
			
		||||
 | 
			
		||||
    def visit_Compare(self, comp):
 | 
			
		||||
        left = comp.left
 | 
			
		||||
        left_explanation, left_result = self.visit(left)
 | 
			
		||||
        for op, next_op in zip(comp.ops, comp.comparators):
 | 
			
		||||
            next_explanation, next_result = self.visit(next_op)
 | 
			
		||||
            op_symbol = operator_map[op.__class__]
 | 
			
		||||
            explanation = "%s %s %s" % (left_explanation, op_symbol,
 | 
			
		||||
                                        next_explanation)
 | 
			
		||||
            source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,)
 | 
			
		||||
            co = self._compile(source)
 | 
			
		||||
            try:
 | 
			
		||||
                result = self.frame.eval(co, __exprinfo_left=left_result,
 | 
			
		||||
                                         __exprinfo_right=next_result)
 | 
			
		||||
            except Exception:
 | 
			
		||||
                raise Failure(explanation)
 | 
			
		||||
            try:
 | 
			
		||||
                if not result:
 | 
			
		||||
                    break
 | 
			
		||||
            except KeyboardInterrupt:
 | 
			
		||||
                raise
 | 
			
		||||
            except:
 | 
			
		||||
                break
 | 
			
		||||
            left_explanation, left_result = next_explanation, next_result
 | 
			
		||||
 | 
			
		||||
        import _pytest._code
 | 
			
		||||
        rcomp = _pytest._code._reprcompare
 | 
			
		||||
        if rcomp:
 | 
			
		||||
            res = rcomp(op_symbol, left_result, next_result)
 | 
			
		||||
            if res:
 | 
			
		||||
                explanation = res
 | 
			
		||||
        return explanation, result
 | 
			
		||||
 | 
			
		||||
    def visit_BoolOp(self, boolop):
 | 
			
		||||
        is_or = isinstance(boolop.op, ast.Or)
 | 
			
		||||
        explanations = []
 | 
			
		||||
        for operand in boolop.values:
 | 
			
		||||
            explanation, result = self.visit(operand)
 | 
			
		||||
            explanations.append(explanation)
 | 
			
		||||
            if result == is_or:
 | 
			
		||||
                break
 | 
			
		||||
        name = is_or and " or " or " and "
 | 
			
		||||
        explanation = "(" + name.join(explanations) + ")"
 | 
			
		||||
        return explanation, result
 | 
			
		||||
 | 
			
		||||
    def visit_UnaryOp(self, unary):
 | 
			
		||||
        pattern = unary_map[unary.op.__class__]
 | 
			
		||||
        operand_explanation, operand_result = self.visit(unary.operand)
 | 
			
		||||
        explanation = pattern % (operand_explanation,)
 | 
			
		||||
        co = self._compile(pattern % ("__exprinfo_expr",))
 | 
			
		||||
        try:
 | 
			
		||||
            result = self.frame.eval(co, __exprinfo_expr=operand_result)
 | 
			
		||||
        except Exception:
 | 
			
		||||
            raise Failure(explanation)
 | 
			
		||||
        return explanation, result
 | 
			
		||||
 | 
			
		||||
    def visit_BinOp(self, binop):
 | 
			
		||||
        left_explanation, left_result = self.visit(binop.left)
 | 
			
		||||
        right_explanation, right_result = self.visit(binop.right)
 | 
			
		||||
        symbol = operator_map[binop.op.__class__]
 | 
			
		||||
        explanation = "(%s %s %s)" % (left_explanation, symbol,
 | 
			
		||||
                                      right_explanation)
 | 
			
		||||
        source = "__exprinfo_left %s __exprinfo_right" % (symbol,)
 | 
			
		||||
        co = self._compile(source)
 | 
			
		||||
        try:
 | 
			
		||||
            result = self.frame.eval(co, __exprinfo_left=left_result,
 | 
			
		||||
                                     __exprinfo_right=right_result)
 | 
			
		||||
        except Exception:
 | 
			
		||||
            raise Failure(explanation)
 | 
			
		||||
        return explanation, result
 | 
			
		||||
 | 
			
		||||
    def visit_Call(self, call):
 | 
			
		||||
        func_explanation, func = self.visit(call.func)
 | 
			
		||||
        arg_explanations = []
 | 
			
		||||
        ns = {"__exprinfo_func" : func}
 | 
			
		||||
        arguments = []
 | 
			
		||||
        for arg in call.args:
 | 
			
		||||
            arg_explanation, arg_result = self.visit(arg)
 | 
			
		||||
            arg_name = "__exprinfo_%s" % (len(ns),)
 | 
			
		||||
            ns[arg_name] = arg_result
 | 
			
		||||
            arguments.append(arg_name)
 | 
			
		||||
            arg_explanations.append(arg_explanation)
 | 
			
		||||
        for keyword in call.keywords:
 | 
			
		||||
            arg_explanation, arg_result = self.visit(keyword.value)
 | 
			
		||||
            arg_name = "__exprinfo_%s" % (len(ns),)
 | 
			
		||||
            ns[arg_name] = arg_result
 | 
			
		||||
            keyword_source = "%s=%%s" % (keyword.arg)
 | 
			
		||||
            arguments.append(keyword_source % (arg_name,))
 | 
			
		||||
            arg_explanations.append(keyword_source % (arg_explanation,))
 | 
			
		||||
        if call.starargs:
 | 
			
		||||
            arg_explanation, arg_result = self.visit(call.starargs)
 | 
			
		||||
            arg_name = "__exprinfo_star"
 | 
			
		||||
            ns[arg_name] = arg_result
 | 
			
		||||
            arguments.append("*%s" % (arg_name,))
 | 
			
		||||
            arg_explanations.append("*%s" % (arg_explanation,))
 | 
			
		||||
        if call.kwargs:
 | 
			
		||||
            arg_explanation, arg_result = self.visit(call.kwargs)
 | 
			
		||||
            arg_name = "__exprinfo_kwds"
 | 
			
		||||
            ns[arg_name] = arg_result
 | 
			
		||||
            arguments.append("**%s" % (arg_name,))
 | 
			
		||||
            arg_explanations.append("**%s" % (arg_explanation,))
 | 
			
		||||
        args_explained = ", ".join(arg_explanations)
 | 
			
		||||
        explanation = "%s(%s)" % (func_explanation, args_explained)
 | 
			
		||||
        args = ", ".join(arguments)
 | 
			
		||||
        source = "__exprinfo_func(%s)" % (args,)
 | 
			
		||||
        co = self._compile(source)
 | 
			
		||||
        try:
 | 
			
		||||
            result = self.frame.eval(co, **ns)
 | 
			
		||||
        except Exception:
 | 
			
		||||
            raise Failure(explanation)
 | 
			
		||||
        pattern = "%s\n{%s = %s\n}"
 | 
			
		||||
        rep = self.frame.repr(result)
 | 
			
		||||
        explanation = pattern % (rep, rep, explanation)
 | 
			
		||||
        return explanation, result
 | 
			
		||||
 | 
			
		||||
    def _is_builtin_name(self, name):
 | 
			
		||||
        pattern = "%r not in globals() and %r not in locals()"
 | 
			
		||||
        source = pattern % (name.id, name.id)
 | 
			
		||||
        co = self._compile(source)
 | 
			
		||||
        try:
 | 
			
		||||
            return self.frame.eval(co)
 | 
			
		||||
        except Exception:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    def visit_Attribute(self, attr):
 | 
			
		||||
        if not isinstance(attr.ctx, ast.Load):
 | 
			
		||||
            return self.generic_visit(attr)
 | 
			
		||||
        source_explanation, source_result = self.visit(attr.value)
 | 
			
		||||
        explanation = "%s.%s" % (source_explanation, attr.attr)
 | 
			
		||||
        source = "__exprinfo_expr.%s" % (attr.attr,)
 | 
			
		||||
        co = self._compile(source)
 | 
			
		||||
        try:
 | 
			
		||||
            result = self.frame.eval(co, __exprinfo_expr=source_result)
 | 
			
		||||
        except Exception:
 | 
			
		||||
            raise Failure(explanation)
 | 
			
		||||
        explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result),
 | 
			
		||||
                                              self.frame.repr(result),
 | 
			
		||||
                                              source_explanation, attr.attr)
 | 
			
		||||
        # Check if the attr is from an instance.
 | 
			
		||||
        source = "%r in getattr(__exprinfo_expr, '__dict__', {})"
 | 
			
		||||
        source = source % (attr.attr,)
 | 
			
		||||
        co = self._compile(source)
 | 
			
		||||
        try:
 | 
			
		||||
            from_instance = self.frame.eval(co, __exprinfo_expr=source_result)
 | 
			
		||||
        except Exception:
 | 
			
		||||
            from_instance = True
 | 
			
		||||
        if from_instance:
 | 
			
		||||
            rep = self.frame.repr(result)
 | 
			
		||||
            pattern = "%s\n{%s = %s\n}"
 | 
			
		||||
            explanation = pattern % (rep, rep, explanation)
 | 
			
		||||
        return explanation, result
 | 
			
		||||
 | 
			
		||||
    def visit_Assert(self, assrt):
 | 
			
		||||
        test_explanation, test_result = self.visit(assrt.test)
 | 
			
		||||
        if test_explanation.startswith("False\n{False =") and \
 | 
			
		||||
                test_explanation.endswith("\n"):
 | 
			
		||||
            test_explanation = test_explanation[15:-2]
 | 
			
		||||
        explanation = "assert %s" % (test_explanation,)
 | 
			
		||||
        if not test_result:
 | 
			
		||||
            try:
 | 
			
		||||
                raise BuiltinAssertionError
 | 
			
		||||
            except Exception:
 | 
			
		||||
                raise Failure(explanation)
 | 
			
		||||
        return explanation, test_result
 | 
			
		||||
 | 
			
		||||
    def visit_Assign(self, assign):
 | 
			
		||||
        value_explanation, value_result = self.visit(assign.value)
 | 
			
		||||
        explanation = "... = %s" % (value_explanation,)
 | 
			
		||||
        name = ast.Name("__exprinfo_expr", ast.Load(),
 | 
			
		||||
                        lineno=assign.value.lineno,
 | 
			
		||||
                        col_offset=assign.value.col_offset)
 | 
			
		||||
        new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno,
 | 
			
		||||
                                col_offset=assign.col_offset)
 | 
			
		||||
        mod = ast.Module([new_assign])
 | 
			
		||||
        co = self._compile(mod, "exec")
 | 
			
		||||
        try:
 | 
			
		||||
            self.frame.exec_(co, __exprinfo_expr=value_result)
 | 
			
		||||
        except Exception:
 | 
			
		||||
            raise Failure(explanation)
 | 
			
		||||
        return explanation, value_result
 | 
			
		||||
| 
						 | 
				
			
			@ -1,561 +0,0 @@
 | 
			
		|||
import inspect
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
from compiler import parse, ast, pycodegen
 | 
			
		||||
 | 
			
		||||
import py
 | 
			
		||||
from _pytest._code.assertion import BuiltinAssertionError, _format_explanation
 | 
			
		||||
 | 
			
		||||
passthroughex = py.builtin._sysex
 | 
			
		||||
 | 
			
		||||
class Failure:
 | 
			
		||||
    def __init__(self, node):
 | 
			
		||||
        self.exc, self.value, self.tb = sys.exc_info()
 | 
			
		||||
        self.node = node
 | 
			
		||||
 | 
			
		||||
class View(object):
 | 
			
		||||
    """View base class.
 | 
			
		||||
 | 
			
		||||
    If C is a subclass of View, then C(x) creates a proxy object around
 | 
			
		||||
    the object x.  The actual class of the proxy is not C in general,
 | 
			
		||||
    but a *subclass* of C determined by the rules below.  To avoid confusion
 | 
			
		||||
    we call view class the class of the proxy (a subclass of C, so of View)
 | 
			
		||||
    and object class the class of x.
 | 
			
		||||
 | 
			
		||||
    Attributes and methods not found in the proxy are automatically read on x.
 | 
			
		||||
    Other operations like setting attributes are performed on the proxy, as
 | 
			
		||||
    determined by its view class.  The object x is available from the proxy
 | 
			
		||||
    as its __obj__ attribute.
 | 
			
		||||
 | 
			
		||||
    The view class selection is determined by the __view__ tuples and the
 | 
			
		||||
    optional __viewkey__ method.  By default, the selected view class is the
 | 
			
		||||
    most specific subclass of C whose __view__ mentions the class of x.
 | 
			
		||||
    If no such subclass is found, the search proceeds with the parent
 | 
			
		||||
    object classes.  For example, C(True) will first look for a subclass
 | 
			
		||||
    of C with __view__ = (..., bool, ...) and only if it doesn't find any
 | 
			
		||||
    look for one with __view__ = (..., int, ...), and then ..., object,...
 | 
			
		||||
    If everything fails the class C itself is considered to be the default.
 | 
			
		||||
 | 
			
		||||
    Alternatively, the view class selection can be driven by another aspect
 | 
			
		||||
    of the object x, instead of the class of x, by overriding __viewkey__.
 | 
			
		||||
    See last example at the end of this module.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    _viewcache = {}
 | 
			
		||||
    __view__ = ()
 | 
			
		||||
 | 
			
		||||
    def __new__(rootclass, obj, *args, **kwds):
 | 
			
		||||
        self = object.__new__(rootclass)
 | 
			
		||||
        self.__obj__ = obj
 | 
			
		||||
        self.__rootclass__ = rootclass
 | 
			
		||||
        key = self.__viewkey__()
 | 
			
		||||
        try:
 | 
			
		||||
            self.__class__ = self._viewcache[key]
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            self.__class__ = self._selectsubclass(key)
 | 
			
		||||
        return self
 | 
			
		||||
 | 
			
		||||
    def __getattr__(self, attr):
 | 
			
		||||
        # attributes not found in the normal hierarchy rooted on View
 | 
			
		||||
        # are looked up in the object's real class
 | 
			
		||||
        return getattr(self.__obj__, attr)
 | 
			
		||||
 | 
			
		||||
    def __viewkey__(self):
 | 
			
		||||
        return self.__obj__.__class__
 | 
			
		||||
 | 
			
		||||
    def __matchkey__(self, key, subclasses):
 | 
			
		||||
        if inspect.isclass(key):
 | 
			
		||||
            keys = inspect.getmro(key)
 | 
			
		||||
        else:
 | 
			
		||||
            keys = [key]
 | 
			
		||||
        for key in keys:
 | 
			
		||||
            result = [C for C in subclasses if key in C.__view__]
 | 
			
		||||
            if result:
 | 
			
		||||
                return result
 | 
			
		||||
        return []
 | 
			
		||||
 | 
			
		||||
    def _selectsubclass(self, key):
 | 
			
		||||
        subclasses = list(enumsubclasses(self.__rootclass__))
 | 
			
		||||
        for C in subclasses:
 | 
			
		||||
            if not isinstance(C.__view__, tuple):
 | 
			
		||||
                C.__view__ = (C.__view__,)
 | 
			
		||||
        choices = self.__matchkey__(key, subclasses)
 | 
			
		||||
        if not choices:
 | 
			
		||||
            return self.__rootclass__
 | 
			
		||||
        elif len(choices) == 1:
 | 
			
		||||
            return choices[0]
 | 
			
		||||
        else:
 | 
			
		||||
            # combine the multiple choices
 | 
			
		||||
            return type('?', tuple(choices), {})
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return '%s(%r)' % (self.__rootclass__.__name__, self.__obj__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def enumsubclasses(cls):
 | 
			
		||||
    for subcls in cls.__subclasses__():
 | 
			
		||||
        for subsubclass in enumsubclasses(subcls):
 | 
			
		||||
            yield subsubclass
 | 
			
		||||
    yield cls
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Interpretable(View):
 | 
			
		||||
    """A parse tree node with a few extra methods."""
 | 
			
		||||
    explanation = None
 | 
			
		||||
 | 
			
		||||
    def is_builtin(self, frame):
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def eval(self, frame):
 | 
			
		||||
        # fall-back for unknown expression nodes
 | 
			
		||||
        try:
 | 
			
		||||
            expr = ast.Expression(self.__obj__)
 | 
			
		||||
            expr.filename = '<eval>'
 | 
			
		||||
            self.__obj__.filename = '<eval>'
 | 
			
		||||
            co = pycodegen.ExpressionCodeGenerator(expr).getCode()
 | 
			
		||||
            result = frame.eval(co)
 | 
			
		||||
        except passthroughex:
 | 
			
		||||
            raise
 | 
			
		||||
        except:
 | 
			
		||||
            raise Failure(self)
 | 
			
		||||
        self.result = result
 | 
			
		||||
        self.explanation = self.explanation or frame.repr(self.result)
 | 
			
		||||
 | 
			
		||||
    def run(self, frame):
 | 
			
		||||
        # fall-back for unknown statement nodes
 | 
			
		||||
        try:
 | 
			
		||||
            expr = ast.Module(None, ast.Stmt([self.__obj__]))
 | 
			
		||||
            expr.filename = '<run>'
 | 
			
		||||
            co = pycodegen.ModuleCodeGenerator(expr).getCode()
 | 
			
		||||
            frame.exec_(co)
 | 
			
		||||
        except passthroughex:
 | 
			
		||||
            raise
 | 
			
		||||
        except:
 | 
			
		||||
            raise Failure(self)
 | 
			
		||||
 | 
			
		||||
    def nice_explanation(self):
 | 
			
		||||
        return _format_explanation(self.explanation)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Name(Interpretable):
 | 
			
		||||
    __view__ = ast.Name
 | 
			
		||||
 | 
			
		||||
    def is_local(self, frame):
 | 
			
		||||
        source = '%r in locals() is not globals()' % self.name
 | 
			
		||||
        try:
 | 
			
		||||
            return frame.is_true(frame.eval(source))
 | 
			
		||||
        except passthroughex:
 | 
			
		||||
            raise
 | 
			
		||||
        except:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    def is_global(self, frame):
 | 
			
		||||
        source = '%r in globals()' % self.name
 | 
			
		||||
        try:
 | 
			
		||||
            return frame.is_true(frame.eval(source))
 | 
			
		||||
        except passthroughex:
 | 
			
		||||
            raise
 | 
			
		||||
        except:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    def is_builtin(self, frame):
 | 
			
		||||
        source = '%r not in locals() and %r not in globals()' % (
 | 
			
		||||
            self.name, self.name)
 | 
			
		||||
        try:
 | 
			
		||||
            return frame.is_true(frame.eval(source))
 | 
			
		||||
        except passthroughex:
 | 
			
		||||
            raise
 | 
			
		||||
        except:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    def eval(self, frame):
 | 
			
		||||
        super(Name, self).eval(frame)
 | 
			
		||||
        if not self.is_local(frame):
 | 
			
		||||
            self.explanation = self.name
 | 
			
		||||
 | 
			
		||||
class Compare(Interpretable):
 | 
			
		||||
    __view__ = ast.Compare
 | 
			
		||||
 | 
			
		||||
    def eval(self, frame):
 | 
			
		||||
        expr = Interpretable(self.expr)
 | 
			
		||||
        expr.eval(frame)
 | 
			
		||||
        for operation, expr2 in self.ops:
 | 
			
		||||
            if hasattr(self, 'result'):
 | 
			
		||||
                # shortcutting in chained expressions
 | 
			
		||||
                if not frame.is_true(self.result):
 | 
			
		||||
                    break
 | 
			
		||||
            expr2 = Interpretable(expr2)
 | 
			
		||||
            expr2.eval(frame)
 | 
			
		||||
            self.explanation = "%s %s %s" % (
 | 
			
		||||
                expr.explanation, operation, expr2.explanation)
 | 
			
		||||
            source = "__exprinfo_left %s __exprinfo_right" % operation
 | 
			
		||||
            try:
 | 
			
		||||
                self.result = frame.eval(source,
 | 
			
		||||
                                         __exprinfo_left=expr.result,
 | 
			
		||||
                                         __exprinfo_right=expr2.result)
 | 
			
		||||
            except passthroughex:
 | 
			
		||||
                raise
 | 
			
		||||
            except:
 | 
			
		||||
                raise Failure(self)
 | 
			
		||||
            expr = expr2
 | 
			
		||||
 | 
			
		||||
class And(Interpretable):
 | 
			
		||||
    __view__ = ast.And
 | 
			
		||||
 | 
			
		||||
    def eval(self, frame):
 | 
			
		||||
        explanations = []
 | 
			
		||||
        for expr in self.nodes:
 | 
			
		||||
            expr = Interpretable(expr)
 | 
			
		||||
            expr.eval(frame)
 | 
			
		||||
            explanations.append(expr.explanation)
 | 
			
		||||
            self.result = expr.result
 | 
			
		||||
            if not frame.is_true(expr.result):
 | 
			
		||||
                break
 | 
			
		||||
        self.explanation = '(' + ' and '.join(explanations) + ')'
 | 
			
		||||
 | 
			
		||||
class Or(Interpretable):
 | 
			
		||||
    __view__ = ast.Or
 | 
			
		||||
 | 
			
		||||
    def eval(self, frame):
 | 
			
		||||
        explanations = []
 | 
			
		||||
        for expr in self.nodes:
 | 
			
		||||
            expr = Interpretable(expr)
 | 
			
		||||
            expr.eval(frame)
 | 
			
		||||
            explanations.append(expr.explanation)
 | 
			
		||||
            self.result = expr.result
 | 
			
		||||
            if frame.is_true(expr.result):
 | 
			
		||||
                break
 | 
			
		||||
        self.explanation = '(' + ' or '.join(explanations) + ')'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# == Unary operations ==
 | 
			
		||||
keepalive = []
 | 
			
		||||
for astclass, astpattern in {
 | 
			
		||||
    ast.Not    : 'not __exprinfo_expr',
 | 
			
		||||
    ast.Invert : '(~__exprinfo_expr)',
 | 
			
		||||
    }.items():
 | 
			
		||||
 | 
			
		||||
    class UnaryArith(Interpretable):
 | 
			
		||||
        __view__ = astclass
 | 
			
		||||
 | 
			
		||||
        def eval(self, frame, astpattern=astpattern):
 | 
			
		||||
            expr = Interpretable(self.expr)
 | 
			
		||||
            expr.eval(frame)
 | 
			
		||||
            self.explanation = astpattern.replace('__exprinfo_expr',
 | 
			
		||||
                                                  expr.explanation)
 | 
			
		||||
            try:
 | 
			
		||||
                self.result = frame.eval(astpattern,
 | 
			
		||||
                                         __exprinfo_expr=expr.result)
 | 
			
		||||
            except passthroughex:
 | 
			
		||||
                raise
 | 
			
		||||
            except:
 | 
			
		||||
                raise Failure(self)
 | 
			
		||||
 | 
			
		||||
    keepalive.append(UnaryArith)
 | 
			
		||||
 | 
			
		||||
# == Binary operations ==
 | 
			
		||||
for astclass, astpattern in {
 | 
			
		||||
    ast.Add    : '(__exprinfo_left + __exprinfo_right)',
 | 
			
		||||
    ast.Sub    : '(__exprinfo_left - __exprinfo_right)',
 | 
			
		||||
    ast.Mul    : '(__exprinfo_left * __exprinfo_right)',
 | 
			
		||||
    ast.Div    : '(__exprinfo_left / __exprinfo_right)',
 | 
			
		||||
    ast.Mod    : '(__exprinfo_left % __exprinfo_right)',
 | 
			
		||||
    ast.Power  : '(__exprinfo_left ** __exprinfo_right)',
 | 
			
		||||
    }.items():
 | 
			
		||||
 | 
			
		||||
    class BinaryArith(Interpretable):
 | 
			
		||||
        __view__ = astclass
 | 
			
		||||
 | 
			
		||||
        def eval(self, frame, astpattern=astpattern):
 | 
			
		||||
            left = Interpretable(self.left)
 | 
			
		||||
            left.eval(frame)
 | 
			
		||||
            right = Interpretable(self.right)
 | 
			
		||||
            right.eval(frame)
 | 
			
		||||
            self.explanation = (astpattern
 | 
			
		||||
                                .replace('__exprinfo_left',  left .explanation)
 | 
			
		||||
                                .replace('__exprinfo_right', right.explanation))
 | 
			
		||||
            try:
 | 
			
		||||
                self.result = frame.eval(astpattern,
 | 
			
		||||
                                         __exprinfo_left=left.result,
 | 
			
		||||
                                         __exprinfo_right=right.result)
 | 
			
		||||
            except passthroughex:
 | 
			
		||||
                raise
 | 
			
		||||
            except:
 | 
			
		||||
                raise Failure(self)
 | 
			
		||||
 | 
			
		||||
    keepalive.append(BinaryArith)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CallFunc(Interpretable):
 | 
			
		||||
    __view__ = ast.CallFunc
 | 
			
		||||
 | 
			
		||||
    def is_bool(self, frame):
 | 
			
		||||
        source = 'isinstance(__exprinfo_value, bool)'
 | 
			
		||||
        try:
 | 
			
		||||
            return frame.is_true(frame.eval(source,
 | 
			
		||||
                                            __exprinfo_value=self.result))
 | 
			
		||||
        except passthroughex:
 | 
			
		||||
            raise
 | 
			
		||||
        except:
 | 
			
		||||
            return False
 | 
			
		||||
 | 
			
		||||
    def eval(self, frame):
 | 
			
		||||
        node = Interpretable(self.node)
 | 
			
		||||
        node.eval(frame)
 | 
			
		||||
        explanations = []
 | 
			
		||||
        vars = {'__exprinfo_fn': node.result}
 | 
			
		||||
        source = '__exprinfo_fn('
 | 
			
		||||
        for a in self.args:
 | 
			
		||||
            if isinstance(a, ast.Keyword):
 | 
			
		||||
                keyword = a.name
 | 
			
		||||
                a = a.expr
 | 
			
		||||
            else:
 | 
			
		||||
                keyword = None
 | 
			
		||||
            a = Interpretable(a)
 | 
			
		||||
            a.eval(frame)
 | 
			
		||||
            argname = '__exprinfo_%d' % len(vars)
 | 
			
		||||
            vars[argname] = a.result
 | 
			
		||||
            if keyword is None:
 | 
			
		||||
                source += argname + ','
 | 
			
		||||
                explanations.append(a.explanation)
 | 
			
		||||
            else:
 | 
			
		||||
                source += '%s=%s,' % (keyword, argname)
 | 
			
		||||
                explanations.append('%s=%s' % (keyword, a.explanation))
 | 
			
		||||
        if self.star_args:
 | 
			
		||||
            star_args = Interpretable(self.star_args)
 | 
			
		||||
            star_args.eval(frame)
 | 
			
		||||
            argname = '__exprinfo_star'
 | 
			
		||||
            vars[argname] = star_args.result
 | 
			
		||||
            source += '*' + argname + ','
 | 
			
		||||
            explanations.append('*' + star_args.explanation)
 | 
			
		||||
        if self.dstar_args:
 | 
			
		||||
            dstar_args = Interpretable(self.dstar_args)
 | 
			
		||||
            dstar_args.eval(frame)
 | 
			
		||||
            argname = '__exprinfo_kwds'
 | 
			
		||||
            vars[argname] = dstar_args.result
 | 
			
		||||
            source += '**' + argname + ','
 | 
			
		||||
            explanations.append('**' + dstar_args.explanation)
 | 
			
		||||
        self.explanation = "%s(%s)" % (
 | 
			
		||||
            node.explanation, ', '.join(explanations))
 | 
			
		||||
        if source.endswith(','):
 | 
			
		||||
            source = source[:-1]
 | 
			
		||||
        source += ')'
 | 
			
		||||
        try:
 | 
			
		||||
            self.result = frame.eval(source, **vars)
 | 
			
		||||
        except passthroughex:
 | 
			
		||||
            raise
 | 
			
		||||
        except:
 | 
			
		||||
            raise Failure(self)
 | 
			
		||||
        if not node.is_builtin(frame) or not self.is_bool(frame):
 | 
			
		||||
            r = frame.repr(self.result)
 | 
			
		||||
            self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation)
 | 
			
		||||
 | 
			
		||||
class Getattr(Interpretable):
 | 
			
		||||
    __view__ = ast.Getattr
 | 
			
		||||
 | 
			
		||||
    def eval(self, frame):
 | 
			
		||||
        expr = Interpretable(self.expr)
 | 
			
		||||
        expr.eval(frame)
 | 
			
		||||
        source = '__exprinfo_expr.%s' % self.attrname
 | 
			
		||||
        try:
 | 
			
		||||
            self.result = frame.eval(source, __exprinfo_expr=expr.result)
 | 
			
		||||
        except passthroughex:
 | 
			
		||||
            raise
 | 
			
		||||
        except:
 | 
			
		||||
            raise Failure(self)
 | 
			
		||||
        self.explanation = '%s.%s' % (expr.explanation, self.attrname)
 | 
			
		||||
        # if the attribute comes from the instance, its value is interesting
 | 
			
		||||
        source = ('hasattr(__exprinfo_expr, "__dict__") and '
 | 
			
		||||
                  '%r in __exprinfo_expr.__dict__' % self.attrname)
 | 
			
		||||
        try:
 | 
			
		||||
            from_instance = frame.is_true(
 | 
			
		||||
                frame.eval(source, __exprinfo_expr=expr.result))
 | 
			
		||||
        except passthroughex:
 | 
			
		||||
            raise
 | 
			
		||||
        except:
 | 
			
		||||
            from_instance = True
 | 
			
		||||
        if from_instance:
 | 
			
		||||
            r = frame.repr(self.result)
 | 
			
		||||
            self.explanation = '%s\n{%s = %s\n}' % (r, r, self.explanation)
 | 
			
		||||
 | 
			
		||||
# == Re-interpretation of full statements ==
 | 
			
		||||
 | 
			
		||||
class Assert(Interpretable):
 | 
			
		||||
    __view__ = ast.Assert
 | 
			
		||||
 | 
			
		||||
    def run(self, frame):
 | 
			
		||||
        test = Interpretable(self.test)
 | 
			
		||||
        test.eval(frame)
 | 
			
		||||
        # simplify 'assert False where False = ...'
 | 
			
		||||
        if (test.explanation.startswith('False\n{False = ') and
 | 
			
		||||
            test.explanation.endswith('\n}')):
 | 
			
		||||
            test.explanation = test.explanation[15:-2]
 | 
			
		||||
        # print the result as  'assert <explanation>'
 | 
			
		||||
        self.result = test.result
 | 
			
		||||
        self.explanation = 'assert ' + test.explanation
 | 
			
		||||
        if not frame.is_true(test.result):
 | 
			
		||||
            try:
 | 
			
		||||
                raise BuiltinAssertionError
 | 
			
		||||
            except passthroughex:
 | 
			
		||||
                raise
 | 
			
		||||
            except:
 | 
			
		||||
                raise Failure(self)
 | 
			
		||||
 | 
			
		||||
class Assign(Interpretable):
 | 
			
		||||
    __view__ = ast.Assign
 | 
			
		||||
 | 
			
		||||
    def run(self, frame):
 | 
			
		||||
        expr = Interpretable(self.expr)
 | 
			
		||||
        expr.eval(frame)
 | 
			
		||||
        self.result = expr.result
 | 
			
		||||
        self.explanation = '... = ' + expr.explanation
 | 
			
		||||
        # fall-back-run the rest of the assignment
 | 
			
		||||
        ass = ast.Assign(self.nodes, ast.Name('__exprinfo_expr'))
 | 
			
		||||
        mod = ast.Module(None, ast.Stmt([ass]))
 | 
			
		||||
        mod.filename = '<run>'
 | 
			
		||||
        co = pycodegen.ModuleCodeGenerator(mod).getCode()
 | 
			
		||||
        try:
 | 
			
		||||
            frame.exec_(co, __exprinfo_expr=expr.result)
 | 
			
		||||
        except passthroughex:
 | 
			
		||||
            raise
 | 
			
		||||
        except:
 | 
			
		||||
            raise Failure(self)
 | 
			
		||||
 | 
			
		||||
class Discard(Interpretable):
 | 
			
		||||
    __view__ = ast.Discard
 | 
			
		||||
 | 
			
		||||
    def run(self, frame):
 | 
			
		||||
        expr = Interpretable(self.expr)
 | 
			
		||||
        expr.eval(frame)
 | 
			
		||||
        self.result = expr.result
 | 
			
		||||
        self.explanation = expr.explanation
 | 
			
		||||
 | 
			
		||||
class Stmt(Interpretable):
 | 
			
		||||
    __view__ = ast.Stmt
 | 
			
		||||
 | 
			
		||||
    def run(self, frame):
 | 
			
		||||
        for stmt in self.nodes:
 | 
			
		||||
            stmt = Interpretable(stmt)
 | 
			
		||||
            stmt.run(frame)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def report_failure(e):
 | 
			
		||||
    explanation = e.node.nice_explanation()
 | 
			
		||||
    if explanation:
 | 
			
		||||
        explanation = ", in: " + explanation
 | 
			
		||||
    else:
 | 
			
		||||
        explanation = ""
 | 
			
		||||
    sys.stdout.write("%s: %s%s\n" % (e.exc.__name__, e.value, explanation))
 | 
			
		||||
 | 
			
		||||
def check(s, frame=None):
 | 
			
		||||
    from _pytest._code import Frame
 | 
			
		||||
    if frame is None:
 | 
			
		||||
        frame = sys._getframe(1)
 | 
			
		||||
        frame = Frame(frame)
 | 
			
		||||
    expr = parse(s, 'eval')
 | 
			
		||||
    assert isinstance(expr, ast.Expression)
 | 
			
		||||
    node = Interpretable(expr.node)
 | 
			
		||||
    try:
 | 
			
		||||
        node.eval(frame)
 | 
			
		||||
    except passthroughex:
 | 
			
		||||
        raise
 | 
			
		||||
    except Failure:
 | 
			
		||||
        e = sys.exc_info()[1]
 | 
			
		||||
        report_failure(e)
 | 
			
		||||
    else:
 | 
			
		||||
        if not frame.is_true(node.result):
 | 
			
		||||
            sys.stderr.write("assertion failed: %s\n" % node.nice_explanation())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
###########################################################
 | 
			
		||||
# API / Entry points
 | 
			
		||||
# #########################################################
 | 
			
		||||
 | 
			
		||||
def interpret(source, frame, should_fail=False):
 | 
			
		||||
    module = Interpretable(parse(source, 'exec').node)
 | 
			
		||||
    import _pytest._code
 | 
			
		||||
    if isinstance(frame, py.std.types.FrameType):
 | 
			
		||||
        frame = _pytest._code.Frame(frame)
 | 
			
		||||
    try:
 | 
			
		||||
        module.run(frame)
 | 
			
		||||
    except Failure:
 | 
			
		||||
        e = sys.exc_info()[1]
 | 
			
		||||
        return getfailure(e)
 | 
			
		||||
    except passthroughex:
 | 
			
		||||
        raise
 | 
			
		||||
    except:
 | 
			
		||||
        import traceback
 | 
			
		||||
        traceback.print_exc()
 | 
			
		||||
    if should_fail:
 | 
			
		||||
        return ("(assertion failed, but when it was re-run for "
 | 
			
		||||
                "printing intermediate values, it did not fail.  Suggestions: "
 | 
			
		||||
                "compute assert expression before the assert or use --nomagic)")
 | 
			
		||||
    else:
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
def getmsg(excinfo):
 | 
			
		||||
    import _pytest._code
 | 
			
		||||
    if isinstance(excinfo, tuple):
 | 
			
		||||
        excinfo = _pytest._code.ExceptionInfo(excinfo)
 | 
			
		||||
    #frame, line = gettbline(tb)
 | 
			
		||||
    #frame = pytest.code.Frame(frame)
 | 
			
		||||
    #return interpret(line, frame)
 | 
			
		||||
 | 
			
		||||
    tb = excinfo.traceback[-1]
 | 
			
		||||
    source = str(tb.statement).strip()
 | 
			
		||||
    x = interpret(source, tb.frame, should_fail=True)
 | 
			
		||||
    if not isinstance(x, str):
 | 
			
		||||
        raise TypeError("interpret returned non-string %r" % (x,))
 | 
			
		||||
    return x
 | 
			
		||||
 | 
			
		||||
def getfailure(e):
 | 
			
		||||
    explanation = e.node.nice_explanation()
 | 
			
		||||
    if str(e.value):
 | 
			
		||||
        lines = explanation.split('\n')
 | 
			
		||||
        lines[0] += "  << %s" % (e.value,)
 | 
			
		||||
        explanation = '\n'.join(lines)
 | 
			
		||||
    text = "%s: %s" % (e.exc.__name__, explanation)
 | 
			
		||||
    if text.startswith('AssertionError: assert '):
 | 
			
		||||
        text = text[16:]
 | 
			
		||||
    return text
 | 
			
		||||
 | 
			
		||||
def run(s, frame=None):
 | 
			
		||||
    import _pytest._code
 | 
			
		||||
    if frame is None:
 | 
			
		||||
        frame = sys._getframe(1)
 | 
			
		||||
        frame = _pytest._code.Frame(frame)
 | 
			
		||||
    module = Interpretable(parse(s, 'exec').node)
 | 
			
		||||
    try:
 | 
			
		||||
        module.run(frame)
 | 
			
		||||
    except Failure:
 | 
			
		||||
        e = sys.exc_info()[1]
 | 
			
		||||
        report_failure(e)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    # example:
 | 
			
		||||
    def f():
 | 
			
		||||
        return 5
 | 
			
		||||
    def g():
 | 
			
		||||
        return 3
 | 
			
		||||
    def h(x):
 | 
			
		||||
        return 'never'
 | 
			
		||||
    check("f() * g() == 5")
 | 
			
		||||
    check("not f()")
 | 
			
		||||
    check("not (f() and g() or 0)")
 | 
			
		||||
    check("f() == g()")
 | 
			
		||||
    i = 4
 | 
			
		||||
    check("i == f()")
 | 
			
		||||
    check("len(f()) == 0")
 | 
			
		||||
    check("isinstance(2+3+4, float)")
 | 
			
		||||
 | 
			
		||||
    run("x = i")
 | 
			
		||||
    check("x == 5")
 | 
			
		||||
 | 
			
		||||
    run("assert not f(), 'oops'")
 | 
			
		||||
    run("a, b, c = 1, 2")
 | 
			
		||||
    run("a, b, c = f()")
 | 
			
		||||
 | 
			
		||||
    check("max([f(),g()]) == 4")
 | 
			
		||||
    check("'hello'[g()] == 'h'")
 | 
			
		||||
    run("'guk%d' % h(f())")
 | 
			
		||||
| 
						 | 
				
			
			@ -1,96 +0,0 @@
 | 
			
		|||
import sys
 | 
			
		||||
 | 
			
		||||
import py
 | 
			
		||||
from .code import Frame
 | 
			
		||||
 | 
			
		||||
BuiltinAssertionError = py.builtin.builtins.AssertionError
 | 
			
		||||
 | 
			
		||||
_reprcompare = None # if set, will be called by assert reinterp for comparison ops
 | 
			
		||||
 | 
			
		||||
def _format_explanation(explanation):
 | 
			
		||||
    """This formats an explanation
 | 
			
		||||
 | 
			
		||||
    Normally all embedded newlines are escaped, however there are
 | 
			
		||||
    three exceptions: \n{, \n} and \n~.  The first two are intended
 | 
			
		||||
    cover nested explanations, see function and attribute explanations
 | 
			
		||||
    for examples (.visit_Call(), visit_Attribute()).  The last one is
 | 
			
		||||
    for when one explanation needs to span multiple lines, e.g. when
 | 
			
		||||
    displaying diffs.
 | 
			
		||||
    """
 | 
			
		||||
    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('}') 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:])
 | 
			
		||||
        elif line.startswith('}'):
 | 
			
		||||
            assert line.startswith('}')
 | 
			
		||||
            stack.pop()
 | 
			
		||||
            stackcnt.pop()
 | 
			
		||||
            result[stack[-1]] += line[1:]
 | 
			
		||||
        else:
 | 
			
		||||
            assert line.startswith('~')
 | 
			
		||||
            result.append('  '*len(stack) + line[1:])
 | 
			
		||||
    assert len(stack) == 1
 | 
			
		||||
    return '\n'.join(result)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AssertionError(BuiltinAssertionError):
 | 
			
		||||
    def __init__(self, *args):
 | 
			
		||||
        BuiltinAssertionError.__init__(self, *args)
 | 
			
		||||
        if args:
 | 
			
		||||
            try:
 | 
			
		||||
                self.msg = str(args[0])
 | 
			
		||||
            except py.builtin._sysex:
 | 
			
		||||
                raise
 | 
			
		||||
            except:
 | 
			
		||||
                self.msg = "<[broken __repr__] %s at %0xd>" %(
 | 
			
		||||
                    args[0].__class__, id(args[0]))
 | 
			
		||||
        else:
 | 
			
		||||
            f = Frame(sys._getframe(1))
 | 
			
		||||
            try:
 | 
			
		||||
                source = f.code.fullsource
 | 
			
		||||
                if source is not None:
 | 
			
		||||
                    try:
 | 
			
		||||
                        source = source.getstatement(f.lineno, assertion=True)
 | 
			
		||||
                    except IndexError:
 | 
			
		||||
                        source = None
 | 
			
		||||
                    else:
 | 
			
		||||
                        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 = reinterpret(source, f, should_fail=True)
 | 
			
		||||
            else:
 | 
			
		||||
                self.msg = "<could not determine information>"
 | 
			
		||||
            if not self.args:
 | 
			
		||||
                self.args = (self.msg,)
 | 
			
		||||
 | 
			
		||||
if sys.version_info > (3, 0):
 | 
			
		||||
    AssertionError.__module__ = "builtins"
 | 
			
		||||
    reinterpret_old = "old reinterpretation not available for py3"
 | 
			
		||||
else:
 | 
			
		||||
    from _pytest._code._assertionold import interpret as reinterpret_old
 | 
			
		||||
if sys.version_info >= (2, 6) or (sys.platform.startswith("java")):
 | 
			
		||||
    from _pytest._code._assertionnew import interpret as reinterpret
 | 
			
		||||
else:
 | 
			
		||||
    reinterpret = reinterpret_old
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -177,11 +177,11 @@ class TracebackEntry(object):
 | 
			
		|||
    def reinterpret(self):
 | 
			
		||||
        """Reinterpret the failing statement and returns a detailed information
 | 
			
		||||
           about what operations are performed."""
 | 
			
		||||
        import _pytest._code
 | 
			
		||||
        from _pytest.assertion.reinterpret import reinterpret
 | 
			
		||||
        if self.exprinfo is None:
 | 
			
		||||
            source = str(self.statement).strip()
 | 
			
		||||
            x = _pytest._code._reinterpret(source, self.frame, should_fail=True)
 | 
			
		||||
            if not isinstance(x, str):
 | 
			
		||||
            source = py.builtin._totext(self.statement).strip()
 | 
			
		||||
            x = reinterpret(source, self.frame, should_fail=True)
 | 
			
		||||
            if not py.builtin._istext(x):
 | 
			
		||||
                raise TypeError("interpret returned non-string %r" % (x,))
 | 
			
		||||
            self.exprinfo = x
 | 
			
		||||
        return self.exprinfo
 | 
			
		||||
| 
						 | 
				
			
			@ -760,10 +760,10 @@ oldbuiltins = {}
 | 
			
		|||
def patch_builtins(assertion=True, compile=True):
 | 
			
		||||
    """ put compile and AssertionError builtins to Python's builtins. """
 | 
			
		||||
    if assertion:
 | 
			
		||||
        from _pytest._code import assertion
 | 
			
		||||
        from _pytest.assertion import reinterpret
 | 
			
		||||
        l = oldbuiltins.setdefault('AssertionError', [])
 | 
			
		||||
        l.append(py.builtin.builtins.AssertionError)
 | 
			
		||||
        py.builtin.builtins.AssertionError = assertion.AssertionError
 | 
			
		||||
        py.builtin.builtins.AssertionError = reinterpret.AssertionError
 | 
			
		||||
    if compile:
 | 
			
		||||
        import _pytest._code
 | 
			
		||||
        l = oldbuiltins.setdefault('compile', [])
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,309 +0,0 @@
 | 
			
		|||
import pytest, py
 | 
			
		||||
 | 
			
		||||
def exvalue():
 | 
			
		||||
    return py.std.sys.exc_info()[1]
 | 
			
		||||
 | 
			
		||||
def f():
 | 
			
		||||
    return 2
 | 
			
		||||
 | 
			
		||||
def test_assert():
 | 
			
		||||
    try:
 | 
			
		||||
        assert f() == 3
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        s = str(e)
 | 
			
		||||
        assert s.startswith('assert 2 == 3\n')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_assert_within_finally():
 | 
			
		||||
    excinfo = pytest.raises(ZeroDivisionError, """
 | 
			
		||||
        try:
 | 
			
		||||
            1/0
 | 
			
		||||
        finally:
 | 
			
		||||
            i = 42
 | 
			
		||||
    """)
 | 
			
		||||
    s = excinfo.exconly()
 | 
			
		||||
    assert py.std.re.search("division.+by zero", s) is not None
 | 
			
		||||
 | 
			
		||||
    #def g():
 | 
			
		||||
    #    A.f()
 | 
			
		||||
    #excinfo = getexcinfo(TypeError, g)
 | 
			
		||||
    #msg = getmsg(excinfo)
 | 
			
		||||
    #assert msg.find("must be called with A") != -1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_assert_multiline_1():
 | 
			
		||||
    try:
 | 
			
		||||
        assert (f() ==
 | 
			
		||||
                3)
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        s = str(e)
 | 
			
		||||
        assert s.startswith('assert 2 == 3\n')
 | 
			
		||||
 | 
			
		||||
def test_assert_multiline_2():
 | 
			
		||||
    try:
 | 
			
		||||
        assert (f() == (4,
 | 
			
		||||
                   3)[-1])
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        s = str(e)
 | 
			
		||||
        assert s.startswith('assert 2 ==')
 | 
			
		||||
 | 
			
		||||
def test_in():
 | 
			
		||||
    try:
 | 
			
		||||
        assert "hi" in [1, 2]
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        s = str(e)
 | 
			
		||||
        assert s.startswith("assert 'hi' in")
 | 
			
		||||
 | 
			
		||||
def test_is():
 | 
			
		||||
    try:
 | 
			
		||||
        assert 1 is 2
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        s = str(e)
 | 
			
		||||
        assert s.startswith("assert 1 is 2")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.skipif("sys.version_info < (2,6)")
 | 
			
		||||
def test_attrib():
 | 
			
		||||
    class Foo(object):
 | 
			
		||||
        b = 1
 | 
			
		||||
    i = Foo()
 | 
			
		||||
    try:
 | 
			
		||||
        assert i.b == 2
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        s = str(e)
 | 
			
		||||
        assert s.startswith("assert 1 == 2")
 | 
			
		||||
 | 
			
		||||
@pytest.mark.skipif("sys.version_info < (2,6)")
 | 
			
		||||
def test_attrib_inst():
 | 
			
		||||
    class Foo(object):
 | 
			
		||||
        b = 1
 | 
			
		||||
    try:
 | 
			
		||||
        assert Foo().b == 2
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        s = str(e)
 | 
			
		||||
        assert s.startswith("assert 1 == 2")
 | 
			
		||||
 | 
			
		||||
def test_len():
 | 
			
		||||
    l = list(range(42))
 | 
			
		||||
    try:
 | 
			
		||||
        assert len(l) == 100
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        s = str(e)
 | 
			
		||||
        assert s.startswith("assert 42 == 100")
 | 
			
		||||
        assert "where 42 = len([" in s
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_assert_keyword_arg():
 | 
			
		||||
    def f(x=3):
 | 
			
		||||
        return False
 | 
			
		||||
    try:
 | 
			
		||||
        assert f(x=5)
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        assert "x=5" in e.msg
 | 
			
		||||
 | 
			
		||||
# These tests should both fail, but should fail nicely...
 | 
			
		||||
class WeirdRepr:
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return '<WeirdRepr\nsecond line>'
 | 
			
		||||
 | 
			
		||||
def bug_test_assert_repr():
 | 
			
		||||
    v = WeirdRepr()
 | 
			
		||||
    try:
 | 
			
		||||
        assert v == 1
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        assert e.msg.find('WeirdRepr') != -1
 | 
			
		||||
        assert e.msg.find('second line') != -1
 | 
			
		||||
        assert 0
 | 
			
		||||
 | 
			
		||||
def test_assert_non_string():
 | 
			
		||||
    try:
 | 
			
		||||
        assert 0, ['list']
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        assert e.msg.find("list") != -1
 | 
			
		||||
 | 
			
		||||
def test_assert_implicit_multiline():
 | 
			
		||||
    try:
 | 
			
		||||
        x = [1,2,3]
 | 
			
		||||
        assert x != [1,
 | 
			
		||||
           2, 3]
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        assert e.msg.find('assert [1, 2, 3] !=') != -1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_assert_with_brokenrepr_arg():
 | 
			
		||||
    class BrokenRepr:
 | 
			
		||||
        def __repr__(self): 0 / 0
 | 
			
		||||
    e = AssertionError(BrokenRepr())
 | 
			
		||||
    if e.msg.find("broken __repr__") == -1:
 | 
			
		||||
        pytest.fail("broken __repr__ not handle correctly")
 | 
			
		||||
 | 
			
		||||
def test_multiple_statements_per_line():
 | 
			
		||||
    try:
 | 
			
		||||
        a = 1; assert a == 2
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        assert "assert 1 == 2" in e.msg
 | 
			
		||||
 | 
			
		||||
def test_power():
 | 
			
		||||
    try:
 | 
			
		||||
        assert 2**3 == 7
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        assert "assert (2 ** 3) == 7" in e.msg
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestView:
 | 
			
		||||
 | 
			
		||||
    def setup_class(cls):
 | 
			
		||||
        cls.View = pytest.importorskip("_pytest._code._assertionold").View
 | 
			
		||||
 | 
			
		||||
    def test_class_dispatch(self):
 | 
			
		||||
        ### Use a custom class hierarchy with existing instances
 | 
			
		||||
 | 
			
		||||
        class Picklable(self.View):
 | 
			
		||||
            pass
 | 
			
		||||
 | 
			
		||||
        class Simple(Picklable):
 | 
			
		||||
            __view__ = object
 | 
			
		||||
            def pickle(self):
 | 
			
		||||
                return repr(self.__obj__)
 | 
			
		||||
 | 
			
		||||
        class Seq(Picklable):
 | 
			
		||||
            __view__ = list, tuple, dict
 | 
			
		||||
            def pickle(self):
 | 
			
		||||
                return ';'.join(
 | 
			
		||||
                    [Picklable(item).pickle() for item in self.__obj__])
 | 
			
		||||
 | 
			
		||||
        class Dict(Seq):
 | 
			
		||||
            __view__ = dict
 | 
			
		||||
            def pickle(self):
 | 
			
		||||
                return Seq.pickle(self) + '!' + Seq(self.values()).pickle()
 | 
			
		||||
 | 
			
		||||
        assert Picklable(123).pickle() == '123'
 | 
			
		||||
        assert Picklable([1,[2,3],4]).pickle() == '1;2;3;4'
 | 
			
		||||
        assert Picklable({1:2}).pickle() == '1!2'
 | 
			
		||||
 | 
			
		||||
    def test_viewtype_class_hierarchy(self):
 | 
			
		||||
        # Use a custom class hierarchy based on attributes of existing instances
 | 
			
		||||
        class Operation:
 | 
			
		||||
            "Existing class that I don't want to change."
 | 
			
		||||
            def __init__(self, opname, *args):
 | 
			
		||||
                self.opname = opname
 | 
			
		||||
                self.args = args
 | 
			
		||||
 | 
			
		||||
        existing = [Operation('+', 4, 5),
 | 
			
		||||
                    Operation('getitem', '', 'join'),
 | 
			
		||||
                    Operation('setattr', 'x', 'y', 3),
 | 
			
		||||
                    Operation('-', 12, 1)]
 | 
			
		||||
 | 
			
		||||
        class PyOp(self.View):
 | 
			
		||||
            def __viewkey__(self):
 | 
			
		||||
                return self.opname
 | 
			
		||||
            def generate(self):
 | 
			
		||||
                return '%s(%s)' % (self.opname, ', '.join(map(repr, self.args)))
 | 
			
		||||
 | 
			
		||||
        class PyBinaryOp(PyOp):
 | 
			
		||||
            __view__ = ('+', '-', '*', '/')
 | 
			
		||||
            def generate(self):
 | 
			
		||||
                return '%s %s %s' % (self.args[0], self.opname, self.args[1])
 | 
			
		||||
 | 
			
		||||
        codelines = [PyOp(op).generate() for op in existing]
 | 
			
		||||
        assert codelines == ["4 + 5", "getitem('', 'join')",
 | 
			
		||||
            "setattr('x', 'y', 3)", "12 - 1"]
 | 
			
		||||
 | 
			
		||||
def test_underscore_api():
 | 
			
		||||
    import _pytest._code
 | 
			
		||||
    _pytest._code._AssertionError
 | 
			
		||||
    _pytest._code._reinterpret_old # used by pypy
 | 
			
		||||
    _pytest._code._reinterpret
 | 
			
		||||
 | 
			
		||||
@pytest.mark.skipif("sys.version_info < (2,6)")
 | 
			
		||||
def test_assert_customizable_reprcompare(monkeypatch):
 | 
			
		||||
    util = pytest.importorskip("_pytest.assertion.util")
 | 
			
		||||
    monkeypatch.setattr(util, '_reprcompare', lambda *args: 'hello')
 | 
			
		||||
    try:
 | 
			
		||||
        assert 3 == 4
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        s = str(e)
 | 
			
		||||
        assert "hello" in s
 | 
			
		||||
 | 
			
		||||
def test_assert_long_source_1():
 | 
			
		||||
    try:
 | 
			
		||||
        assert len == [
 | 
			
		||||
            (None, ['somet text', 'more text']),
 | 
			
		||||
        ]
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        s = str(e)
 | 
			
		||||
        assert 're-run' not in s
 | 
			
		||||
        assert 'somet text' in s
 | 
			
		||||
 | 
			
		||||
def test_assert_long_source_2():
 | 
			
		||||
    try:
 | 
			
		||||
        assert(len == [
 | 
			
		||||
            (None, ['somet text', 'more text']),
 | 
			
		||||
        ])
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        s = str(e)
 | 
			
		||||
        assert 're-run' not in s
 | 
			
		||||
        assert 'somet text' in s
 | 
			
		||||
 | 
			
		||||
def test_assert_raise_alias(testdir):
 | 
			
		||||
    testdir.makepyfile("""
 | 
			
		||||
    import sys
 | 
			
		||||
    EX = AssertionError
 | 
			
		||||
    def test_hello():
 | 
			
		||||
        raise EX("hello"
 | 
			
		||||
            "multi"
 | 
			
		||||
            "line")
 | 
			
		||||
    """)
 | 
			
		||||
    result = testdir.runpytest()
 | 
			
		||||
    result.stdout.fnmatch_lines([
 | 
			
		||||
        "*def test_hello*",
 | 
			
		||||
        "*raise EX*",
 | 
			
		||||
        "*1 failed*",
 | 
			
		||||
    ])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.mark.skipif("sys.version_info < (2,5)")
 | 
			
		||||
def test_assert_raise_subclass():
 | 
			
		||||
    class SomeEx(AssertionError):
 | 
			
		||||
        def __init__(self, *args):
 | 
			
		||||
            super(SomeEx, self).__init__()
 | 
			
		||||
    try:
 | 
			
		||||
        raise SomeEx("hello")
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        s = str(exvalue())
 | 
			
		||||
        assert 're-run' not in s
 | 
			
		||||
        assert 'could not determine' in s
 | 
			
		||||
 | 
			
		||||
def test_assert_raises_in_nonzero_of_object_pytest_issue10():
 | 
			
		||||
    class A(object):
 | 
			
		||||
        def __nonzero__(self):
 | 
			
		||||
            raise ValueError(42)
 | 
			
		||||
        def __lt__(self, other):
 | 
			
		||||
            return A()
 | 
			
		||||
        def __repr__(self):
 | 
			
		||||
            return "<MY42 object>"
 | 
			
		||||
    def myany(x):
 | 
			
		||||
        return True
 | 
			
		||||
    try:
 | 
			
		||||
        assert not(myany(A() < 0))
 | 
			
		||||
    except AssertionError:
 | 
			
		||||
        e = exvalue()
 | 
			
		||||
        s = str(e)
 | 
			
		||||
        assert "<MY42 object> < 0" in s
 | 
			
		||||
		Loading…
	
		Reference in New Issue