* deprecate py.magic.invoke/revoke in favour of

the new py.code.patch_builtins, py.code.unpatch_builtins

* deprecate py.magic.patch/revert

* deprecate py.magic.AssertionError in favour of py.code._AssertionError

* introduced pytest_assertion plugin.

--HG--
branch : trunk
This commit is contained in:
holger krekel
2009-08-27 17:26:02 +02:00
parent e391662cff
commit 13932b7f4b
26 changed files with 564 additions and 696 deletions

View File

@@ -0,0 +1,173 @@
import py
from py.__.code.assertion import View
def setup_module(mod):
py.code.patch_builtins(assertion=True, compile=False)
def teardown_module(mod):
py.code.unpatch_builtins(assertion=True, compile=False)
def f():
return 2
def test_assert():
try:
assert f() == 3
except AssertionError, e:
s = str(e)
assert s.startswith('assert 2 == 3\n')
def test_assert_with_explicit_message():
try:
assert f() == 3, "hello"
except AssertionError, e:
assert e.msg == 'hello'
def test_assert_within_finally():
class A:
def f():
pass
excinfo = py.test.raises(TypeError, """
try:
A().f()
finally:
i = 42
""")
s = excinfo.exconly()
assert s.find("takes no argument") != -1
#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:
s = str(e)
assert s.startswith('assert 2 == 3\n')
def test_assert_multiline_2():
try:
assert (f() == (4,
3)[-1])
except AssertionError, e:
s = str(e)
assert s.startswith('assert 2 ==')
def test_assert_non_string_message():
class A:
def __str__(self):
return "hello"
try:
assert 0 == 1, A()
except AssertionError, e:
assert e.msg == "hello"
# 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:
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:
assert e.msg.find("list") != -1
def test_assert_implicit_multiline():
try:
x = [1,2,3]
assert x != [1,
2, 3]
except AssertionError, e:
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:
py.test.fail("broken __repr__ not handle correctly")
class TestView:
def test_class_dispatch(self):
### Use a custom class hierarchy with existing instances
class Picklable(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(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_AssertionError(testdir):
testdir.makepyfile("""
import py
def test_hello(recwarn):
err = py.magic.AssertionError
recwarn.pop(DeprecationWarning)
assert err is py.code._AssertionError
""")
result = testdir.runpytest()
assert "1 passed" in result.stdout.str()

View File

@@ -164,5 +164,18 @@ class TestSafeRepr:
s = safe_repr(Function())
except Exception, e:
py.test.fail("saferepr failed for newstyle class")
def test_builtin_patch_unpatch(monkeypatch):
import __builtin__ as cpy_builtin
comp = cpy_builtin.compile
def mycompile(*args, **kwargs):
return comp(*args, **kwargs)
monkeypatch.setattr(cpy_builtin, 'AssertionError', None)
monkeypatch.setattr(cpy_builtin, 'compile', mycompile)
py.code.patch_builtins()
assert cpy_builtin.AssertionError
assert cpy_builtin.compile != mycompile
py.code.unpatch_builtins()
assert cpy_builtin.AssertionError is None
assert cpy_builtin.compile == mycompile

View File

@@ -577,11 +577,11 @@ raise ValueError()
x = 1
assert x == 2
""")
py.magic.invoke(assertion=True)
py.code.patch_builtins(assertion=True)
try:
excinfo = py.test.raises(AssertionError, mod.somefunc)
finally:
py.magic.revoke(assertion=True)
py.code.unpatch_builtins(assertion=True)
p = FormattedExcinfo()
reprentry = p.repr_traceback_entry(excinfo.traceback[-1], excinfo)

View File

@@ -0,0 +1,64 @@
import py
def check_assertion():
excinfo = py.test.raises(AssertionError, "assert 1 == 2")
s = excinfo.exconly(tryshort=True)
if not s == "assert 1 == 2":
raise ValueError("assertion not enabled: got %s" % s)
def test_invoke_assertion(recwarn, monkeypatch):
monkeypatch.setattr(py.std.__builtin__, 'AssertionError', None)
py.magic.invoke(assertion=True)
try:
check_assertion()
finally:
py.magic.revoke(assertion=True)
recwarn.pop(DeprecationWarning)
def test_invoke_compile(recwarn, monkeypatch):
monkeypatch.setattr(py.std.__builtin__, 'compile', None)
py.magic.invoke(compile=True)
try:
co = compile("""if 1:
def f():
return 1
\n""", '', 'exec')
d = {}
exec co in d
assert py.code.Source(d['f'])
finally:
py.magic.revoke(compile=True)
recwarn.pop(DeprecationWarning)
def test_patch_revert(recwarn):
class a:
pass
py.test.raises(AttributeError, "py.magic.patch(a, 'i', 42)")
a.i = 42
py.magic.patch(a, 'i', 23)
assert a.i == 23
recwarn.pop(DeprecationWarning)
py.magic.revert(a, 'i')
assert a.i == 42
recwarn.pop(DeprecationWarning)
def test_double_patch(recwarn):
class a:
i = 42
assert py.magic.patch(a, 'i', 2) == 42
recwarn.pop(DeprecationWarning)
assert py.magic.patch(a, 'i', 3) == 2
assert a.i == 3
assert py.magic.revert(a, 'i') == 3
recwarn.pop(DeprecationWarning)
assert a.i == 2
assert py.magic.revert(a, 'i') == 2
assert a.i == 42
def test_valueerror(recwarn):
class a:
i = 2
pass
py.test.raises(ValueError, "py.magic.revert(a, 'i')")
recwarn.pop(DeprecationWarning)