From commits-noreply at bitbucket.org Wed Mar 2 18:04:39 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Wed, 02 Mar 2011 17:04:39 -0000 Subject: [py-svn] commit/pytest: 2 new changesets Message-ID: <20110302170439.18129.15069@bitbucket01.managed.contegix.com> 2 new changesets in pytest: http://bitbucket.org/hpk42/pytest/changeset/12f5391260d3/ changeset: r2162:12f5391260d3 user: hpk42 date: 2011-02-27 12:52:27 summary: fix help string affected #: 1 file (7 bytes) --- a/_pytest/terminal.py Wed Feb 16 00:32:57 2011 +0100 +++ b/_pytest/terminal.py Sun Feb 27 12:52:27 2011 +0100 @@ -25,7 +25,7 @@ group._addoption('--tb', metavar="style", action="store", dest="tbstyle", default='long', type="choice", choices=['long', 'short', 'no', 'line', 'native'], - help="traceback print mode (long/short/line/no).") + help="traceback print mode (long/short/line/native/no).") group._addoption('--fulltrace', action="store_true", dest="fulltrace", default=False, help="don't cut any tracebacks (default is to cut).") http://bitbucket.org/hpk42/pytest/changeset/4d4d9fa7529d/ changeset: r2163:4d4d9fa7529d user: hpk42 date: 2011-03-02 18:03:43 summary: fix issue 28 - setup_method now works with pytest_generate_tests affected #: 5 files (595 bytes) --- a/CHANGELOG Sun Feb 27 12:52:27 2011 +0100 +++ b/CHANGELOG Wed Mar 02 18:03:43 2011 +0100 @@ -1,6 +1,8 @@ Changes between 2.0.1 and 2.0.2 ---------------------------------------------- +- fix issue28 - setup_method and pytest_generate_tests work together + - fix issue24 - pytest_assertrepr_compare produces an in-line exception on python3 --- a/_pytest/python.py Sun Feb 27 12:52:27 2011 +0100 +++ b/_pytest/python.py Wed Mar 02 18:03:43 2011 +0100 @@ -297,13 +297,8 @@ class FunctionMixin(PyobjMixin): """ mixin for the code common to Function and Generator. """ - def setup(self): """ perform setup for this test function. """ - if inspect.ismethod(self.obj): - name = 'setup_method' - else: - name = 'setup_function' if hasattr(self, '_preservedparent'): obj = self._preservedparent elif isinstance(self.parent, Instance): @@ -311,6 +306,10 @@ self.obj = self._getobj() else: obj = self.parent.obj + if inspect.ismethod(self.obj): + name = 'setup_method' + else: + name = 'setup_function' setup_func_or_method = getattr(obj, name, None) if setup_func_or_method is not None: setup_func_or_method(self.obj) --- a/pytest.py Sun Feb 27 12:52:27 2011 +0100 +++ b/pytest.py Wed Mar 02 18:03:43 2011 +0100 @@ -1,7 +1,7 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.2.dev0' +__version__ = '2.0.2.dev1' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins --- a/setup.py Sun Feb 27 12:52:27 2011 +0100 +++ b/setup.py Wed Mar 02 18:03:43 2011 +0100 @@ -22,7 +22,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.2.dev0', + version='2.0.2.dev1', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], --- a/testing/test_python.py Sun Feb 27 12:52:27 2011 +0100 +++ b/testing/test_python.py Wed Mar 02 18:03:43 2011 +0100 @@ -1062,6 +1062,21 @@ "*2 pass*", ]) + def test_issue28_setup_method_in_generate_tests(self, testdir): + p = testdir.makepyfile(""" + def pytest_generate_tests(metafunc): + metafunc.addcall({'arg1': 1}) + + class TestClass: + def test_method(self, arg1): + assert arg1 == self.val + def setup_method(self, func): + self.val = 1 + """) + result = testdir.runpytest(p) + result.stdout.fnmatch_lines([ + "*1 pass*", + ]) def test_conftest_funcargs_only_available_in_subdir(testdir): sub1 = testdir.mkpydir("sub1") Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Mar 3 12:11:33 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Thu, 03 Mar 2011 11:11:33 -0000 Subject: [py-svn] commit/py: hpk42: improve error message, fix changelog Message-ID: <20110303111133.10793.18291@bitbucket03.managed.contegix.com> 1 new changeset in py: http://bitbucket.org/hpk42/py/changeset/02d1c65a6a46/ changeset: r2008:02d1c65a6a46 user: hpk42 date: 2011-03-03 12:11:24 summary: improve error message, fix changelog affected #: 2 files (278 bytes) --- a/CHANGELOG Tue Feb 15 13:50:54 2011 +0100 +++ b/CHANGELOG Thu Mar 03 12:11:24 2011 +0100 @@ -1,3 +1,11 @@ +Changes between 1.4.1 and 1.4.2 +================================================== + +- fix (pytest) issue23 - tmpdir argument now works on Python3.2 and WindowsXP + (which apparently starts to offer os.symlink now) + +- better error message for syntax errors from compiled code + Changes between 1.4.0 and 1.4.1 ================================================== --- a/py/_code/source.py Tue Feb 15 13:50:54 2011 +0100 +++ b/py/_code/source.py Thu Mar 03 12:11:24 2011 +0100 @@ -215,7 +215,7 @@ msglines = self.lines[:ex.lineno] if ex.offset: msglines.append(" "*ex.offset + '^') - msglines.append("syntax error probably generated here: %s" % filename) + msglines.append("(code was compiled probably from here: %s)" % filename) newex = SyntaxError('\n'.join(msglines)) newex.offset = ex.offset newex.lineno = ex.lineno Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Mar 3 12:19:30 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Thu, 03 Mar 2011 11:19:30 -0000 Subject: [py-svn] commit/pytest: hpk42: fix issue30 - better handling and reporting of errors in xfail expressions Message-ID: <20110303111930.27914.88708@bitbucket01.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/dedf96819b5c/ changeset: r2164:dedf96819b5c user: hpk42 date: 2011-03-03 12:19:17 summary: fix issue30 - better handling and reporting of errors in xfail expressions affected #: 4 files (1.6 KB) --- a/CHANGELOG Wed Mar 02 18:03:43 2011 +0100 +++ b/CHANGELOG Thu Mar 03 12:19:17 2011 +0100 @@ -1,10 +1,13 @@ Changes between 2.0.1 and 2.0.2 ---------------------------------------------- +- fix issue30 - better handling and error reporting for errors in xfail + expressions + - fix issue28 - setup_method and pytest_generate_tests work together -- fix issue24 - pytest_assertrepr_compare produces an in-line - exception on python3 +- fix issue23 - tmpdir argument now works on Python3.2 and WindowsXP + (which apparently starts to offer os.symlink now) - fixed some typos in the docs (thanks Victor) --- a/_pytest/skipping.py Wed Mar 02 18:03:43 2011 +0100 +++ b/_pytest/skipping.py Thu Mar 03 12:19:17 2011 +0100 @@ -1,6 +1,7 @@ """ support for skip/xfail functions and markers. """ import py, pytest +import sys def pytest_addoption(parser): group = parser.getgroup("general") @@ -32,7 +33,28 @@ return bool(self.holder) __nonzero__ = __bool__ + def wasvalid(self): + return not hasattr(self, 'exc') + def istrue(self): + try: + return self._istrue() + except KeyboardInterrupt: + raise + except: + self.exc = sys.exc_info() + if isinstance(self.exc[1], SyntaxError): + msg = [" " * (self.exc[1].offset + 4) + "^",] + msg.append("SyntaxError: invalid syntax") + else: + msg = py.std.traceback.format_exception_only(*self.exc[:2]) + pytest.fail("Error evaluating %r expression\n" + " %s\n" + "%s" + %(self.name, self.expr, "\n".join(msg)), + pytrace=False) + + def _istrue(self): if self.holder: d = {'os': py.std.os, 'sys': py.std.sys, 'config': self.item.config} if self.holder.args: @@ -99,16 +121,17 @@ return rep rep = __multicall__.execute() evalxfail = item._evalxfail - if not item.config.option.runxfail and evalxfail.istrue(): - if call.excinfo: - rep.outcome = "skipped" - rep.keywords['xfail'] = evalxfail.getexplanation() - elif call.when == "call": - rep.outcome = "failed" - rep.keywords['xfail'] = evalxfail.getexplanation() - else: - if 'xfail' in rep.keywords: - del rep.keywords['xfail'] + if not item.config.option.runxfail: + if evalxfail.wasvalid() and evalxfail.istrue(): + if call.excinfo: + rep.outcome = "skipped" + rep.keywords['xfail'] = evalxfail.getexplanation() + elif call.when == "call": + rep.outcome = "failed" + rep.keywords['xfail'] = evalxfail.getexplanation() + return rep + if 'xfail' in rep.keywords: + del rep.keywords['xfail'] return rep # called by terminalreporter progress reporting @@ -179,7 +202,8 @@ except KeyError: #import sys #print >>sys.stderr, ("cache-miss: %r" % expr) - config._evalcache[expr] = x = eval(expr, d) + exprcode = py.code.compile(expr, mode="eval") + config._evalcache[expr] = x = eval(exprcode, d) return x --- a/setup.py Wed Mar 02 18:03:43 2011 +0100 +++ b/setup.py Thu Mar 03 12:19:17 2011 +0100 @@ -29,7 +29,7 @@ author='holger krekel, Guido Wesdorp, Carl Friedrich Bolz, Armin Rigo, Maciej Fijalkowski & others', author_email='holger at merlinux.eu', entry_points= make_entry_points(), - install_requires=['py>1.4.0'], + install_requires=['py>1.4.1'], classifiers=['Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', @@ -67,4 +67,4 @@ return {'console_scripts': l} if __name__ == '__main__': - main() \ No newline at end of file + main() --- a/testing/test_skipping.py Wed Mar 02 18:03:43 2011 +0100 +++ b/testing/test_skipping.py Thu Mar 03 12:19:17 2011 +0100 @@ -470,3 +470,31 @@ "XPASS*test_3*", "SKIP*four*", ]) + +def test_errors_in_xfail_skip_expressions(testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.skipif("asd") + def test_nameerror(): + pass + @pytest.mark.xfail("syntax error") + def test_syntax(): + pass + + def test_func(): + pass + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "*ERROR*test_nameerror*", + "*evaluating*skipif*expression*", + "*asd*", + "*ERROR*test_syntax*", + "*evaluating*xfail*expression*", + " syntax error", + " ^", + "SyntaxError: invalid syntax", + "*1 pass*2 error*", + ]) + + Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Mar 3 23:23:10 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Thu, 03 Mar 2011 22:23:10 -0000 Subject: [py-svn] commit/pytest: hpk42: fix issue30 (the second time) Message-ID: <20110303222310.3603.9902@bitbucket03.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/f71ec78f9a13/ changeset: r2165:f71ec78f9a13 user: hpk42 date: 2011-03-03 23:22:55 summary: fix issue30 (the second time) put module globals into namespace for xfail and skipif expressions affected #: 7 files (2.5 KB) --- a/CHANGELOG Thu Mar 03 12:19:17 2011 +0100 +++ b/CHANGELOG Thu Mar 03 23:22:55 2011 +0100 @@ -1,15 +1,37 @@ Changes between 2.0.1 and 2.0.2 ---------------------------------------------- -- fix issue30 - better handling and error reporting for errors in xfail - expressions +- fix issue30 - extended xfail/skipif handling and better reporting. + If you have a syntax error in your skip/xfail + expressions you now get nice error reports. + + Also you can now access module globals from xfail/skipif + expressions so that this works now:: + + import mymodule + @pytest.mark.skipif("mymodule.__version__[0] == "1") + def test_function(): + pass + + This will not run the test function if the module's version string + does not start with a "1". Note that specifying a string instead + of a boolean expressions allows py.test to report meaningful information + when summarizing a test run as to what conditions lead to skipping + (or xfail-ing) tests. - fix issue28 - setup_method and pytest_generate_tests work together + The setup_method fixture method now gets called also for + test function invocations generated from the pytest_generate_tests + hook. - fix issue23 - tmpdir argument now works on Python3.2 and WindowsXP - (which apparently starts to offer os.symlink now) + Starting with Python3.2 os.symlink may be supported. By requiring + a newer py lib version the py.path.local() implementation acknowledges + this. -- fixed some typos in the docs (thanks Victor) +- fixed typos in the docs (thanks Victor, Brianna) and particular + thanks to Laura who also revieved the documentation which + lead to some improvements. Changes between 2.0.0 and 2.0.1 ---------------------------------------------- --- a/_pytest/skipping.py Thu Mar 03 12:19:17 2011 +0100 +++ b/_pytest/skipping.py Thu Mar 03 23:22:55 2011 +0100 @@ -54,9 +54,18 @@ %(self.name, self.expr, "\n".join(msg)), pytrace=False) + def _getglobals(self): + d = {'os': py.std.os, 'sys': py.std.sys, 'config': self.item.config} + func = self.item.obj + try: + d.update(func.__globals__) + except AttributeError: + d.update(func.func_globals) + return d + def _istrue(self): if self.holder: - d = {'os': py.std.os, 'sys': py.std.sys, 'config': self.item.config} + d = self._getglobals() if self.holder.args: self.result = False for expr in self.holder.args: @@ -64,7 +73,7 @@ if isinstance(expr, str): result = cached_eval(self.item.config, expr, d) else: - result = expr + pytest.fail("expression is not a string") if result: self.result = True self.expr = expr @@ -82,7 +91,7 @@ if not hasattr(self, 'expr'): return "" else: - return "condition: " + self.expr + return "condition: " + str(self.expr) return expl --- a/doc/example/xfail_demo.py Thu Mar 03 12:19:17 2011 +0100 +++ b/doc/example/xfail_demo.py Thu Mar 03 23:22:55 2011 +0100 @@ -17,5 +17,9 @@ def test_hello4(): assert 0 + at xfail('pytest.__version__[0] != "17"') def test_hello5(): + assert 0 + +def test_hello6(): pytest.xfail("reason") --- a/doc/skipping.txt Thu Mar 03 12:19:17 2011 +0100 +++ b/doc/skipping.txt Thu Mar 03 23:22:55 2011 +0100 @@ -5,16 +5,17 @@ ===================================================================== You can skip or "xfail" test functions, either by marking functions -through a decorator or by calling the ``pytest.skip|xfail`` helpers. +through a decorator or by calling the ``pytest.skip|xfail`` functions. + A *skip* means that you expect your test to pass unless a certain configuration or condition (e.g. wrong Python interpreter, missing dependency) prevents it to run. And *xfail* means that you expect your test to fail because there is an implementation problem. py.test counts and lists *xfailing* tests separately and you can provide info such as a bug number or a URL to provide a human readable problem context. Usually detailed information about skipped/xfailed tests is not shown -to avoid cluttering the output. You can use the ``-r`` option to -see details corresponding to the "short" letters shown in the -test progress:: +at the end of a test run to avoid cluttering the output. You can use +the ``-r`` option to see details corresponding to the "short" letters +shown in the test progress:: py.test -rxs # show extra info on skips and xfail tests @@ -28,15 +29,32 @@ Here is an example for marking a test function to be skipped when run on a Python3 interpreter:: + import sys @pytest.mark.skipif("sys.version_info >= (3,0)") def test_function(): ... During test function setup the skipif condition is evaluated by calling ``eval(expr, namespace)``. The namespace -contains the ``sys`` and ``os`` modules and the test -``config`` object. The latter allows you to skip based -on a test configuration value e.g. like this:: +contains all the module globals of the test function so that +you can for example check for versions:: + + import mymodule + + @pytest.mark.skipif("mymodule.__version__ < '1.2'") + def test_function(): + ... + +The test function will be skipped and not run if +mymodule is below the specified version. The reason +for specifying the condition as a string is mainly that +you can see more detailed reporting of xfail/skip reasons. + +Actually, the namespace is first initialized by +putting the ``sys`` and ``os`` modules and the test +``config`` object into it. And is then updated with +the module globals. The latter allows you to skip based +on a test configuration value:: @pytest.mark.skipif("not config.getvalue('db')") def test_function(...): @@ -52,7 +70,7 @@ ... -skip test functions of a class +skip all test functions of a class -------------------------------------- As with all function :ref:`marking` you can do it at @@ -128,7 +146,7 @@ ========================= short test summary info ========================== XFAIL xfail_demo.py::test_hello XFAIL xfail_demo.py::test_hello2 - reason: [NOTRUN] + reason: [NOTRUN] XFAIL xfail_demo.py::test_hello3 condition: hasattr(os, 'sep') XFAIL xfail_demo.py::test_hello4 --- a/pytest.py Thu Mar 03 12:19:17 2011 +0100 +++ b/pytest.py Thu Mar 03 23:22:55 2011 +0100 @@ -1,7 +1,7 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.2.dev1' +__version__ = '2.0.2.dev2' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins --- a/setup.py Thu Mar 03 12:19:17 2011 +0100 +++ b/setup.py Thu Mar 03 23:22:55 2011 +0100 @@ -22,7 +22,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.2.dev1', + version='2.0.2.dev2', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], @@ -67,4 +67,4 @@ return {'console_scripts': l} if __name__ == '__main__': - main() + main() \ No newline at end of file --- a/testing/test_skipping.py Thu Mar 03 12:19:17 2011 +0100 +++ b/testing/test_skipping.py Thu Mar 03 23:22:55 2011 +0100 @@ -497,4 +497,34 @@ "*1 pass*2 error*", ]) +def test_xfail_skipif_with_globals(testdir): + testdir.makepyfile(""" + import pytest + x = 3 + @pytest.mark.skipif("x == 3") + def test_skip1(): + pass + @pytest.mark.xfail("x == 3") + def test_boolean(): + assert 0 + """) + result = testdir.runpytest("-rsx") + result.stdout.fnmatch_lines([ + "*SKIP*x == 3*", + "*XFAIL*test_boolean*", + "*x == 3*", + ]) +def test_direct_gives_error(testdir): + testdir.makepyfile(""" + import pytest + @pytest.mark.skipif(True) + def test_skip1(): + pass + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "*1 error*", + ]) + + Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Thu Mar 3 23:40:48 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Thu, 03 Mar 2011 22:40:48 -0000 Subject: [py-svn] commit/pytest: hpk42: incorporate typo/grammar fixes from Laura and respond to a number of issues she raised in comments. Message-ID: <20110303224048.6407.7326@bitbucket01.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/636a8513f4e0/ changeset: r2166:636a8513f4e0 user: hpk42 date: 2011-03-03 23:40:38 summary: incorporate typo/grammar fixes from Laura and respond to a number of issues she raised in comments. Also fixed links and some other bits and pieces. affected #: 35 files (2.0 KB) --- a/CHANGELOG Thu Mar 03 23:22:55 2011 +0100 +++ b/CHANGELOG Thu Mar 03 23:40:38 2011 +0100 @@ -29,9 +29,8 @@ a newer py lib version the py.path.local() implementation acknowledges this. -- fixed typos in the docs (thanks Victor, Brianna) and particular - thanks to Laura who also revieved the documentation which - lead to some improvements. +- fixed typos in the docs (thanks Victor Garcia, Brianna Laugher) and particular + thanks to Laura Creighton who also revieved parts of the documentation. Changes between 2.0.0 and 2.0.1 ---------------------------------------------- --- a/_pytest/capture.py Thu Mar 03 23:22:55 2011 +0100 +++ b/_pytest/capture.py Thu Mar 03 23:40:38 2011 +0100 @@ -192,18 +192,16 @@ return rep def pytest_funcarg__capsys(request): - """captures writes to sys.stdout/sys.stderr and makes - them available successively via a ``capsys.readouterr()`` method - which returns a ``(out, err)`` tuple of captured snapshot strings. + """enables capturing of writes to sys.stdout/sys.stderr and makes + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. """ return CaptureFuncarg(py.io.StdCapture) def pytest_funcarg__capfd(request): - """captures writes to file descriptors 1 and 2 and makes - snapshotted ``(out, err)`` string tuples available - via the ``capsys.readouterr()`` method. If the underlying - platform does not have ``os.dup`` (e.g. Jython) tests using - this funcarg will automatically skip. + """enables capturing of writes to file descriptors 1 and 2 and makes + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. """ if not hasattr(os, 'dup'): py.test.skip("capfd funcarg needs os.dup") --- a/_pytest/monkeypatch.py Thu Mar 03 23:22:55 2011 +0100 +++ b/_pytest/monkeypatch.py Thu Mar 03 23:40:38 2011 +0100 @@ -14,8 +14,8 @@ monkeypatch.delenv(name, value, raising=True) monkeypatch.syspath_prepend(path) - All modifications will be undone when the requesting - test function finished its execution. The ``raising`` + All modifications will be undone after the requesting + test function has finished. The ``raising`` parameter determines if a KeyError or AttributeError will be raised if the set/deletion operation has no target. """ --- a/_pytest/recwarn.py Thu Mar 03 23:22:55 2011 +0100 +++ b/_pytest/recwarn.py Thu Mar 03 23:40:38 2011 +0100 @@ -8,6 +8,9 @@ * ``pop(category=None)``: return last warning matching the category. * ``clear()``: clear list of warnings + + See http://docs.python.org/library/warnings.html for information + on warning categories. """ if sys.version_info >= (2,7): import warnings --- a/_pytest/tmpdir.py Thu Mar 03 23:22:55 2011 +0100 +++ b/_pytest/tmpdir.py Thu Mar 03 23:40:38 2011 +0100 @@ -59,7 +59,7 @@ def pytest_funcarg__tmpdir(request): """return a temporary directory path object - unique to each test function invocation, + which is unique to each test function invocation, created as a sub directory of the base temporary directory. The returned object is a `py.path.local`_ path object. --- a/doc/assert.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/assert.txt Thu Mar 03 23:40:38 2011 +0100 @@ -1,15 +1,15 @@ -Writing and reporting of assertions in tests -============================================ +The writing and reporting of assertions in tests +================================================== .. _`assert with the assert statement`: assert with the ``assert`` statement --------------------------------------------------------- -``py.test`` allows to use the standard python ``assert`` for verifying +``py.test`` allows you to use the standard python ``assert`` for verifying expectations and values in Python tests. For example, you can write the -following in your tests:: +following:: # content of test_assert1.py def f(): @@ -18,12 +18,12 @@ def test_function(): assert f() == 4 -to state that your object has a certain ``attribute``. In case this +to assert that your object returns a certain value. If this assertion fails you will see the value of ``x``:: $ py.test test_assert1.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_assert1.py F @@ -37,30 +37,33 @@ E + where 3 = f() test_assert1.py:5: AssertionError - ========================= 1 failed in 0.02 seconds ========================= + ========================= 1 failed in 0.03 seconds ========================= Reporting details about the failing assertion is achieved by re-evaluating -the assert expression and recording intermediate values. +the assert expression and recording the intermediate values. Note: If evaluating the assert expression has side effects you may get a warning that the intermediate values could not be determined safely. A -common example for this issue is reading from a file and comparing in one -line:: +common example of this issue is an assertion which reads from a file:: assert f.read() != '...' -This might fail but when re-interpretation comes along it might pass. You can -rewrite this (and any other expression with side effects) easily, though:: +If this assertion fails then the re-evaluation will probably succeed! +This is because ``f.read()`` will return an empty string when it is +called the second time during the re-evaluation. However, it is +easy to rewrite the assertion and avoid any trouble:: content = f.read() assert content != '...' + assertions about expected exceptions ------------------------------------------ In order to write assertions about raised exceptions, you can use ``pytest.raises`` as a context manager like this:: + import pytest with pytest.raises(ZeroDivisionError): 1 / 0 @@ -105,7 +108,7 @@ $ py.test test_assert2.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_assert2.py F --- a/doc/builtin.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/builtin.txt Thu Mar 03 23:40:38 2011 +0100 @@ -12,7 +12,7 @@ import pytest help(pytest) -to get an overview on available globally available helpers. +to get an overview on the globally available helpers. .. automodule:: pytest :members: @@ -27,20 +27,18 @@ pytestconfig the pytest config object with access to command line opts. capsys - captures writes to sys.stdout/sys.stderr and makes - them available successively via a ``capsys.readouterr()`` method - which returns a ``(out, err)`` tuple of captured snapshot strings. + enables capturing of writes to sys.stdout/sys.stderr and makes + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. capfd - captures writes to file descriptors 1 and 2 and makes - snapshotted ``(out, err)`` string tuples available - via the ``capsys.readouterr()`` method. If the underlying - platform does not have ``os.dup`` (e.g. Jython) tests using - this funcarg will automatically skip. + enables capturing of writes to file descriptors 1 and 2 and makes + captured output available via ``capsys.readouterr()`` method calls + which return a ``(out, err)`` tuple. tmpdir return a temporary directory path object - unique to each test function invocation, + which is unique to each test function invocation, created as a sub directory of the base temporary directory. The returned object is a `py.path.local`_ path object. @@ -57,8 +55,8 @@ monkeypatch.delenv(name, value, raising=True) monkeypatch.syspath_prepend(path) - All modifications will be undone when the requesting - test function finished its execution. The ``raising`` + All modifications will be undone after the requesting + test function has finished. The ``raising`` parameter determines if a KeyError or AttributeError will be raised if the set/deletion operation has no target. @@ -68,3 +66,6 @@ * ``pop(category=None)``: return last warning matching the category. * ``clear()``: clear list of warnings + See http://docs.python.org/library/warnings.html for information + on warning categories. + --- a/doc/capture.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/capture.txt Thu Mar 03 23:40:38 2011 +0100 @@ -1,16 +1,44 @@ .. _`captures`: -Capturing of stdout/stderr output +Capturing of the stdout/stderr output ========================================================= -By default ``stdout`` and ``stderr`` output is captured separately for -setup and test execution code. If a test or a setup method fails its -according output will usually be shown along with the failure traceback. -In addition, ``stdin`` is set to a "null" object which will fail all -attempts to read from it. This is important if some code paths in -test otherwise might lead to waiting for input - which is usually -not desired when running automated tests. +Default stdout/stderr/stdin capturing behaviour +--------------------------------------------------------- + +During test execution any output sent to ``stdout`` and ``stderr`` is +captured. If a test or a setup method fails its according captured +output will usually be shown along with the failure traceback. + +In addition, ``stdin`` is set to a "null" object which will +fail on attempts to read from it because it is rarely desired +to wait for interactive input when running automated tests. + +By default capturing is done by intercepting writes to low level +file descriptors. This allows to capture output from simple +print statements as well as output from a subprocess started by +a test. + +Setting capturing methods or disabling capturing +------------------------------------------------- + +There are two ways in which ``py.test`` can perform capturing: + +* file descriptor (FD) level capturing (default): All writes going to the + operating system file descriptors 1 and 2 will be captured. + +* ``sys`` level capturing: Only writes to Python files ``sys.stdout`` + and ``sys.stderr`` will be captured. No capturing of writes to + filedescriptors is performed. + +.. _`disable capturing`: + +You can influence output capturing mechanisms from the command line:: + + py.test -s # disable all capturing + py.test --capture=sys # replace sys.stdout/stderr with in-mem files + py.test --capture=fd # also point filedescriptors 1 and 2 to temp file .. _printdebugging: @@ -36,7 +64,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 2 items test_module.py .F @@ -50,33 +78,9 @@ test_module.py:9: AssertionError ----------------------------- Captured stdout ------------------------------ - setting up + setting up ==================== 1 failed, 1 passed in 0.02 seconds ==================== -Setting capturing methods or disabling capturing -------------------------------------------------- - -There are two ways in which ``py.test`` can perform capturing: - -* ``fd`` level capturing (default): All writes going to the operating - system file descriptors 1 and 2 will be captured, for example writes such - as ``os.write(1, 'hello')``. Capturing on ``fd``-level also includes - **output from subprocesses**. - -* ``sys`` level capturing: The ``sys.stdout`` and ``sys.stderr`` will - will be replaced with in-memory files and the ``print`` builtin or - output from code like ``sys.stderr.write(...)`` will be captured with - this method. - -.. _`disable capturing`: - -You can influence output capturing mechanisms from the command line:: - - py.test -s # disable all capturing - py.test --capture=sys # replace sys.stdout/stderr with in-mem files - py.test --capture=fd # also point filedescriptors 1 and 2 to temp file - - Accessing captured output from a test function --------------------------------------------------- --- a/doc/customize.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/customize.txt Thu Mar 03 23:40:38 2011 +0100 @@ -4,20 +4,20 @@ Command line options and configuration file settings ----------------------------------------------------------------- -You can get help on options and ini-config values by running:: +You can get help on command line options and values in INI-style +configurations files by using the general help option:: py.test -h # prints options _and_ config file settings This will display command line and configuration file settings which were registered by installed plugins. +How test configuration is read from configuration INI-files +------------------------------------------------------------- -how test configuration is read from setup/tox ini-files --------------------------------------------------------- - -py.test searched for the first matching ini-style configuration file +py.test searches for the first matching ini-style configuration file in the directories of command line argument and the directories above. -It looks for filenames in this order:: +It looks for file basenames in this order:: pytest.ini tox.ini @@ -44,29 +44,27 @@ .. _`how to change command line options defaults`: .. _`adding default options`: -how to change command line options defaults +How to change command line options defaults ------------------------------------------------ -py.test provides a simple way to set some default -command line options. For example, if you want -to always see detailed info on skipped and xfailed -tests, as well as have terser "dot progress output", -you can add this to your root directory:: +It can be tedious to type the same series of command line options +every time you use py.test . For example, if you always want to see +detailed info on skipped and xfailed tests, as well as have terser "dot" +progress output, you can write it into a configuration file:: # content of pytest.ini # (or tox.ini or setup.cfg) [pytest] addopts = -rsxX -q -From now on, running ``py.test`` will implicitly add -the specified options. +From now on, running ``py.test`` will add the specified options. builtin configuration file options ---------------------------------------------- .. confval:: minversion - specifies a minimal pytest version needed for running tests. + specifies a minimal pytest version required for running tests. minversion = 2.1 # will fail if we run with pytest-2.0 @@ -97,14 +95,14 @@ [!seq] matches any char not in seq Default patterns are ``.* _* CVS {args}``. Setting a ``norecurse`` - replaces the default. Here is a customizing example for avoiding - a different set of directories:: + replaces the default. Here is an example of how to avoid + certain directories:: # content of setup.cfg [pytest] norecursedirs = .svn _build tmp* - This would tell py.test to not recurse into typical subversion or + This would tell py.test to not look into typical subversion or sphinx-build directories or into any ``tmp`` prefixed directory. .. confval:: python_files --- a/doc/develop.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/develop.txt Thu Mar 03 23:40:38 2011 +0100 @@ -22,7 +22,7 @@ http://pypi.python.org/pypi/pytest/ -activating a checkout with setuptools +Activating a checkout with setuptools -------------------------------------------- With a working Distribute_ or setuptools_ installation you can type:: --- a/doc/doctest.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/doctest.txt Thu Mar 03 23:40:38 2011 +0100 @@ -1,5 +1,5 @@ -doctest integration for modules and test files. +doctest integration for modules and test files ========================================================= By default all files matching the ``test*.txt`` pattern will @@ -44,7 +44,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items mymodule.py . --- a/doc/example/mysetup.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/example/mysetup.txt Thu Mar 03 23:40:38 2011 +0100 @@ -26,7 +26,7 @@ To run this test py.test needs to find and call a factory to obtain the required ``mysetup`` function argument. To make an according factory findable we write down a specifically named factory -method in a :ref:`local plugin`:: +method in a :ref:`local plugin ` :: # content of conftest.py from myapp import MyApp @@ -49,7 +49,7 @@ $ py.test test_sample.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_sample.py F @@ -57,7 +57,7 @@ ================================= FAILURES ================================= _______________________________ test_answer ________________________________ - mysetup = + mysetup = def test_answer(mysetup): app = mysetup.myapp() @@ -122,12 +122,12 @@ $ py.test test_ssh.py -rs =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_ssh.py s ========================= short test summary info ========================== - SKIP [1] /tmp/doc-exec-166/conftest.py:22: specify ssh host with --ssh + SKIP [1] /tmp/doc-exec-35/conftest.py:22: specify ssh host with --ssh ======================== 1 skipped in 0.02 seconds ========================= --- a/doc/example/nonpython.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/example/nonpython.txt Thu Mar 03 23:40:38 2011 +0100 @@ -27,7 +27,7 @@ nonpython $ py.test test_simple.yml =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 2 items test_simple.yml .F @@ -37,7 +37,7 @@ usecase execution failed spec failed: 'some': 'other' no further details known at this point. - ==================== 1 failed, 1 passed in 0.06 seconds ==================== + ==================== 1 failed, 1 passed in 0.36 seconds ==================== You get one dot for the passing ``sub1: sub1`` check and one failure. Obviously in the above ``conftest.py`` you'll want to implement a more @@ -56,7 +56,7 @@ nonpython $ py.test -v =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 -- /home/hpk/venv/0/bin/python + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 -- /home/hpk/venv/0/bin/python collecting ... collected 2 items test_simple.yml:1: usecase: ok PASSED @@ -67,7 +67,7 @@ usecase execution failed spec failed: 'some': 'other' no further details known at this point. - ==================== 1 failed, 1 passed in 0.06 seconds ==================== + ==================== 1 failed, 1 passed in 0.08 seconds ==================== While developing your custom test collection and execution it's also interesting to just look at the collection tree:: --- a/doc/example/parametrize.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/example/parametrize.txt Thu Mar 03 23:40:38 2011 +0100 @@ -125,7 +125,7 @@ ================================= FAILURES ================================= __________________________ test_db_initialized[1] __________________________ - db = + db = def test_db_initialized(db): # a dummy test @@ -179,7 +179,7 @@ ================================= FAILURES ================================= __________________________ test_db_initialized[1] __________________________ - db = + db = def test_db_initialized(db): # a dummy test @@ -190,7 +190,7 @@ test_backends.py:6: Failed _________________________ TestClass.test_equals[0] _________________________ - self = , a = 1, b = 2 + self = , a = 1, b = 2 def test_equals(self, a, b): > assert a == b @@ -199,7 +199,7 @@ test_parametrize.py:17: AssertionError ______________________ TestClass.test_zerodivision[1] ______________________ - self = , a = 3, b = 2 + self = , a = 3, b = 2 def test_zerodivision(self, a, b): > pytest.raises(ZeroDivisionError, "a/b") @@ -247,7 +247,7 @@ ================================= FAILURES ================================= _________________________ TestClass.test_equals[0] _________________________ - self = , a = 1, b = 2 + self = , a = 1, b = 2 @params([dict(a=1, b=2), dict(a=3, b=3), ]) def test_equals(self, a, b): @@ -257,7 +257,7 @@ test_parametrize2.py:19: AssertionError ______________________ TestClass.test_zerodivision[1] ______________________ - self = , a = 3, b = 2 + self = , a = 3, b = 2 @params([dict(a=1, b=0), dict(a=3, b=2)]) def test_zerodivision(self, a, b): @@ -286,4 +286,4 @@ . $ py.test -q multipython.py collecting ... collected 75 items ....s....s....s....ssssss....s....s....s....ssssss....s....s....s....ssssss - 48 passed, 27 skipped in 1.59 seconds + 48 passed, 27 skipped in 1.92 seconds --- a/doc/example/reportingdemo.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/example/reportingdemo.txt Thu Mar 03 23:40:38 2011 +0100 @@ -13,7 +13,7 @@ assertion $ py.test failure_demo.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 39 items failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF @@ -30,7 +30,7 @@ failure_demo.py:15: AssertionError _________________________ TestFailing.test_simple __________________________ - self = + self = def test_simple(self): def f(): @@ -40,13 +40,13 @@ > assert f() == g() E assert 42 == 43 - E + where 42 = () - E + and 43 = () + E + where 42 = () + E + and 43 = () failure_demo.py:28: AssertionError ____________________ TestFailing.test_simple_multiline _____________________ - self = + self = def test_simple_multiline(self): otherfunc_multi( @@ -66,19 +66,19 @@ failure_demo.py:12: AssertionError ___________________________ TestFailing.test_not ___________________________ - self = + self = def test_not(self): def f(): return 42 > assert not f() E assert not 42 - E + where 42 = () + E + where 42 = () failure_demo.py:38: AssertionError _________________ TestSpecialisedExplanations.test_eq_text _________________ - self = + self = def test_eq_text(self): > assert 'spam' == 'eggs' @@ -89,7 +89,7 @@ failure_demo.py:42: AssertionError _____________ TestSpecialisedExplanations.test_eq_similar_text _____________ - self = + self = def test_eq_similar_text(self): > assert 'foo 1 bar' == 'foo 2 bar' @@ -102,7 +102,7 @@ failure_demo.py:45: AssertionError ____________ TestSpecialisedExplanations.test_eq_multiline_text ____________ - self = + self = def test_eq_multiline_text(self): > assert 'foo\nspam\nbar' == 'foo\neggs\nbar' @@ -115,7 +115,7 @@ failure_demo.py:48: AssertionError ______________ TestSpecialisedExplanations.test_eq_long_text _______________ - self = + self = def test_eq_long_text(self): a = '1'*100 + 'a' + '2'*100 @@ -132,7 +132,7 @@ failure_demo.py:53: AssertionError _________ TestSpecialisedExplanations.test_eq_long_text_multiline __________ - self = + self = def test_eq_long_text_multiline(self): a = '1\n'*100 + 'a' + '2\n'*100 @@ -156,7 +156,7 @@ failure_demo.py:58: AssertionError _________________ TestSpecialisedExplanations.test_eq_list _________________ - self = + self = def test_eq_list(self): > assert [0, 1, 2] == [0, 1, 3] @@ -166,7 +166,7 @@ failure_demo.py:61: AssertionError ______________ TestSpecialisedExplanations.test_eq_list_long _______________ - self = + self = def test_eq_list_long(self): a = [0]*100 + [1] + [3]*100 @@ -178,7 +178,7 @@ failure_demo.py:66: AssertionError _________________ TestSpecialisedExplanations.test_eq_dict _________________ - self = + self = def test_eq_dict(self): > assert {'a': 0, 'b': 1} == {'a': 0, 'b': 2} @@ -191,7 +191,7 @@ failure_demo.py:69: AssertionError _________________ TestSpecialisedExplanations.test_eq_set __________________ - self = + self = def test_eq_set(self): > assert set([0, 10, 11, 12]) == set([0, 20, 21]) @@ -207,7 +207,7 @@ failure_demo.py:72: AssertionError _____________ TestSpecialisedExplanations.test_eq_longer_list ______________ - self = + self = def test_eq_longer_list(self): > assert [1,2] == [1,2,3] @@ -217,7 +217,7 @@ failure_demo.py:75: AssertionError _________________ TestSpecialisedExplanations.test_in_list _________________ - self = + self = def test_in_list(self): > assert 1 in [0, 2, 3, 4, 5] @@ -226,7 +226,7 @@ failure_demo.py:78: AssertionError __________ TestSpecialisedExplanations.test_not_in_text_multiline __________ - self = + self = def test_not_in_text_multiline(self): text = 'some multiline\ntext\nwhich\nincludes foo\nand a\ntail' @@ -244,7 +244,7 @@ failure_demo.py:82: AssertionError ___________ TestSpecialisedExplanations.test_not_in_text_single ____________ - self = + self = def test_not_in_text_single(self): text = 'single foo line' @@ -257,7 +257,7 @@ failure_demo.py:86: AssertionError _________ TestSpecialisedExplanations.test_not_in_text_single_long _________ - self = + self = def test_not_in_text_single_long(self): text = 'head ' * 50 + 'foo ' + 'tail ' * 20 @@ -270,7 +270,7 @@ failure_demo.py:90: AssertionError ______ TestSpecialisedExplanations.test_not_in_text_single_long_term _______ - self = + self = def test_not_in_text_single_long_term(self): text = 'head ' * 50 + 'f'*70 + 'tail ' * 20 @@ -289,7 +289,7 @@ i = Foo() > assert i.b == 2 E assert 1 == 2 - E + where 1 = .b + E + where 1 = .b failure_demo.py:101: AssertionError _________________________ test_attribute_instance __________________________ @@ -299,8 +299,8 @@ b = 1 > assert Foo().b == 2 E assert 1 == 2 - E + where 1 = .b - E + where = () + E + where 1 = .b + E + where = () failure_demo.py:107: AssertionError __________________________ test_attribute_failure __________________________ @@ -316,7 +316,7 @@ failure_demo.py:116: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - self = + self = def _get_b(self): > raise Exception('Failed to get attrib') @@ -332,15 +332,15 @@ b = 2 > assert Foo().b == Bar().b E assert 1 == 2 - E + where 1 = .b - E + where = () - E + and 2 = .b - E + where = () + E + where 1 = .b + E + where = () + E + and 2 = .b + E + where = () failure_demo.py:124: AssertionError __________________________ TestRaises.test_raises __________________________ - self = + self = def test_raises(self): s = 'qwe' @@ -352,10 +352,10 @@ > int(s) E ValueError: invalid literal for int() with base 10: 'qwe' - <0-codegen /home/hpk/p/pytest/_pytest/python.py:822>:1: ValueError + <0-codegen /home/hpk/p/pytest/_pytest/python.py:825>:1: ValueError ______________________ TestRaises.test_raises_doesnt _______________________ - self = + self = def test_raises_doesnt(self): > raises(IOError, "int('3')") @@ -364,7 +364,7 @@ failure_demo.py:136: Failed __________________________ TestRaises.test_raise ___________________________ - self = + self = def test_raise(self): > raise ValueError("demo error") @@ -373,7 +373,7 @@ failure_demo.py:139: ValueError ________________________ TestRaises.test_tupleerror ________________________ - self = + self = def test_tupleerror(self): > a,b = [1] @@ -382,7 +382,7 @@ failure_demo.py:142: ValueError ______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______ - self = + self = def test_reinterpret_fails_with_print_for_the_fun_of_it(self): l = [1,2,3] @@ -395,7 +395,7 @@ l is [1, 2, 3] ________________________ TestRaises.test_some_error ________________________ - self = + self = def test_some_error(self): > if namenotexi: @@ -423,7 +423,7 @@ <2-codegen 'abc-123' /home/hpk/p/pytest/doc/example/assertion/failure_demo.py:162>:2: AssertionError ____________________ TestMoreErrors.test_complex_error _____________________ - self = + self = def test_complex_error(self): def f(): @@ -452,7 +452,7 @@ failure_demo.py:5: AssertionError ___________________ TestMoreErrors.test_z1_unpack_error ____________________ - self = + self = def test_z1_unpack_error(self): l = [] @@ -462,7 +462,7 @@ failure_demo.py:179: ValueError ____________________ TestMoreErrors.test_z2_type_error _____________________ - self = + self = def test_z2_type_error(self): l = 3 @@ -472,20 +472,20 @@ failure_demo.py:183: TypeError ______________________ TestMoreErrors.test_startswith ______________________ - self = + self = def test_startswith(self): s = "123" g = "456" > assert s.startswith(g) E assert False - E + where False = ('456') - E + where = '123'.startswith + E + where False = ('456') + E + where = '123'.startswith failure_demo.py:188: AssertionError __________________ TestMoreErrors.test_startswith_nested ___________________ - self = + self = def test_startswith_nested(self): def f(): @@ -494,15 +494,15 @@ return "456" > assert f().startswith(g()) E assert False - E + where False = ('456') - E + where = '123'.startswith - E + where '123' = () - E + and '456' = () + E + where False = ('456') + E + where = '123'.startswith + E + where '123' = () + E + and '456' = () failure_demo.py:195: AssertionError _____________________ TestMoreErrors.test_global_func ______________________ - self = + self = def test_global_func(self): > assert isinstance(globf(42), float) @@ -513,19 +513,19 @@ failure_demo.py:198: AssertionError _______________________ TestMoreErrors.test_instance _______________________ - self = + self = def test_instance(self): self.x = 6*7 > assert self.x != 42 E assert 42 != 42 E + where 42 = 42 - E + where 42 = .x + E + where 42 = .x failure_demo.py:202: AssertionError _______________________ TestMoreErrors.test_compare ________________________ - self = + self = def test_compare(self): > assert globf(10) < 5 @@ -535,7 +535,7 @@ failure_demo.py:205: AssertionError _____________________ TestMoreErrors.test_try_finally ______________________ - self = + self = def test_try_finally(self): x = 1 @@ -544,4 +544,4 @@ E assert 1 == 0 failure_demo.py:210: AssertionError - ======================== 39 failed in 0.22 seconds ========================= + ======================== 39 failed in 0.26 seconds ========================= --- a/doc/example/simple.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/example/simple.txt Thu Mar 03 23:40:38 2011 +0100 @@ -109,13 +109,13 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev0 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 gw0 I / gw1 I / gw2 I / gw3 I gw0 [0] / gw1 [0] / gw2 [0] / gw3 [0] scheduling tests via LoadScheduling - ============================= in 0.37 seconds ============================= + ============================= in 0.35 seconds ============================= .. _`excontrolskip`: @@ -156,12 +156,12 @@ $ py.test -rs # "-rs" means report details on the little 's' =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev0 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 2 items test_module.py .s ========================= short test summary info ========================== - SKIP [1] /tmp/doc-exec-275/conftest.py:9: need --runslow option to run + SKIP [1] /tmp/doc-exec-40/conftest.py:9: need --runslow option to run =================== 1 passed, 1 skipped in 0.02 seconds ==================== @@ -169,7 +169,7 @@ $ py.test --runslow =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev0 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 2 items test_module.py .. @@ -213,7 +213,7 @@ E Failed: not configured: 42 test_checkconfig.py:8: Failed - 1 failed in 0.02 seconds + 1 failed in 0.03 seconds Detect if running from within a py.test run -------------------------------------------------------------- @@ -261,7 +261,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev0 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 project deps: mylib-1.1 collecting ... collected 0 items @@ -284,7 +284,7 @@ $ py.test -v =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev0 -- /home/hpk/venv/0/bin/python + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 -- /home/hpk/venv/0/bin/python info1: did you know that ... did you? collecting ... collected 0 items @@ -295,7 +295,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev0 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 0 items ============================= in 0.00 seconds ============================= --- a/doc/extracol Thu Mar 03 23:22:55 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -changing Python test discovery patterns --------------------------------------------------- - -You can influence python test file, function and class prefixes through -the :confval:`python_patterns` configuration valueto determine which -files are checked and which test functions are found. Example for using -a scheme that builds on ``check`` rather than on ``test`` prefixes:: - - - # content of setup.cfg - [pytest] - python_patterns = - files: check_*.py - functions: check_ - classes: Check - -See - :confval:`python_funcprefixes` and :confval:`python_classprefixes` - - - changing test file discovery - ----------------------------------------------------- - - You can specify patterns where python tests are found:: - - python_testfilepatterns = - testing/**/{purebasename}.py - testing/*.py - - .. note:: - - conftest.py files are never considered for test discovery --- a/doc/faq.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/faq.txt Thu Mar 03 23:40:38 2011 +0100 @@ -12,25 +12,26 @@ Why a ``py.test`` instead of a ``pytest`` command? ++++++++++++++++++++++++++++++++++++++++++++++++++ -Some historic, some practical reasons: ``py.test`` used to be part of -the ``py`` package which provided several developer utilities, -all starting with ``py.``, providing nice TAB-completion. If +Some of the reasons are historic, others are practical. ``py.test`` +used to be part of the ``py`` package which provided several developer +utilities, all starting with ``py.``, thus providing nice +TAB-completion. If you install ``pip install pycmd`` you get these tools from a separate package. These days the command line tool could be called ``pytest`` -but then again many people have gotten used to the old name and there -is another tool named "pytest" so we just decided to stick with +since many people have gotten used to the old name and there +is another tool named "pytest" we just decided to stick with ``py.test``. -What's the relation to nose and unittest? +How does py.test relate to nose and unittest? +++++++++++++++++++++++++++++++++++++++++++++++++ py.test and nose_ share basic philosophy when it comes -to running Python tests. In fact, you can run many tests -written nose with py.test. nose_ was originally created +to running and writing Python tests. In fact, you can run many tests +written for nose with py.test. nose_ was originally created as a clone of ``py.test`` when py.test was in the ``0.8`` release -cycle. As of version 2.0 support for running unittest test -suites is majorly improved and you should be able to run -many Django and Twisted test suites. +cycle. Note that starting with pytest-2.0 support for running unittest +test suites is majorly improved and you should be able to run +many Django and Twisted test suites without modification. .. _features: test/features.html @@ -39,22 +40,20 @@ ++++++++++++++++++++++++++++++++++++++++++ Around 2007 (version ``0.8``) some people claimed that py.test -was using too much "magic". It has been refactored a lot. Thrown -out old code. Deprecated unused approaches and code. And it is today -probably one of the smallest, most universally runnable and most -customizable testing frameworks for Python. It's true that -``py.test`` uses metaprogramming techniques, i.e. it views -test code similar to how compilers view programs, using a -somewhat abstract internal model. +was using too much "magic". Partly this has been fixed by removing +unused, deprecated or complicated code. It is today probably one +of the smallest, most universally runnable and most +customizable testing frameworks for Python. However, +``py.test`` still uses many metaprogramming techniques and +reading its source is thus likely not something for Python beginners. -It's also true that the no-boilerplate testing is implemented by making -use of the Python assert statement through "re-interpretation": +A second "magic" issue arguably the assert statement re-intepreation: When an ``assert`` statement fails, py.test re-interprets the expression to show intermediate values if a test fails. If your expression -has side effects the intermediate values may not be the same, obfuscating -the initial error (this is also explained at the command line if it happens). +has side effects (better to avoid them anyway!) the intermediate values +may not be the same, obfuscating the initial error (this is also +explained at the command line if it happens). ``py.test --no-assert`` turns off assert re-interpretation. -Sidenote: it is good practise to avoid asserts with side effects. .. _`py namespaces`: index.html .. _`py/__init__.py`: http://bitbucket.org/hpk42/py-trunk/src/trunk/py/__init__.py @@ -69,7 +68,7 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ For simple applications and for people experienced with nose_ or -unittest-style test setup using `xUnit style setup`_ often +unittest-style test setup using `xUnit style setup`_ probably feels natural. For larger test suites, parametrized testing or setup of complex test resources using funcargs_ may feel more natural. Moreover, funcargs are ideal for writing advanced test support @@ -86,13 +85,11 @@ Why the ``pytest_funcarg__*`` name for funcarg factories? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -We alternatively implemented an explicit registration mechanism for -function argument factories. But lacking a good use case for this -indirection and flexibility we decided to go for `Convention over -Configuration`_ and rather have factories specified by convention. -Besides removing the need for an registration indirection it allows to -"grep" for ``pytest_funcarg__MYARG`` and will safely find all factory -functions for the ``MYARG`` function argument. +We like `Convention over Configuration`_ and didn't see much point +in allowing a more flexible or abstract mechanism. Moreover, +is is nice to be able to search for ``pytest_funcarg__MYARG`` in +a source code and safely find all factory functions for +the ``MYARG`` function argument. .. _`Convention over Configuration`: http://en.wikipedia.org/wiki/Convention_over_Configuration --- a/doc/funcargs.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/funcargs.txt Thu Mar 03 23:40:38 2011 +0100 @@ -1,5 +1,5 @@ ============================================================== -creating and managing test function arguments +Injecting objects into test functions (funcargs) ============================================================== .. currentmodule:: _pytest.python @@ -11,16 +11,26 @@ Dependency injection through function arguments ================================================= -py.test allows to inject values into test functions through the *funcarg -mechanism*: For each argument name in a test function signature a factory is -looked up and called to create the value. The factory can live in the -same test class, test module, in a per-directory ``conftest.py`` file or -in an external plugin. It has full access to the requesting test -function, can register finalizers and invoke lifecycle-caching -helpers. As can be expected from a systematic dependency -injection mechanism, this allows full de-coupling of resource and -fixture setup from test code, enabling more maintainable and -easy-to-modify test suites. +py.test lets you inject objects into test functions and precisely +control their life cycle in relation to the test execution. It is +also possible to run a test function multiple times with different objects. + +The basic mechanism for injecting objects is also called the +*funcarg mechanism* because objects are ultimatly injected +by calling a test function with it as an argument. Unlike the +classical xUnit approach *funcargs* relate more to `Dependency Injection`_ +because they help to de-couple test code from objects required for +them to execute. + +.. _`Dependency injection`: http://en.wikipedia.org/wiki/Dependency_injection + +To create a value with which to call a test function a factory function +is called which gets full access to the test function context and can +register finalizers or invoke lifecycle-caching helpers. The factory +can be implemented in same test class or test module, or in a +per-directory ``conftest.py`` file or even in an external plugin. This +allows full de-coupling of test code and objects needed for test +execution. A test function may be invoked multiple times in which case we speak of :ref:`parametrized testing `. This can be @@ -28,13 +38,13 @@ or with multiple numerical arguments sets and want to reuse the same set of test functions. + .. _funcarg: -Basic funcarg example ------------------------ +Basic injection example +-------------------------------- -Let's look at a simple self-contained example that you can put -into a test module:: +Let's look at a simple self-contained test module:: # content of ./test_simplefactory.py def pytest_funcarg__myfuncarg(request): @@ -43,11 +53,15 @@ def test_function(myfuncarg): assert myfuncarg == 17 +This test function needs an injected object named ``myfuncarg``. +py.test will discover and call the factory named +``pytest_funcarg__myfuncarg`` within the same module in this case. + Running the test looks like this:: $ py.test test_simplefactory.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_simplefactory.py F @@ -64,8 +78,8 @@ test_simplefactory.py:5: AssertionError ========================= 1 failed in 0.02 seconds ========================= -This means that the test function was called with a ``myfuncarg`` value -of ``42`` and the assert fails accordingly. Here is how py.test +This means that indeed the test function was called with a ``myfuncarg`` +argument value of ``42`` and the assert fails. Here is how py.test comes to call the test function this way: 1. py.test :ref:`finds ` the ``test_function`` because @@ -76,14 +90,15 @@ 2. ``pytest_funcarg__myfuncarg(request)`` is called and returns the value for ``myfuncarg``. -3. the test function can now be called: ``test_function(42)`` - and results in the above exception because of the assertion +3. the test function can now be called: ``test_function(42)``. + This results in the above exception because of the assertion mismatch. Note that if you misspell a function argument or want to use one that isn't available, you'll see an error -with a list of available function arguments. You can -also issue:: +with a list of available function arguments. + +You can always issue:: py.test --funcargs test_simplefactory.py @@ -152,7 +167,7 @@ $ py.test test_example.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 10 items test_example.py .........F @@ -167,7 +182,7 @@ E assert 9 < 9 test_example.py:7: AssertionError - ==================== 1 failed, 9 passed in 0.03 seconds ==================== + ==================== 1 failed, 9 passed in 0.05 seconds ==================== Note that the ``pytest_generate_tests(metafunc)`` hook is called during the test collection phase which is separate from the actual test running. @@ -190,7 +205,7 @@ $ py.test -v -k 7 test_example.py # or -k test_func[7] =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 -- /home/hpk/venv/0/bin/python + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 -- /home/hpk/venv/0/bin/python collecting ... collected 10 items test_example.py:6: test_func[7] PASSED --- a/doc/getting-started.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/getting-started.txt Thu Mar 03 23:40:38 2011 +0100 @@ -16,7 +16,7 @@ To check your installation has installed the correct version:: $ py.test --version - This is py.test version 2.0.1, imported from /home/hpk/p/pytest/pytest.py + This is py.test version 2.0.2.dev2, imported from /home/hpk/p/pytest/pytest.py setuptools registered plugins: pytest-xdist-1.6.dev2 at /home/hpk/p/pytest-xdist/xdist/plugin.pyc pytest-pep8-0.7 at /home/hpk/p/pytest-pep8/pytest_pep8.pyc @@ -41,7 +41,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_sample.py F @@ -57,7 +57,7 @@ test_sample.py:5: AssertionError ========================= 1 failed in 0.02 seconds ========================= -py.test found the ``test_answer`` function by following :ref:`standard test discovery rules `, basically detecting the ``test_`` prefixes. We got a failure report because our little ``func(3)`` call did not return ``5``. The report is formatted using the :ref:`standard traceback reporting`. +py.test found the ``test_answer`` function by following :ref:`standard test discovery rules `, basically detecting the ``test_`` prefixes. We got a failure report because our little ``func(3)`` call did not return ``5``. .. note:: @@ -80,10 +80,10 @@ .. _`assert statement`: http://docs.python.org/reference/simple_stmts.html#the-assert-statement -Asserting a certain exception is raised +Asserting that a certain exception is raised -------------------------------------------------------------- -If you want to assert some code raises an exception you can +If you want to assert that some code raises an exception you can use the ``raises`` helper:: # content of test_sysexit.py @@ -107,9 +107,9 @@ Grouping multiple tests in a class -------------------------------------------------------------- -If you start to have more than a few tests it often makes sense -to group tests logically, in classes and modules. Let's put two -tests in a class like this:: +Once you start to have more than a few tests it often makes sense +to group tests logically, in classes and modules. Let's write a class +containing two tests:: # content of test_class.py class TestClass: @@ -131,7 +131,7 @@ ================================= FAILURES ================================= ____________________________ TestClass.test_two ____________________________ - self = + self = def test_two(self): x = "hello" @@ -140,7 +140,7 @@ E + where False = hasattr('hello', 'check') test_class.py:8: AssertionError - 1 failed, 1 passed in 0.02 seconds + 1 failed, 1 passed in 0.04 seconds The first test passed, the second failed. Again we can easily see the intermediate values used in the assertion, helping us to @@ -169,7 +169,7 @@ ================================= FAILURES ================================= _____________________________ test_needsfiles ______________________________ - tmpdir = local('/tmp/pytest-101/test_needsfiles0') + tmpdir = local('/tmp/pytest-92/test_needsfiles0') def test_needsfiles(tmpdir): print tmpdir @@ -178,8 +178,8 @@ test_tmpdir.py:3: AssertionError ----------------------------- Captured stdout ------------------------------ - /tmp/pytest-101/test_needsfiles0 - 1 failed in 0.03 seconds + /tmp/pytest-92/test_needsfiles0 + 1 failed in 0.14 seconds Before the test runs, a unique-per-test-invocation temporary directory was created. More info at :ref:`tmpdir handling`. @@ -194,7 +194,7 @@ Here are a few suggestions where to go next: * :ref:`cmdline` for command line invocation examples -* :ref:`good practises` for virtualenv, test layout, genscript support +* :ref:`good practises ` for virtualenv, test layout, genscript support * :ref:`apiref` for documentation and examples on using py.test * :ref:`plugins` managing and writing plugins @@ -228,7 +228,7 @@ - **Jython2.5.1 on Windows XP**: `Jython does not create command line launchers`_ so ``py.test`` will not work correctly. You may install py.test on CPython and type ``py.test --genscript=mytest`` and then use - ``jython mytest`` to run py.test for your tests to run in Jython. + ``jython mytest`` to run py.test for your tests to run with Jython. :ref:`examples` for more complex examples --- a/doc/goodpractises.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/goodpractises.txt Thu Mar 03 23:40:38 2011 +0100 @@ -8,14 +8,11 @@ Work with virtual environments ----------------------------------------------------------- -We recommend to work with virtualenv_ environments and use easy_install_ +We recommend to use virtualenv_ environments and use easy_install_ (or pip_) for installing your application dependencies as well as -the ``pytest`` package itself. This way you get a much more reproducible +the ``pytest`` package itself. This way you will get a much more reproducible environment. A good tool to help you automate test runs against multiple -dependency configurations or Python interpreters is `tox`_, -independently created by the main py.test author. The latter -is also useful for integration with the continuous integration -server Hudson_. +dependency configurations or Python interpreters is `tox`_. .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv .. _`buildout`: http://www.buildout.org/ @@ -24,10 +21,11 @@ Use tox and Continuous Integration servers ------------------------------------------------- -If you are (often) releasing code to the public you +If you frequently relase code to the public you may want to look into `tox`_, the virtualenv test automation tool and its `pytest support `_. -The basic idea is to generate a JUnitXML file through the ``--junitxml=PATH`` option and have a continuous integration server like Hudson_ pick it up. +The basic idea is to generate a JUnitXML file through the ``--junitxml=PATH`` option and have a continuous integration server like Jenkins_ pick it up +and generate reports. .. _standalone: .. _`genscript method`: @@ -90,7 +88,7 @@ this will execute your tests using ``runtest.py``. As this is a standalone version of ``py.test`` no prior installation whatsoever is required for calling the test command. You can also pass additional -arguments to the subprocess-calls like your test directory or other +arguments to the subprocess-calls such as your test directory or other options. .. _`test discovery`: @@ -101,14 +99,14 @@ ``py.test`` implements the following standard test discovery: -* collection starts from initial command line arguments +* collection starts from the initial command line arguments which may be directories, filenames or test ids. * recurse into directories, unless they match :confval:`norecursedirs` * ``test_*.py`` or ``*_test.py`` files, imported by their `package name`_. * ``Test`` prefixed test classes (without an ``__init__`` method) * ``test_`` prefixed test functions or methods are test items -For changing and customization example, see :doc:`example/pythoncollection`. +For examples of how to cnd cusotmize your test discovery :doc:`example/pythoncollection`. py.test additionally discovers tests using the standard :ref:`unittest.TestCase ` subclassing technique. @@ -154,8 +152,8 @@ Test modules are imported under their fully qualified name as follows: - * find ``basedir`` -- this is the first "upward" directory not - containing an ``__init__.py`` + * find ``basedir`` -- this is the first "upward" (towards the root) + directory not containing an ``__init__.py`` * perform ``sys.path.insert(0, basedir)`` to make the fully qualified test module path importable. --- a/doc/index.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/index.txt Thu Mar 03 23:40:38 2011 +0100 @@ -4,23 +4,25 @@ ============================================= -- **a mature fully featured testing tool** +- **a mature full-featured testing tool** - runs on Posix/Windows, Python 2.4-3.2, PyPy and Jython - continuously `tested on many Python interpreters `_ - - used in :ref:`many projects and organisations `, ranging from 10 to 10000 tests + - used in :ref:`many projects and organisations `, in test + suites ranging from 10 to 10s of thousands of tests - has :ref:`comprehensive documentation ` - comes with :ref:`tested examples ` - supports :ref:`good integration practises ` - **provides no-boilerplate testing** - - makes it :ref:`easy to get started `, refined :ref:`usage options ` + - makes it :ref:`easy to get started `, + - refined :ref:`usage options ` - :ref:`assert with the assert statement` - helpful :ref:`traceback and failing assertion reporting ` - - allows :ref:`print debugging ` and :ref:`generic output - capturing ` - - supports :pep:`8` compliant coding style in tests + - allows :ref:`print debugging ` and :ref:`the + capturing of standard output during test execution ` + - supports :pep:`8` compliant coding styles in tests - **supports functional testing and complex test setups** @@ -39,7 +41,7 @@ tests, including running testcases made for Django and trial - supports extended :ref:`xUnit style setup ` - supports domain-specific :ref:`non-python tests` - - supports generating testing coverage reports + - supports the generation of testing coverage reports - `Javascript unit- and functional testing`_ - **extensive plugin and customization system** --- a/doc/links.inc Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/links.inc Thu Mar 03 23:40:38 2011 +0100 @@ -16,4 +16,5 @@ .. _`pip`: http://pypi.python.org/pypi/pip .. _`virtualenv`: http://pypi.python.org/pypi/virtualenv .. _hudson: http://hudson-ci.org/ +.. _jenkins: http://jenkins-ci.org/ .. _tox: http://codespeak.net/tox --- a/doc/mark.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/mark.txt Thu Mar 03 23:40:38 2011 +0100 @@ -7,12 +7,12 @@ .. currentmodule:: _pytest.mark By using the ``pytest.mark`` helper you can instantiate -decorators that will set named meta data on test functions. +decorators that will set named metadata on test functions. Marking a single function ---------------------------------------------------- -You can "mark" a test function with meta data like this:: +You can "mark" a test function with metadata like this:: import pytest @pytest.mark.webtest @@ -20,7 +20,7 @@ ... This will set the function attribute ``webtest`` to a :py:class:`MarkInfo` -instance. You can also specify parametrized meta data like this:: +instance. You can also specify parametrized metadata like this:: # content of test_mark.py @@ -44,7 +44,7 @@ ---------------------------------------------------- If you are programming with Python2.6 you may use ``pytest.mark`` decorators -with classes to apply markers to all its test methods:: +with classes to apply markers to all of its test methods:: # content of test_mark_classlevel.py import pytest @@ -88,7 +88,7 @@ $ py.test -k webtest # running with the above defined examples yields =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 4 items test_mark.py .. @@ -100,7 +100,7 @@ $ py.test -k-webtest =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 4 items ===================== 4 tests deselected by '-webtest' ===================== @@ -110,7 +110,7 @@ $ py.test -kTestClass =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 4 items test_mark_classlevel.py .. --- a/doc/monkeypatch.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/monkeypatch.txt Thu Mar 03 23:40:38 2011 +0100 @@ -9,8 +9,8 @@ tested such as network access. The ``monkeypatch`` function argument helps you to safely set/delete an attribute, dictionary item or environment variable or to modify ``sys.path`` for importing. -See the `monkeypatch blog post`_ one some introduction material -and motivation. +See the `monkeypatch blog post`_ for some introduction material +and a discussion of its motivation. .. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/ @@ -18,7 +18,7 @@ Simple example: patching ``os.path.expanduser`` --------------------------------------------------- -If you e.g. want to pretend that ``os.expanduser`` returns a certain +If, for instance, you want to pretend that ``os.expanduser`` returns a certain directory, you can use the :py:meth:`monkeypatch.setattr` method to patch this function before calling into a function which uses it:: @@ -39,7 +39,7 @@ .. background check: $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 0 items ============================= in 0.00 seconds ============================= --- a/doc/naming20.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/naming20.txt Thu Mar 03 23:40:38 2011 +0100 @@ -16,5 +16,5 @@ py.test.cmdline.main -> pytest.main The old ``py.test.*`` ways to access functionality remain -valid but you are encouraged to do global renames according +valid but you are encouraged to do global renaming according to the above rules in your test code. --- a/doc/plugins.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/plugins.txt Thu Mar 03 23:40:38 2011 +0100 @@ -1,8 +1,8 @@ +.. _plugins: + Working with plugins and conftest files ============================================= -.. _`local plugin`: - py.test implements all aspects of configuration, collection, running and reporting by calling `well specified hooks`_. Virtually any Python module can be registered as a plugin. It can implement any number of hook functions (usually two or three) which all have a ``pytest_`` prefix, making hook functions easy to distinguish and find. There are three basic locations types: * `builtin plugins`_: loaded from py.test's own ``pytest/plugin`` directory. @@ -12,14 +12,17 @@ .. _`pytest/plugin`: http://bitbucket.org/hpk42/pytest/src/tip/pytest/plugin/ .. _`conftest.py plugins`: .. _`conftest.py`: +.. _`localplugin`: +.. _`conftest`: conftest.py: local per-directory plugins -------------------------------------------------------------- local ``conftest.py`` plugins contain directory-specific hook implementations. Session and test running activities will -invoke all hooks defined in "higher up" ``conftest.py`` files. -Example: Assume the following layout and content of files:: +invoke all hooks defined in ``conftest.py`` files closer to the +root of the filesystem. Example: Assume the following layout +and content of files:: a/conftest.py: def pytest_runtest_setup(item): @@ -39,11 +42,6 @@ py.test test_flat.py # will not show "setting up" py.test a/test_sub.py # will show "setting up" -A note on ordering: ``py.test`` loads all ``conftest.py`` files upwards -from the command line file arguments. It usually performs look up -right-to-left, i.e. the hooks in "closer" conftest files will be called -earlier than further away ones. - .. Note:: If you have ``conftest.py`` files which do not reside in a python package directory (i.e. one containing an ``__init__.py``) then @@ -112,12 +110,12 @@ ----------------------------------------------- If you want to make your plugin externally available, you -may define a so called entry point for your distribution so +may define a so-called entry point for your distribution so that ``py.test`` finds your plugin module. Entry points are a feature that is provided by `setuptools`_ or `Distribute`_. -The concrete entry point is ``pytest11``. To make your plugin -available you can insert the following lines in your -setuptools/distribute-based setup-invocation: +py.test looks up the ``pytest11`` entrypoint to discover its +plugins and you can thus make your plugin available by definig +it in your setuptools/distribute-based setup-invocation: .. sourcecode:: python @@ -137,8 +135,8 @@ ) If a package is installed this way, py.test will load -``myproject.pluginmodule`` and accordingly call functions -if they match the `well specified hooks`_. +``myproject.pluginmodule`` as a plugin which can define +`well specified hooks`_. Plugin discovery order at tool startup -------------------------------------------- @@ -260,11 +258,11 @@ py.test calls hook functions to implement initialization, running, test execution and reporting. When py.test loads a plugin it validates -that all hook functions conform to their respective hook specification. +that each hook function conforms to its respective hook specification. Each hook function name and its argument names need to match a hook -specification exactly but it is allowed for a hook function to accept -*less* parameters than specified. If you mistype argument names or the -hook name itself you get useful errors. +specification. However, a hook function may accept *fewer* parameters +by simply not specifying them. If you mistype argument names or the +hook name itself you get an error showing the available arguments. initialisation, command line and configuration hooks -------------------------------------------------------------------- @@ -292,8 +290,9 @@ For deeper understanding you may look at the default implementation of these hooks in :py:mod:`_pytest.runner` and maybe also -in :py:mod:`_pytest.pdb` which intercepts creation -of reports in order to drop to interactive debugging. +in :py:mod:`_pytest.pdb` which interacts with :py:mod:`_pytest.capture` +and its input/output capturing in order to immediately drop +into interactive debugging when a test failure occurs. The :py:mod:`_pytest.terminal` reported specifically uses the reporting hook to print information about a test run. --- a/doc/projects.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/projects.txt Thu Mar 03 23:40:38 2011 +0100 @@ -46,7 +46,7 @@ * `Shootq `_ * `Stups department of Heinrich Heine University D?sseldorf `_ * `cellzome `_ -* `Open End, Gotenborg `_ +* `Open End, Gothenborg `_ * `Laboraratory of Bioinformatics, Warsaw `_ * `merlinux, Germany `_ * many more ... (please be so kind to send a note via :ref:`contact`) --- a/doc/pytest.ini Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/pytest.ini Thu Mar 03 23:40:38 2011 +0100 @@ -1,2 +1,2 @@ [pytest] -# just defined to prevent the root level tox.ini to kick in +# just defined to prevent the root level tox.ini from kicking in --- a/doc/skipping.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/skipping.txt Thu Mar 03 23:40:38 2011 +0100 @@ -5,19 +5,18 @@ ===================================================================== You can skip or "xfail" test functions, either by marking functions -through a decorator or by calling the ``pytest.skip|xfail`` functions. +with a decorator or by calling the ``pytest.skip|xfail`` functions. A *skip* means that you expect your test to pass unless a certain configuration or condition (e.g. wrong Python interpreter, missing dependency) prevents it to run. And *xfail* means that you expect your test to fail because there is an implementation problem. py.test counts and lists *xfailing* tests separately -and you can provide info such as a bug number or a URL to provide a -human readable problem context. +and it is possible to give additional information, such as bug number or a URL. -Usually detailed information about skipped/xfailed tests is not shown +Detailed information about skipped/xfailed tests is by default not shown at the end of a test run to avoid cluttering the output. You can use the ``-r`` option to see details corresponding to the "short" letters shown in the test progress:: - py.test -rxs # show extra info on skips and xfail tests + py.test -rxs # show extra info on skips and xfails (See :ref:`how to change command line options defaults`) @@ -26,7 +25,7 @@ Skipping a single function ------------------------------------------- -Here is an example for marking a test function to be skipped +Here is an example of marking a test function to be skipped when run on a Python3 interpreter:: import sys @@ -60,7 +59,7 @@ def test_function(...): ... -Create a shortcut for your conditional skip decorator +You can create a shortcut for your conditional skip decorator at module level like this:: win32only = pytest.mark.skipif("sys.platform != 'win32'") @@ -73,9 +72,9 @@ skip all test functions of a class -------------------------------------- -As with all function :ref:`marking` you can do it at +As with all function :ref:`mark` you can skip test functions at the `whole class- or module level`_. Here is an example -for skipping all methods of a test class based on platform:: +for skipping all methods of a test class based on the platform:: class TestPosixCalls: pytestmark = pytest.mark.skipif("sys.platform == 'win32'") @@ -93,9 +92,7 @@ def test_function(self): "will not be setup or run under 'win32' platform" -It is fine in general to apply multiple "skipif" decorators -on a single function - this means that if any of the conditions -apply the function will be skipped. +Using multiple "skipif" decorators on a single function is generally fine - it means that if any of the conditions apply the function execution will be skipped. .. _`whole class- or module level`: mark.html#scoped-marking @@ -122,16 +119,16 @@ you can force the running and reporting of an ``xfail`` marked test as if it weren't marked at all. -Same as with skipif_ you can also selectively expect a failure -depending on platform:: +As with skipif_ you can also mark your expectation of a failure +on a particular platform:: @pytest.mark.xfail("sys.version_info >= (3,0)") def test_function(): ... -You can also avoid running an "xfail" test at all or +You can furthermore prevent the running of an "xfail" test or specify a reason such as a bug ID or similar. Here is -a simple test file with usages: +a simple test file with the several usages: .. literalinclude:: example/xfail_demo.py @@ -139,10 +136,10 @@ example $ py.test -rx xfail_demo.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 - collecting ... collected 5 items + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + collecting ... collected 6 items - xfail_demo.py xxxxx + xfail_demo.py xxxxxx ========================= short test summary info ========================== XFAIL xfail_demo.py::test_hello XFAIL xfail_demo.py::test_hello2 @@ -152,9 +149,11 @@ XFAIL xfail_demo.py::test_hello4 bug 110 XFAIL xfail_demo.py::test_hello5 + condition: pytest.__version__[0] != "17" + XFAIL xfail_demo.py::test_hello6 reason: reason - ======================== 5 xfailed in 0.04 seconds ========================= + ======================== 6 xfailed in 0.06 seconds ========================= imperative xfail from within a test or setup function ------------------------------------------------------ @@ -177,8 +176,8 @@ docutils = pytest.importorskip("docutils") If ``docutils`` cannot be imported here, this will lead to a -skip outcome of the test. You can also skip depending if -if a library does not come with a high enough version:: +skip outcome of the test. You can also skip based on the +version number of a library:: docutils = pytest.importorskip("docutils", minversion="0.3") @@ -188,7 +187,7 @@ ------------------------------------------------------ If for some reason you cannot declare skip-conditions -you can also imperatively produce a Skip-outcome from +you can also imperatively produce a skip-outcome from within test or setup code. Example:: def test_function(): --- a/doc/tmpdir.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/tmpdir.txt Thu Mar 03 23:40:38 2011 +0100 @@ -28,7 +28,7 @@ $ py.test test_tmpdir.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_tmpdir.py F @@ -36,7 +36,7 @@ ================================= FAILURES ================================= _____________________________ test_create_file _____________________________ - tmpdir = local('/tmp/pytest-102/test_create_file0') + tmpdir = local('/tmp/pytest-93/test_create_file0') def test_create_file(tmpdir): p = tmpdir.mkdir("sub").join("hello.txt") @@ -47,14 +47,14 @@ E assert 0 test_tmpdir.py:7: AssertionError - ========================= 1 failed in 0.03 seconds ========================= + ========================= 1 failed in 0.04 seconds ========================= .. _`base temporary directory`: the default base temporary directory ----------------------------------------------- -Temporary directories are by default created as sub directories of +Temporary directories are by default created as sub-directories of the system temporary directory. The base name will be ``pytest-NUM`` where ``NUM`` will be incremented with each test run. Moreover, entries older than 3 temporary directories will be removed. --- a/doc/unittest.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/unittest.txt Thu Mar 03 23:40:38 2011 +0100 @@ -8,7 +8,7 @@ It will automatically collect ``unittest.TestCase`` subclasses and their ``test`` methods in test files. It will invoke ``setUp/tearDown`` methods but also perform py.test's standard ways -of treating tests like e.g. IO capturing:: +of treating tests such as IO capturing:: # content of test_unittest.py @@ -24,7 +24,7 @@ $ py.test test_unittest.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.1 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 collecting ... collected 1 items test_unittest.py F --- a/doc/usage.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/usage.txt Thu Mar 03 23:40:38 2011 +0100 @@ -12,7 +12,7 @@ .. versionadded:: 2.0 -If you use Python-2.5 or above you can invoke testing through the +If you use Python-2.5 or later you can invoke testing through the Python interpreter from the command line:: python -m pytest [...] @@ -20,8 +20,8 @@ This is equivalent to invoking the command line script ``py.test [...]`` directly. -Getting help on version, option names, environment vars ------------------------------------------------------------ +Getting help on version, option names, environment variables +-------------------------------------------------------------- :: @@ -96,7 +96,7 @@ .. versionadded: 2.0.0 In previous versions you could only enter PDB tracing if -you :ref:`disable capturing`. +you disable capturing on the command line via ``py.test -s``. creating JUnitXML format files ---------------------------------------------------- --- a/doc/xdist.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/xdist.txt Thu Mar 03 23:40:38 2011 +0100 @@ -7,13 +7,13 @@ The `pytest-xdist`_ plugin extends py.test with some unique test execution modes: -* Looponfail: run your tests repeatedly in a subprocess. After each run py.test - waits until a file in your project changes and then re-runs the previously - failing tests. This is repeated until all tests pass after which again - a full run is performed. +* Looponfail: run your tests repeatedly in a subprocess. After each + run, py.test waits until a file in your project changes and then + re-runs the previously failing tests. This is repeated until all + tests pass. At this point a full run is again performed. * multiprocess Load-balancing: if you have multiple CPUs or hosts you can use - those for a combined test run. This allows to speed up + them for a combined test run. This allows to speed up development or to use special resources of remote machines. * Multi-Platform coverage: you can specify different Python interpreters @@ -25,8 +25,8 @@ You may specify different Python versions and interpreters. -Installation ------------------------ +Installation of xdist plugin +------------------------------ Install the plugin with:: @@ -55,13 +55,13 @@ py.test -n NUM Especially for longer running tests or tests requiring -a lot of IO this can lead to considerable speed ups. +a lot of I/O this can lead to considerable speed ups. Running tests in a Python subprocess +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -To instantiate a python2.4 sub process and send tests to it, you may type:: +To instantiate a Python-2.4 subprocess and send tests to it, you may type:: py.test -d --tx popen//python=python2.4 @@ -70,10 +70,10 @@ If you prefix the --tx option value like this:: - --tx 3*popen//python=python2.4 + py.test -d --tx 3*popen//python=python2.4 -then three subprocesses would be created and tests -will be load-balanced across these three processes. +then three subprocesses would be created and the tests +will be distributed to three subprocesses and run simultanously. .. _looponfailing: @@ -82,11 +82,13 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ For refactoring a project with a medium or large test suite -you can use the looponfailing mode, simply add the ``--f`` option:: +you can use the looponfailing mode. Simply add the ``--f`` option:: py.test -f -and py.test will run your tests, then wait for file changes and re-run the failing test set. Of course you can pass in more options to select tests or test files. File changes are detected by looking at the root directory - you can override this automatic default by an ini-file setting:: +and py.test will run your tests. Assuming you have failures it will then +wait for file changes and re-run the failing test set. File changes are detected by looking at ``looponfailingroots`` root directories and all of their contents (recursively). If the default for this value does not work for you you +can change it in your project by setting a configuration option:: # content of a pytest.ini, setup.cfg or tox.ini file [pytest] @@ -98,26 +100,28 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Suppose you have a package ``mypkg`` which contains some -tests that you can successfully run locally. And you +tests that you can successfully run locally. And you also have a ssh-reachable machine ``myhost``. Then you can ad-hoc distribute your tests by typing:: py.test -d --tx ssh=myhostpopen --rsyncdir mypkg mypkg This will synchronize your ``mypkg`` package directory -to an remote ssh account and then locally collect tests -and send them to remote places for execution. +with a remote ssh account and then collect and run your +tests at the remote side. You can specify multiple ``--rsyncdir`` directories to be sent to the remote side. -**NOTE:** For py.test to collect and send tests correctly -you not only need to make sure all code and tests -directories are rsynced, but that any test (sub) directory -also has an ``__init__.py`` file because internally -py.test references tests as a fully qualified python -module path. **You will otherwise get strange errors** -during setup of the remote side. +.. XXX CHECK + + **NOTE:** For py.test to collect and send tests correctly + you not only need to make sure all code and tests + directories are rsynced, but that any test (sub) directory + also has an ``__init__.py`` file because internally + py.test references tests as a fully qualified python + module path. **You will otherwise get strange errors** + during setup of the remote side. Sending tests to remote Socket Servers +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -158,8 +162,7 @@ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pytest (since version 2.0) supports ini-style configuration. -You can for example make running with three subprocesses -your default like this:: +For example, you could make running with three subprocesses your default:: [pytest] addopts = -n3 --- a/doc/xunit_setup.txt Thu Mar 03 23:22:55 2011 +0100 +++ b/doc/xunit_setup.txt Thu Mar 03 23:40:38 2011 +0100 @@ -65,7 +65,7 @@ with a setup_method call. """ -If you rather define test functions directly at module level +If you would rather define test functions directly at module level you can also use the following functions to implement fixtures:: def setup_function(function): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sat Mar 5 14:29:17 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Sat, 05 Mar 2011 13:29:17 -0000 Subject: [py-svn] commit/pytest: hpk42: don't expose _fillfuncargs (no clue why it ever was exposed) Message-ID: <20110305132917.28527.52750@bitbucket01.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/931e46b39d9c/ changeset: r2170:931e46b39d9c user: hpk42 date: 2011-03-05 14:29:10 summary: don't expose _fillfuncargs (no clue why it ever was exposed) affected #: 1 file (40 bytes) --- a/testing/test_python.py Sat Mar 05 14:16:27 2011 +0100 +++ b/testing/test_python.py Sat Mar 05 14:29:10 2011 +0100 @@ -588,7 +588,8 @@ item.config.pluginmanager.register(Provider()) if hasattr(item, '_args'): del item._args - pytest._fillfuncargs(item) + from _pytest.python import fillfuncargs + fillfuncargs(item) assert len(item.funcargs) == 1 class TestRequest: Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sat Mar 5 14:31:11 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Sat, 05 Mar 2011 13:31:11 -0000 Subject: [py-svn] commit/pytest: hpk42: actually don't expose unused _fillfuncargs Message-ID: <20110305133111.28525.58769@bitbucket01.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/c8fc62195a92/ changeset: r2171:c8fc62195a92 user: hpk42 date: 2011-03-05 14:31:01 summary: actually don't expose unused _fillfuncargs affected #: 1 file (29 bytes) --- a/_pytest/python.py Sat Mar 05 14:29:10 2011 +0100 +++ b/_pytest/python.py Sat Mar 05 14:31:01 2011 +0100 @@ -34,7 +34,7 @@ 'collect': { 'Module': Module, 'Class': Class, 'Instance': Instance, 'Function': Function, 'Generator': Generator, - '_fillfuncargs': fillfuncargs} + } } def pytest_funcarg__pytestconfig(request): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sat Mar 5 14:16:34 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Sat, 05 Mar 2011 13:16:34 -0000 Subject: [py-svn] commit/pytest: 2 new changesets Message-ID: <20110305131634.25681.33974@bitbucket02.managed.contegix.com> 2 new changesets in pytest: http://bitbucket.org/hpk42/pytest/changeset/1eb351cf53d9/ changeset: r2168:1eb351cf53d9 user: hpk42 date: 2011-03-05 13:08:43 summary: improve and clarify skipping docs affected #: 2 files (1.1 KB) --- a/ISSUES.txt Sat Mar 05 12:11:35 2011 +0100 +++ b/ISSUES.txt Sat Mar 05 13:08:43 2011 +0100 @@ -88,6 +88,16 @@ on common spellings for operating systems and python interpreter versions. +pytest.mark.xfail signature change +------------------------------------------------------- +tags: feature 2.1 + +change to pytest.mark.xfail(reason, (optional)condition) +to better implement the word meaning. It also signals +better that we always have some kind of an implementation +reason that can be formualated. +Compatibility? Maybe rename to "pytest.mark.xfail"? + introduce py.test.mark registration ----------------------------------------- tags: feature 2.1 --- a/doc/skipping.txt Sat Mar 05 12:11:35 2011 +0100 +++ b/doc/skipping.txt Sat Mar 05 13:08:43 2011 +0100 @@ -1,20 +1,22 @@ - .. _`skip and xfail`: -skip and xfail mechanisms +skip and xfail: dealing with tests that can not succeed ===================================================================== -You can skip or "xfail" test functions, either by marking functions -with a decorator or by calling the ``pytest.skip|xfail`` functions. +If you have test functions that cannot be run on certain platforms +or that you expect to fail you can mark them accordingly or you +may call helper functions during execution of setup or test functions. -A *skip* means that you expect your test to pass unless a certain configuration or condition (e.g. wrong Python interpreter, missing dependency) prevents it to run. And *xfail* means that you expect your test to fail because there is an -implementation problem. py.test counts and lists *xfailing* tests separately -and it is possible to give additional information, such as bug number or a URL. +A *skip* means that you expect your test to pass unless a certain +configuration or condition (e.g. wrong Python interpreter, missing +dependency) prevents it to run. And *xfail* means that your test +can run but you expect it to fail because there is an implementation problem. -Detailed information about skipped/xfailed tests is by default not shown -at the end of a test run to avoid cluttering the output. You can use -the ``-r`` option to see details corresponding to the "short" letters -shown in the test progress:: +py.test counts and lists *skip* and *xfail* tests separately. However, +detailed information about skipped/xfailed tests is not shown by default +to avoid cluttering the output. You can use the ``-r`` option to see +details corresponding to the "short" letters shown in the test +progress:: py.test -rxs # show extra info on skips and xfails @@ -22,7 +24,7 @@ .. _skipif: -Skipping a single function +Marking a test function to be skipped ------------------------------------------- Here is an example of marking a test function to be skipped @@ -34,9 +36,9 @@ ... During test function setup the skipif condition is -evaluated by calling ``eval(expr, namespace)``. The namespace -contains all the module globals of the test function so that -you can for example check for versions:: +evaluated by calling ``eval('sys.version_info >= (3,0)', namespace)``. +(*New in version 2.0.2*) The namespace contains all the module globals of the test function so that +you can for example check for versions of a module you are using:: import mymodule @@ -44,23 +46,15 @@ def test_function(): ... -The test function will be skipped and not run if -mymodule is below the specified version. The reason +The test function will not be run ("skipped") if +``mymodule`` is below the specified version. The reason for specifying the condition as a string is mainly that -you can see more detailed reporting of xfail/skip reasons. +py.test can report a summary of skip conditions. +For information on the construction of the ``namespace`` +see `evaluation of skipif/xfail conditions`_. -Actually, the namespace is first initialized by -putting the ``sys`` and ``os`` modules and the test -``config`` object into it. And is then updated with -the module globals. The latter allows you to skip based -on a test configuration value:: - - @pytest.mark.skipif("not config.getvalue('db')") - def test_function(...): - ... - -You can create a shortcut for your conditional skip decorator -at module level like this:: +You can of course create a shortcut for your conditional skip +decorator at module level like this:: win32only = pytest.mark.skipif("sys.platform != 'win32'") @@ -68,11 +62,10 @@ def test_function(): ... - skip all test functions of a class -------------------------------------- -As with all function :ref:`mark` you can skip test functions at the +As with all function :ref:`marking ` you can skip test functions at the `whole class- or module level`_. Here is an example for skipping all methods of a test class based on the platform:: @@ -82,9 +75,10 @@ def test_function(self): "will not be setup or run under 'win32' platform" -The ``pytestmark`` decorator will be applied to each test function. -If your code targets python2.6 or above you can equivalently use -the skipif decorator on classes:: +The ``pytestmark`` special name tells py.test to apply it to each test +function in the class. If your code targets python2.6 or above you can +more naturally use the skipif decorator (and any other marker) on +classes:: @pytest.mark.skipif("sys.platform == 'win32'") class TestPosixCalls: @@ -155,6 +149,31 @@ ======================== 6 xfailed in 0.06 seconds ========================= +.. _`evaluation of skipif/xfail conditions`: + +evaluation of skipif/xfail expressions +---------------------------------------------------- + +.. versionadded:: 2.0.2 + +The evaluation of a condition string in ``pytest.mark.skipif(conditionstring)`` +or ``pytest.mark.xfail(conditionstring)`` takes place in a namespace +dictionary which is constructed as follows: + +* the namespace is initialized by putting the ``sys`` and ``os`` modules + and the pytest ``config`` object into it. + +* updated with the module globals of the test function for which the + expression is applied. + +The pytest ``config`` object allows you to skip based on a test configuration value +which you might have added:: + + @pytest.mark.skipif("not config.getvalue('db')") + def test_function(...): + ... + + imperative xfail from within a test or setup function ------------------------------------------------------ http://bitbucket.org/hpk42/pytest/changeset/02a623da9d67/ changeset: r2169:02a623da9d67 user: hpk42 date: 2011-03-05 14:16:27 summary: avoid deprecation warnings for our internal accesses affected #: 4 files (525 bytes) --- a/CHANGELOG Sat Mar 05 13:08:43 2011 +0100 +++ b/CHANGELOG Sat Mar 05 14:16:27 2011 +0100 @@ -32,6 +32,8 @@ - fixed typos in the docs (thanks Victor Garcia, Brianna Laugher) and particular thanks to Laura Creighton who also revieved parts of the documentation. +- more precise (avoiding of) deprecation warnings for node.Class|Function accesses + Changes between 2.0.0 and 2.0.1 ---------------------------------------------- --- a/_pytest/main.py Sat Mar 05 13:08:43 2011 +0100 +++ b/_pytest/main.py Sat Mar 05 14:16:27 2011 +0100 @@ -121,9 +121,6 @@ def compatproperty(name): def fget(self): - #print "retrieving %r property from %s" %(name, self.fspath) - py.log._apiwarn("2.0", "use pytest.%s for " - "test collection and item classes" % name) return getattr(pytest, name) return property(fget, None, None, "deprecated attribute %r, use pytest.%s" % (name,name)) @@ -157,6 +154,14 @@ File = compatproperty("File") Item = compatproperty("Item") + def _getcustomclass(self, name): + cls = getattr(self, name) + if cls != getattr(pytest, name): + py.log._apiwarn("2.0", "use of node.%s is deprecated, " + "use pytest_pycollect_makeitem(...) to create custom " + "collection nodes" % name) + return cls + def __repr__(self): return "<%s %r>" %(self.__class__.__name__, getattr(self, 'name', None)) --- a/_pytest/python.py Sat Mar 05 13:08:43 2011 +0100 +++ b/_pytest/python.py Sat Mar 05 14:16:27 2011 +0100 @@ -73,7 +73,8 @@ if collector._istestclasscandidate(name, obj): #if hasattr(collector.obj, 'unittest'): # return # we assume it's a mixin class for a TestCase derived one - return collector.Class(name, parent=collector) + Class = collector._getcustomclass("Class") + return Class(name, parent=collector) elif collector.funcnamefilter(name) and hasattr(obj, '__call__'): if is_generator(obj): return Generator(name, parent=collector) @@ -213,16 +214,18 @@ extra.append(cls()) plugins = self.getplugins() + extra gentesthook.pcall(plugins, metafunc=metafunc) + Function = self._getcustomclass("Function") if not metafunc._calls: - return self.Function(name, parent=self) + return Function(name, parent=self) l = [] for callspec in metafunc._calls: subname = "%s[%s]" %(name, callspec.id) - function = self.Function(name=subname, parent=self, + function = Function(name=subname, parent=self, callspec=callspec, callobj=funcobj, keywords={callspec.id:True}) l.append(function) return l + class Module(pytest.File, PyCollectorMixin): def _getobj(self): return self._memoizedcall('_obj', self._importtestmodule) @@ -272,7 +275,7 @@ class Class(PyCollectorMixin, pytest.Collector): def collect(self): - return [self.Instance(name="()", parent=self)] + return [self._getcustomclass("Instance")(name="()", parent=self)] def setup(self): setup_class = getattr(self.obj, 'setup_class', None) --- a/testing/test_collection.py Sat Mar 05 13:08:43 2011 +0100 +++ b/testing/test_collection.py Sat Mar 05 14:16:27 2011 +0100 @@ -15,15 +15,10 @@ """) recwarn.clear() assert modcol.Module == pytest.Module - recwarn.pop(DeprecationWarning) assert modcol.Class == pytest.Class - recwarn.pop(DeprecationWarning) assert modcol.Item == pytest.Item - recwarn.pop(DeprecationWarning) assert modcol.File == pytest.File - recwarn.pop(DeprecationWarning) assert modcol.Function == pytest.Function - recwarn.pop(DeprecationWarning) def test_check_equality(self, testdir): modcol = testdir.getmodulecol(""" Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sat Mar 5 14:59:13 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Sat, 05 Mar 2011 13:59:13 -0000 Subject: [py-svn] commit/pytest: hpk42: avoid this test on pypy because syntax errors on pypy-1.4.1 are not precise it seems Message-ID: <20110305135913.27951.65191@bitbucket03.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/ddf448707b62/ changeset: r2172:ddf448707b62 user: hpk42 date: 2011-03-05 14:59:06 summary: avoid this test on pypy because syntax errors on pypy-1.4.1 are not precise it seems affected #: 1 file (56 bytes) --- a/testing/test_skipping.py Sat Mar 05 14:31:01 2011 +0100 +++ b/testing/test_skipping.py Sat Mar 05 14:59:06 2011 +0100 @@ -471,6 +471,7 @@ "SKIP*four*", ]) + at pytest.mark.xfail("hasattr(sys, 'pypy_version_info')") def test_errors_in_xfail_skip_expressions(testdir): testdir.makepyfile(""" import pytest Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sat Mar 5 12:11:49 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Sat, 05 Mar 2011 11:11:49 -0000 Subject: [py-svn] commit/pytest: hpk42: fix and improve error reporting for parametrizing funcargs (originally reported by antlong) Message-ID: <20110305111149.28526.52031@bitbucket01.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/6052cd017741/ changeset: r2167:6052cd017741 user: hpk42 date: 2011-03-05 12:11:35 summary: fix and improve error reporting for parametrizing funcargs (originally reported by antlong) affected #: 4 files (976 bytes) --- a/_pytest/python.py Thu Mar 03 23:40:38 2011 +0100 +++ b/_pytest/python.py Sat Mar 05 12:11:35 2011 +0100 @@ -486,10 +486,11 @@ return True -def getfuncargnames(function): +def getfuncargnames(function, startindex=None): # XXX merge with main.py's varnames argnames = py.std.inspect.getargs(py.code.getrawcode(function))[0] - startindex = py.std.inspect.ismethod(function) and 1 or 0 + if startindex is None: + startindex = py.std.inspect.ismethod(function) and 1 or 0 defaults = getattr(function, 'func_defaults', getattr(function, '__defaults__', None)) or () numdefaults = len(defaults) @@ -518,7 +519,8 @@ self.config = config self.module = module self.function = function - self.funcargnames = getfuncargnames(function) + self.funcargnames = getfuncargnames(function, + startindex=int(cls is not None)) self.cls = cls self.module = module self._calls = [] @@ -526,7 +528,11 @@ def addcall(self, funcargs=None, id=_notexists, param=_notexists): """ add a new call to the underlying test function during the - collection phase of a test run. + collection phase of a test run. Note that request.addcall() is + called during the test collection phase prior and independently + to actual test execution. Therefore you should perform setup + of resources in a funcarg factory which can be instrumented + with the ``param``. :arg funcargs: argument keyword dictionary used when invoking the test function. @@ -538,10 +544,13 @@ :arg param: will be exposed to a later funcarg factory invocation through the ``request.param`` attribute. It allows to defer test fixture setup activities to when an actual - test is run. Note that request.addcall() is called during - the collection phase of a test run. + test is run. """ assert funcargs is None or isinstance(funcargs, dict) + if funcargs is not None: + for name in funcargs: + if name not in self.funcargnames: + pytest.fail("funcarg %r not used in this function." % name) if id is None: raise ValueError("id=None not allowed") if id is _notexists: --- a/pytest.py Thu Mar 03 23:40:38 2011 +0100 +++ b/pytest.py Sat Mar 05 12:11:35 2011 +0100 @@ -1,7 +1,7 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.2.dev2' +__version__ = '2.0.2.dev3' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins --- a/setup.py Thu Mar 03 23:40:38 2011 +0100 +++ b/setup.py Sat Mar 05 12:11:35 2011 +0100 @@ -22,7 +22,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.2.dev2', + version='2.0.2.dev3', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], --- a/testing/test_python.py Thu Mar 03 23:40:38 2011 +0100 +++ b/testing/test_python.py Sat Mar 05 12:11:35 2011 +0100 @@ -915,11 +915,12 @@ assert metafunc._calls[2].param == 1 def test_addcall_funcargs(self): - def func(arg1): pass + def func(x): pass metafunc = funcargs.Metafunc(func) class obj: pass metafunc.addcall(funcargs={"x": 2}) metafunc.addcall(funcargs={"x": 3}) + pytest.raises(pytest.fail.Exception, "metafunc.addcall({'xyz': 0})") assert len(metafunc._calls) == 2 assert metafunc._calls[0].funcargs == {'x': 2} assert metafunc._calls[1].funcargs == {'x': 3} @@ -1003,6 +1004,21 @@ "*1 failed, 3 passed*" ]) + def test_noself_in_method(self, testdir): + p = testdir.makepyfile(""" + def pytest_generate_tests(metafunc): + assert 'xyz' not in metafunc.funcargnames + + class TestHello: + def test_hello(xyz): + pass + """) + result = testdir.runpytest(p) + result.stdout.fnmatch_lines([ + "*1 pass*", + ]) + + def test_generate_plugin_and_module(self, testdir): testdir.makeconftest(""" def pytest_generate_tests(metafunc): @@ -1339,5 +1355,3 @@ "*MyInstance*", "*MyFunction*test_hello*", ]) - - Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sat Mar 5 18:22:40 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Sat, 05 Mar 2011 17:22:40 -0000 Subject: [py-svn] commit/pytest: 2 new changesets Message-ID: <20110305172240.27950.74179@bitbucket03.managed.contegix.com> 2 new changesets in pytest: http://bitbucket.org/hpk42/pytest/changeset/dabda93214ff/ changeset: r2173:dabda93214ff user: RonnyPfannschmidt date: 2011-03-05 17:49:51 summary: unittest plugin: prune __unittest marked modules from traces affected #: 2 files (527 bytes) --- a/_pytest/unittest.py Sat Mar 05 14:59:06 2011 +0100 +++ b/_pytest/unittest.py Sat Mar 05 17:49:51 2011 +0100 @@ -102,6 +102,10 @@ def runtest(self): self._testcase(result=self) + def _prunetraceback(self, excinfo): + pytest.Function._prunetraceback(self, excinfo) + excinfo.traceback = excinfo.traceback.filter(lambda x:not x.frame.f_globals.get('__unittest')) + @pytest.mark.tryfirst def pytest_runtest_makereport(item, call): if isinstance(item, TestCaseFunction): --- a/testing/test_unittest.py Sat Mar 05 14:59:06 2011 +0100 +++ b/testing/test_unittest.py Sat Mar 05 17:49:51 2011 +0100 @@ -396,3 +396,15 @@ "*tearDown()*", "*_post_teardown()*", ]) + + +def test_unittest_not_shown_in_traceback(testdir): + testdir.makepyfile(""" + import unittest + class t(unittest.TestCase): + def test_hello(self): + x = 3 + self.assertEquals(x, 4) + """) + res = testdir.runpytest() + assert "failUnlessEqual" not in res.stdout.str() http://bitbucket.org/hpk42/pytest/changeset/3d6a55da94de/ changeset: r2174:3d6a55da94de user: hpk42 date: 2011-03-05 18:22:33 summary: add changelog entry about unittest change, bump version affected #: 3 files (73 bytes) --- a/CHANGELOG Sat Mar 05 17:49:51 2011 +0100 +++ b/CHANGELOG Sat Mar 05 18:22:33 2011 +0100 @@ -34,6 +34,8 @@ - more precise (avoiding of) deprecation warnings for node.Class|Function accesses +- avoid std unittest assertion helper code in tracebacks (thanks Ronny) + Changes between 2.0.0 and 2.0.1 ---------------------------------------------- --- a/pytest.py Sat Mar 05 17:49:51 2011 +0100 +++ b/pytest.py Sat Mar 05 18:22:33 2011 +0100 @@ -1,7 +1,7 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.2.dev3' +__version__ = '2.0.2.dev4' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins --- a/setup.py Sat Mar 05 17:49:51 2011 +0100 +++ b/setup.py Sat Mar 05 18:22:33 2011 +0100 @@ -22,7 +22,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.2.dev3', + version='2.0.2.dev4', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sun Mar 6 08:57:06 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Sun, 06 Mar 2011 07:57:06 -0000 Subject: [py-svn] commit/pytest: hpk42: re-introduce pytest._fillfuncargs - it's actually used by oejskit, Message-ID: <20110306075706.25682.37540@bitbucket02.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/a3511ec33ee3/ changeset: r2175:a3511ec33ee3 user: hpk42 date: 2011-03-06 08:56:58 summary: re-introduce pytest._fillfuncargs - it's actually used by oejskit, added a test documenting this. affected #: 2 files (158 bytes) --- a/_pytest/python.py Sat Mar 05 18:22:33 2011 +0100 +++ b/_pytest/python.py Sun Mar 06 08:56:58 2011 +0100 @@ -34,7 +34,7 @@ 'collect': { 'Module': Module, 'Class': Class, 'Instance': Instance, 'Function': Function, 'Generator': Generator, - } + '_fillfuncargs': fillfuncargs} } def pytest_funcarg__pytestconfig(request): --- a/testing/test_python.py Sat Mar 05 18:22:33 2011 +0100 +++ b/testing/test_python.py Sun Mar 06 08:56:58 2011 +0100 @@ -517,6 +517,10 @@ repr(cs) class TestFillFuncArgs: + def test_fillfuncargs_exposed(self): + # used by oejskit + assert pytest._fillfuncargs == funcargs.fillfuncargs + def test_funcarg_lookupfails(self, testdir): testdir.makeconftest(""" def pytest_funcarg__xyzsomething(request): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sun Mar 6 18:32:30 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Sun, 06 Mar 2011 17:32:30 -0000 Subject: [py-svn] commit/pytest: hpk42: fix issue27 - --collectonly and -k keyword selection now work together. Message-ID: <20110306173230.27951.96605@bitbucket03.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/39bc4edbfdf1/ changeset: r2176:39bc4edbfdf1 user: hpk42 date: 2011-03-06 18:32:00 summary: fix issue27 - --collectonly and -k keyword selection now work together. internally, collectonly and terminal reporting has been unified. affected #: 8 files (1.8 KB) --- a/CHANGELOG Sun Mar 06 08:56:58 2011 +0100 +++ b/CHANGELOG Sun Mar 06 18:32:00 2011 +0100 @@ -1,12 +1,12 @@ Changes between 2.0.1 and 2.0.2 ---------------------------------------------- -- fix issue30 - extended xfail/skipif handling and better reporting. +- fix issue30 - extended xfail/skipif handling and improved reporting. If you have a syntax error in your skip/xfail expressions you now get nice error reports. Also you can now access module globals from xfail/skipif - expressions so that this works now:: + expressions so that this for example works now:: import mymodule @pytest.mark.skipif("mymodule.__version__[0] == "1") @@ -24,6 +24,11 @@ test function invocations generated from the pytest_generate_tests hook. +- fix issue27 - collectonly and keyword-selection (-k) now work together + Also, if you do "py.test --collectonly -q" you now get a flat list + of test ids that you can use to paste to the py.test commandline + in order to execute a particular test. + - fix issue23 - tmpdir argument now works on Python3.2 and WindowsXP Starting with Python3.2 os.symlink may be supported. By requiring a newer py lib version the py.path.local() implementation acknowledges --- a/_pytest/terminal.py Sun Mar 06 08:56:58 2011 +0100 +++ b/_pytest/terminal.py Sun Mar 06 18:32:00 2011 +0100 @@ -32,22 +32,19 @@ def pytest_configure(config): config.option.verbose -= config.option.quiet - if config.option.collectonly: - reporter = CollectonlyReporter(config) - else: - # we try hard to make printing resilient against - # later changes on FD level. - stdout = py.std.sys.stdout - if hasattr(os, 'dup') and hasattr(stdout, 'fileno'): - try: - newfd = os.dup(stdout.fileno()) - #print "got newfd", newfd - except ValueError: - pass - else: - stdout = os.fdopen(newfd, stdout.mode, 1) - config._toclose = stdout - reporter = TerminalReporter(config, stdout) + # we try hard to make printing resilient against + # later changes on FD level. + stdout = py.std.sys.stdout + if hasattr(os, 'dup') and hasattr(stdout, 'fileno'): + try: + newfd = os.dup(stdout.fileno()) + #print "got newfd", newfd + except ValueError: + pass + else: + stdout = os.fdopen(newfd, stdout.mode, 1) + config._toclose = stdout + reporter = TerminalReporter(config, stdout) config.pluginmanager.register(reporter, 'terminalreporter') if config.option.debug or config.option.traceconfig: def mywriter(tags, args): @@ -273,11 +270,44 @@ for line in flatten(lines): self.write_line(line) - def pytest_collection_finish(self): + def pytest_collection_finish(self, session): + if self.config.option.collectonly: + self._printcollecteditems(session.items) + if self.stats.get('failed'): + self._tw.sep("!", "collection failures") + for rep in self.stats.get('failed'): + rep.toterminal(self._tw) + return 1 + return 0 if not self.showheader: return #for i, testarg in enumerate(self.config.args): # self.write_line("test path %d: %s" %(i+1, testarg)) + + def _printcollecteditems(self, items): + # to print out items and their parent collectors + # we take care to leave out Instances aka () + # because later versions are going to get rid of them anyway + if self.config.option.verbose < 0: + for item in items: + nodeid = item.nodeid + nodeid = nodeid.replace("::()::", "::") + self._tw.line(nodeid) + return + stack = [] + indent = "" + for item in items: + needed_collectors = item.listchain()[1:] # strip root node + while stack: + if stack == needed_collectors[:len(stack)]: + break + stack.pop() + for col in needed_collectors[len(stack):]: + stack.append(col) + #if col.name == "()": + # continue + indent = (len(stack)-1) * " " + self._tw.line("%s%s" %(indent, col)) def pytest_sessionfinish(self, exitstatus, __multicall__): __multicall__.execute() @@ -403,52 +433,6 @@ self.write_sep("=", "%d tests deselected by %r" %( len(self.stats['deselected']), self.config.option.keyword), bold=True) - -class CollectonlyReporter: - INDENT = " " - - def __init__(self, config, out=None): - self.config = config - if out is None: - out = py.std.sys.stdout - self._tw = py.io.TerminalWriter(out) - self.indent = "" - self._failed = [] - - def outindent(self, line): - self._tw.line(self.indent + str(line)) - - def pytest_internalerror(self, excrepr): - for line in str(excrepr).split("\n"): - self._tw.line("INTERNALERROR> " + line) - - def pytest_collectstart(self, collector): - if collector.session != collector: - self.outindent(collector) - self.indent += self.INDENT - - def pytest_itemcollected(self, item): - self.outindent(item) - - def pytest_collectreport(self, report): - if not report.passed: - if hasattr(report.longrepr, 'reprcrash'): - msg = report.longrepr.reprcrash.message - else: - # XXX unify (we have CollectErrorRepr here) - msg = str(report.longrepr[2]) - self.outindent("!!! %s !!!" % msg) - #self.outindent("!!! error !!!") - self._failed.append(report) - self.indent = self.indent[:-len(self.INDENT)] - - def pytest_collection_finish(self): - if self._failed: - self._tw.sep("!", "collection failures") - for rep in self._failed: - rep.toterminal(self._tw) - return self._failed and 1 or 0 - def repr_pythonversion(v=None): if v is None: v = sys.version_info --- a/pytest.py Sun Mar 06 08:56:58 2011 +0100 +++ b/pytest.py Sun Mar 06 18:32:00 2011 +0100 @@ -1,7 +1,7 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.2.dev4' +__version__ = '2.0.2.dev5' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins --- a/setup.py Sun Mar 06 08:56:58 2011 +0100 +++ b/setup.py Sun Mar 06 18:32:00 2011 +0100 @@ -22,7 +22,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.2.dev4', + version='2.0.2.dev5', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], --- a/testing/acceptance_test.py Sun Mar 06 08:56:58 2011 +0100 +++ b/testing/acceptance_test.py Sun Mar 06 18:32:00 2011 +0100 @@ -89,9 +89,11 @@ import pytest class MyFile(pytest.File): def collect(self): - return + return [MyItem("hello", parent=self)] def pytest_collect_file(path, parent): return MyFile(path, parent) + class MyItem(pytest.Item): + pass """) p = testdir.makepyfile("def test_hello(): pass") result = testdir.runpytest(p, "--collectonly") --- a/testing/test_collection.py Sun Mar 06 08:56:58 2011 +0100 +++ b/testing/test_collection.py Sun Mar 06 18:32:00 2011 +0100 @@ -94,6 +94,8 @@ tmpdir.ensure(".whatever", 'test_notfound.py') tmpdir.ensure(".bzr", 'test_notfound.py') tmpdir.ensure("normal", 'test_found.py') + for x in tmpdir.visit("test_*.py"): + x.write("def test_hello(): pass") result = testdir.runpytest("--collectonly") s = result.stdout.str() --- a/testing/test_python.py Sun Mar 06 08:56:58 2011 +0100 +++ b/testing/test_python.py Sun Mar 06 18:32:00 2011 +0100 @@ -359,8 +359,8 @@ if path.basename == "test_xyz.py": return MyModule(path, parent) """) - testdir.makepyfile("def some(): pass") - testdir.makepyfile(test_xyz="") + testdir.makepyfile("def test_some(): pass") + testdir.makepyfile(test_xyz="def test_func(): pass") result = testdir.runpytest("--collectonly") result.stdout.fnmatch_lines([ "*" - ]) - item = modcol.collect()[0] - rep.config.hook.pytest_itemcollected(item=item) - linecomp.assert_contains_lines([ + result = testdir.runpytest("--collectonly",) + result.stdout.fnmatch_lines([ + "", " ", ]) - report = rep.config.hook.pytest_make_collect_report(collector=modcol) - rep.config.hook.pytest_collectreport(report=report) - assert rep.indent == indent - def test_collectonly_skipped_module(self, testdir, linecomp): - modcol = testdir.getmodulecol(configargs=['--collectonly'], source=""" + def test_collectonly_skipped_module(self, testdir): + testdir.makepyfile(""" import pytest - pytest.skip("nomod") + pytest.skip("hello") """) - rep = CollectonlyReporter(modcol.config, out=linecomp.stringio) - modcol.config.pluginmanager.register(rep) - cols = list(testdir.genitems([modcol])) - assert len(cols) == 0 - linecomp.assert_contains_lines(""" - - !!! Skipped: nomod !!! - """) + result = testdir.runpytest("--collectonly", "-rs") + result.stdout.fnmatch_lines([ + "SKIP*hello*", + "*1 skip*", + ]) - def test_collectonly_failed_module(self, testdir, linecomp): - modcol = testdir.getmodulecol(configargs=['--collectonly'], source=""" - raise ValueError(0) - """) - rep = CollectonlyReporter(modcol.config, out=linecomp.stringio) - modcol.config.pluginmanager.register(rep) - cols = list(testdir.genitems([modcol])) - assert len(cols) == 0 - linecomp.assert_contains_lines(""" - - !!! ValueError: 0 !!! - """) + def test_collectonly_failed_module(self, testdir): + testdir.makepyfile("""raise ValueError(0)""") + result = testdir.runpytest("--collectonly") + result.stdout.fnmatch_lines([ + "*raise ValueError*", + "*1 error*", + ]) def test_collectonly_fatal(self, testdir): p1 = testdir.makeconftest(""" @@ -228,11 +209,11 @@ stderr = result.stderr.str().strip() #assert stderr.startswith("inserting into sys.path") assert result.ret == 0 - extra = result.stdout.fnmatch_lines([ + result.stdout.fnmatch_lines([ "*", "* ", "* ", - "* ", + #"* ", "* ", ]) @@ -241,11 +222,11 @@ result = testdir.runpytest("--collectonly", p) stderr = result.stderr.str().strip() assert result.ret == 1 - extra = result.stdout.fnmatch_lines(py.code.Source(""" - * - *ImportError* - *!!!*failures*!!! - *test_collectonly_error.py:1* + result.stdout.fnmatch_lines(py.code.Source(""" + *ERROR* + *import Errlk* + *ImportError* + *1 error* """).strip()) Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sun Mar 6 18:32:40 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Sun, 06 Mar 2011 17:32:40 -0000 Subject: [py-svn] commit/py: hpk42: finalize small py lib release Message-ID: <20110306173240.28527.65538@bitbucket01.managed.contegix.com> 1 new changeset in py: http://bitbucket.org/hpk42/py/changeset/a7beea9c0e38/ changeset: r2009:a7beea9c0e38 user: hpk42 date: 2011-03-06 18:28:00 summary: finalize small py lib release affected #: 3 files (11 bytes) --- a/README.txt Thu Mar 03 12:11:24 2011 +0100 +++ b/README.txt Sun Mar 06 18:28:00 2011 +0100 @@ -16,5 +16,5 @@ Mailing lists and more contact points: http://pylib.org/contact.html -(c) Holger Krekel and others, 2004-2010 +(c) Holger Krekel and others, 2004-2011 --- a/py/__init__.py Thu Mar 03 12:11:24 2011 +0100 +++ b/py/__init__.py Sun Mar 06 18:28:00 2011 +0100 @@ -8,7 +8,7 @@ (c) Holger Krekel and others, 2004-2010 """ -__version__ = '1.4.2.dev0' +__version__ = '1.4.2' from py import _apipkg --- a/setup.py Thu Mar 03 12:11:24 2011 +0100 +++ b/setup.py Sun Mar 06 18:28:00 2011 +0100 @@ -9,7 +9,7 @@ name='py', description='library with cross-python path, ini-parsing, io, code, log facilities', long_description = open('README.txt').read(), - version='1.4.2.dev0', + version='1.4.2', url='http://pylib.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], @@ -37,4 +37,4 @@ ) if __name__ == '__main__': - main() + main() \ No newline at end of file Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Mon Mar 7 13:16:59 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Mon, 07 Mar 2011 12:16:59 -0000 Subject: [py-svn] commit/py: hpk42: fix un-coloring on windows by resetting the color before the newline Message-ID: <20110307121659.28525.55359@bitbucket01.managed.contegix.com> 1 new changeset in py: http://bitbucket.org/hpk42/py/changeset/489711be9a2d/ changeset: r2010:489711be9a2d user: hpk42 date: 2011-03-07 13:16:52 summary: fix un-coloring on windows by resetting the color before the newline affected #: 2 files (129 bytes) --- a/CHANGELOG Sun Mar 06 18:28:00 2011 +0100 +++ b/CHANGELOG Mon Mar 07 13:16:52 2011 +0100 @@ -6,6 +6,8 @@ - better error message for syntax errors from compiled code +- small fix to better deal with (un-)colored terminal output on windows + Changes between 1.4.0 and 1.4.1 ================================================== --- a/py/_io/terminalwriter.py Sun Mar 06 18:28:00 2011 +0100 +++ b/py/_io/terminalwriter.py Mon Mar 07 13:16:52 2011 +0100 @@ -211,7 +211,8 @@ SetConsoleTextAttribute(handle, oldcolors) def line(self, s="", **kw): - self.write(s+"\n", **kw) + self.write(s, **kw) # works better for resetting colors + self.write("\n") class WriteFile(object): def __init__(self, writemethod, encoding=None): Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Mon Mar 7 13:17:23 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Mon, 07 Mar 2011 12:17:23 -0000 Subject: [py-svn] commit/pytest: 2 new changesets Message-ID: <20110307121723.28526.71639@bitbucket01.managed.contegix.com> 2 new changesets in pytest: http://bitbucket.org/hpk42/pytest/changeset/2c11c4a67f9b/ changeset: r2177:2c11c4a67f9b user: hpk42 date: 2011-03-07 11:53:14 summary: mention that one might need to use the pypi.testrun.org repository affected #: 1 file (191 bytes) --- a/doc/develop.txt Sun Mar 06 18:32:00 2011 +0100 +++ b/doc/develop.txt Mon Mar 07 11:53:14 2011 +0100 @@ -31,4 +31,10 @@ in order to work inline with the tools and the lib of your checkout. +If this command complains that it could not find the required version +of "py" then you need to use the development pypi repository:: + + python setup.py develop -i http://pypi.testrun.org + + .. include:: links.inc http://bitbucket.org/hpk42/pytest/changeset/221f4351b833/ changeset: r2178:221f4351b833 user: hpk42 date: 2011-03-07 13:17:07 summary: fix issue25 --pdb and win32/python encodings cause a crash in certain situations. The reason is not clear but avoiding a fresh copy of the terminal writer helps, maybe because the underlying file object has some state? affected #: 4 files (293 bytes) --- a/CHANGELOG Mon Mar 07 11:53:14 2011 +0100 +++ b/CHANGELOG Mon Mar 07 13:17:07 2011 +0100 @@ -29,6 +29,8 @@ of test ids that you can use to paste to the py.test commandline in order to execute a particular test. +- fix issue25 avoid reported problems with --pdb and python3.2/encodings output + - fix issue23 - tmpdir argument now works on Python3.2 and WindowsXP Starting with Python3.2 os.symlink may be supported. By requiring a newer py lib version the py.path.local() implementation acknowledges --- a/_pytest/pdb.py Mon Mar 07 11:53:14 2011 +0100 +++ b/_pytest/pdb.py Mon Mar 07 13:17:07 2011 +0100 @@ -52,7 +52,10 @@ if "xfail" in rep.keywords: return rep # we assume that the above execute() suspended capturing - tw = py.io.TerminalWriter() + # XXX we re-use the TerminalReporter's terminalwriter + # because this seems to avoid some encoding related troubles + # for not completely clear reasons. + tw = item.config.pluginmanager.getplugin("terminalreporter")._tw tw.line() tw.sep(">", "traceback") rep.toterminal(tw) --- a/pytest.py Mon Mar 07 11:53:14 2011 +0100 +++ b/pytest.py Mon Mar 07 13:17:07 2011 +0100 @@ -1,7 +1,7 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.2.dev5' +__version__ = '2.0.2.dev6' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins --- a/setup.py Mon Mar 07 11:53:14 2011 +0100 +++ b/setup.py Mon Mar 07 13:17:07 2011 +0100 @@ -22,7 +22,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.2.dev5', + version='2.0.2.dev6', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Mon Mar 7 18:29:02 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Mon, 07 Mar 2011 17:29:02 -0000 Subject: [py-svn] commit/pytest: hpk42: half the overhead for calling a test function by introducing some caching Message-ID: <20110307172902.27949.76158@bitbucket03.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/2385ebbf4532/ changeset: r2179:2385ebbf4532 user: hpk42 date: 2011-03-07 18:28:45 summary: half the overhead for calling a test function by introducing some caching affected #: 7 files (996 bytes) --- a/CHANGELOG Mon Mar 07 13:17:07 2011 +0100 +++ b/CHANGELOG Mon Mar 07 18:28:45 2011 +0100 @@ -1,6 +1,8 @@ Changes between 2.0.1 and 2.0.2 ---------------------------------------------- +- tackle issue32 - half the overhead for running test functions + - fix issue30 - extended xfail/skipif handling and improved reporting. If you have a syntax error in your skip/xfail expressions you now get nice error reports. --- a/_pytest/core.py Mon Mar 07 13:17:07 2011 +0100 +++ b/_pytest/core.py Mon Mar 07 18:28:45 2011 +0100 @@ -60,6 +60,7 @@ class PluginManager(object): def __init__(self, load=False): self._name2plugin = {} + self._listattrcache = {} self._plugins = [] self._hints = [] self.trace = TagTracer().get("pluginmanage") @@ -272,6 +273,11 @@ def listattr(self, attrname, plugins=None): if plugins is None: plugins = self._plugins + key = (attrname,) + tuple(plugins) + try: + return list(self._listattrcache[key]) + except KeyError: + pass l = [] last = [] for plugin in plugins: @@ -286,6 +292,7 @@ except AttributeError: continue l.extend(last) + self._listattrcache[key] = list(l) return l def call_plugin(self, plugin, methname, kwargs): @@ -340,14 +347,20 @@ return kwargs def varnames(func): + try: + return func._varnames + except AttributeError: + pass if not inspect.isfunction(func) and not inspect.ismethod(func): func = getattr(func, '__call__', func) ismethod = inspect.ismethod(func) rawcode = py.code.getrawcode(func) try: - return rawcode.co_varnames[ismethod:rawcode.co_argcount] + x = rawcode.co_varnames[ismethod:rawcode.co_argcount] except AttributeError: - return () + x = () + py.builtin._getfuncdict(func)['_varnames'] = x + return x class HookRelay: def __init__(self, hookspecs, pm, prefix="pytest_"): --- a/_pytest/helpconfig.py Mon Mar 07 13:17:07 2011 +0100 +++ b/_pytest/helpconfig.py Mon Mar 07 18:28:45 2011 +0100 @@ -2,6 +2,7 @@ import py import pytest import inspect, sys +from _pytest.core import varnames def pytest_addoption(parser): group = parser.getgroup('debugconfig') @@ -135,12 +136,11 @@ fail = True else: #print "checking", method - method_args = getargs(method) - #print "method_args", method_args + method_args = list(varnames(method)) if '__multicall__' in method_args: method_args.remove('__multicall__') hook = hooks[name] - hookargs = getargs(hook) + hookargs = varnames(hook) for arg in method_args: if arg not in hookargs: Print("argument %r not available" %(arg, )) @@ -162,11 +162,6 @@ return name == "pytest_plugins" or \ name.startswith("pytest_funcarg__") -def getargs(func): - args = inspect.getargs(py.code.getrawcode(func))[0] - startindex = inspect.ismethod(func) and 1 or 0 - return args[startindex:] - def collectattr(obj): methods = {} for apiname in dir(obj): --- a/_pytest/main.py Mon Mar 07 13:17:07 2011 +0100 +++ b/_pytest/main.py Mon Mar 07 18:28:45 2011 +0100 @@ -326,7 +326,13 @@ return self._location except AttributeError: location = self.reportinfo() - fspath = self.session.fspath.bestrelpath(location[0]) + # bestrelpath is a quite slow function + cache = self.config.__dict__.setdefault("_bestrelpathcache", {}) + try: + fspath = cache[location[0]] + except KeyError: + fspath = self.session.fspath.bestrelpath(location[0]) + cache[location[0]] = fspath location = (fspath, location[1], str(location[2])) self._location = location return location --- a/pytest.py Mon Mar 07 13:17:07 2011 +0100 +++ b/pytest.py Mon Mar 07 18:28:45 2011 +0100 @@ -1,7 +1,7 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.2.dev6' +__version__ = '2.0.2.dev7' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins --- a/setup.py Mon Mar 07 13:17:07 2011 +0100 +++ b/setup.py Mon Mar 07 18:28:45 2011 +0100 @@ -22,7 +22,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.2.dev6', + version='2.0.2.dev7', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], --- a/testing/test_core.py Mon Mar 07 13:17:07 2011 +0100 +++ b/testing/test_core.py Mon Mar 07 18:28:45 2011 +0100 @@ -433,6 +433,9 @@ pluginmanager.register(p3) methods = pluginmanager.listattr('m') assert methods == [p2.m, p3.m, p1.m] + # listattr keeps a cache and deleting + # a function attribute requires clearing it + pluginmanager._listattrcache.clear() del P1.m.__dict__['tryfirst'] pytest.mark.trylast(getattr(P2.m, 'im_func', P2.m)) Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Tue Mar 8 13:37:10 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Tue, 08 Mar 2011 12:37:10 -0000 Subject: [py-svn] commit/pytest: hpk42: fix slightly wrong verbose output for non subclasses on windows Message-ID: <20110308123710.30891.34671@bitbucket02.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/6cbbd04b2f99/ changeset: r2180:6cbbd04b2f99 user: hpk42 date: 2011-03-08 13:37:00 summary: fix slightly wrong verbose output for non subclasses on windows affected #: 3 files (581 bytes) --- a/CHANGELOG Mon Mar 07 18:28:45 2011 +0100 +++ b/CHANGELOG Tue Mar 08 13:37:00 2011 +0100 @@ -41,6 +41,9 @@ - fixed typos in the docs (thanks Victor Garcia, Brianna Laugher) and particular thanks to Laura Creighton who also revieved parts of the documentation. +- fix slighly wrong output of verbose progress reporting for classes + (thanks Amaury) + - more precise (avoiding of) deprecation warnings for node.Class|Function accesses - avoid std unittest assertion helper code in tracebacks (thanks Ronny) --- a/_pytest/terminal.py Mon Mar 07 18:28:45 2011 +0100 +++ b/_pytest/terminal.py Tue Mar 08 13:37:00 2011 +0100 @@ -283,7 +283,7 @@ return #for i, testarg in enumerate(self.config.args): # self.write_line("test path %d: %s" %(i+1, testarg)) - + def _printcollecteditems(self, items): # to print out items and their parent collectors # we take care to leave out Instances aka () @@ -335,7 +335,7 @@ excrepr.reprcrash.toterminal(self._tw) def _locationline(self, collect_fspath, fspath, lineno, domain): - if fspath and fspath != collect_fspath: + if fspath and fspath.replace("\\", "/") != collect_fspath: fspath = "%s <- %s" % (collect_fspath, fspath) if lineno is not None: lineno += 1 --- a/testing/test_terminal.py Mon Mar 07 18:28:45 2011 +0100 +++ b/testing/test_terminal.py Tue Mar 08 13:37:00 2011 +0100 @@ -130,6 +130,20 @@ "*test_p2.py <- *test_p1.py:2: TestMore.test_p1*", ]) + def test_itemreport_directclasses_not_shown_as_subclasses(self, testdir): + a = testdir.mkpydir("a") + a.join("test_hello.py").write(py.code.Source(""" + class TestClass: + def test_method(self): + pass + """)) + result = testdir.runpytest("-v") + assert result.ret == 0 + result.stdout.fnmatch_lines([ + "*a/test_hello.py*PASS*", + ]) + assert " <- " not in result.stdout.str() + def test_keyboard_interrupt(self, testdir, option): p = testdir.makepyfile(""" def test_foobar(): @@ -399,6 +413,7 @@ "*test_verbose_reporting.py:10: test_gen*FAIL*", ]) assert result.ret == 1 + pytestconfig.pluginmanager.skipifmissing("xdist") result = testdir.runpytest(p1, '-v', '-n 1') result.stdout.fnmatch_lines([ @@ -507,7 +522,7 @@ result.stderr.fnmatch_lines([ "*registered*PluginManager*" ]) - + class TestGenericReporting: """ this test class can be subclassed with a different option Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Tue Mar 8 13:45:10 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Tue, 08 Mar 2011 12:45:10 -0000 Subject: [py-svn] commit/pytest: hpk42: simplify _locationline helper Message-ID: <20110308124510.30892.2814@bitbucket02.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/f87840066573/ changeset: r2181:f87840066573 user: hpk42 date: 2011-03-08 13:44:53 summary: simplify _locationline helper affected #: 1 file (33 bytes) --- a/_pytest/terminal.py Tue Mar 08 13:37:00 2011 +0100 +++ b/_pytest/terminal.py Tue Mar 08 13:44:53 2011 +0100 @@ -335,19 +335,19 @@ excrepr.reprcrash.toterminal(self._tw) def _locationline(self, collect_fspath, fspath, lineno, domain): + # collect_fspath comes from testid which has a "/"-normalized path if fspath and fspath.replace("\\", "/") != collect_fspath: fspath = "%s <- %s" % (collect_fspath, fspath) - if lineno is not None: - lineno += 1 - if fspath and lineno and domain: - line = "%(fspath)s:%(lineno)s: %(domain)s" - elif fspath and domain: - line = "%(fspath)s: %(domain)s" - elif fspath and lineno: - line = "%(fspath)s:%(lineno)s %(extrapath)s" + if fspath: + line = str(fspath) + if lineno is not None: + lineno += 1 + line += ":" + str(lineno) + if domain: + line += ": " + str(domain) else: - line = "[nolocation]" - return line % locals() + " " + line = "[location]" + return line + " " def _getfailureheadline(self, rep): if hasattr(rep, 'location'): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Mar 9 11:09:53 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Wed, 09 Mar 2011 10:09:53 -0000 Subject: [py-svn] commit/pytest: hpk42: bump to release version, regenerate docs Message-ID: <20110309100953.24102.89074@bitbucket03.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/0ee09ffb6691/ changeset: r2182:0ee09ffb6691 user: hpk42 date: 2011-03-09 10:58:36 summary: bump to release version, regenerate docs affected #: 21 files (2.0 KB) --- a/CHANGELOG Tue Mar 08 13:44:53 2011 +0100 +++ b/CHANGELOG Wed Mar 09 10:58:36 2011 +0100 @@ -1,7 +1,8 @@ Changes between 2.0.1 and 2.0.2 ---------------------------------------------- -- tackle issue32 - half the overhead for running test functions +- tackle issue32 - speed up test runs of very quick test functions + by reducing the relative overhead - fix issue30 - extended xfail/skipif handling and improved reporting. If you have a syntax error in your skip/xfail @@ -9,7 +10,8 @@ Also you can now access module globals from xfail/skipif expressions so that this for example works now:: - + + import pytest import mymodule @pytest.mark.skipif("mymodule.__version__[0] == "1") def test_function(): --- a/doc/announce/index.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/announce/index.txt Wed Mar 09 10:58:36 2011 +0100 @@ -5,6 +5,7 @@ .. toctree:: :maxdepth: 2 + release-2.0.2 release-2.0.1 release-2.0.0 --- a/doc/assert.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/assert.txt Wed Mar 09 10:58:36 2011 +0100 @@ -23,7 +23,7 @@ $ py.test test_assert1.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 1 items test_assert1.py F @@ -37,7 +37,7 @@ E + where 3 = f() test_assert1.py:5: AssertionError - ========================= 1 failed in 0.03 seconds ========================= + ========================= 1 failed in 0.07 seconds ========================= Reporting details about the failing assertion is achieved by re-evaluating the assert expression and recording the intermediate values. @@ -108,7 +108,7 @@ $ py.test test_assert2.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 1 items test_assert2.py F --- a/doc/capture.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/capture.txt Wed Mar 09 10:58:36 2011 +0100 @@ -64,7 +64,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 2 items test_module.py .F @@ -78,7 +78,7 @@ test_module.py:9: AssertionError ----------------------------- Captured stdout ------------------------------ - setting up + setting up ==================== 1 failed, 1 passed in 0.02 seconds ==================== Accessing captured output from a test function --- a/doc/doctest.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/doctest.txt Wed Mar 09 10:58:36 2011 +0100 @@ -44,9 +44,9 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 1 items mymodule.py . - ========================= 1 passed in 0.02 seconds ========================= + ========================= 1 passed in 0.01 seconds ========================= --- a/doc/example/mysetup.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/example/mysetup.txt Wed Mar 09 10:58:36 2011 +0100 @@ -49,7 +49,7 @@ $ py.test test_sample.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 1 items test_sample.py F @@ -57,7 +57,7 @@ ================================= FAILURES ================================= _______________________________ test_answer ________________________________ - mysetup = + mysetup = def test_answer(mysetup): app = mysetup.myapp() @@ -122,12 +122,12 @@ $ py.test test_ssh.py -rs =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 1 items test_ssh.py s ========================= short test summary info ========================== - SKIP [1] /tmp/doc-exec-35/conftest.py:22: specify ssh host with --ssh + SKIP [1] /tmp/doc-exec-36/conftest.py:22: specify ssh host with --ssh ======================== 1 skipped in 0.02 seconds ========================= --- a/doc/example/nonpython.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/example/nonpython.txt Wed Mar 09 10:58:36 2011 +0100 @@ -27,7 +27,7 @@ nonpython $ py.test test_simple.yml =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 2 items test_simple.yml .F @@ -37,7 +37,7 @@ usecase execution failed spec failed: 'some': 'other' no further details known at this point. - ==================== 1 failed, 1 passed in 0.36 seconds ==================== + ==================== 1 failed, 1 passed in 0.51 seconds ==================== You get one dot for the passing ``sub1: sub1`` check and one failure. Obviously in the above ``conftest.py`` you'll want to implement a more @@ -56,7 +56,7 @@ nonpython $ py.test -v =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 -- /home/hpk/venv/0/bin/python + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 -- /home/hpk/venv/0/bin/python collecting ... collected 2 items test_simple.yml:1: usecase: ok PASSED @@ -67,12 +67,17 @@ usecase execution failed spec failed: 'some': 'other' no further details known at this point. - ==================== 1 failed, 1 passed in 0.08 seconds ==================== + ==================== 1 failed, 1 passed in 0.06 seconds ==================== While developing your custom test collection and execution it's also interesting to just look at the collection tree:: nonpython $ py.test --collectonly + =========================== test session starts ============================ + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 + collecting ... collected 2 items + + ============================= in 0.06 seconds ============================= --- a/doc/example/parametrize.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/example/parametrize.txt Wed Mar 09 10:58:36 2011 +0100 @@ -62,7 +62,7 @@ E assert 4 < 4 test_compute.py:3: AssertionError - 1 failed, 4 passed in 0.03 seconds + 1 failed, 4 passed in 0.02 seconds As expected when running the full range of ``param1`` values we'll get an error on the last one. @@ -113,9 +113,14 @@ Let's first see how it looks like at collection time:: $ py.test test_backends.py --collectonly + =========================== test session starts ============================ + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 + collecting ... collected 2 items + + ============================= in 0.00 seconds ============================= And then when we run the test:: @@ -125,7 +130,7 @@ ================================= FAILURES ================================= __________________________ test_db_initialized[1] __________________________ - db = + db = def test_db_initialized(db): # a dummy test @@ -179,7 +184,7 @@ ================================= FAILURES ================================= __________________________ test_db_initialized[1] __________________________ - db = + db = def test_db_initialized(db): # a dummy test @@ -190,7 +195,7 @@ test_backends.py:6: Failed _________________________ TestClass.test_equals[0] _________________________ - self = , a = 1, b = 2 + self = , a = 1, b = 2 def test_equals(self, a, b): > assert a == b @@ -199,14 +204,14 @@ test_parametrize.py:17: AssertionError ______________________ TestClass.test_zerodivision[1] ______________________ - self = , a = 3, b = 2 + self = , a = 3, b = 2 def test_zerodivision(self, a, b): > pytest.raises(ZeroDivisionError, "a/b") E Failed: DID NOT RAISE test_parametrize.py:20: Failed - 3 failed, 3 passed in 0.04 seconds + 3 failed, 3 passed in 0.03 seconds Parametrizing test methods through a decorator -------------------------------------------------------------- @@ -247,7 +252,7 @@ ================================= FAILURES ================================= _________________________ TestClass.test_equals[0] _________________________ - self = , a = 1, b = 2 + self = , a = 1, b = 2 @params([dict(a=1, b=2), dict(a=3, b=3), ]) def test_equals(self, a, b): @@ -257,7 +262,7 @@ test_parametrize2.py:19: AssertionError ______________________ TestClass.test_zerodivision[1] ______________________ - self = , a = 3, b = 2 + self = , a = 3, b = 2 @params([dict(a=1, b=0), dict(a=3, b=2)]) def test_zerodivision(self, a, b): @@ -265,7 +270,7 @@ E Failed: DID NOT RAISE test_parametrize2.py:23: Failed - 2 failed, 2 passed in 0.03 seconds + 2 failed, 2 passed in 0.02 seconds checking serialization between Python interpreters -------------------------------------------------------------- @@ -286,4 +291,4 @@ . $ py.test -q multipython.py collecting ... collected 75 items ....s....s....s....ssssss....s....s....s....ssssss....s....s....s....ssssss - 48 passed, 27 skipped in 1.92 seconds + 48 passed, 27 skipped in 3.74 seconds --- a/doc/example/pythoncollection.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/example/pythoncollection.txt Wed Mar 09 10:58:36 2011 +0100 @@ -42,11 +42,16 @@ then the test collection looks like this:: $ py.test --collectonly + =========================== test session starts ============================ + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 + collecting ... collected 2 items + + ============================= in 0.01 seconds ============================= interpret cmdline arguments as Python packages ----------------------------------------------------- @@ -76,9 +81,14 @@ You can always peek at the collection tree without running tests like this:: . $ py.test --collectonly pythoncollection.py + =========================== test session starts ============================ + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 + collecting ... collected 3 items + + ============================= in 0.06 seconds ============================= --- a/doc/example/reportingdemo.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/example/reportingdemo.txt Wed Mar 09 10:58:36 2011 +0100 @@ -13,7 +13,7 @@ assertion $ py.test failure_demo.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 39 items failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF @@ -30,7 +30,7 @@ failure_demo.py:15: AssertionError _________________________ TestFailing.test_simple __________________________ - self = + self = def test_simple(self): def f(): @@ -40,13 +40,13 @@ > assert f() == g() E assert 42 == 43 - E + where 42 = () - E + and 43 = () + E + where 42 = () + E + and 43 = () failure_demo.py:28: AssertionError ____________________ TestFailing.test_simple_multiline _____________________ - self = + self = def test_simple_multiline(self): otherfunc_multi( @@ -66,19 +66,19 @@ failure_demo.py:12: AssertionError ___________________________ TestFailing.test_not ___________________________ - self = + self = def test_not(self): def f(): return 42 > assert not f() E assert not 42 - E + where 42 = () + E + where 42 = () failure_demo.py:38: AssertionError _________________ TestSpecialisedExplanations.test_eq_text _________________ - self = + self = def test_eq_text(self): > assert 'spam' == 'eggs' @@ -89,7 +89,7 @@ failure_demo.py:42: AssertionError _____________ TestSpecialisedExplanations.test_eq_similar_text _____________ - self = + self = def test_eq_similar_text(self): > assert 'foo 1 bar' == 'foo 2 bar' @@ -102,7 +102,7 @@ failure_demo.py:45: AssertionError ____________ TestSpecialisedExplanations.test_eq_multiline_text ____________ - self = + self = def test_eq_multiline_text(self): > assert 'foo\nspam\nbar' == 'foo\neggs\nbar' @@ -115,7 +115,7 @@ failure_demo.py:48: AssertionError ______________ TestSpecialisedExplanations.test_eq_long_text _______________ - self = + self = def test_eq_long_text(self): a = '1'*100 + 'a' + '2'*100 @@ -132,7 +132,7 @@ failure_demo.py:53: AssertionError _________ TestSpecialisedExplanations.test_eq_long_text_multiline __________ - self = + self = def test_eq_long_text_multiline(self): a = '1\n'*100 + 'a' + '2\n'*100 @@ -156,7 +156,7 @@ failure_demo.py:58: AssertionError _________________ TestSpecialisedExplanations.test_eq_list _________________ - self = + self = def test_eq_list(self): > assert [0, 1, 2] == [0, 1, 3] @@ -166,7 +166,7 @@ failure_demo.py:61: AssertionError ______________ TestSpecialisedExplanations.test_eq_list_long _______________ - self = + self = def test_eq_list_long(self): a = [0]*100 + [1] + [3]*100 @@ -178,7 +178,7 @@ failure_demo.py:66: AssertionError _________________ TestSpecialisedExplanations.test_eq_dict _________________ - self = + self = def test_eq_dict(self): > assert {'a': 0, 'b': 1} == {'a': 0, 'b': 2} @@ -191,7 +191,7 @@ failure_demo.py:69: AssertionError _________________ TestSpecialisedExplanations.test_eq_set __________________ - self = + self = def test_eq_set(self): > assert set([0, 10, 11, 12]) == set([0, 20, 21]) @@ -207,7 +207,7 @@ failure_demo.py:72: AssertionError _____________ TestSpecialisedExplanations.test_eq_longer_list ______________ - self = + self = def test_eq_longer_list(self): > assert [1,2] == [1,2,3] @@ -217,7 +217,7 @@ failure_demo.py:75: AssertionError _________________ TestSpecialisedExplanations.test_in_list _________________ - self = + self = def test_in_list(self): > assert 1 in [0, 2, 3, 4, 5] @@ -226,7 +226,7 @@ failure_demo.py:78: AssertionError __________ TestSpecialisedExplanations.test_not_in_text_multiline __________ - self = + self = def test_not_in_text_multiline(self): text = 'some multiline\ntext\nwhich\nincludes foo\nand a\ntail' @@ -244,7 +244,7 @@ failure_demo.py:82: AssertionError ___________ TestSpecialisedExplanations.test_not_in_text_single ____________ - self = + self = def test_not_in_text_single(self): text = 'single foo line' @@ -257,7 +257,7 @@ failure_demo.py:86: AssertionError _________ TestSpecialisedExplanations.test_not_in_text_single_long _________ - self = + self = def test_not_in_text_single_long(self): text = 'head ' * 50 + 'foo ' + 'tail ' * 20 @@ -270,7 +270,7 @@ failure_demo.py:90: AssertionError ______ TestSpecialisedExplanations.test_not_in_text_single_long_term _______ - self = + self = def test_not_in_text_single_long_term(self): text = 'head ' * 50 + 'f'*70 + 'tail ' * 20 @@ -289,7 +289,7 @@ i = Foo() > assert i.b == 2 E assert 1 == 2 - E + where 1 = .b + E + where 1 = .b failure_demo.py:101: AssertionError _________________________ test_attribute_instance __________________________ @@ -299,8 +299,8 @@ b = 1 > assert Foo().b == 2 E assert 1 == 2 - E + where 1 = .b - E + where = () + E + where 1 = .b + E + where = () failure_demo.py:107: AssertionError __________________________ test_attribute_failure __________________________ @@ -316,7 +316,7 @@ failure_demo.py:116: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - self = + self = def _get_b(self): > raise Exception('Failed to get attrib') @@ -332,15 +332,15 @@ b = 2 > assert Foo().b == Bar().b E assert 1 == 2 - E + where 1 = .b - E + where = () - E + and 2 = .b - E + where = () + E + where 1 = .b + E + where = () + E + and 2 = .b + E + where = () failure_demo.py:124: AssertionError __________________________ TestRaises.test_raises __________________________ - self = + self = def test_raises(self): s = 'qwe' @@ -352,10 +352,10 @@ > int(s) E ValueError: invalid literal for int() with base 10: 'qwe' - <0-codegen /home/hpk/p/pytest/_pytest/python.py:825>:1: ValueError + <0-codegen /home/hpk/p/pytest/_pytest/python.py:837>:1: ValueError ______________________ TestRaises.test_raises_doesnt _______________________ - self = + self = def test_raises_doesnt(self): > raises(IOError, "int('3')") @@ -364,7 +364,7 @@ failure_demo.py:136: Failed __________________________ TestRaises.test_raise ___________________________ - self = + self = def test_raise(self): > raise ValueError("demo error") @@ -373,7 +373,7 @@ failure_demo.py:139: ValueError ________________________ TestRaises.test_tupleerror ________________________ - self = + self = def test_tupleerror(self): > a,b = [1] @@ -382,7 +382,7 @@ failure_demo.py:142: ValueError ______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______ - self = + self = def test_reinterpret_fails_with_print_for_the_fun_of_it(self): l = [1,2,3] @@ -395,7 +395,7 @@ l is [1, 2, 3] ________________________ TestRaises.test_some_error ________________________ - self = + self = def test_some_error(self): > if namenotexi: @@ -423,7 +423,7 @@ <2-codegen 'abc-123' /home/hpk/p/pytest/doc/example/assertion/failure_demo.py:162>:2: AssertionError ____________________ TestMoreErrors.test_complex_error _____________________ - self = + self = def test_complex_error(self): def f(): @@ -452,7 +452,7 @@ failure_demo.py:5: AssertionError ___________________ TestMoreErrors.test_z1_unpack_error ____________________ - self = + self = def test_z1_unpack_error(self): l = [] @@ -462,7 +462,7 @@ failure_demo.py:179: ValueError ____________________ TestMoreErrors.test_z2_type_error _____________________ - self = + self = def test_z2_type_error(self): l = 3 @@ -472,20 +472,20 @@ failure_demo.py:183: TypeError ______________________ TestMoreErrors.test_startswith ______________________ - self = + self = def test_startswith(self): s = "123" g = "456" > assert s.startswith(g) E assert False - E + where False = ('456') - E + where = '123'.startswith + E + where False = ('456') + E + where = '123'.startswith failure_demo.py:188: AssertionError __________________ TestMoreErrors.test_startswith_nested ___________________ - self = + self = def test_startswith_nested(self): def f(): @@ -494,15 +494,15 @@ return "456" > assert f().startswith(g()) E assert False - E + where False = ('456') - E + where = '123'.startswith - E + where '123' = () - E + and '456' = () + E + where False = ('456') + E + where = '123'.startswith + E + where '123' = () + E + and '456' = () failure_demo.py:195: AssertionError _____________________ TestMoreErrors.test_global_func ______________________ - self = + self = def test_global_func(self): > assert isinstance(globf(42), float) @@ -513,19 +513,19 @@ failure_demo.py:198: AssertionError _______________________ TestMoreErrors.test_instance _______________________ - self = + self = def test_instance(self): self.x = 6*7 > assert self.x != 42 E assert 42 != 42 E + where 42 = 42 - E + where 42 = .x + E + where 42 = .x failure_demo.py:202: AssertionError _______________________ TestMoreErrors.test_compare ________________________ - self = + self = def test_compare(self): > assert globf(10) < 5 @@ -535,7 +535,7 @@ failure_demo.py:205: AssertionError _____________________ TestMoreErrors.test_try_finally ______________________ - self = + self = def test_try_finally(self): x = 1 @@ -544,4 +544,4 @@ E assert 1 == 0 failure_demo.py:210: AssertionError - ======================== 39 failed in 0.26 seconds ========================= + ======================== 39 failed in 0.19 seconds ========================= --- a/doc/example/simple.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/example/simple.txt Wed Mar 09 10:58:36 2011 +0100 @@ -109,13 +109,13 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 gw0 I / gw1 I / gw2 I / gw3 I gw0 [0] / gw1 [0] / gw2 [0] / gw3 [0] scheduling tests via LoadScheduling - ============================= in 0.35 seconds ============================= + ============================= in 0.51 seconds ============================= .. _`excontrolskip`: @@ -156,12 +156,12 @@ $ py.test -rs # "-rs" means report details on the little 's' =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 2 items test_module.py .s ========================= short test summary info ========================== - SKIP [1] /tmp/doc-exec-40/conftest.py:9: need --runslow option to run + SKIP [1] /tmp/doc-exec-41/conftest.py:9: need --runslow option to run =================== 1 passed, 1 skipped in 0.02 seconds ==================== @@ -169,7 +169,7 @@ $ py.test --runslow =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 2 items test_module.py .. @@ -213,7 +213,7 @@ E Failed: not configured: 42 test_checkconfig.py:8: Failed - 1 failed in 0.03 seconds + 1 failed in 0.01 seconds Detect if running from within a py.test run -------------------------------------------------------------- @@ -261,7 +261,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 project deps: mylib-1.1 collecting ... collected 0 items @@ -284,7 +284,7 @@ $ py.test -v =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 -- /home/hpk/venv/0/bin/python + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 -- /home/hpk/venv/0/bin/python info1: did you know that ... did you? collecting ... collected 0 items @@ -295,7 +295,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 0 items ============================= in 0.00 seconds ============================= --- a/doc/funcargs.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/funcargs.txt Wed Mar 09 10:58:36 2011 +0100 @@ -61,7 +61,7 @@ $ py.test test_simplefactory.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 1 items test_simplefactory.py F @@ -167,7 +167,7 @@ $ py.test test_example.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 10 items test_example.py .........F @@ -182,13 +182,16 @@ E assert 9 < 9 test_example.py:7: AssertionError - ==================== 1 failed, 9 passed in 0.05 seconds ==================== + ==================== 1 failed, 9 passed in 0.02 seconds ==================== Note that the ``pytest_generate_tests(metafunc)`` hook is called during the test collection phase which is separate from the actual test running. Let's just look at what is collected:: $ py.test --collectonly test_example.py + =========================== test session starts ============================ + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 + collecting ... collected 10 items @@ -200,12 +203,14 @@ + + ============================= in 0.00 seconds ============================= If you want to select only the run with the value ``7`` you could do:: $ py.test -v -k 7 test_example.py # or -k test_func[7] =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 -- /home/hpk/venv/0/bin/python + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 -- /home/hpk/venv/0/bin/python collecting ... collected 10 items test_example.py:6: test_func[7] PASSED --- a/doc/getting-started.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/getting-started.txt Wed Mar 09 10:58:36 2011 +0100 @@ -16,10 +16,9 @@ To check your installation has installed the correct version:: $ py.test --version - This is py.test version 2.0.2.dev2, imported from /home/hpk/p/pytest/pytest.py + This is py.test version 2.0.2, imported from /home/hpk/p/pytest/pytest.py setuptools registered plugins: pytest-xdist-1.6.dev2 at /home/hpk/p/pytest-xdist/xdist/plugin.pyc - pytest-pep8-0.7 at /home/hpk/p/pytest-pep8/pytest_pep8.pyc If you get an error checkout :ref:`installation issues`. @@ -41,7 +40,7 @@ $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 1 items test_sample.py F @@ -100,7 +99,7 @@ $ py.test -q test_sysexit.py collecting ... collected 1 items . - 1 passed in 0.01 seconds + 1 passed in 0.00 seconds .. todo:: For further ways to assert exceptions see the `raises` @@ -131,7 +130,7 @@ ================================= FAILURES ================================= ____________________________ TestClass.test_two ____________________________ - self = + self = def test_two(self): x = "hello" @@ -140,7 +139,7 @@ E + where False = hasattr('hello', 'check') test_class.py:8: AssertionError - 1 failed, 1 passed in 0.04 seconds + 1 failed, 1 passed in 0.02 seconds The first test passed, the second failed. Again we can easily see the intermediate values used in the assertion, helping us to @@ -169,7 +168,7 @@ ================================= FAILURES ================================= _____________________________ test_needsfiles ______________________________ - tmpdir = local('/tmp/pytest-92/test_needsfiles0') + tmpdir = local('/tmp/pytest-0/test_needsfiles0') def test_needsfiles(tmpdir): print tmpdir @@ -178,8 +177,8 @@ test_tmpdir.py:3: AssertionError ----------------------------- Captured stdout ------------------------------ - /tmp/pytest-92/test_needsfiles0 - 1 failed in 0.14 seconds + /tmp/pytest-0/test_needsfiles0 + 1 failed in 0.02 seconds Before the test runs, a unique-per-test-invocation temporary directory was created. More info at :ref:`tmpdir handling`. --- a/doc/mark.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/mark.txt Wed Mar 09 10:58:36 2011 +0100 @@ -88,19 +88,19 @@ $ py.test -k webtest # running with the above defined examples yields =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 4 items test_mark.py .. test_mark_classlevel.py .. - ========================= 4 passed in 0.02 seconds ========================= + ========================= 4 passed in 0.01 seconds ========================= And you can also run all tests except the ones that match the keyword:: $ py.test -k-webtest =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 4 items ===================== 4 tests deselected by '-webtest' ===================== @@ -110,7 +110,7 @@ $ py.test -kTestClass =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 4 items test_mark_classlevel.py .. --- a/doc/monkeypatch.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/monkeypatch.txt Wed Mar 09 10:58:36 2011 +0100 @@ -39,7 +39,7 @@ .. background check: $ py.test =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 0 items ============================= in 0.00 seconds ============================= --- a/doc/skipping.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/skipping.txt Wed Mar 09 10:58:36 2011 +0100 @@ -130,14 +130,14 @@ example $ py.test -rx xfail_demo.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 6 items xfail_demo.py xxxxxx ========================= short test summary info ========================== XFAIL xfail_demo.py::test_hello XFAIL xfail_demo.py::test_hello2 - reason: [NOTRUN] + reason: [NOTRUN] XFAIL xfail_demo.py::test_hello3 condition: hasattr(os, 'sep') XFAIL xfail_demo.py::test_hello4 @@ -147,7 +147,7 @@ XFAIL xfail_demo.py::test_hello6 reason: reason - ======================== 6 xfailed in 0.06 seconds ========================= + ======================== 6 xfailed in 0.04 seconds ========================= .. _`evaluation of skipif/xfail conditions`: --- a/doc/tmpdir.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/tmpdir.txt Wed Mar 09 10:58:36 2011 +0100 @@ -28,7 +28,7 @@ $ py.test test_tmpdir.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 1 items test_tmpdir.py F @@ -36,7 +36,7 @@ ================================= FAILURES ================================= _____________________________ test_create_file _____________________________ - tmpdir = local('/tmp/pytest-93/test_create_file0') + tmpdir = local('/tmp/pytest-1/test_create_file0') def test_create_file(tmpdir): p = tmpdir.mkdir("sub").join("hello.txt") @@ -47,7 +47,7 @@ E assert 0 test_tmpdir.py:7: AssertionError - ========================= 1 failed in 0.04 seconds ========================= + ========================= 1 failed in 0.02 seconds ========================= .. _`base temporary directory`: --- a/doc/unittest.txt Tue Mar 08 13:44:53 2011 +0100 +++ b/doc/unittest.txt Wed Mar 09 10:58:36 2011 +0100 @@ -24,7 +24,7 @@ $ py.test test_unittest.py =========================== test session starts ============================ - platform linux2 -- Python 2.6.6 -- pytest-2.0.2.dev2 + platform linux2 -- Python 2.6.6 -- pytest-2.0.2 collecting ... collected 1 items test_unittest.py F @@ -37,26 +37,12 @@ def test_method(self): x = 1 > self.assertEquals(x, 3) + E AssertionError: 1 != 3 - test_unittest.py:8: - _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - - self = , first = 1, second = 3 - msg = None - - def failUnlessEqual(self, first, second, msg=None): - """Fail if the two objects are unequal as determined by the '==' - operator. - """ - if not first == second: - raise self.failureException, \ - > (msg or '%r != %r' % (first, second)) - E AssertionError: 1 != 3 - - /usr/lib/python2.6/unittest.py:350: AssertionError + test_unittest.py:8: AssertionError ----------------------------- Captured stdout ------------------------------ hello - ========================= 1 failed in 0.03 seconds ========================= + ========================= 1 failed in 0.02 seconds ========================= .. _`unittest.py style`: http://docs.python.org/library/unittest.html --- a/pytest.py Tue Mar 08 13:44:53 2011 +0100 +++ b/pytest.py Wed Mar 09 10:58:36 2011 +0100 @@ -1,7 +1,7 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.2.dev7' +__version__ = '2.0.2' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins --- a/setup.py Tue Mar 08 13:44:53 2011 +0100 +++ b/setup.py Wed Mar 09 10:58:36 2011 +0100 @@ -22,7 +22,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.2.dev7', + version='2.0.2', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Mar 9 14:02:36 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Wed, 09 Mar 2011 13:02:36 -0000 Subject: [py-svn] commit/pytest: 2 new changesets Message-ID: <20110309130236.24102.80952@bitbucket03.managed.contegix.com> 2 new changesets in pytest: http://bitbucket.org/hpk42/pytest/changeset/84e5c54b7244/ changeset: r2183:84e5c54b7244 user: hpk42 date: 2011-03-09 13:59:00 summary: fix install location affected #: 1 file (8 bytes) --- a/doc/Makefile Wed Mar 09 10:58:36 2011 +0100 +++ b/doc/Makefile Wed Mar 09 13:59:00 2011 +0100 @@ -40,7 +40,7 @@ -rm -rf $(BUILDDIR)/* install: clean html - rsync -avz _build/html/ code:www-pytest/2.0.2dev + rsync -avz _build/html/ code:www-pytest/ html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html http://bitbucket.org/hpk42/pytest/changeset/080969ec04a4/ changeset: r2184:080969ec04a4 user: hpk42 date: 2011-03-09 14:02:20 summary: Added tag 2.0.2 for changeset 84e5c54b7244 affected #: 1 file (47 bytes) --- a/.hgtags Wed Mar 09 13:59:00 2011 +0100 +++ b/.hgtags Wed Mar 09 14:02:20 2011 +0100 @@ -33,3 +33,4 @@ 90fffd35373e9f125af233f78b19416f0938d841 1.3.4 e9e127acd6f0497324ef7f40cfb997cad4c4cd17 2.0.0 e4497c2aed358c1988cf7be83ca9394c3c707fa2 2.0.1 +84e5c54b72448194a0f6f815da7e048ac8019d50 2.0.2 Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Mar 9 14:02:45 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Wed, 09 Mar 2011 13:02:45 -0000 Subject: [py-svn] commit/py: 2 new changesets Message-ID: <20110309130245.17734.80986@bitbucket02.managed.contegix.com> 2 new changesets in py: http://bitbucket.org/hpk42/py/changeset/04ab22db4ff7/ changeset: r2011:04ab22db4ff7 user: hpk42 date: 2011-03-09 13:52:30 summary: fix doc welcome affected #: 1 file (30 bytes) --- a/doc/index.txt Mon Mar 07 13:16:52 2011 +0100 +++ b/doc/index.txt Wed Mar 09 13:52:30 2011 +0100 @@ -6,7 +6,7 @@ Welcome to py's documentation! ================================= -:ref:`1.4.1 release announcement ` and :ref:`CHANGELOG ` +see :ref:`CHANGELOG ` for latest changes. .. note:: http://bitbucket.org/hpk42/py/changeset/c35eced8aa16/ changeset: r2012:c35eced8aa16 user: hpk42 date: 2011-03-09 13:54:26 summary: Added tag 1.4.2 for changeset 04ab22db4ff7 affected #: 1 file (47 bytes) --- a/.hgtags Wed Mar 09 13:52:30 2011 +0100 +++ b/.hgtags Wed Mar 09 13:54:26 2011 +0100 @@ -33,3 +33,4 @@ 90fffd35373e9f125af233f78b19416f0938d841 1.3.4 5346ab41b059c95a48cbe1e8a7bae96ce6e0da27 1.4.0 1f3125cba7976538952be268f107c1d0c36c5ce8 1.4.1 +04ab22db4ff737cf31e91d75a0f5d7077f324167 1.4.2 Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Fri Mar 11 13:57:25 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Fri, 11 Mar 2011 12:57:25 -0000 Subject: [py-svn] commit/py: hpk42: fix windows terminal coloring for skipped tests Message-ID: <20110311125725.12896.1187@bitbucket01.managed.contegix.com> 1 new changeset in py: http://bitbucket.org/hpk42/py/changeset/4f65870debef/ changeset: r2013:4f65870debef user: hpk42 date: 2011-03-11 13:48:50 summary: fix windows terminal coloring for skipped tests affected #: 4 files (249 bytes) --- a/CHANGELOG Wed Mar 09 13:54:26 2011 +0100 +++ b/CHANGELOG Fri Mar 11 13:48:50 2011 +0100 @@ -1,3 +1,8 @@ +Changes between 1.4.2 and 1.4.3.dev +================================================== + +- fix terminal coloring issue for skipped tests (thanks Amaury) + Changes between 1.4.1 and 1.4.2 ================================================== --- a/py/__init__.py Wed Mar 09 13:54:26 2011 +0100 +++ b/py/__init__.py Fri Mar 11 13:48:50 2011 +0100 @@ -8,7 +8,7 @@ (c) Holger Krekel and others, 2004-2010 """ -__version__ = '1.4.2' +__version__ = '1.4.3.dev0' from py import _apipkg --- a/py/_io/terminalwriter.py Wed Mar 09 13:54:26 2011 +0100 +++ b/py/_io/terminalwriter.py Fri Mar 11 13:48:50 2011 +0100 @@ -199,8 +199,10 @@ attr |= FOREGROUND_BLUE elif kw.pop('green', False): attr |= FOREGROUND_GREEN + elif kw.pop('yellow', False): + attr |= FOREGROUND_GREEN|FOREGROUND_RED else: - attr |= FOREGROUND_BLACK # (oldcolors & 0x0007) + attr |= oldcolors & 0x0007 SetConsoleTextAttribute(handle, attr) if not isinstance(self._file, WriteFile): --- a/setup.py Wed Mar 09 13:54:26 2011 +0100 +++ b/setup.py Fri Mar 11 13:48:50 2011 +0100 @@ -9,7 +9,7 @@ name='py', description='library with cross-python path, ini-parsing, io, code, log facilities', long_description = open('README.txt').read(), - version='1.4.2', + version='1.4.3.dev0', url='http://pylib.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], @@ -37,4 +37,4 @@ ) if __name__ == '__main__': - main() \ No newline at end of file + main() Repository URL: https://bitbucket.org/hpk42/py/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sat Mar 12 20:12:32 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Sat, 12 Mar 2011 19:12:32 -0000 Subject: [py-svn] commit/pytest: 3 new changesets Message-ID: <20110312191232.24102.16721@bitbucket03.managed.contegix.com> 3 new changesets in pytest: http://bitbucket.org/hpk42/pytest/changeset/bed26832e732/ changeset: r2185:bed26832e732 user: hpk42 date: 2011-03-11 15:25:37 summary: fix issue link affected #: 1 file (7 bytes) --- a/doc/_templates/layout.html Wed Mar 09 14:02:20 2011 +0100 +++ b/doc/_templates/layout.html Fri Mar 11 15:25:37 2011 +0100 @@ -19,7 +19,7 @@ install |  examples |  customize |  - issues|  + issuescontact  http://bitbucket.org/hpk42/pytest/changeset/a983d50fb892/ changeset: r2186:a983d50fb892 user: hpk42 date: 2011-03-11 15:43:24 summary: speed up skipping affected #: 4 files (197 bytes) --- a/CHANGELOG Fri Mar 11 15:25:37 2011 +0100 +++ b/CHANGELOG Fri Mar 11 15:43:24 2011 +0100 @@ -1,3 +1,9 @@ +Changes between 2.0.2 and 2.0.3.dev +---------------------------------------------- + +- speed up skips (by not doing a full traceback represenation + internally) + Changes between 2.0.1 and 2.0.2 ---------------------------------------------- --- a/_pytest/runner.py Fri Mar 11 15:25:37 2011 +0100 +++ b/_pytest/runner.py Fri Mar 11 15:43:24 2011 +0100 @@ -153,7 +153,7 @@ longrepr = excinfo elif excinfo.errisinstance(py.test.skip.Exception): outcome = "skipped" - r = item._repr_failure_py(excinfo, "line").reprcrash + r = excinfo._getreprcrash() longrepr = (str(r.path), r.lineno, r.message) else: outcome = "failed" --- a/pytest.py Fri Mar 11 15:25:37 2011 +0100 +++ b/pytest.py Fri Mar 11 15:43:24 2011 +0100 @@ -1,7 +1,7 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.2' +__version__ = '2.0.3.dev0' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins --- a/setup.py Fri Mar 11 15:25:37 2011 +0100 +++ b/setup.py Fri Mar 11 15:43:24 2011 +0100 @@ -22,7 +22,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.2', + version='2.0.3.dev0', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], @@ -67,4 +67,4 @@ return {'console_scripts': l} if __name__ == '__main__': - main() \ No newline at end of file + main() http://bitbucket.org/hpk42/pytest/changeset/d7103764b795/ changeset: r2187:d7103764b795 user: hpk42 date: 2011-03-12 20:12:19 summary: don't import stuff at genscript import time but rather when it is used affected #: 4 files (124 bytes) --- a/CHANGELOG Fri Mar 11 15:43:24 2011 +0100 +++ b/CHANGELOG Sat Mar 12 20:12:19 2011 +0100 @@ -1,6 +1,9 @@ Changes between 2.0.2 and 2.0.3.dev ---------------------------------------------- +- don't require zlib (and other libs) for genscript plugin without + --genscript actually being used. + - speed up skips (by not doing a full traceback represenation internally) --- a/_pytest/genscript.py Fri Mar 11 15:43:24 2011 +0100 +++ b/_pytest/genscript.py Sat Mar 12 20:12:19 2011 +0100 @@ -1,8 +1,5 @@ """ generate a single-file self-contained version of py.test """ import py -import pickle -import zlib -import base64 def find_toplevel(name): for syspath in py.std.sys.path: @@ -31,9 +28,9 @@ return name2src def compress_mapping(mapping): - data = pickle.dumps(mapping, 2) - data = zlib.compress(data, 9) - data = base64.encodestring(data) + data = py.std.pickle.dumps(mapping, 2) + data = py.std.zlib.compress(data, 9) + data = py.std.base64.encodestring(data) data = data.decode('ascii') return data @@ -44,7 +41,6 @@ mapping.update(pkg_to_mapping(name)) return compress_mapping(mapping) - def generate_script(entry, packages): data = compress_packages(packages) tmpl = py.path.local(__file__).dirpath().join('standalonetemplate.py') --- a/pytest.py Fri Mar 11 15:43:24 2011 +0100 +++ b/pytest.py Sat Mar 12 20:12:19 2011 +0100 @@ -1,7 +1,7 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.3.dev0' +__version__ = '2.0.3.dev1' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins --- a/setup.py Fri Mar 11 15:43:24 2011 +0100 +++ b/setup.py Sat Mar 12 20:12:19 2011 +0100 @@ -22,7 +22,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.3.dev0', + version='2.0.3.dev1', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], @@ -67,4 +67,4 @@ return {'console_scripts': l} if __name__ == '__main__': - main() + main() \ No newline at end of file Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Mar 16 16:36:38 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Wed, 16 Mar 2011 15:36:38 -0000 Subject: [py-svn] commit/pytest: hpk42: fix issue33 - no collection error for classes prefixed "test" deriving from object Message-ID: <20110316153638.24102.35289@bitbucket03.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/6c9eb22fb7a3/ changeset: r2188:6c9eb22fb7a3 user: hpk42 date: 2011-03-16 16:36:18 summary: fix issue33 - no collection error for classes prefixed "test" deriving from object affected #: 5 files (523 bytes) --- a/CHANGELOG Sat Mar 12 20:12:19 2011 +0100 +++ b/CHANGELOG Wed Mar 16 16:36:18 2011 +0100 @@ -1,6 +1,9 @@ Changes between 2.0.2 and 2.0.3.dev ---------------------------------------------- +- fix issue34: avoid collection failure with "test" prefixed classes + deriving from object. + - don't require zlib (and other libs) for genscript plugin without --genscript actually being used. --- a/_pytest/python.py Sat Mar 12 20:12:19 2011 +0100 +++ b/_pytest/python.py Wed Mar 16 16:36:18 2011 +0100 @@ -70,11 +70,13 @@ res = __multicall__.execute() if res is not None: return res - if collector._istestclasscandidate(name, obj): + if inspect.isclass(obj): #if hasattr(collector.obj, 'unittest'): # return # we assume it's a mixin class for a TestCase derived one - Class = collector._getcustomclass("Class") - return Class(name, parent=collector) + if collector.classnamefilter(name): + if not hasinit(obj): + Class = collector._getcustomclass("Class") + return Class(name, parent=collector) elif collector.funcnamefilter(name) and hasattr(obj, '__call__'): if is_generator(obj): return Generator(name, parent=collector) @@ -194,14 +196,6 @@ return self.ihook.pytest_pycollect_makeitem( collector=self, name=name, obj=obj) - def _istestclasscandidate(self, name, obj): - if self.classnamefilter(name) and \ - inspect.isclass(obj): - if hasinit(obj): - # XXX WARN - return False - return True - def _genfunctions(self, name, funcobj): module = self.getparent(Module).obj clscol = self.getparent(Class) --- a/pytest.py Sat Mar 12 20:12:19 2011 +0100 +++ b/pytest.py Wed Mar 16 16:36:18 2011 +0100 @@ -1,7 +1,7 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.3.dev1' +__version__ = '2.0.3.dev2' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins --- a/setup.py Sat Mar 12 20:12:19 2011 +0100 +++ b/setup.py Wed Mar 16 16:36:18 2011 +0100 @@ -22,7 +22,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.3.dev1', + version='2.0.3.dev2', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], --- a/testing/test_python.py Sat Mar 12 20:12:19 2011 +0100 +++ b/testing/test_python.py Wed Mar 16 16:36:18 2011 +0100 @@ -46,6 +46,16 @@ l = modcol.collect() assert len(l) == 0 + def test_class_subclassobject(self, testdir): + testdir.getmodulecol(""" + class test(object): + pass + """) + result = testdir.runpytest() + result.stdout.fnmatch_lines([ + "*collected 0*", + ]) + class TestGenerator: def test_generative_functions(self, testdir): modcol = testdir.getmodulecol(""" Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Mar 16 18:01:30 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Wed, 16 Mar 2011 17:01:30 -0000 Subject: [py-svn] commit/pytest: hpk42: offer a semi-internal method to create a config object in subprocesses Message-ID: <20110316170130.17734.22086@bitbucket02.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/6f036850385f/ changeset: r2189:6f036850385f user: hpk42 date: 2011-03-16 18:00:52 summary: offer a semi-internal method to create a config object in subprocesses (helps pytest-xdist plugin to fix issue34) affected #: 2 files (373 bytes) --- a/_pytest/config.py Wed Mar 16 16:36:18 2011 +0100 +++ b/_pytest/config.py Wed Mar 16 18:00:52 2011 +0100 @@ -252,6 +252,16 @@ self.hook = self.pluginmanager.hook self._inicache = {} + @classmethod + def fromdictargs(cls, option_dict, args): + """ constructor useable for subprocesses. """ + config = cls() + config._preparse(args, addopts=False) + config.option.__dict__.update(option_dict) + for x in config.option.plugins: + config.pluginmanager.consider_pluginarg(x) + return config + def _onimportconftest(self, conftestmodule): self.trace("loaded conftestmodule %r" %(conftestmodule,)) self.pluginmanager.consider_conftest(conftestmodule) --- a/_pytest/core.py Wed Mar 16 16:36:18 2011 +0100 +++ b/_pytest/core.py Wed Mar 16 18:00:52 2011 +0100 @@ -164,14 +164,17 @@ def consider_preparse(self, args): for opt1,opt2 in zip(args, args[1:]): if opt1 == "-p": - if opt2.startswith("no:"): - name = opt2[3:] - if self.getplugin(name) is not None: - self.unregister(None, name=name) - self._name2plugin[name] = -1 - else: - if self.getplugin(opt2) is None: - self.import_plugin(opt2) + self.consider_pluginarg(opt2) + + def consider_pluginarg(self, arg): + if arg.startswith("no:"): + name = arg[3:] + if self.getplugin(name) is not None: + self.unregister(None, name=name) + self._name2plugin[name] = -1 + else: + if self.getplugin(arg) is None: + self.import_plugin(arg) def consider_conftest(self, conftestmodule): if self.register(conftestmodule, name=conftestmodule.__file__): Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Mar 16 18:01:41 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Wed, 16 Mar 2011 17:01:41 -0000 Subject: [py-svn] commit/pytest-xdist: hpk42: fix issue34 Message-ID: <20110316170141.17735.8233@bitbucket02.managed.contegix.com> 1 new changeset in pytest-xdist: http://bitbucket.org/hpk42/pytest-xdist/changeset/90734eb951b5/ changeset: r100:90734eb951b5 user: hpk42 date: 2011-03-16 17:59:14 summary: fix issue34 affected #: 7 files (749 bytes) --- a/CHANGELOG Tue Dec 07 12:47:36 2010 +0100 +++ b/CHANGELOG Wed Mar 16 17:59:14 2011 +0100 @@ -1,3 +1,10 @@ +1.6 (dev) +------------------------- + +- terser collection reporting + +- fix issue34 - distributed testing with -p plugin now works correctly + 1.5 ------------------------- --- a/setup.py Tue Dec 07 12:47:36 2010 +0100 +++ b/setup.py Wed Mar 16 17:59:14 2011 +0100 @@ -2,7 +2,7 @@ setup( name="pytest-xdist", - version='1.6.dev2', + version='1.6.dev3', description='py.test xdist plugin for distributed testing and loop-on-failing modes', long_description=open('README.txt').read(), license='GPLv2 or later', @@ -13,7 +13,7 @@ packages = ['xdist'], entry_points = {'pytest11': ['xdist = xdist.plugin'],}, zip_safe=False, - install_requires = ['execnet>=1.0.8', 'pytest>1.9.9'], + install_requires = ['execnet>=1.0.8', 'pytest>2.0.2'], classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', --- a/testing/acceptance_test.py Tue Dec 07 12:47:36 2010 +0100 +++ b/testing/acceptance_test.py Wed Mar 16 17:59:14 2011 +0100 @@ -407,5 +407,18 @@ "*1 skipped*" ]) - - +def test_issue34_pluginloading_in_subprocess(testdir): + testdir.tmpdir.join("plugin123.py").write(py.code.Source(""" + def pytest_namespace(): + return {'sample_variable': 'testing'} + """)) + testdir.makepyfile(""" + import pytest + def test_hello(): + assert pytest.sample_variable == "testing" + """) + result = testdir.runpytest("-n1", "-p", "plugin123") + assert result.ret == 0 + result.stdout.fnmatch_lines([ + "*1 passed*", + ]) --- a/testing/test_remote.py Tue Dec 07 12:47:36 2010 +0100 +++ b/testing/test_remote.py Wed Mar 16 17:59:14 2011 +0100 @@ -62,7 +62,7 @@ config1 = testdir.parseconfig() config2 = remote_initconfig(config1.option.__dict__, config1.args) assert config2.option.__dict__ == config1.option.__dict__ - assert config2.pluginmanager.getplugin("terminal") == None + assert config2.pluginmanager.getplugin("terminal") in (-1, None) class TestReportSerialization: def test_itemreport_outcomes(self, testdir): --- a/xdist/__init__.py Tue Dec 07 12:47:36 2010 +0100 +++ b/xdist/__init__.py Wed Mar 16 17:59:14 2011 +0100 @@ -1,2 +1,2 @@ # -__version__ = '1.6.dev2' +__version__ = '1.6.dev3' --- a/xdist/looponfail.py Tue Dec 07 12:47:36 2010 +0100 +++ b/xdist/looponfail.py Wed Mar 16 17:59:14 2011 +0100 @@ -120,9 +120,7 @@ #fullwidth, hasmarkup = channel.receive() from _pytest.config import Config - config = Config() - config.option.__dict__.update(option_dict) - config._preparse(list(args)) + config = Config.fromdictargs(option_dict, list(args)) config.args = args from xdist.looponfail import SlaveFailSession SlaveFailSession(config, channel).main() --- a/xdist/remote.py Tue Dec 07 12:47:36 2010 +0100 +++ b/xdist/remote.py Wed Mar 16 17:59:14 2011 +0100 @@ -109,10 +109,8 @@ def remote_initconfig(option_dict, args): from _pytest.config import Config - config = Config() - config.pluginmanager.unregister(name="terminal") - config._preparse(args, addopts=False) - config.option.__dict__.update(option_dict) + option_dict['plugins'].append("no:terminal") + config = Config.fromdictargs(option_dict, args) config.option.looponfail = False config.option.usepdb = False config.option.dist = "no" Repository URL: https://bitbucket.org/hpk42/pytest-xdist/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Wed Mar 16 19:05:40 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Wed, 16 Mar 2011 18:05:40 -0000 Subject: [py-svn] commit/pytest: hpk42: add @classmethod although it's not strictly neccessary for basic cases. Message-ID: <20110316180540.24101.72871@bitbucket03.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/a7ef3cbb38f3/ changeset: r2190:a7ef3cbb38f3 user: hpk42 date: 2011-03-16 19:05:28 summary: add @classmethod although it's not strictly neccessary for basic cases. affected #: 1 file (34 bytes) --- a/doc/xunit_setup.txt Wed Mar 16 18:00:52 2011 +0100 +++ b/doc/xunit_setup.txt Wed Mar 16 19:05:28 2011 +0100 @@ -39,11 +39,13 @@ Similarly, the following methods are called at class level before and after all test methods of the class are called:: + @classmethod def setup_class(cls): """ setup up any state specific to the execution of the given class (which usually contains tests). """ + @classmethod def teardown_class(cls): """ teardown any state that was previously setup with a call to setup_class. Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sat Mar 19 18:00:25 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Sat, 19 Mar 2011 17:00:25 -0000 Subject: [py-svn] commit/pytest: hpk42: fix missing reason/name information for skipped tests Message-ID: <20110319170025.24046.94100@bitbucket01.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/5485ef79f4ad/ changeset: r2191:5485ef79f4ad user: hpk42 date: 2011-03-19 17:59:07 summary: fix missing reason/name information for skipped tests affected #: 5 files (1.1 KB) --- a/CHANGELOG Wed Mar 16 19:05:28 2011 +0100 +++ b/CHANGELOG Sat Mar 19 17:59:07 2011 +0100 @@ -1,6 +1,9 @@ Changes between 2.0.2 and 2.0.3.dev ---------------------------------------------- +- fix missing skip reason/meta information in junitxml files, reported + via http://lists.idyll.org/pipermail/testing-in-python/2011-March/003928.html + - fix issue34: avoid collection failure with "test" prefixed classes deriving from object. --- a/_pytest/junitxml.py Wed Mar 16 19:05:28 2011 +0100 +++ b/_pytest/junitxml.py Sat Mar 19 17:59:07 2011 +0100 @@ -106,7 +106,13 @@ '%s', report.keywords['xfail']) else: - self.appendlog("") + filename, lineno, skipreason = report.longrepr + if skipreason.startswith("Skipped: "): + skipreason = skipreason[9:] + self.appendlog('%s', + skipreason, "%s:%s: %s" % report.longrepr, + ) self._closetestcase() self.skipped += 1 --- a/pytest.py Wed Mar 16 19:05:28 2011 +0100 +++ b/pytest.py Sat Mar 19 17:59:07 2011 +0100 @@ -1,7 +1,7 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.3.dev2' +__version__ = '2.0.3.dev3' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins --- a/setup.py Wed Mar 16 19:05:28 2011 +0100 +++ b/setup.py Sat Mar 19 17:59:07 2011 +0100 @@ -22,7 +22,7 @@ name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.3.dev2', + version='2.0.3.dev3', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], --- a/testing/test_junitxml.py Wed Mar 16 19:05:28 2011 +0100 +++ b/testing/test_junitxml.py Sat Mar 19 17:59:07 2011 +0100 @@ -58,6 +58,26 @@ assert_attr(fnode, message="test setup failure") assert "ValueError" in fnode.toxml() + def test_skip_contains_name_reason(self, testdir): + testdir.makepyfile(""" + import pytest + def test_skip(): + pytest.skip("hello23") + """) + result, dom = runandparse(testdir) + assert result.ret == 0 + node = dom.getElementsByTagName("testsuite")[0] + assert_attr(node, skips=1) + tnode = node.getElementsByTagName("testcase")[0] + assert_attr(tnode, + classname="test_skip_contains_name_reason", + name="test_skip") + snode = tnode.getElementsByTagName("skipped")[0] + assert_attr(snode, + type="pytest.skip", + message="hello23", + ) + def test_classname_instance(self, testdir): testdir.makepyfile(""" class TestClass: Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. From commits-noreply at bitbucket.org Sat Mar 19 20:13:26 2011 From: commits-noreply at bitbucket.org (Bitbucket) Date: Sat, 19 Mar 2011 19:13:26 -0000 Subject: [py-svn] commit/pytest: hpk42: shift version string to _pytest directory Message-ID: <20110319191326.6846.40748@bitbucket03.managed.contegix.com> 1 new changeset in pytest: http://bitbucket.org/hpk42/pytest/changeset/b8f6abd0c27f/ changeset: r2192:b8f6abd0c27f user: hpk42 date: 2011-03-19 20:13:04 summary: shift version string to _pytest directory affected #: 2 files (32 bytes) --- a/_pytest/__init__.py Sat Mar 19 17:59:07 2011 +0100 +++ b/_pytest/__init__.py Sat Mar 19 20:13:04 2011 +0100 @@ -1,1 +1,2 @@ # +__version__ = '2.0.3.dev3' --- a/pytest.py Sat Mar 19 17:59:07 2011 +0100 +++ b/pytest.py Sat Mar 19 20:13:04 2011 +0100 @@ -1,11 +1,11 @@ """ unit and functional testing with Python. """ -__version__ = '2.0.3.dev3' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins from _pytest import core as cmdline +from _pytest import __version__ if __name__ == '__main__': # if run as a script or by 'python -m pytest' raise SystemExit(main()) Repository URL: https://bitbucket.org/hpk42/pytest/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.