refactor explanation formatting things into their own module
This commit is contained in:
parent
f423ce9c01
commit
250160b4b0
|
@ -7,6 +7,7 @@ import marshal
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
from _pytest.monkeypatch import monkeypatch
|
from _pytest.monkeypatch import monkeypatch
|
||||||
|
from _pytest.assertion import reinterpret, util
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from _pytest.assertion.rewrite import rewrite_asserts
|
from _pytest.assertion.rewrite import rewrite_asserts
|
||||||
|
@ -31,7 +32,6 @@ def pytest_configure(config):
|
||||||
config._cleanup.append(m.undo)
|
config._cleanup.append(m.undo)
|
||||||
warn_about_missing_assertion()
|
warn_about_missing_assertion()
|
||||||
if not config.getvalue("noassert") and not config.getvalue("nomagic"):
|
if not config.getvalue("noassert") and not config.getvalue("nomagic"):
|
||||||
from _pytest.assertion import reinterpret
|
|
||||||
def callbinrepr(op, left, right):
|
def callbinrepr(op, left, right):
|
||||||
hook_result = config.hook.pytest_assertrepr_compare(
|
hook_result = config.hook.pytest_assertrepr_compare(
|
||||||
config=config, op=op, left=left, right=right)
|
config=config, op=op, left=left, right=right)
|
||||||
|
@ -40,7 +40,7 @@ def pytest_configure(config):
|
||||||
return '\n~'.join(new_expl)
|
return '\n~'.join(new_expl)
|
||||||
m.setattr(py.builtin.builtins, 'AssertionError',
|
m.setattr(py.builtin.builtins, 'AssertionError',
|
||||||
reinterpret.AssertionError)
|
reinterpret.AssertionError)
|
||||||
m.setattr(sys.modules[__name__], '_reprcompare', callbinrepr)
|
m.setattr(util, '_reprcompare', callbinrepr)
|
||||||
else:
|
else:
|
||||||
rewrite_asserts = None
|
rewrite_asserts = None
|
||||||
|
|
||||||
|
@ -99,186 +99,4 @@ def warn_about_missing_assertion():
|
||||||
sys.stderr.write("WARNING: failing tests may report as passing because "
|
sys.stderr.write("WARNING: failing tests may report as passing because "
|
||||||
"assertions are turned off! (are you using python -O?)\n")
|
"assertions are turned off! (are you using python -O?)\n")
|
||||||
|
|
||||||
# if set, will be called by assert reinterp for comparison ops
|
pytest_assertrepr_compare = util.assertrepr_compare
|
||||||
_reprcompare = None
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
# Provide basestring in python3
|
|
||||||
try:
|
|
||||||
basestring = basestring
|
|
||||||
except NameError:
|
|
||||||
basestring = str
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_assertrepr_compare(op, left, right):
|
|
||||||
"""return specialised explanations for some operators/operands"""
|
|
||||||
width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op
|
|
||||||
left_repr = py.io.saferepr(left, maxsize=int(width/2))
|
|
||||||
right_repr = py.io.saferepr(right, maxsize=width-len(left_repr))
|
|
||||||
summary = '%s %s %s' % (left_repr, op, right_repr)
|
|
||||||
|
|
||||||
issequence = lambda x: isinstance(x, (list, tuple))
|
|
||||||
istext = lambda x: isinstance(x, basestring)
|
|
||||||
isdict = lambda x: isinstance(x, dict)
|
|
||||||
isset = lambda x: isinstance(x, set)
|
|
||||||
|
|
||||||
explanation = None
|
|
||||||
try:
|
|
||||||
if op == '==':
|
|
||||||
if istext(left) and istext(right):
|
|
||||||
explanation = _diff_text(left, right)
|
|
||||||
elif issequence(left) and issequence(right):
|
|
||||||
explanation = _compare_eq_sequence(left, right)
|
|
||||||
elif isset(left) and isset(right):
|
|
||||||
explanation = _compare_eq_set(left, right)
|
|
||||||
elif isdict(left) and isdict(right):
|
|
||||||
explanation = _diff_text(py.std.pprint.pformat(left),
|
|
||||||
py.std.pprint.pformat(right))
|
|
||||||
elif op == 'not in':
|
|
||||||
if istext(left) and istext(right):
|
|
||||||
explanation = _notin_text(left, right)
|
|
||||||
except py.builtin._sysex:
|
|
||||||
raise
|
|
||||||
except:
|
|
||||||
excinfo = py.code.ExceptionInfo()
|
|
||||||
explanation = ['(pytest_assertion plugin: representation of '
|
|
||||||
'details failed. Probably an object has a faulty __repr__.)',
|
|
||||||
str(excinfo)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
if not explanation:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Don't include pageloads of data, should be configurable
|
|
||||||
if len(''.join(explanation)) > 80*8:
|
|
||||||
explanation = ['Detailed information too verbose, truncated']
|
|
||||||
|
|
||||||
return [summary] + explanation
|
|
||||||
|
|
||||||
|
|
||||||
def _diff_text(left, right):
|
|
||||||
"""Return the explanation for the diff between text
|
|
||||||
|
|
||||||
This will skip leading and trailing characters which are
|
|
||||||
identical to keep the diff minimal.
|
|
||||||
"""
|
|
||||||
explanation = []
|
|
||||||
i = 0 # just in case left or right has zero length
|
|
||||||
for i in range(min(len(left), len(right))):
|
|
||||||
if left[i] != right[i]:
|
|
||||||
break
|
|
||||||
if i > 42:
|
|
||||||
i -= 10 # Provide some context
|
|
||||||
explanation = ['Skipping %s identical '
|
|
||||||
'leading characters in diff' % i]
|
|
||||||
left = left[i:]
|
|
||||||
right = right[i:]
|
|
||||||
if len(left) == len(right):
|
|
||||||
for i in range(len(left)):
|
|
||||||
if left[-i] != right[-i]:
|
|
||||||
break
|
|
||||||
if i > 42:
|
|
||||||
i -= 10 # Provide some context
|
|
||||||
explanation += ['Skipping %s identical '
|
|
||||||
'trailing characters in diff' % i]
|
|
||||||
left = left[:-i]
|
|
||||||
right = right[:-i]
|
|
||||||
explanation += [line.strip('\n')
|
|
||||||
for line in py.std.difflib.ndiff(left.splitlines(),
|
|
||||||
right.splitlines())]
|
|
||||||
return explanation
|
|
||||||
|
|
||||||
|
|
||||||
def _compare_eq_sequence(left, right):
|
|
||||||
explanation = []
|
|
||||||
for i in range(min(len(left), len(right))):
|
|
||||||
if left[i] != right[i]:
|
|
||||||
explanation += ['At index %s diff: %r != %r' %
|
|
||||||
(i, left[i], right[i])]
|
|
||||||
break
|
|
||||||
if len(left) > len(right):
|
|
||||||
explanation += ['Left contains more items, '
|
|
||||||
'first extra item: %s' % py.io.saferepr(left[len(right)],)]
|
|
||||||
elif len(left) < len(right):
|
|
||||||
explanation += ['Right contains more items, '
|
|
||||||
'first extra item: %s' % py.io.saferepr(right[len(left)],)]
|
|
||||||
return explanation # + _diff_text(py.std.pprint.pformat(left),
|
|
||||||
# py.std.pprint.pformat(right))
|
|
||||||
|
|
||||||
|
|
||||||
def _compare_eq_set(left, right):
|
|
||||||
explanation = []
|
|
||||||
diff_left = left - right
|
|
||||||
diff_right = right - left
|
|
||||||
if diff_left:
|
|
||||||
explanation.append('Extra items in the left set:')
|
|
||||||
for item in diff_left:
|
|
||||||
explanation.append(py.io.saferepr(item))
|
|
||||||
if diff_right:
|
|
||||||
explanation.append('Extra items in the right set:')
|
|
||||||
for item in diff_right:
|
|
||||||
explanation.append(py.io.saferepr(item))
|
|
||||||
return explanation
|
|
||||||
|
|
||||||
|
|
||||||
def _notin_text(term, text):
|
|
||||||
index = text.find(term)
|
|
||||||
head = text[:index]
|
|
||||||
tail = text[index+len(term):]
|
|
||||||
correct_text = head + tail
|
|
||||||
diff = _diff_text(correct_text, text)
|
|
||||||
newdiff = ['%s is contained here:' % py.io.saferepr(term, maxsize=42)]
|
|
||||||
for line in diff:
|
|
||||||
if line.startswith('Skipping'):
|
|
||||||
continue
|
|
||||||
if line.startswith('- '):
|
|
||||||
continue
|
|
||||||
if line.startswith('+ '):
|
|
||||||
newdiff.append(' ' + line[2:])
|
|
||||||
else:
|
|
||||||
newdiff.append(line)
|
|
||||||
return newdiff
|
|
||||||
|
|
|
@ -7,8 +7,7 @@ import sys
|
||||||
import ast
|
import ast
|
||||||
|
|
||||||
import py
|
import py
|
||||||
from _pytest import assertion
|
from _pytest.assertion import util
|
||||||
from _pytest.assertion import _format_explanation
|
|
||||||
from _pytest.assertion.reinterpret import BuiltinAssertionError
|
from _pytest.assertion.reinterpret import BuiltinAssertionError
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,7 +61,7 @@ def run(offending_line, frame=None):
|
||||||
return interpret(offending_line, frame)
|
return interpret(offending_line, frame)
|
||||||
|
|
||||||
def getfailure(failure):
|
def getfailure(failure):
|
||||||
explanation = _format_explanation(failure.explanation)
|
explanation = util.format_explanation(failure.explanation)
|
||||||
value = failure.cause[1]
|
value = failure.cause[1]
|
||||||
if str(value):
|
if str(value):
|
||||||
lines = explanation.splitlines()
|
lines = explanation.splitlines()
|
||||||
|
@ -185,8 +184,8 @@ class DebugInterpreter(ast.NodeVisitor):
|
||||||
break
|
break
|
||||||
left_explanation, left_result = next_explanation, next_result
|
left_explanation, left_result = next_explanation, next_result
|
||||||
|
|
||||||
if assertion._reprcompare is not None:
|
if util._reprcompare is not None:
|
||||||
res = assertion._reprcompare(op_symbol, left_result, next_result)
|
res = util._reprcompare(op_symbol, left_result, next_result)
|
||||||
if res:
|
if res:
|
||||||
explanation = res
|
explanation = res
|
||||||
return explanation, result
|
return explanation, result
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import py
|
import py
|
||||||
import sys, inspect
|
import sys, inspect
|
||||||
from compiler import parse, ast, pycodegen
|
from compiler import parse, ast, pycodegen
|
||||||
from _pytest.assertion import _format_explanation
|
from _pytest.assertion.util import format_explanation
|
||||||
from _pytest.assertion.reinterpret import BuiltinAssertionError
|
from _pytest.assertion.reinterpret import BuiltinAssertionError
|
||||||
|
|
||||||
passthroughex = py.builtin._sysex
|
passthroughex = py.builtin._sysex
|
||||||
|
@ -132,7 +132,7 @@ class Interpretable(View):
|
||||||
raise Failure(self)
|
raise Failure(self)
|
||||||
|
|
||||||
def nice_explanation(self):
|
def nice_explanation(self):
|
||||||
return _format_explanation(self.explanation)
|
return format_explanation(self.explanation)
|
||||||
|
|
||||||
|
|
||||||
class Name(Interpretable):
|
class Name(Interpretable):
|
||||||
|
|
|
@ -5,6 +5,7 @@ import collections
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
import py
|
import py
|
||||||
|
from _pytest.assertion import util
|
||||||
|
|
||||||
|
|
||||||
def rewrite_asserts(mod):
|
def rewrite_asserts(mod):
|
||||||
|
@ -13,6 +14,7 @@ def rewrite_asserts(mod):
|
||||||
|
|
||||||
|
|
||||||
_saferepr = py.io.saferepr
|
_saferepr = py.io.saferepr
|
||||||
|
from _pytest.assertion.util import format_explanation as _format_explanation
|
||||||
|
|
||||||
def _format_boolop(operands, explanations, is_or):
|
def _format_boolop(operands, explanations, is_or):
|
||||||
show_explanations = []
|
show_explanations = []
|
||||||
|
@ -30,9 +32,8 @@ def _call_reprcompare(ops, results, expls, each_obj):
|
||||||
done = True
|
done = True
|
||||||
if done:
|
if done:
|
||||||
break
|
break
|
||||||
from _pytest.assertion import _reprcompare
|
if util._reprcompare is not None:
|
||||||
if _reprcompare is not None:
|
custom = util._reprcompare(ops[i], each_obj[i], each_obj[i + 1])
|
||||||
custom = _reprcompare(ops[i], each_obj[i], each_obj[i + 1])
|
|
||||||
if custom is not None:
|
if custom is not None:
|
||||||
return custom
|
return custom
|
||||||
return expl
|
return expl
|
||||||
|
@ -94,7 +95,6 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
# Insert some special imports at the top of the module but after any
|
# Insert some special imports at the top of the module but after any
|
||||||
# docstrings and __future__ imports.
|
# docstrings and __future__ imports.
|
||||||
aliases = [ast.alias(py.builtin.builtins.__name__, "@py_builtins"),
|
aliases = [ast.alias(py.builtin.builtins.__name__, "@py_builtins"),
|
||||||
ast.alias("_pytest.assertion", "@pytest_a"),
|
|
||||||
ast.alias("_pytest.assertion.rewrite", "@pytest_ar")]
|
ast.alias("_pytest.assertion.rewrite", "@pytest_ar")]
|
||||||
expect_docstring = True
|
expect_docstring = True
|
||||||
pos = 0
|
pos = 0
|
||||||
|
@ -153,11 +153,11 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
|
|
||||||
def display(self, expr):
|
def display(self, expr):
|
||||||
"""Call py.io.saferepr on the expression."""
|
"""Call py.io.saferepr on the expression."""
|
||||||
return self.helper("ar", "saferepr", expr)
|
return self.helper("saferepr", expr)
|
||||||
|
|
||||||
def helper(self, mod, name, *args):
|
def helper(self, name, *args):
|
||||||
"""Call a helper in this module."""
|
"""Call a helper in this module."""
|
||||||
py_name = ast.Name("@pytest_" + mod, ast.Load())
|
py_name = ast.Name("@pytest_ar", ast.Load())
|
||||||
attr = ast.Attribute(py_name, "_" + name, ast.Load())
|
attr = ast.Attribute(py_name, "_" + name, ast.Load())
|
||||||
return ast.Call(attr, list(args), [], None, None)
|
return ast.Call(attr, list(args), [], None, None)
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
explanation = "assert " + explanation
|
explanation = "assert " + explanation
|
||||||
template = ast.Str(explanation)
|
template = ast.Str(explanation)
|
||||||
msg = self.pop_format_context(template)
|
msg = self.pop_format_context(template)
|
||||||
fmt = self.helper("a", "format_explanation", msg)
|
fmt = self.helper("format_explanation", msg)
|
||||||
body.append(ast.Assert(top_condition, fmt))
|
body.append(ast.Assert(top_condition, fmt))
|
||||||
# Delete temporary variables.
|
# Delete temporary variables.
|
||||||
names = [ast.Name(name, ast.Del()) for name in self.variables]
|
names = [ast.Name(name, ast.Del()) for name in self.variables]
|
||||||
|
@ -242,7 +242,7 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
explanations.append(explanation)
|
explanations.append(explanation)
|
||||||
expls = ast.Tuple([ast.Str(expl) for expl in explanations], ast.Load())
|
expls = ast.Tuple([ast.Str(expl) for expl in explanations], ast.Load())
|
||||||
is_or = ast.Num(isinstance(boolop.op, ast.Or))
|
is_or = ast.Num(isinstance(boolop.op, ast.Or))
|
||||||
expl_template = self.helper("ar", "format_boolop",
|
expl_template = self.helper("format_boolop",
|
||||||
ast.Tuple(operands, ast.Load()), expls,
|
ast.Tuple(operands, ast.Load()), expls,
|
||||||
is_or)
|
is_or)
|
||||||
expl = self.pop_format_context(expl_template)
|
expl = self.pop_format_context(expl_template)
|
||||||
|
@ -321,7 +321,7 @@ class AssertionRewriter(ast.NodeVisitor):
|
||||||
self.statements.append(ast.Assign([store_names[i]], res_expr))
|
self.statements.append(ast.Assign([store_names[i]], res_expr))
|
||||||
left_res, left_expl = next_res, next_expl
|
left_res, left_expl = next_res, next_expl
|
||||||
# Use py.code._reprcompare if that's available.
|
# Use py.code._reprcompare if that's available.
|
||||||
expl_call = self.helper("ar", "call_reprcompare",
|
expl_call = self.helper("call_reprcompare",
|
||||||
ast.Tuple(syms, ast.Load()),
|
ast.Tuple(syms, ast.Load()),
|
||||||
ast.Tuple(load_names, ast.Load()),
|
ast.Tuple(load_names, ast.Load()),
|
||||||
ast.Tuple(expls, ast.Load()),
|
ast.Tuple(expls, ast.Load()),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"PYTEST_DONT_REWRITE"
|
"PYTEST_DONT_REWRITE"
|
||||||
import pytest, py
|
import pytest, py
|
||||||
|
|
||||||
from _pytest import assertion
|
from _pytest.assertion import util
|
||||||
|
|
||||||
def exvalue():
|
def exvalue():
|
||||||
return py.std.sys.exc_info()[1]
|
return py.std.sys.exc_info()[1]
|
||||||
|
@ -249,7 +249,7 @@ class TestView:
|
||||||
|
|
||||||
@py.test.mark.skipif("sys.version_info < (2,6)")
|
@py.test.mark.skipif("sys.version_info < (2,6)")
|
||||||
def test_assert_customizable_reprcompare(monkeypatch):
|
def test_assert_customizable_reprcompare(monkeypatch):
|
||||||
monkeypatch.setattr(assertion, '_reprcompare', lambda *args: 'hello')
|
monkeypatch.setattr(util, '_reprcompare', lambda *args: 'hello')
|
||||||
try:
|
try:
|
||||||
assert 3 == 4
|
assert 3 == 4
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
|
|
|
@ -2,7 +2,7 @@ import sys
|
||||||
|
|
||||||
import py, pytest
|
import py, pytest
|
||||||
import _pytest.assertion as plugin
|
import _pytest.assertion as plugin
|
||||||
from _pytest.assertion import reinterpret
|
from _pytest.assertion import reinterpret, util
|
||||||
|
|
||||||
needsnewassert = pytest.mark.skipif("sys.version_info < (2,6)")
|
needsnewassert = pytest.mark.skipif("sys.version_info < (2,6)")
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ class TestBinReprIntegration:
|
||||||
self.right = right
|
self.right = right
|
||||||
mockhook = MockHook()
|
mockhook = MockHook()
|
||||||
monkeypatch = request.getfuncargvalue("monkeypatch")
|
monkeypatch = request.getfuncargvalue("monkeypatch")
|
||||||
monkeypatch.setattr(plugin, '_reprcompare', mockhook)
|
monkeypatch.setattr(util, '_reprcompare', mockhook)
|
||||||
return mockhook
|
return mockhook
|
||||||
|
|
||||||
def test_pytest_assertrepr_compare_called(self, hook):
|
def test_pytest_assertrepr_compare_called(self, hook):
|
||||||
|
@ -41,13 +41,13 @@ class TestBinReprIntegration:
|
||||||
assert hook.right == [0, 2]
|
assert hook.right == [0, 2]
|
||||||
|
|
||||||
def test_configure_unconfigure(self, testdir, hook):
|
def test_configure_unconfigure(self, testdir, hook):
|
||||||
assert hook == plugin._reprcompare
|
assert hook == util._reprcompare
|
||||||
config = testdir.parseconfig()
|
config = testdir.parseconfig()
|
||||||
plugin.pytest_configure(config)
|
plugin.pytest_configure(config)
|
||||||
assert hook != plugin._reprcompare
|
assert hook != util._reprcompare
|
||||||
from _pytest.config import pytest_unconfigure
|
from _pytest.config import pytest_unconfigure
|
||||||
pytest_unconfigure(config)
|
pytest_unconfigure(config)
|
||||||
assert hook == plugin._reprcompare
|
assert hook == util._reprcompare
|
||||||
|
|
||||||
def callequal(left, right):
|
def callequal(left, right):
|
||||||
return plugin.pytest_assertrepr_compare('==', left, right)
|
return plugin.pytest_assertrepr_compare('==', left, right)
|
||||||
|
|
|
@ -4,16 +4,16 @@ import pytest
|
||||||
|
|
||||||
ast = pytest.importorskip("ast")
|
ast = pytest.importorskip("ast")
|
||||||
|
|
||||||
from _pytest import assertion
|
from _pytest.assertion import util
|
||||||
from _pytest.assertion.rewrite import rewrite_asserts
|
from _pytest.assertion.rewrite import rewrite_asserts
|
||||||
|
|
||||||
|
|
||||||
def setup_module(mod):
|
def setup_module(mod):
|
||||||
mod._old_reprcompare = assertion._reprcompare
|
mod._old_reprcompare = util._reprcompare
|
||||||
py.code._reprcompare = None
|
py.code._reprcompare = None
|
||||||
|
|
||||||
def teardown_module(mod):
|
def teardown_module(mod):
|
||||||
assertion._reprcompare = mod._old_reprcompare
|
util._reprcompare = mod._old_reprcompare
|
||||||
del mod._old_reprcompare
|
del mod._old_reprcompare
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,29 +53,29 @@ class TestAssertionRewrite:
|
||||||
m = rewrite(s)
|
m = rewrite(s)
|
||||||
assert isinstance(m.body[0], ast.Expr)
|
assert isinstance(m.body[0], ast.Expr)
|
||||||
assert isinstance(m.body[0].value, ast.Str)
|
assert isinstance(m.body[0].value, ast.Str)
|
||||||
for imp in m.body[1:4]:
|
for imp in m.body[1:3]:
|
||||||
assert isinstance(imp, ast.Import)
|
assert isinstance(imp, ast.Import)
|
||||||
assert imp.lineno == 2
|
assert imp.lineno == 2
|
||||||
assert imp.col_offset == 0
|
assert imp.col_offset == 0
|
||||||
assert isinstance(m.body[4], ast.Assign)
|
assert isinstance(m.body[3], ast.Assign)
|
||||||
s = """from __future__ import with_statement\nother_stuff"""
|
s = """from __future__ import with_statement\nother_stuff"""
|
||||||
m = rewrite(s)
|
m = rewrite(s)
|
||||||
assert isinstance(m.body[0], ast.ImportFrom)
|
assert isinstance(m.body[0], ast.ImportFrom)
|
||||||
for imp in m.body[1:4]:
|
for imp in m.body[1:3]:
|
||||||
assert isinstance(imp, ast.Import)
|
assert isinstance(imp, ast.Import)
|
||||||
assert imp.lineno == 2
|
assert imp.lineno == 2
|
||||||
assert imp.col_offset == 0
|
assert imp.col_offset == 0
|
||||||
assert isinstance(m.body[4], ast.Expr)
|
assert isinstance(m.body[3], ast.Expr)
|
||||||
s = """'doc string'\nfrom __future__ import with_statement\nother"""
|
s = """'doc string'\nfrom __future__ import with_statement\nother"""
|
||||||
m = rewrite(s)
|
m = rewrite(s)
|
||||||
assert isinstance(m.body[0], ast.Expr)
|
assert isinstance(m.body[0], ast.Expr)
|
||||||
assert isinstance(m.body[0].value, ast.Str)
|
assert isinstance(m.body[0].value, ast.Str)
|
||||||
assert isinstance(m.body[1], ast.ImportFrom)
|
assert isinstance(m.body[1], ast.ImportFrom)
|
||||||
for imp in m.body[2:5]:
|
for imp in m.body[2:4]:
|
||||||
assert isinstance(imp, ast.Import)
|
assert isinstance(imp, ast.Import)
|
||||||
assert imp.lineno == 3
|
assert imp.lineno == 3
|
||||||
assert imp.col_offset == 0
|
assert imp.col_offset == 0
|
||||||
assert isinstance(m.body[5], ast.Expr)
|
assert isinstance(m.body[4], ast.Expr)
|
||||||
|
|
||||||
def test_dont_rewrite(self):
|
def test_dont_rewrite(self):
|
||||||
s = """'PYTEST_DONT_REWRITE'\nassert 14"""
|
s = """'PYTEST_DONT_REWRITE'\nassert 14"""
|
||||||
|
@ -230,13 +230,13 @@ class TestAssertionRewrite:
|
||||||
def test_custom_reprcompare(self, monkeypatch):
|
def test_custom_reprcompare(self, monkeypatch):
|
||||||
def my_reprcompare(op, left, right):
|
def my_reprcompare(op, left, right):
|
||||||
return "42"
|
return "42"
|
||||||
monkeypatch.setattr(assertion, "_reprcompare", my_reprcompare)
|
monkeypatch.setattr(util, "_reprcompare", my_reprcompare)
|
||||||
def f():
|
def f():
|
||||||
assert 42 < 3
|
assert 42 < 3
|
||||||
assert getmsg(f) == "assert 42"
|
assert getmsg(f) == "assert 42"
|
||||||
def my_reprcompare(op, left, right):
|
def my_reprcompare(op, left, right):
|
||||||
return "%s %s %s" % (left, op, right)
|
return "%s %s %s" % (left, op, right)
|
||||||
monkeypatch.setattr(assertion, "_reprcompare", my_reprcompare)
|
monkeypatch.setattr(util, "_reprcompare", my_reprcompare)
|
||||||
def f():
|
def f():
|
||||||
assert 1 < 3 < 5 <= 4 < 7
|
assert 1 < 3 < 5 <= 4 < 7
|
||||||
assert getmsg(f) == "assert 5 <= 4"
|
assert getmsg(f) == "assert 5 <= 4"
|
||||||
|
|
Loading…
Reference in New Issue