merge Ronny's changes, add some documentation and changelog entries
--HG-- branch : trunk
This commit is contained in:
commit
6951da7da0
|
@ -4,6 +4,14 @@ Changes between 1.3.1 and 1.3.x
|
||||||
New features
|
New features
|
||||||
++++++++++++++++++
|
++++++++++++++++++
|
||||||
|
|
||||||
|
- fix issue103: introduce additional "with py.test.raises(exc):" form, example::
|
||||||
|
|
||||||
|
with py.test.raises(ZeroDivisionError):
|
||||||
|
x = 0
|
||||||
|
1 / x
|
||||||
|
|
||||||
|
(thanks Ronny Pfannschmidt)
|
||||||
|
|
||||||
- Funcarg factories can now dynamically apply a marker to a
|
- Funcarg factories can now dynamically apply a marker to a
|
||||||
test invocation. This is particularly useful if a factory
|
test invocation. This is particularly useful if a factory
|
||||||
provides parameters to a test which you expect-to-fail:
|
provides parameters to a test which you expect-to-fail:
|
||||||
|
|
|
@ -130,14 +130,20 @@ first failed and then succeeded.
|
||||||
asserting expected exceptions
|
asserting expected exceptions
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
In order to write assertions about exceptions, you use
|
In order to write assertions about exceptions, you can use
|
||||||
one of two forms::
|
``py.test.raises`` as a context manager like this::
|
||||||
|
|
||||||
py.test.raises(Exception, func, *args, **kwargs)
|
with py.test.raises(ZeroDivisionError):
|
||||||
py.test.raises(Exception, "func(*args, **kwargs)")
|
1 / 0
|
||||||
|
|
||||||
|
If you want to write test code that works on Python2.4 as well,
|
||||||
|
you may also use two other ways to test for an expected exception::
|
||||||
|
|
||||||
|
py.test.raises(ExpectedException, func, *args, **kwargs)
|
||||||
|
py.test.raises(ExpectedException, "func(*args, **kwargs)")
|
||||||
|
|
||||||
both of which execute the specified function with args and kwargs and
|
both of which execute the specified function with args and kwargs and
|
||||||
asserts that the given ``Exception`` is raised. The reporter will
|
asserts that the given ``ExpectedException`` is raised. The reporter will
|
||||||
provide you with helpful output in case of failures such as *no
|
provide you with helpful output in case of failures such as *no
|
||||||
exception* or *wrong exception*.
|
exception* or *wrong exception*.
|
||||||
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
#
|
|
|
@ -1,65 +0,0 @@
|
||||||
import threading
|
|
||||||
|
|
||||||
|
|
||||||
class PathServer:
|
|
||||||
|
|
||||||
def __init__(self, channel):
|
|
||||||
self.channel = channel
|
|
||||||
self.C2P = {}
|
|
||||||
self.next_id = 0
|
|
||||||
threading.Thread(target=self.serve).start()
|
|
||||||
|
|
||||||
def p2c(self, path):
|
|
||||||
id = self.next_id
|
|
||||||
self.next_id += 1
|
|
||||||
self.C2P[id] = path
|
|
||||||
return id
|
|
||||||
|
|
||||||
def command_LIST(self, id, *args):
|
|
||||||
path = self.C2P[id]
|
|
||||||
answer = [(self.p2c(p), p.basename) for p in path.listdir(*args)]
|
|
||||||
self.channel.send(answer)
|
|
||||||
|
|
||||||
def command_DEL(self, id):
|
|
||||||
del self.C2P[id]
|
|
||||||
|
|
||||||
def command_GET(self, id, spec):
|
|
||||||
path = self.C2P[id]
|
|
||||||
self.channel.send(path._getbyspec(spec))
|
|
||||||
|
|
||||||
def command_READ(self, id):
|
|
||||||
path = self.C2P[id]
|
|
||||||
self.channel.send(path.read())
|
|
||||||
|
|
||||||
def command_JOIN(self, id, resultid, *args):
|
|
||||||
path = self.C2P[id]
|
|
||||||
assert resultid not in self.C2P
|
|
||||||
self.C2P[resultid] = path.join(*args)
|
|
||||||
|
|
||||||
def command_DIRPATH(self, id, resultid):
|
|
||||||
path = self.C2P[id]
|
|
||||||
assert resultid not in self.C2P
|
|
||||||
self.C2P[resultid] = path.dirpath()
|
|
||||||
|
|
||||||
def serve(self):
|
|
||||||
try:
|
|
||||||
while 1:
|
|
||||||
msg = self.channel.receive()
|
|
||||||
meth = getattr(self, 'command_' + msg[0])
|
|
||||||
meth(*msg[1:])
|
|
||||||
except EOFError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import py
|
|
||||||
gw = execnet.PopenGateway()
|
|
||||||
channel = gw._channelfactory.new()
|
|
||||||
srv = PathServer(channel)
|
|
||||||
c = gw.remote_exec("""
|
|
||||||
import remotepath
|
|
||||||
p = remotepath.RemotePath(channel.receive(), channel.receive())
|
|
||||||
channel.send(len(p.listdir()))
|
|
||||||
""")
|
|
||||||
c.send(channel)
|
|
||||||
c.send(srv.p2c(py.path.local('/tmp')))
|
|
||||||
print(c.receive())
|
|
|
@ -1,21 +0,0 @@
|
||||||
import py
|
|
||||||
from remotepath import RemotePath
|
|
||||||
|
|
||||||
|
|
||||||
SRC = open('channeltest.py', 'r').read()
|
|
||||||
|
|
||||||
SRC += '''
|
|
||||||
import py
|
|
||||||
srv = PathServer(channel.receive())
|
|
||||||
channel.send(srv.p2c(py.path.local("/tmp")))
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
#gw = execnet.SshGateway('codespeak.net')
|
|
||||||
gw = execnet.PopenGateway()
|
|
||||||
gw.remote_init_threads(5)
|
|
||||||
c = gw.remote_exec(SRC, stdout=py.std.sys.stdout, stderr=py.std.sys.stderr)
|
|
||||||
subchannel = gw._channelfactory.new()
|
|
||||||
c.send(subchannel)
|
|
||||||
|
|
||||||
p = RemotePath(subchannel, c.receive())
|
|
|
@ -1,47 +0,0 @@
|
||||||
import py, itertools
|
|
||||||
from py._path import common
|
|
||||||
|
|
||||||
COUNTER = itertools.count()
|
|
||||||
|
|
||||||
class RemotePath(common.PathBase):
|
|
||||||
sep = '/'
|
|
||||||
|
|
||||||
def __init__(self, channel, id, basename=None):
|
|
||||||
self._channel = channel
|
|
||||||
self._id = id
|
|
||||||
self._basename = basename
|
|
||||||
self._specs = {}
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
self._channel.send(('DEL', self._id))
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return 'RemotePath(%s)' % self.basename
|
|
||||||
|
|
||||||
def listdir(self, *args):
|
|
||||||
self._channel.send(('LIST', self._id) + args)
|
|
||||||
return [RemotePath(self._channel, id, basename)
|
|
||||||
for (id, basename) in self._channel.receive()]
|
|
||||||
|
|
||||||
def dirpath(self):
|
|
||||||
id = ~COUNTER.next()
|
|
||||||
self._channel.send(('DIRPATH', self._id, id))
|
|
||||||
return RemotePath(self._channel, id)
|
|
||||||
|
|
||||||
def join(self, *args):
|
|
||||||
id = ~COUNTER.next()
|
|
||||||
self._channel.send(('JOIN', self._id, id) + args)
|
|
||||||
return RemotePath(self._channel, id)
|
|
||||||
|
|
||||||
def _getbyspec(self, spec):
|
|
||||||
parts = spec.split(',')
|
|
||||||
ask = [x for x in parts if x not in self._specs]
|
|
||||||
if ask:
|
|
||||||
self._channel.send(('GET', self._id, ",".join(ask)))
|
|
||||||
for part, value in zip(ask, self._channel.receive()):
|
|
||||||
self._specs[part] = value
|
|
||||||
return [self._specs[x] for x in parts]
|
|
||||||
|
|
||||||
def read(self):
|
|
||||||
self._channel.send(('READ', self._id))
|
|
||||||
return self._channel.receive()
|
|
|
@ -353,18 +353,30 @@ def xfail(reason=""):
|
||||||
xfail.Exception = XFailed
|
xfail.Exception = XFailed
|
||||||
|
|
||||||
def raises(ExpectedException, *args, **kwargs):
|
def raises(ExpectedException, *args, **kwargs):
|
||||||
""" if args[0] is callable: raise AssertionError if calling it with
|
""" assert that a code block/function call raises an exception.
|
||||||
|
|
||||||
|
If using Python 2.5 or above, you may use this function as a
|
||||||
|
context manager::
|
||||||
|
|
||||||
|
>>> with raises(ZeroDivisionError):
|
||||||
|
... 1/0
|
||||||
|
|
||||||
|
Or you can one of two forms:
|
||||||
|
|
||||||
|
if args[0] is callable: raise AssertionError if calling it with
|
||||||
the remaining arguments does not raise the expected exception.
|
the remaining arguments does not raise the expected exception.
|
||||||
if args[0] is a string: raise AssertionError if executing the
|
if args[0] is a string: raise AssertionError if executing the
|
||||||
the string in the calling scope does not raise expected exception.
|
the string in the calling scope does not raise expected exception.
|
||||||
for examples:
|
examples:
|
||||||
x = 5
|
>>> x = 5
|
||||||
raises(TypeError, lambda x: x + 'hello', x=x)
|
>>> raises(TypeError, lambda x: x + 'hello', x=x)
|
||||||
raises(TypeError, "x + 'hello'")
|
>>> raises(TypeError, "x + 'hello'")
|
||||||
"""
|
"""
|
||||||
__tracebackhide__ = True
|
__tracebackhide__ = True
|
||||||
assert args
|
|
||||||
if isinstance(args[0], str):
|
if not args:
|
||||||
|
return RaisesContext(ExpectedException)
|
||||||
|
elif isinstance(args[0], str):
|
||||||
code, = args
|
code, = args
|
||||||
assert isinstance(code, str)
|
assert isinstance(code, str)
|
||||||
frame = sys._getframe(1)
|
frame = sys._getframe(1)
|
||||||
|
@ -391,6 +403,26 @@ def raises(ExpectedException, *args, **kwargs):
|
||||||
raise ExceptionFailure(msg="DID NOT RAISE",
|
raise ExceptionFailure(msg="DID NOT RAISE",
|
||||||
expr=args, expected=ExpectedException)
|
expr=args, expected=ExpectedException)
|
||||||
|
|
||||||
|
|
||||||
|
class RaisesContext(object):
|
||||||
|
|
||||||
|
def __init__(self, ExpectedException):
|
||||||
|
self.ExpectedException = ExpectedException
|
||||||
|
self.excinfo = None
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *tp):
|
||||||
|
__tracebackhide__ = True
|
||||||
|
if tp[0] is None:
|
||||||
|
raise ExceptionFailure(msg="DID NOT RAISE",
|
||||||
|
expr=(),
|
||||||
|
expected=self.ExpectedException)
|
||||||
|
self.excinfo = py.code.ExceptionInfo(tp)
|
||||||
|
return issubclass(self.excinfo.type, self.ExpectedException)
|
||||||
|
|
||||||
|
|
||||||
raises.Exception = ExceptionFailure
|
raises.Exception = ExceptionFailure
|
||||||
|
|
||||||
def importorskip(modname, minversion=None):
|
def importorskip(modname, minversion=None):
|
||||||
|
|
|
@ -340,6 +340,37 @@ class TestRaises:
|
||||||
except py.test.raises.Exception:
|
except py.test.raises.Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@py.test.mark.skipif('sys.version < "2.5"')
|
||||||
|
def test_raises_as_contextmanager(self, testdir):
|
||||||
|
testdir.makepyfile("""
|
||||||
|
from __future__ import with_statement
|
||||||
|
import py
|
||||||
|
|
||||||
|
def test_simple():
|
||||||
|
with py.test.raises(ZeroDivisionError) as ctx:
|
||||||
|
1/0
|
||||||
|
|
||||||
|
print ctx.excinfo
|
||||||
|
assert ctx.excinfo.type is ZeroDivisionError
|
||||||
|
|
||||||
|
|
||||||
|
def test_noraise():
|
||||||
|
with py.test.raises(py.test.raises.Exception):
|
||||||
|
with py.test.raises(ValueError):
|
||||||
|
int()
|
||||||
|
|
||||||
|
def test_raise_wrong_exception_passes_by():
|
||||||
|
with py.test.raises(ZeroDivisionError):
|
||||||
|
with py.test.raises(ValueError):
|
||||||
|
1/0
|
||||||
|
""")
|
||||||
|
result = testdir.runpytest()
|
||||||
|
result.stdout.fnmatch_lines([
|
||||||
|
'*3 passed*',
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_pytest_exit():
|
def test_pytest_exit():
|
||||||
try:
|
try:
|
||||||
py.test.exit("hello")
|
py.test.exit("hello")
|
||||||
|
|
Loading…
Reference in New Issue