Compare commits

...

304 Commits
2.5.2 ... 2.6.3

Author SHA1 Message Date
holger krekel
b57545bd21 fix doc release version 2014-09-24 14:59:55 +02:00
holger krekel
2eef674615 regen and fix some docs (tox -e regen)
bump versions, depend on already released py-1.4.25
2014-09-24 14:46:56 +02:00
holger krekel
bf7c5ea32c add changelog: check xfail/skip also with non-python function test items. Thanks
Floris Bruynooghe.
2014-09-24 13:55:55 +02:00
Floris Bruynooghe
62b8712ca9 Let xfail work on non-python Items
For some reason xfail was only implemented on non-python Item
instances.  This removes this guard which means plugins creating new
items can raise pytest.xfail.Exception and it will work as expected.
2014-09-23 23:55:26 +01:00
holger krekel
68105b3ae4 mention Wolfang wrt pytest_enter_pdb 2014-09-23 15:43:46 +02:00
holger krekel
be503f1c43 Merged in wosc/pytest (pull request #204)
Introduce pytest_enter_pdb hook
2014-09-23 14:04:47 +02:00
holger krekel
5abca55412 Merged in nicoddemus/pytest (pull request #203)
fix issue575: xunit-xml reporting collection errors as failures
2014-09-22 19:25:34 +02:00
holger krekel
79d2edcbff Merged in flub/pytest (pull request #207)
Show both user assertion msg as explanation (issue549)
2014-09-22 19:16:10 +02:00
holger krekel
e2c6a77f06 Merged in davidszotten/pytest/stop_leaking_fds (pull request #206)
stop leaking file descriptors
2014-09-22 15:02:48 +02:00
David Szotten
35eec99d41 stop leaking file descriptors
tripps --lsof on os x but not on linux. there's possibly a bug in the leak
detector (not investigated here)

--HG--
branch : stop_leaking_fds
2014-09-22 13:56:07 +01:00
holger krekel
e4fde1048b Merged in davidszotten/pytest/dontreadfrominput-encoding (pull request #205)
add `encoding` attr to DontReadFromInput
2014-09-22 13:34:50 +02:00
David Szotten
bc4eecbbac add encoding attr to DontReadFromInput
required by https://docs.python.org/2/library/stdtypes.html#file.encoding

and used e.g. by ipdb at _import_ time

--HG--
branch : dontreadfrominput-encoding
2014-09-22 12:19:27 +01:00
Wolfgang Schnerring
1408c9f077 Introduce pytest_enter_pdb hook 2014-09-18 14:58:42 +02:00
Bruno Oliveira
418607846a fix issue575: xunit-xml reporting collection errors as failures 2014-09-15 22:04:46 -03:00
holger krekel
6aa5611ae5 fix issue584: fix py3 syntax errors for example/special.txt.
Thanks Bruno Oliveira.
2014-09-15 15:04:09 +02:00
holger krekel
c5c9fb93aa fix link to pylib 2014-09-15 14:04:31 +02:00
Anatoly Bubenkov
86961291e5 add badges to the readme 2014-09-15 11:07:28 +00:00
Anatoly Bubenkov
7c1dadee51 Merged in conftest-nodeid (pull request #202)
fix conftest related fixture visibility issue
2014-09-15 13:04:07 +02:00
Anatoly Bubenkov
b16553e34e Close branch conftest-nodeid
--HG--
branch : conftest-nodeid
2014-09-15 13:04:07 +02:00
holger krekel
b6dcfd4377 fix conftest related fixture visibility issue: when running with a
CWD outside a test package pytest would get fixture discovery wrong.
Thanks to Wolfgang Schnerring for figuring out a reproducable example.

--HG--
branch : conftest-nodeid
2014-09-15 12:44:16 +02:00
holger krekel
1a80487e71 fix issue589: fix bad interaction with numpy and others when showing
exceptions.  check for precise "maximum recursion depth exceed" exception
instead of presuming any RuntimeError is that one (implemented in py dep)
Thanks Charles Cloud for analysing the issue.
2014-09-14 17:24:27 +02:00
holger krekel
488720da8d fix a broken link 2014-09-10 09:57:12 +02:00
holger krekel
0264121c10 fix issue587: claim only python2.6 compat in README/pypi project page, thanks sscarwell 2014-09-09 11:22:39 +02:00
Floris Bruynooghe
d2f448ecee Improve pytest.raises examples
Fixes issue #586.
2014-09-08 14:26:31 +01:00
Floris Bruynooghe
c692a0ee9c Remove jython from tested python versions
After testing with the jython 2.7 beta it seems it will require some
work to get jython back working.  So for now remove it from this list
so it doesn't get picked up by normal test runs.
2014-09-06 18:44:18 +01:00
Floris Bruynooghe
4063b7f8e0 Mention PR #194 in the changelog 2014-09-06 00:00:43 +01:00
Floris Bruynooghe
a8dfe34bfb Merged in uweschmitt/pytest/default (pull request #194) 2014-09-05 23:57:18 +01:00
Floris Bruynooghe
7d9d502a01 Use py3k compatible .__getattr__() code
From the python-dev thread it seemed like using
object.__getattribute__(self, 'name') is the cleanest way of
implementing a class wich uses .__getattr__() and should be
pickelable.  That only works on new-style classes so this also turns
HookProxy into a new-style class on py2.

This also re-writes the test to not use cPickle so it runs on py3k.
2014-09-05 23:55:14 +01:00
holger krekel
09a44f4cac fix issue582: fix setuptools example, thanks Laszlo Papp and Ronny
Pfannschmidt.
2014-09-05 15:34:01 +02:00
holger krekel
b14b9515a5 mention XXX regendoc for release process 2014-09-05 13:55:58 +02:00
holger krekel
2a504a5bcd regen docs for 2.6.2 2014-09-05 13:55:00 +02:00
holger krekel
dfcdf644fe Added tag 2.6.2 for changeset a4f25c5e6498 2014-09-05 13:47:48 +02:00
holger krekel
7dad3cb157 prepare 2.6.2, release announcement, also add HOWTORELEASE.rst 2014-09-05 13:13:23 +02:00
holger krekel
745737e337 strike python2.5 from test code cc @flub 2014-09-05 09:50:40 +02:00
Floris Bruynooghe
eae1055fb0 Merged in nocoddemus/pytest/cx_freeze-support (pull request #189) 2014-09-03 21:55:46 +01:00
holger krekel
2e1c36bbb6 merged in flub/pytest (PR #195) 2014-09-02 12:33:19 +02:00
holger krekel
e3cea41dcd fix issue572 - python3 compat of tmpdir example in docs. 2014-09-02 12:20:16 +02:00
Benjamin Peterson
c0f091d540 remove debugging turd 2014-09-01 16:51:44 -04:00
Benjamin Peterson
d4cd1aad8e improvements to rewrite cache invalidation
- stat the source path before it is read.
- Validate the source size in addition to mtime.
2014-09-01 16:51:27 -04:00
Floris Bruynooghe
39a297afe6 Improve test by also matching expected output 2014-08-30 21:57:01 +01:00
Floris Bruynooghe
068548f7a9 Merged in flub/pytest (pull request #196) 2014-08-27 21:00:24 +01:00
Bruno Oliveira
0c163ce624 Updating plugins_index
Also fixed duplicated links when repository is not github or
bitbucket
2014-08-26 20:38:19 -03:00
Floris Bruynooghe
7760cf1881 Fix doctest tox run
The new failures in the failure demo apparently affect the
doctests tox run.
2014-08-23 19:01:26 +02:00
Floris Bruynooghe
37bd1e03cb Show user assertion messages and instrospection together
User provided messages, or any valid expression given as second
argument to the assert statement, are now shown in addition to the
py.test introspection details.  Formerly any user provided message
would entirely replace the introspection details.

Fixes issue549.
2014-08-23 18:14:25 +02:00
Bruno Oliveira
fc95877622 Added changelog entry for freeze_includes()
--HG--
branch : cx_freeze-support
2014-08-23 10:10:32 -03:00
Bruno Oliveira
03b694a1d0 merging with default
--HG--
branch : cx_freeze-support
2014-08-23 10:05:40 -03:00
Floris Bruynooghe
79c2a47985 Improve the docstring further 2014-08-23 12:10:16 +02:00
Floris Bruynooghe
9289d77a80 Mention why no universal wheel in changelog
Fixes issue566.
2014-08-22 20:22:51 +02:00
Floris Bruynooghe
2eee2d0099 Merged in sontek/pytest/fix_universal (pull request #198)
Removed marking pytest as universal, py26 and py27 are not compatible.
2014-08-22 20:16:17 +02:00
sontek@gmail.com
0ea46e6aef Removed marking pytest as universal, py26 and py27 are not compatible.
--HG--
branch : fix_universal
2014-08-21 12:47:53 -07:00
Floris Bruynooghe
b0ac3581dd Mention doc fix in changelog 2014-08-19 21:00:46 +02:00
Floris Bruynooghe
e7ed45a5d4 Explain why this is important 2014-08-19 20:50:25 +02:00
uweschmitt
d1bde69c1e added smoke test for bug fixed in 3716:dc080608b6d1 2014-08-19 12:57:37 +02:00
Thomas Weißschuh
7cf859085e [doc] fix requests monkeypatch example 2014-08-18 19:44:34 +00:00
Floris Bruynooghe
424479cf0f Escape newlines in repr for assertion rewriting
The assertion formatting mini-language depends on newlines being
escaped.  Unfortunately if the repr of an object contained
newlines the rewriting module did not escape those, which is now
fixed.

Fixes issue453.
2014-08-18 20:07:38 +02:00
Floris Bruynooghe
98dcd764bc Depend on newer version of py
This fixes issue560, a test for which is included here as well.
2014-08-14 23:23:04 +01:00
Bruno Oliveira
ccd67733fb standard lib modules no longer required in freeze_includes() and updated docs
--HG--
branch : cx_freeze-support
2014-08-11 20:20:41 -03:00
Bruno Oliveira
5873ca5146 Merging with default
--HG--
branch : cx_freeze-support
2014-08-11 20:07:11 -03:00
Bruno Oliveira
d2903507d8 Moved freeze_includes() to genscript
--HG--
branch : cx_freeze-support
2014-08-11 20:03:14 -03:00
uweschmitt
224b3a2eda hopefully final fix for strange infinite recursion bug 2014-08-11 12:57:47 +02:00
uweschmitt
5d024c7433 hopefully final fix for strange infinite recursion bug 2014-08-11 12:42:36 +02:00
holger krekel
9232b88df3 actually regen fixture docs with python3.4 instead of python2.7 (doh) 2014-08-08 15:25:16 +02:00
holger krekel
e98f77037e fix issue561 example adapted to python3. 2014-08-08 15:20:37 +02:00
holger krekel
672e42e558 fix doc config for latex 2014-08-07 23:05:02 +02:00
holger krekel
36d7df4542 Added tag 2.6.1 for changeset a4f9639702ba 2014-08-07 22:55:17 +02:00
holger krekel
e5eaf02e19 finalize pytest-2.6.1 release, regen docs 2014-08-07 21:41:51 +02:00
uweschmitt
c0d1f3f7ef even better fix as replacement for last commit which was wrong 2014-08-07 17:17:05 +02:00
uweschmitt
9597d3dafe better fix as replacement for last commit 2014-08-07 16:56:45 +02:00
uweschmitt
f7282b84bd fixed strange infinite recursion bug 2014-08-07 16:13:12 +02:00
holger krekel
1d7b574b31 fix issue555: just add "errors" attribute to internal Capture stream. 2014-08-07 11:05:42 +02:00
holger krekel
d16fdb378c merge PR192, streamline a bit. 2014-08-07 10:42:23 +02:00
Bruno Oliveira
cc092afd3b updated CHANGELOG and trace error message as requested in review
fixes issue #437

--HG--
branch : assertionrewrite-currupted-pyc
2014-08-04 20:38:50 -03:00
Bruno Oliveira
fd4485a540 Fixed assertionrewrite._read_pyc to handle corrupted pyc files properly
This seems to be the cause for issues #437 and #301.

--HG--
branch : assertionrewrite-currupted-pyc
2014-08-02 18:01:28 -03:00
Floris Bruynooghe
3b8779ad17 Mention change in -v output in changelog 2014-08-01 23:11:25 +01:00
Floris Bruynooghe
3e875178ad Merge default 2014-08-01 23:06:24 +01:00
holger krekel
97b671057d put some imports back to function-level and streamline py2/py3 compat in one place 2014-08-01 10:12:53 +02:00
holger krekel
d6fc489b2b Backed out changeset e57017ad86ce -- logging should not be imported 2014-08-01 08:13:44 +02:00
Floris Bruynooghe
4e8438afc8 Simply show the node ID for verbose output
This strips the line number, /@\d/, from the verbose output so it is
directly the node ID of the test.  This in turn means no special logic
for accepting the line number as part of the node ID is needed when
parsing the command line.
2014-08-01 00:29:35 +01:00
Bruno Oliveira
b1f8038abf Minor fixed in test_capture
This test failed only in py34. We don't import logging directly,
but it seems that one of the standard modules that are now
globally imported started including this on py34.

Just removed the assert as it doesn't seem central to the
test's objective.
2014-07-31 19:52:08 -03:00
Bruno Oliveira
5603a0cd4b Removing py.std usage from _pytest 2014-07-31 19:13:40 -03:00
Bruno Oliveira
3c649cf91d guarding scripts with __main__ and doc changes
tox-flakes environment tries to import the modules for
checking, and that may fail because of its dependencies

--HG--
branch : cx_freeze-support
2014-07-30 22:28:03 -03:00
Bruno Oliveira
82d573e391 fixed line endings for test_doctest.txt
--HG--
branch : cx_freeze-support
2014-07-30 21:57:19 -03:00
Bruno Oliveira
b7b96b24d8 Docs about cx_freeze support and minor adjustments
--HG--
branch : cx_freeze-support
2014-07-30 21:50:00 -03:00
Bruno Oliveira
990e7bf3b9 first implementation and tox environment for cx-freeze support
--HG--
branch : cx_freeze-support
2014-07-30 19:16:51 -03:00
holger krekel
bcdc3d0154 reorder talks, more talks from pelme and others 2014-07-29 15:06:37 +02:00
holger krekel
faea7e1407 add flub and pelme talks at EuroPython2014, remove one past training note 2014-07-29 15:00:45 +02:00
holger krekel
7c701948d5 Merged in nicoddemus/pytest/cx_freeze-docs (pull request #188)
Documentation example on how to integrate pytest and cx_freeze
2014-07-29 12:43:04 +02:00
Bruno Oliveira
899b804ec1 Improved the text a little
--HG--
branch : cx_freeze-docs
2014-07-28 22:46:57 -03:00
Bruno Oliveira
66bd4e485a Adding blurb about using pytest runner and cx_freeze
--HG--
branch : cx_freeze-docs
2014-07-28 22:40:23 -03:00
Anatoly Bubenkov
8ff8dd3ae9 Merged in fix_initial_parsing (pull request #186)
Fix issue544 and fix another issue with parsing ``::``
2014-07-28 14:16:02 +02:00
holger krekel
0d17dc1e19 add a comment for why we only consider .py files when removing @
--HG--
branch : fix_initial_parsing
2014-07-28 13:56:10 +02:00
holger krekel
83e0b52294 speedup @ replacement for the massive lists from pytest-bdd :)
--HG--
branch : fix_initial_parsing
2014-07-28 13:53:53 +02:00
holger krekel
1265612465 fix issue547 2.6 regression: capsys/capfd now work again when output capturing ("-s") is disabled. 2014-07-28 13:17:37 +02:00
holger krekel
40eed363e8 fix issue544 by only removing "@NUM" at the end of a part (parts are
separated by "::") and if the part has an .py extension.

--HG--
branch : fix_initial_parsing
2014-07-28 12:07:15 +02:00
holger krekel
5ccd3f2fc5 fix conftest detection if commandline arguments contain "::" syntax
--HG--
branch : fix_initial_parsing
2014-07-28 11:48:37 +02:00
holger krekel
ba878c6d9d add changelog entry and refactor unittest.mock.patch fix a bit 2014-07-28 10:34:01 +02:00
holger krekel
8792261df1 Merged in ticosax/pytest/mock-unittest-252 (pull request #184)
Injection of fixture doesn't work when decorated with unittest.mock.patch
2014-07-28 10:31:31 +02:00
holger krekel
c2ed29070a address issue170 by merging David Mohr's PR on adding "raises" as an optional
argument to pytest.mark.xfail.
2014-07-28 09:59:22 +02:00
holger krekel
38104dfc92 Merged in squisher/pytest/xfail-cause (pull request #183)
Add mark.xfail argument raises so that unexpected exceptions show up as test failures.
2014-07-28 09:55:02 +02:00
Nicolas Delaby
2e55c4ba61 unittest.mock from stdlib should come last
--HG--
branch : mock-unittest-252
2014-07-27 12:11:39 +02:00
Nicolas Delaby
e6ad6e02d2 Handle also unittest.mock
Move handling in dedicated function to isolate its logic

--HG--
branch : mock-unittest-252
2014-07-27 10:43:50 +02:00
david@mcbf.net
d08c4ce0ad Tiny example update for clarification
--HG--
branch : xfail-cause
2014-07-26 18:24:55 +02:00
david@mcbf.net
309e3d38a0 Directly pass multiple parameters with mark.parametrize()
--HG--
branch : xfail-cause
2014-07-26 18:19:27 +02:00
david@mcbf.net
91e2b23258 Update documentation
--HG--
branch : xfail-cause
2014-07-26 18:10:32 +02:00
david@mcbf.net
6a4492a22d isinstance() on exception value instead of comparing types, consolidate tests
--HG--
branch : xfail-cause
2014-07-26 17:46:50 +02:00
Nicolas Delaby
0dd378da30 Injection of fixture doesn't work when decorated with unittest.mock.patch
This is a continuation of #182

--HG--
branch : mock-unittest-252
2014-07-26 17:26:18 +02:00
david@mcbf.net
7b273b8577 Add mark.xfail argument raises so that unexpected exceptions show up as test failures.
--HG--
branch : xfail-cause
2014-07-26 15:11:05 +02:00
holger krekel
d98521b0d9 Added tag 2.6.0 for changeset 88af949b9611 2014-07-20 13:15:44 +02:00
holger krekel
52011e84d3 merge 2014-07-20 13:15:21 +02:00
holger krekel
de583ed7a3 some notes about upcoming trainings 2014-07-20 13:07:38 +02:00
holger krekel
f8480caae4 Added tag 2.6.0 for changeset 60725b17a9d1 2014-07-20 13:03:11 +02:00
holger krekel
47d9e6ca1f fix release announce 2014-07-20 11:07:18 +02:00
Bruno Oliveira
6f0a33dfdc Updating plugins_index 2014-07-18 21:10:50 -03:00
Floris Bruynooghe
1641d00cb1 Merge default 2014-07-18 01:34:08 +01:00
Floris Bruynooghe
2d7a32f7ea Add test case for using different modules 2014-07-18 01:30:29 +01:00
holger krekel
06acbb9f5e bump doc version 2014-07-17 17:22:44 +02:00
holger krekel
7b630d9080 mention next open trainings at EP2014 and in Freiburg in November 2014 2014-07-17 17:21:45 +02:00
holger krekel
98de64badc regen docs for pytest-2.6 2014-07-17 16:55:24 +02:00
holger krekel
1e241e1f2a mention py34 compatibility 2014-07-17 16:49:10 +02:00
holger krekel
ff2c18fedb bump version, preliminary announcement 2014-07-17 16:38:54 +02:00
holger krekel
bf64a800d6 pytest depends on the freshly released 1.4.22 to function properly 2014-07-17 10:55:52 +02:00
Jurko Gospodnetić
efc57391eb remove extra parentheses - stylistic code change 2014-07-17 08:35:36 +02:00
Benjamin Peterson
dc65aa1fea avoid importing old assertion interpretation code by default (fixes #537) 2014-07-16 17:21:18 -07:00
holger krekel
80ad3fb8ed Merged in wooparadog/pytest (pull request #163)
Also replace `report.longrepr` with `bin_xml_escape`ed skipreason
2014-07-15 22:17:15 +02:00
holger krekel
bc7110931a Merged in alex_gaynor/pytest/alex_gaynor/marked-pytest-as-being-a-universal-wheel-1405267754279 (pull request #179)
Marked pytest as being a universal wheel.
2014-07-15 11:26:08 +02:00
holger krekel
8c508612ec with pypy this tests leaks one FD but it's probably a residual effect of the testing machinery and Pypy's lazy GC. 2014-07-14 09:17:04 +02:00
Alex Gaynor
b7d046527e Marked pytest as being a universal wheel.
--HG--
branch : alex_gaynor/marked-pytest-as-being-a-universal-wheel-1405267754279
2014-07-13 16:09:24 +00:00
holger krekel
42804c52e8 Merged in bmcorser/pytest-1/bmcorser/scratching-an-itch-love-pytest-1404943207227 (pull request #178)
Scratching an itch. Love py.test!
2014-07-10 09:00:24 +02:00
bmcorser
d88a3712c5 Scratching an itch. Love py.test!
--HG--
branch : bmcorser/scratching-an-itch-love-pytest-1404943207227
2014-07-09 22:00:24 +00:00
Bruno Oliveira
abfedd692e Updating plugins_index 2014-07-08 20:08:19 -03:00
holger krekel
d0b048c86d Merged in msabramo/pytest/norecursedirs_add_star_dot_egg (pull request #177)
Add *.egg to default for norecursedirs
2014-07-03 16:51:17 +02:00
Marc Abramowitz
b6f069f4c3 Add *.egg to default for norecursedirs
--HG--
branch : norecursedirs_add_star_dot_egg
2014-07-03 07:49:03 -07:00
holger krekel
edc2e5ab82 Merged in msabramo/pytest/fix_norecursedirs_doc_typos (pull request #176)
doc/en/customize.txt: Fix norecursedirs typo
2014-07-03 16:47:58 +02:00
Marc Abramowitz
6da9a087f8 doc/en/customize.txt: Fix norecursedirs typo
and update documented default to match current default.

--HG--
branch : fix_norecursedirs_doc_typos
2014-07-03 07:36:07 -07:00
holger krekel
e19462d581 fix ordering of import line of last commit 2014-07-03 13:20:51 +02:00
holger krekel
a811fabb43 avoid importing "py.test" (an old alias module for "pytest") 2014-07-03 12:58:12 +02:00
holger krekel
07e76cbef2 fix issue364: shorten and enhance tracebacks representation by default.
The new "--tb=auto" option (default) will only display long tracebacks
for the first and last entry.  You can get the old behaviour of printing
all entries as long entries with "--tb=long".  Also short entries by
default are now printed very similarly to "--tb=native" ones.
2014-06-29 13:32:53 +02:00
holger krekel
76d5c9e4f4 Merged in c_henz/pytest/explicit-ini-filename (pull request #175)
Implement the "-c" command line switch that allows to explicitly specifiy the config file to load.
2014-06-29 12:08:29 +02:00
holger krekel
abcadc4202 colors as used on the live web page 2014-06-29 09:47:50 +02:00
Christian Henz
b7f6a9f3fd Cleaner implementation of early handling of the '-c' command line switch.
--HG--
branch : explicit-ini-filename
2014-06-28 12:03:55 +02:00
christian@christian-linux.sarrazin.local
c8264385ea Implement the "-c" command line switch that allows to explicitly specifiy the config file to load.
This feature was requested in issue #174.

--HG--
branch : explicit-ini-filename
2014-06-27 17:42:37 +02:00
Floris Bruynooghe
ad8131be9e Re-add accidentally removed changelog items 2014-06-24 22:46:57 +01:00
holger krekel
54c88a6cf3 fix flakes issues 2014-06-16 11:27:32 +02:00
Floris Bruynooghe
115f15600f Add test for inter-dependent fixtures
Together with cc0a46a13ac4 this fixes issue 467.
2014-06-15 19:57:52 +01:00
Bruno Oliveira
65a145e2a7 Updated plugins index 2014-06-10 19:04:52 -03:00
holger krekel
5719a72eeb Merged in zyegfryed/pytest/zyegfryed/fixed-typo-noticed-by-dcramer-httpstwitt-1401780587159 (pull request #172)
Fixed typo noticed by @zeeg (https://twitter.com/zeeg/status/473676721128886272)
2014-06-03 09:49:02 +02:00
Sébastien Fievet
4bc4495115 Fixed typo noticed by @dcramer (https://twitter.com/zeeg/status/473676721128886272)
--HG--
branch : zyegfryed/fixed-typo-noticed-by-dcramer-httpstwitt-1401780587159
2014-06-03 07:30:14 +00:00
holger krekel
c66e9f8f0f fix typo, thanks @dcramer 2014-06-03 07:21:02 +02:00
holger krekel
52eafdc21e also add favicon 2014-06-01 12:36:31 +02:00
holger krekel
85c0d5481b incorporate the new pytest logo 2014-06-01 12:01:40 +02:00
Benjamin Peterson
fd9055fd11 fix test on Python 3.2 2014-05-31 14:51:05 -07:00
Benjamin Peterson
780bdda95a assert reinterpretation: try mangling attributes that look like private class vars (fixes #514) 2014-05-31 14:37:02 -07:00
Bruno Oliveira
fd4b461290 Updated plugins_index and updated python 3 to 3.4 2014-05-28 23:16:49 -03:00
holger krekel
040062e40c improve example for pytest integration with "python setup.py test"
which now has a generic "-a" or "--pytest-args" option where you
can pass additional options as a quoted string.  Thanks Trevor Bekolay.
2014-05-19 20:32:09 +02:00
holger krekel
d853e9167a Merged in tbekolay/pytest/tbekolay/better-setuptools-integration-in-goodpra-1400520902689 (pull request #171)
Better setuptools integration in goodpractices
2014-05-19 20:30:54 +02:00
Trevor Bekolay
d50ad270f0 Better setuptools integration in goodpractices
--HG--
branch : tbekolay/better-setuptools-integration-in-goodpra-1400520902689
2014-05-19 17:35:28 +00:00
holger krekel
30c93701a7 fix issue516: tell in getting-started about current dependencies.
cleanup setup.py a bit and specify supported versions. Thanks Jurko
Gospodnetic for the PR.
2014-05-14 09:58:34 +02:00
holger krekel
b507e1754c fix issue512 : document dependencies in getting-started doc. 2014-05-14 09:14:40 +02:00
holger krekel
748fce94fd Merged in jurko/pytest/setup cleanup (pull request #169)
setup.py cleanup/update (updated from pull request #167)
2014-05-14 09:10:13 +02:00
holger krekel
d6281b4206 - restore compatibility to old getvalueorskip behaviour
- introduce a better NOTSET representation to improve docs
2014-05-14 07:36:31 +02:00
holger krekel
b61ed2cf7e Merged in jurko/pytest/python 3.1 fix (pull request #168)
use py.builtin.callable instead of raw callable in _pytest/runner.py
2014-05-13 22:41:12 +02:00
Jurko Gospodnetić
9263f30c88 use py.builtin.callable instead of raw callable in _pytest/runner.py
This is consistent with how callable() is called from the rest of pytest code
(see _pytest/nose.py & _pytest/python.py) plus, as a nice side-effect, it
makes pytest work correctly on Python 3.1.

--HG--
branch : python 3.1 fix
2014-05-13 21:05:53 +02:00
Jurko Gospodnetić
8f9a88ef7a update the list of officially supported Python versions in setup.py
Removed Python 3.0 & 3.1 off the list and added Python 3.4.

--HG--
branch : setup cleanup
2014-05-13 19:03:17 +02:00
Jurko Gospodnetić
c64af0d9ce stylistic setup.py code cleanup
--HG--
branch : setup cleanup
2014-05-13 19:02:02 +02:00
holger krekel
9181df42da Merged in msabramo/pytest/require_argparse_for_py3_lt_32 (pull request #166)
setup.py: Require argparse for PY3 < 3.2
2014-05-11 19:30:11 +02:00
holger krekel
74e1a49dd7 remove the idea that nose support should be moved to a plugin. 2014-05-10 14:00:09 +02:00
holger krekel
468b1241a5 fix issue512: show "<notset>" for arguments which might not be set
in monkeypatch plugin.  Improves output in documentation.
2014-05-10 13:49:24 +02:00
Marc Abramowitz
24744cf5cf setup.py: Require argparse for PY3 < 3.2
E.g.: python3.1; noticed py31 failure while running tox for six

--HG--
branch : require_argparse_for_py3_lt_32
2014-05-09 23:40:06 -07:00
Floris Bruynooghe
ffc969b6c2 Do not list python 2.5 as supported in the docs 2014-05-01 22:25:03 +01:00
WooParadog
0567a8ee77 Add test for skipped case with utf-8 message 2014-04-24 10:45:39 +08:00
WooParadog
580c8525f0 Use processced skipreason for generating skip Junit node 2014-04-23 15:38:40 +08:00
WooParadog
d6010aa0c9 Also replace report.longrepr with bin_xml_escapeed skipreason 2014-04-23 14:50:21 +08:00
Floris Bruynooghe
c46e2cbbc7 Cache exception raised in fixtures according to their scope
Without this if a session scoped fixture fails it's setup it will
be re-tried each time it is requested.  Especially in case of
skip or failure exceptions this can be undesirable, but caching
makes sense for all exceptions.
2014-04-15 22:22:41 -04:00
Floris Bruynooghe
c47835f5ec Merge pull request #158, fixes issue 504 2014-04-15 11:43:38 -04:00
Floris Bruynooghe
412b56f7cf Changelog for issue 475 2014-04-14 18:12:29 -04:00
Floris Bruynooghe
faba432996 Improve error message if pytest.raises is used wrongly
If the type is not checked then an incomprehensible error will occur
later.  This enforces the type and raies the same exception/msg as
CPython does in that case.

Docstring unmodified, just re-justified for pep8 compat.
2014-04-14 18:09:10 -04:00
Andy Freeland
2ba23e8d08 issue504: verbose output displays node IDs for each test
Replace the verbose per-test reporting format of `file:line test_name RESULT`
with the node ID of the test, i.e. `file@line::class::method[param] RESULT`.

This patch does not update the examples in the docs; @hpk42 has a script
to regenerate those.

--HG--
branch : issue504
2014-04-14 17:42:02 -04:00
Floris Bruynooghe
d74f852fd6 Merged in rouge8/pytest/issue499 (pull request #157)
fix issue499: document selecting tests by node ID
2014-04-14 14:31:07 -04:00
Andy Freeland
1728798e81 Interal link to node ID explanation
--HG--
branch : issue499
2014-04-14 14:24:13 -04:00
Andy Freeland
53a8d20d88 fix issue499: document selecting tests by node ID
--HG--
branch : issue499
2014-04-14 12:27:55 -04:00
Floris Bruynooghe
61446faa17 Update changelog with last change 2014-04-12 17:01:05 -04:00
Floris Bruynooghe
9711e335d9 Change XPASS colour to be yellow rather then red
Unfortunately I'm not sure how to test this.
2014-04-12 10:27:12 -04:00
Anatoly Bubenkov
080a9d2f12 Merged in hpk42/pytest-hpk/nose_test_attr (pull request #154)
support nose-style __test__ attribute to disable collection of test modules/classes/functions
2014-04-10 22:38:53 +02:00
holger krekel
15af7e1662 fix tests to properly fail on failed collectiosn (which was hiding an error)
and also implement __test__=False for test functions properly.

--HG--
branch : nose_test_attr
2014-04-10 13:37:39 +02:00
holger krekel
e42cbc714f fix wrong merge
--HG--
branch : nose_test_attr
2014-04-10 12:58:10 +02:00
holger krekel
5e26e6e553 fix typo in changelog
--HG--
branch : nose_test_attr
2014-04-10 12:56:14 +02:00
holger krekel
d0a4d348fe merge default
--HG--
branch : nose_test_attr
2014-04-10 12:53:33 +02:00
holger krekel
494be731e3 support nose-style `__test__` attribute on modules, classes and
functions, including unittest-style Classes.  If set to True, the
test will not be collected.

--HG--
branch : nose_test_attr
2014-04-10 12:46:27 +02:00
Ronny Pfannschmidt
8ae244a06a Merged in hpk42/pytest-hpk/issue473 (pull request #152)
fix issue473: work around mock putting an unbound method into a class
2014-04-09 06:46:01 +02:00
holger krekel
f91049cec9 fix issue473: work around mock putting an unbound method into a class
dict when double-patching.

--HG--
branch : issue473
2014-04-08 12:50:13 +02:00
Ronny Pfannschmidt
270d0f89ba Merged in hpk42/pytest-hpk/issue498 (pull request #151)
fix issue498: if a fixture finalizer fails, make sure that the fixture
2014-04-07 13:51:03 +02:00
holger krekel
e382ed4245 fix issue439: clarify that capsys/capfd capture output during
test execution, not test setup.
2014-04-07 13:42:48 +02:00
holger krekel
ef7cb47b1e fix issue498: if a fixture finalizer fails, make sure that the fixture
is still invalidated.

--HG--
branch : issue498
2014-04-07 13:29:57 +02:00
holger krekel
6efde60b8b Merged in jurko/pytest/jurko/tox_usage (pull request #150)
runtox.py cleanup
2014-04-06 08:16:24 +02:00
Jurko Gospodnetić
fd059359cc make runtox.py not import external modules unless run as a script
Was not needed since the script actually does nothing unless run as a script.

--HG--
branch : jurko/tox_usage
2014-04-05 08:51:00 +02:00
Jurko Gospodnetić
c2c504797e stylistic runtox.py code cleanup
--HG--
branch : jurko/tox_usage
2014-04-05 08:49:30 +02:00
Jurko Gospodnetić
84f9f45f98 fix runtox.py failure when 'tox' is not available on the current system path
Now just assumes that the tox module is available in the executing Python
environment.

--HG--
branch : jurko/tox_usage
2014-04-05 08:47:04 +02:00
holger krekel
28aa4c891e bump version to 2.6.0.dev1 because i think we are going for a 2.6.0 release next
and not just a 2.5 maintenance one.
2014-04-03 22:27:04 +02:00
holger krekel
6ff0fdb977 fix issue443: fix skip examples to use proper comparison. Thanks Alex
Groenholm.
2014-04-03 22:26:10 +02:00
holger krekel
b0837693d0 add some changelog entries 2014-04-03 10:04:09 +02:00
holger krekel
52851e4388 Merged in jurko/pytest/fix_capfd_fixture_docstring (pull request #149)
correct a capfd fixture docstring typo
2014-04-03 10:02:00 +02:00
holger krekel
cbe31f3748 Merged in msabramo/pytest/makepyfile_utf8 (pull request #134)
Make makepyfile accept UTF-8 so a few cookie tests in test_assertrewrite.py
2014-04-03 10:00:24 +02:00
Jurko Gospodnetić
c9bbdf4f10 correct a capfd fixture docstring typo
--HG--
branch : fix_capfd_fixture_docstring
2014-04-03 09:59:04 +02:00
holger krekel
f984e94fca Merged in jurko/pytest/break_ExceptionInfo_reference_cycles (pull request #144)
break reference cycles caused by storing local reference to exception info
2014-04-03 09:47:41 +02:00
Anatoly Bubenkov
b4fe91943d Merged in hpk42/pytest-hpk/conftest-clean (pull request #148)
cleanup internal conftest handling and avoid the strange None entry in the conftest cache.
2014-04-03 09:38:47 +02:00
Anatoly Bubenkov
7d6317802e Merged in hpk42/pytest-hpk/issue486 (pull request #147)
fix issue486: better reporting and handling of early conftest loading failures
2014-04-03 00:19:05 +02:00
holger krekel
0365e5c3a0 cleanup internal conftest handling and avoid the strange None entry in the conftest cache.
(There is basically no reason to ask for conftestmodules without specifying a path.)

--HG--
branch : conftest-clean
2014-04-02 22:30:45 +02:00
holger krekel
e6859406f1 fix test on py33, thanks msabramo1 2014-04-02 20:49:57 +02:00
holger krekel
51cff6f106 fix issue486: better reporting and handling of early conftest loading failures
--HG--
branch : issue486
2014-04-02 20:42:41 +02:00
holger krekel
68e58e1493 add a test for robustness of capturing when a test closes FD1/2 2014-04-02 20:29:10 +02:00
holger krekel
9f7eac0ba1 Merged in msabramo/pytest/add_drone_io_to_README_rst (pull request #143)
README.rst: Add drone.io link
2014-04-02 19:13:26 +02:00
Floris Bruynooghe
b0e31dca86 Mention fix for issue 453 in changelog 2014-04-02 18:00:25 +01:00
holger krekel
7d10a57514 Merged in msabramo/pytest/remove_unused_import (pull request #146)
testing/test_capture.py: Remove unused stuff for PEP8 compliance
2014-04-02 18:56:46 +02:00
Marc Abramowitz
2c0f6207e9 test_capture.py: More PEP8. Remove unused cap in with.
--HG--
branch : remove_unused_import
2014-04-02 09:48:08 -07:00
Floris Bruynooghe
adb12d0d4f Escape newlines in result from assertrepr hook
The result from the pytest_assertrepr_compare hook should not include
any newlines since that will confuse the mini-formatting language used
by assertion.util.format_explanation.  So simply escape the included
newlines, this way hook writers do not have to worry about this at
all.

Fixes issue 453.
2014-04-02 17:35:22 +01:00
Floris Bruynooghe
844c141d10 Style fixes for pep8
Includes a quotation change for consistent style.
2014-04-02 17:16:37 +01:00
Marc Abramowitz
02d94e69f0 testing/test_capture.py: Remove unused import tempfile
--HG--
branch : remove_unused_import
2014-04-02 09:14:16 -07:00
Marc Abramowitz
1bc56f9838 README.rst: Remove drone.io build badge; keep link
hpk had concerns about the build badge confusing folks when shown on PyPI.

--HG--
branch : add_drone_io_to_README_rst
2014-04-02 06:41:33 -07:00
Jurko Gospodnetić
98ea8fae32 break reference cycles caused by storing local reference to exception info
Such reference cycles unnecessarily cause Python interpreter not to garbage
collect the objects referenced in those cycles as soon they could be collected,
and in turn cause the tests to use more memory than is strictly necessary.

--HG--
branch : break_ExceptionInfo_reference_cycles
2014-04-02 15:34:36 +02:00
holger krekel
36288c5134 fix issue493: don't run tests in doc directory with `python setup.py test`
(use tox -e doctesting for that)
2014-04-02 12:48:35 +02:00
holger krekel
83a3cc9c94 fix issue492: avoid leak in test_writeorg. Thanks Marc Abramowitz. 2014-04-02 12:32:30 +02:00
holger krekel
0c04b44919 fix issue492: avoid leak in test_writeorg 2014-04-02 12:32:21 +02:00
Marc Abramowitz
a5e8860feb README.rst: Add drone.io link and build badge image
--HG--
branch : add_drone_io_to_README_rst
2014-04-02 03:11:35 -07:00
holger krekel
8d95f89a6a fix issue496: add pytest-sugar github repo override and regen index pages, upload it. 2014-04-02 12:03:08 +02:00
holger krekel
3bca62e9e4 fix issue436: improved finding of initial conftest files from command
line arguments by using the result of parse_known_args rather than
the previous flaky heuristics.  Thanks Marc Abramowitz for tests
and initial fixing approaches in this area.
2014-04-02 11:29:23 +02:00
holger krekel
72b4534a0c add changelog entry for some PRs: improvements to pytest's own
test-suite leakage detection, courtesy of PRs from Marc Abramowitz
2014-04-02 09:51:24 +02:00
holger krekel
21b4280126 Merged in msabramo/pytest/test_writeorg_close_tempfile (pull request #136)
test_writeorg: Close a tempfile
2014-04-02 09:30:55 +02:00
holger krekel
30a9debaf1 Merged in msabramo/pytest/refactor_LsofFdLeakChecker (pull request #138)
testing/conftest.py: Refactor lsof fd leak checking
2014-04-02 09:24:16 +02:00
holger krekel
4c5718c78d Merged in msabramo/pytest/doc_plugins_pytest_sugar (pull request #141)
doc/en/plugins_index/index.txt: Update pytest-sugar
2014-04-02 09:20:42 +02:00
Marc Abramowitz
c93b949878 Update entry for pytest-sugar; GitHub icon instead of BitBucket, correct description
--HG--
branch : doc_plugins_pytest_sugar
2014-04-01 18:59:42 -07:00
Marc Abramowitz
cf34adb75f doc/en/plugins_index/index.txt: Update pytest-sugar
--HG--
branch : doc_plugins_pytest_sugar
2014-04-01 18:52:36 -07:00
Marc Abramowitz
f824a73143 Remove cast of fd to int and sorting
Casting of fd can break for non-numeric fd (e.g.: "rtd" on Linux) and isn't
necessary since we don't need to sort.

--HG--
branch : refactor_LsofFdLeakChecker
2014-04-01 15:36:54 -07:00
Marc Abramowitz
e45a33f029 testing/conftest.py: Reintialize config._openfiles for each test
And no longer need getopenfiles or config._numfiles

--HG--
branch : refactor_LsofFdLeakChecker
2014-04-01 14:13:11 -07:00
Marc Abramowitz
064e79761c Improve LsofFdLeakChecker; more reliable and useful leak checking
* Make it invoke lsof with options for machine-readable output
* Parse out file descriptor and filename from lsof output
* Draw attention to file descriptors now open that weren't open before

--HG--
branch : refactor_LsofFdLeakChecker
2014-04-01 13:41:35 -07:00
Marc Abramowitz
f7713c47e8 testing/conftest.py: Refactor lsof fd leak checking
Isolate the logic into one class to make easier to understand, more maintainable.
This may aid in later plugging in an alternative implementation, such as one
that uses psutil
(https://bitbucket.org/hpk42/pytest/pull-request/137/use-psutil-to-detect-open-files-in-tests/diff)

--HG--
branch : refactor_LsofFdLeakChecker
2014-04-01 10:15:27 -07:00
holger krekel
8e4e2ba244 merge main 2014-04-01 15:06:44 +02:00
holger krekel
3b8935c533 remove dupped_stdout logic and related changes, also simplify pytest_runtest_* calls to not use a contextlib with-decorator anymore. 2014-04-01 15:03:17 +02:00
holger krekel
ce8678e6d5 remove non-documented per-conftest capturing option and simplify/refactor all code accordingly. Also make capturing more robust against tests closing FD1/2 and against pdb.set_trace() calls. 2014-04-01 14:32:12 +02:00
holger krekel
2e1f6c85f6 introduce resume/suspend functionality for FDCapture and SysCapture,
fixing problems with early bailouts (from argparse's parse() function e.g.)
that wrote to stdout.
2014-04-01 14:19:58 +02:00
holger krekel
ca5e6830c6 avoid some redundancy by using SysCapture from FDCapture for manipulating sys.std{out,in,err} 2014-04-01 14:19:55 +02:00
holger krekel
69cbac8fb5 rename StdCaptureBase to MultiCapture 2014-04-01 14:19:52 +02:00
Marc Abramowitz
7301981f32 test_writeorg: Close a tempfile
--HG--
branch : test_writeorg_close_tempfile
2014-03-31 08:25:35 -07:00
Marc Abramowitz
555ba4159d Simplify tests; don't use u literal not supported in py32
--HG--
branch : makepyfile_utf8
2014-03-28 12:11:33 -07:00
Marc Abramowitz
f47ae74981 Make makepyfile accept UTF-8 so a few cookie tests in test_assertrewrite.py
don't need to be dedented.

--HG--
branch : makepyfile_utf8
2014-03-28 09:44:18 -07:00
holger krekel
e061ace099 fix toxenv spec for py33-pexpect, thanks Daniel Grana. 2014-03-28 14:51:00 +01:00
holger krekel
85d52481b1 fix issue483: trial/py33 works now properly. Thanks Daniel Grana for PR. 2014-03-28 14:47:34 +01:00
holger krekel
47379d4a79 Merged in dangra/pytest (pull request #132)
no need for im_func and it does not exists in python3
2014-03-28 14:46:34 +01:00
Daniel Grana
0cb9d26d83 add py33-trial tox environment 2014-03-28 10:44:51 -03:00
holger krekel
95cc114b34 add changelog entry:
fix issue412: messing with stdout/stderr FD-level streams is now
captured without crashes.
2014-03-28 11:29:29 +01:00
holger krekel
9d716a39d6 fix issue412 and other encoding issues. Streamline dupfile() into
a new more thoughtful safe_text_dupfile helper.
2014-03-28 11:27:02 +01:00
holger krekel
923dcfd620 cleanup and refine issue412 test (still failing on py33) 2014-03-28 09:46:38 +01:00
holger krekel
b5467645d3 merge 2014-03-28 09:27:44 +01:00
holger krekel
a65380941d Merged in msabramo/pytest/sys_meta_path_remove_hook_only_if_present (pull request #133)
Only try to remove hook from sys.meta_path if it's present
2014-03-28 09:10:58 +01:00
Marc Abramowitz
17d7c60735 test_sys_meta_path_munged: Simplify with makepyfile
--HG--
branch : sys_meta_path_remove_hook_only_if_present
2014-03-28 01:03:52 -07:00
Marc Abramowitz
81f822d528 Only try to remove hook from sys.meta_path if it's present
Prevent error on exit if some code messes with sys.meta_path and removes the
assertionrewrite hook (CaptureMock seems to do this):

      File "/Users/marca/dev/hg-repos/pytest/_pytest/assertion/__init__.py", line 64, in pytest_unconfigure
        sys.meta_path.remove(hook)
    ValueError: list.remove(x): x not in list

--HG--
branch : sys_meta_path_remove_hook_only_if_present
2014-03-28 00:33:12 -07:00
holger krekel
0b340aa1f6 simplify some capturing tests 2014-03-28 07:55:07 +01:00
holger krekel
859915dc5e simplify capturing funcarg handling 2014-03-28 07:13:08 +01:00
holger krekel
a8f4f49a82 simplify reset/stop_capturing and fix capturing wrt to capturing simple os.write() calls 2014-03-28 07:11:25 +01:00
holger krekel
e18c3ed494 unify and normalize Sys/FD Capturing classes
* * *
more unification
2014-03-28 07:03:37 +01:00
holger krekel
2263fcf6b7 remove unused "suspend/resume" on capturing, some formatting cleanup 2014-03-28 07:03:34 +01:00
Daniel Grana
b96d552dbd no need for im_func and it does not exists in python3 2014-03-27 23:57:18 -03:00
Ronny Pfannschmidt
2b2c1e5b7b condition for python3 of the xfailing test for 412 2014-03-27 14:01:38 +01:00
holger krekel
7b63fa5966 merge in current default 2014-03-27 13:57:54 +01:00
Ronny Pfannschmidt
b18040337a xfailing test for issue 412 2014-03-27 13:53:59 +01:00
holger krekel
42e0d7970c Merged in nloadholtes/pytest/nloadholtes/slight-change-to-the-wording-for-readabi-1395890493571 (pull request #131)
Slight change to the wording for readability
2014-03-27 06:40:35 +01:00
Nick Loadholtes
ed0a4fe23b Slight change to the wording for readability
--HG--
branch : nloadholtes/slight-change-to-the-wording-for-readabi-1395890493571
2014-03-27 03:21:58 +00:00
holger krekel
bb0632c7ad extend test 2014-03-26 19:37:49 +01:00
holger krekel
84ab194516 add changelog: merge PR123: improved integration with mock.patch decorator on tests. 2014-03-26 19:06:56 +01:00
holger krekel
530cae9204 Merged in cgilling/pytest (pull request #123)
Fix to work properly when @patch is used with new not equal to DEFAULT
2014-03-26 19:05:46 +01:00
holger krekel
9dc43e84dc Merged in msabramo/pytest/help_show_args_with_equals_instead_of_space (pull request #130)
_pytest/config.py: In --help, show args with `=` instead of space.
2014-03-26 19:04:35 +01:00
Marc Abramowitz
8af265da04 _pytest/config.py: In --help, show args with = instead of space.
The `=` is better because it encourages folks to use the form that doesn't
suffer from issue #436 (https://bitbucket.org/hpk42/pytest/issue/436), which
can cause the arg to be treated as an "anchor" and used as the (unexpected)
path for searching for conftest.py files.

--HG--
branch : help_show_args_with_equals_instead_of_space
2014-03-26 10:47:30 -07:00
Chris Gilling
e3b9382122 use sys.modules.get correctly and reference DEFAULT with respect to it 2014-03-26 09:36:02 -07:00
Chris Gilling
c3f4eb6d57 change try/except to sys.module.get and a conditional 2014-03-26 09:27:33 -07:00
holger krekel
892aa457be fix issue472: clarify that `pytest.config.getvalue()` cannot work
if it's triggered ahead of command line parsing.
2014-03-26 07:15:54 +01:00
holger krekel
8f7b53e55b fix issue490: include pytest_load_initial_conftests in documentation
and improve docstring.
2014-03-25 14:43:58 +01:00
holger krekel
d27c377817 tentatively fix py33 and py25 compat 2014-03-14 15:58:16 +01:00
holger krekel
50abe43216 fix issue #479: properly handle nose/unittest(2) SkipTest exceptions
during collection/loading of test modules.  Thanks to Marc Schlaich
for the complete PR.
2014-03-14 15:44:39 +01:00
holger krekel
ddc67ca13a Merged in schlamar/pytest (pull request #129)
Fixed race condition with SkipTest when module not in sys.modules on collection.
2014-03-14 15:39:01 +01:00
holger krekel
a1d3da4027 Merged in nicoddemus/pytest/integrate-plugin-index-docs (pull request #120)
Integrating plugin_index docs and misc improvements
2014-03-14 15:34:03 +01:00
schlamar
85e7b11ef5 Removed unnecessary iteration in nose.pytest_runtest_makereport. 2014-03-14 15:29:42 +01:00
schlamar
77e1f93ca1 Fixed pyflakes errors. 2014-03-14 14:25:36 +01:00
schlamar
94b1ce65c6 Fixed race condition with SkipTest when module not in sys.modules on collection. 2014-03-14 14:04:54 +01:00
holger krekel
f5b992f68a Merged in jurko/pytest/doc_typo_correction (pull request #122)
fix documentation typo
2014-03-14 13:10:33 +01:00
holger krekel
24a458b4c8 Merged in graingert/pytest/graingert/pep8-good-practices-code-1394196858258 (pull request #125)
pep8 good practices code
2014-03-14 13:06:53 +01:00
holger krekel
ac1d277225 simplify pdb disabling of capturing, also accomodate the new semantics
that capturing is always on during a test session.
2014-03-14 12:49:37 +01:00
holger krekel
9777703e03 - turn on capturing before early conftest loading and make terminal writer
use the original stream.

- avoid resetting capture FDs/sys.stdout for each test by keeping capturing
  always turned on and looking at snapshotted capturing data during runtest
  and collection phases.
2014-03-14 12:49:36 +01:00
holger krekel
f43cda9681 implement a new hook type: hook wrappers using a "yield" to distinguish
between working at the front and at the end of a hook call chain.
The idea is to make it easier for a plugin to "wrap" a certain hook
call and use context managers, in particular allow a major cleanup of
capturing.
2014-03-14 12:49:35 +01:00
holger krekel
b47fdbe0a7 remove externally setting and dealing with "item.outerr" from capturing in favor of a direct interface for adding reporting sections to items.
* * *
refactor makereport implementation to avoid recursion with __multicall__
2014-03-14 12:49:34 +01:00
holger krekel
cde970be69 remove unneccessary indirections and options 2014-03-14 12:49:34 +01:00
holger krekel
cfd43a9b02 add changelog for warning system, bump internal version 2014-03-14 08:15:38 +01:00
holger krekel
ebd10aa6b4 shrink and merge the somewhat obscure and undocumented internal hinting
system with the new warnings one
2014-03-11 22:10:51 +01:00
holger krekel
24db492f53 warn if instances are callable and have a test name 2014-03-11 22:10:18 +01:00
holger krekel
1b387bea62 introduce warning system with this API:
- node.warn() for a node-specific warning
- config.warn() for a global non-node specific warning

Each warning is accompanied by a "warning number" so that we can later
introduce mechanisms for surpressing them.

Each warning will trigger a call to pytest_report_warn(number, node, message)
which is by default implemented by the TerminalReporter which introduces
a new option "-rw" to show details about warnings.
2014-03-11 22:10:17 +01:00
Thomas Grainger
9528b64f7f pep8 good practices code
--HG--
branch : graingert/pep8-good-practices-code-1394196858258
2014-03-07 12:51:51 +00:00
holger krekel
b96559149c Merged in jurko/pytest/pdb_doc_update (pull request #118)
update PDB related pytest docs
2014-03-06 08:36:42 +01:00
Chris Gilling
3388d82c1c Fix to work properly when @patch is used with new not equal to DEFAULT
also updated test_mock to include this situation
2014-03-03 10:36:59 -08:00
Jurko Gospodnetić
9985a7cdca fix documentation typo
--HG--
branch : doc_typo_correction
2014-03-02 22:52:38 +01:00
Bruno Oliveira
1d00c5e109 Using github and bitbucket icons on plugins_index page
--HG--
branch : integrate-plugin-index-docs
2014-02-18 22:40:36 -03:00
Bruno Oliveira
0559f11aa5 Improved text on plugins_index
- Removed "beta" status from it;
- Added links to pytest-plugs app;

--HG--
branch : integrate-plugin-index-docs
2014-02-18 21:33:13 -03:00
Bruno Oliveira
2893cddb68 plugins_index no longer has the package names hard-coded
small number of changes:
- removed hard-coded links to package release versions, using
  a placeholder "latest" instead which is understood by pytest-plugs
- testing against pytest-2.5.2

This changes were implemented so this page only needs
to be updated after pytest releases, not after each package version changes;.
2014-02-11 23:38:30 -02:00
Jurko Gospodnetić
6910641266 reword PDB usage documentation
Documented that since pytest 2.4.0 you can use the raw pdb.set_trace() call
directly without the pytest.set_trace() wrapper or explicitly disabling pytest's
output capture using 'py.test -s'.

Clearly stated how pytest (since version 2.0.0.) automatically disables its
output capture when entering an interactive PDB debugger. This avoids confusing
new users because their tests display different output when running with or
without entering an interactive debugger (even if user does nothing in that
interactive debugger session other than exit it and continue with the regular
test execution).

--HG--
branch : pdb_doc_update
2014-02-01 10:19:09 +01:00
Jurko Gospodnetić
4b81a07303 make all 'PDB' doc references be recognized as links
--HG--
branch : pdb_doc_update
2014-02-01 10:11:42 +01:00
Jurko Gospodnetić
7eb765578a correct inconsistent comment wording
Once the 'the' article was used before 'first' and once it was not, all within
the same code example.

--HG--
branch : pdb_doc_update
2014-02-01 10:07:54 +01:00
holger krekel
e2cf3e0932 Added tag 2.5.2 for changeset 421d3b4d150d 2014-01-29 14:09:33 +01:00
114 changed files with 4340 additions and 2109 deletions

View File

@@ -9,6 +9,7 @@ lib/
bin/
include/
.Python/
.env/
# These lines are suggested according to the svn:ignore property
# Feel free to enable them by uncommenting them
@@ -27,6 +28,7 @@ dist/
*.egg-info
issue/
env/
env3/
3rdparty/
.tox
.cache

View File

@@ -65,3 +65,9 @@ af860de70cc3f157ac34ca1d4bf557a057bff775 2.4.0
8d051f89184bfa3033f5e59819dff9f32a612941 2.4.2
a064ad64d167508a8e9e73766b1a4e6bd10c85db 2.5.0
039d543d1ca02a716c0b0de9a7131beb8021e8a2 2.5.1
421d3b4d150d901de24b1cbeb8955547b1420483 2.5.2
60725b17a9d1af4100abb8be3f9f4ddf6262bf34 2.6.0
60725b17a9d1af4100abb8be3f9f4ddf6262bf34 2.6.0
88af949b9611494e2c65d528f9e565b00fb7e8ca 2.6.0
a4f9639702baa3eb4f3b16e162f74f7b69f3f9e1 2.6.1
a4f25c5e649892b5cc746d21be971e4773478af9 2.6.2

View File

@@ -38,3 +38,10 @@ Anthon van der Neut
Mark Abramowitz
Piotr Banaszkiewicz
Jurko Gospodnetić
Marc Schlaich
Christopher Gilling
Daniel Grana
Andy Freeland
Trevor Bekolay
David Mohr
Nicolas Delaby

193
CHANGELOG
View File

@@ -1,3 +1,196 @@
2.6.3
-----------
- fix issue575: xunit-xml was reporting collection errors as failures
instead of errors, thanks Oleg Sinyavskiy.
- fix issue582: fix setuptools example, thanks Laszlo Papp and Ronny
Pfannschmidt.
- Fix infinite recursion bug when pickling capture.EncodedFile, thanks
Uwe Schmitt.
- fix issue589: fix bad interaction with numpy and others when showing
exceptions. Check for precise "maximum recursion depth exceed" exception
instead of presuming any RuntimeError is that one (implemented in py
dep). Thanks Charles Cloud for analysing the issue.
- fix conftest related fixture visibility issue: when running with a
CWD outside a test package pytest would get fixture discovery wrong.
Thanks to Wolfgang Schnerring for figuring out a reproducable example.
- Introduce pytest_enter_pdb hook (needed e.g. by pytest_timeout to cancel the
timeout when interactively entering pdb). Thanks Wolfgang Schnerring.
- check xfail/skip also with non-python function test items. Thanks
Floris Bruynooghe.
2.6.2
-----------
- Added function pytest.freeze_includes(), which makes it easy to embed
pytest into executables using tools like cx_freeze.
See docs for examples and rationale. Thanks Bruno Oliveira.
- Improve assertion rewriting cache invalidation precision.
- fixed issue561: adapt autouse fixture example for python3.
- fixed issue453: assertion rewriting issue with __repr__ containing
"\n{", "\n}" and "\n~".
- fix issue560: correctly display code if an "else:" or "finally:" is
followed by statements on the same line.
- Fix example in monkeypatch documentation, thanks t-8ch.
- fix issue572: correct tmpdir doc example for python3.
- Do not mark as universal wheel because Python 2.6 is different from
other builds due to the extra argparse dependency. Fixes issue566.
Thanks sontek.
- Implement issue549: user-provided assertion messages now no longer
replace the py.test instrospection message but are shown in addition
to them.
2.6.1
-----------------------------------
- No longer show line numbers in the --verbose output, the output is now
purely the nodeid. The line number is still shown in failure reports.
Thanks Floris Bruynooghe.
- fix issue437 where assertion rewriting could cause pytest-xdist slaves
to collect different tests. Thanks Bruno Oliveira.
- fix issue555: add "errors" attribute to capture-streams to satisfy
some distutils and possibly other code accessing sys.stdout.errors.
- fix issue547 capsys/capfd also work when output capturing ("-s") is disabled.
- address issue170: allow pytest.mark.xfail(...) to specify expected exceptions via
an optional "raises=EXC" argument where EXC can be a single exception
or a tuple of exception classes. Thanks David Mohr for the complete
PR.
- fix integration of pytest with unittest.mock.patch decorator when
it uses the "new" argument. Thanks Nicolas Delaby for test and PR.
- fix issue with detecting conftest files if the arguments contain
"::" node id specifications (copy pasted from "-v" output)
- fix issue544 by only removing "@NUM" at the end of "::" separated parts
and if the part has an ".py" extension
- don't use py.std import helper, rather import things directly.
Thanks Bruno Oliveira.
2.6
-----------------------------------
- Cache exceptions from fixtures according to their scope (issue 467).
- fix issue537: Avoid importing old assertion reinterpretation code by default.
- fix issue364: shorten and enhance tracebacks representation by default.
The new "--tb=auto" option (default) will only display long tracebacks
for the first and last entry. You can get the old behaviour of printing
all entries as long entries with "--tb=long". Also short entries by
default are now printed very similarly to "--tb=native" ones.
- fix issue514: teach assertion reinterpretation about private class attributes
- change -v output to include full node IDs of tests. Users can copy
a node ID from a test run, including line number, and use it as a
positional argument in order to run only a single test.
- fix issue 475: fail early and comprehensible if calling
pytest.raises with wrong exception type.
- fix issue516: tell in getting-started about current dependencies.
- cleanup setup.py a bit and specify supported versions. Thanks Jurko
Gospodnetic for the PR.
- change XPASS colour to yellow rather then red when tests are run
with -v.
- fix issue473: work around mock putting an unbound method into a class
dict when double-patching.
- fix issue498: if a fixture finalizer fails, make sure that
the fixture is still invalidated.
- fix issue453: the result of the pytest_assertrepr_compare hook now gets
it's newlines escaped so that format_exception does not blow up.
- internal new warning system: pytest will now produce warnings when
it detects oddities in your test collection or execution.
Warnings are ultimately sent to a new pytest_logwarning hook which is
currently only implemented by the terminal plugin which displays
warnings in the summary line and shows more details when -rw (report on
warnings) is specified.
- change skips into warnings for test classes with an __init__ and
callables in test modules which look like a test but are not functions.
- fix issue436: improved finding of initial conftest files from command
line arguments by using the result of parse_known_args rather than
the previous flaky heuristics. Thanks Marc Abramowitz for tests
and initial fixing approaches in this area.
- fix issue #479: properly handle nose/unittest(2) SkipTest exceptions
during collection/loading of test modules. Thanks to Marc Schlaich
for the complete PR.
- fix issue490: include pytest_load_initial_conftests in documentation
and improve docstring.
- fix issue472: clarify that ``pytest.config.getvalue()`` cannot work
if it's triggered ahead of command line parsing.
- merge PR123: improved integration with mock.patch decorator on tests.
- fix issue412: messing with stdout/stderr FD-level streams is now
captured without crashes.
- fix issue483: trial/py33 works now properly. Thanks Daniel Grana for PR.
- improve example for pytest integration with "python setup.py test"
which now has a generic "-a" or "--pytest-args" option where you
can pass additional options as a quoted string. Thanks Trevor Bekolay.
- simplified internal capturing mechanism and made it more robust
against tests or setups changing FD1/FD2, also better integrated
now with pytest.pdb() in single tests.
- improvements to pytest's own test-suite leakage detection, courtesy of PRs
from Marc Abramowitz
- fix issue492: avoid leak in test_writeorg. Thanks Marc Abramowitz.
- fix issue493: don't run tests in doc directory with ``python setup.py test``
(use tox -e doctesting for that)
- fix issue486: better reporting and handling of early conftest loading failures
- some cleanup and simplification of internal conftest handling.
- work a bit harder to break reference cycles when catching exceptions.
Thanks Jurko Gospodnetic.
- fix issue443: fix skip examples to use proper comparison. Thanks Alex
Groenholm.
- support nose-style ``__test__`` attribute on modules, classes and
functions, including unittest-style Classes. If set to False, the
test will not be collected.
- fix issue512: show "<notset>" for arguments which might not be set
in monkeypatch plugin. Improves output in documentation.
2.5.2
-----------------------------------

47
HOWTORELEASE.rst Normal file
View File

@@ -0,0 +1,47 @@
How to release pytest (draft)
--------------------------------------------
1. bump version numbers in setup.py and pytest/__init__.py
2. check and finalize CHANGELOG
3. write doc/en/announce/pytest-VERSION.txt and include
it in doc/en/announce/index.txt
4. use devpi for uploading a release tarball to a staging area:
- ``devpi use https://devpi.net/USER/dev``
- ``devpi upload``
5. run from multiple machines:
- ``devpi use https://devpi.net/USER/dev``
- ``devpi test pytest-VERSION``
6. check that tests pass for relevant combinations with
``devpi list pytest``
or look at failures with "devpi list -f pytest".
There will be some failed environments like e.g. the py33-trial
or py27-pexpect tox environments on Win32 platforms
which is ok (tox does not support skipping on
per-platform basis yet).
7. XXX "regen docs" (not easy to do currently as it requires
a development version of the regendoc tool from ronny)
8. go to "doc/en" and upload docs with "make install"
(the latter requires ssh-login permissions on pytest.org
because it uses rsync). Note that the "install" target of
doc/en/Makefile defines where the rsync goes to, typically
to the "latest" section of pytest.org.
9. publish to pypi "devpi push pytest-2.6.2 pypi:NAME" where NAME
is the name of pypi.python.org as configured in your
~/.pypirc file -- it's the same you would use with
"setup.py upload -r NAME"
10. send release announcement to mailing lists:
pytest-dev
testing-in-python
python-announce-list@python.org

View File

@@ -79,15 +79,6 @@ style tests, i.e. it leverages existing test suites without needing
to rewrite them. Together with the previously mentioned setup_test()
maybe the setupfunc could be ommitted?
checks / deprecations for next release
---------------------------------------------------------------
tags: bug 2.4 core xdist
* check oejskit plugin compatibility
* move pytest_nose out of pylib because it implicitely extends
the protocol now - setup/teardown is called at module level.
consider making calling of setup/teardown configurable
optimizations
---------------------------------------------------------------
tags: 2.4 core

View File

@@ -1,3 +1,7 @@
.. image:: https://drone.io/bitbucket.org/hpk42/pytest/status.png
:target: https://drone.io/bitbucket.org/hpk42/pytest/latest
.. image:: https://pypip.in/v/pytest/badge.png
:target: https://crate.io/packages/pytest/
Documentation: http://pytest.org/latest/
@@ -5,6 +9,8 @@ Changelog: http://pytest.org/latest/changelog.html
Issues: https://bitbucket.org/hpk42/pytest/issues?status=open
CI: https://drone.io/bitbucket.org/hpk42/pytest
The ``pytest`` testing tool makes it easy to write small tests, yet
scales to support complex functional testing. It provides
@@ -17,8 +23,9 @@ scales to support complex functional testing. It provides
- multi-paradigm support: you can use ``pytest`` to run test suites based
on `unittest <http://pytest.org/latest/unittest.html>`_ (or trial),
`nose <http://pytest.org/latest/nose.html>`_
- single-source compatibility to Python2.5 all the way up to Python3.3,
PyPy-1.9 and Jython-2.5.1.
- single-source compatibility from Python2.6 all the way up to
Python3.4, PyPy-2.3, (jython-2.5 untested)
- many `external plugins <http://pytest.org/latest/plugins.html#installing-external-plugins-searching>`_.

View File

@@ -1,2 +1,2 @@
#
__version__ = '2.5.2'
__version__ = '2.6.3'

View File

@@ -6,20 +6,32 @@ import sys
from _pytest.monkeypatch import monkeypatch
from _pytest.assertion import util
def pytest_addoption(parser):
group = parser.getgroup("debugconfig")
group.addoption('--assert', action="store", dest="assertmode",
group.addoption('--assert',
action="store",
dest="assertmode",
choices=("rewrite", "reinterp", "plain",),
default="rewrite", metavar="MODE",
help="""control assertion debugging tools.
'plain' performs no assertion debugging.
'reinterp' reinterprets assert statements after they failed to provide assertion expression information.
'rewrite' (the default) rewrites assert statements in test modules on import
to provide assert expression information. """)
group.addoption('--no-assert', action="store_true", default=False,
dest="noassert", help="DEPRECATED equivalent to --assert=plain")
group.addoption('--nomagic', '--no-magic', action="store_true",
default=False, help="DEPRECATED equivalent to --assert=plain")
default="rewrite",
metavar="MODE",
help="""control assertion debugging tools. 'plain'
performs no assertion debugging. 'reinterp'
reinterprets assert statements after they failed
to provide assertion expression information.
'rewrite' (the default) rewrites assert
statements in test modules on import to
provide assert expression information. """)
group.addoption('--no-assert',
action="store_true",
default=False,
dest="noassert",
help="DEPRECATED equivalent to --assert=plain")
group.addoption('--nomagic', '--no-magic',
action="store_true",
default=False,
help="DEPRECATED equivalent to --assert=plain")
class AssertionState:
"""State for the assertion plugin."""
@@ -28,6 +40,7 @@ class AssertionState:
self.mode = mode
self.trace = config.trace.root.get("assertion")
def pytest_configure(config):
mode = config.getvalue("assertmode")
if config.getvalue("noassert") or config.getvalue("nomagic"):
@@ -41,7 +54,7 @@ def pytest_configure(config):
# Both Jython and CPython 2.6.0 have AST bugs that make the
# assertion rewriting hook malfunction.
if (sys.platform.startswith('java') or
sys.version_info[:3] == (2, 6, 0)):
sys.version_info[:3] == (2, 6, 0)):
mode = "reinterp"
if mode != "plain":
_load_modules(mode)
@@ -58,11 +71,13 @@ def pytest_configure(config):
config._assertstate.hook = hook
config._assertstate.trace("configured with mode set to %r" % (mode,))
def pytest_unconfigure(config):
hook = config._assertstate.hook
if hook is not None:
if hook is not None and hook in sys.meta_path:
sys.meta_path.remove(hook)
def pytest_collection(session):
# this hook is only called when test modules are collected
# so for example not in the master process of pytest-xdist
@@ -71,36 +86,55 @@ def pytest_collection(session):
if hook is not None:
hook.set_session(session)
def pytest_runtest_setup(item):
"""Setup the pytest_assertrepr_compare hook
The newinterpret and rewrite modules will use util._reprcompare if
it exists to use custom reporting via the
pytest_assertrepr_compare hook. This sets up this custom
comparison for the test.
"""
def callbinrepr(op, left, right):
"""Call the pytest_assertrepr_compare hook and prepare the result
This uses the first result from the hook and then ensures the
following:
* Overly verbose explanations are dropped unles -vv was used.
* Embedded newlines are escaped to help util.format_explanation()
later.
* If the rewrite mode is used embedded %-characters are replaced
to protect later % formatting.
The result can be formatted by util.format_explanation() for
pretty printing.
"""
hook_result = item.ihook.pytest_assertrepr_compare(
config=item.config, op=op, left=left, right=right)
for new_expl in hook_result:
if new_expl:
# Don't include pageloads of data unless we are very
# verbose (-vv)
if (sum(len(p) for p in new_expl[1:]) > 80*8
and item.config.option.verbose < 2):
new_expl[1:] = [py.builtin._totext(
'Detailed information truncated, use "-vv" to show')]
res = py.builtin._totext('\n~').join(new_expl)
new_expl = [line.replace("\n", "\\n") for line in new_expl]
res = py.builtin._totext("\n~").join(new_expl)
if item.config.getvalue("assertmode") == "rewrite":
# The result will be fed back a python % formatting
# operation, which will fail if there are extraneous
# '%'s in the string. Escape them here.
res = res.replace("%", "%%")
return res
util._reprcompare = callbinrepr
def pytest_runtest_teardown(item):
util._reprcompare = None
def pytest_sessionfinish(session):
hook = session.config._assertstate.hook
if hook is not None:
hook.session = None
def _load_modules(mode):
"""Lazily import assertion related code."""
global rewrite, reinterpret
@@ -108,6 +142,7 @@ def _load_modules(mode):
if mode == "rewrite":
from _pytest.assertion import rewrite # noqa
def warn_about_missing_assertion(mode):
try:
assert False
@@ -121,8 +156,10 @@ def warn_about_missing_assertion(mode):
specifically = "failing tests may report as passing"
sys.stderr.write("WARNING: " + specifically +
" because assert statements are not executed "
"by the underlying Python interpreter "
"(are you using python -O?)\n")
" because assert statements are not executed "
"by the underlying Python interpreter "
"(are you using python -O?)\n")
# Expose this plugin's implementation for the pytest_assertrepr_compare hook
pytest_assertrepr_compare = util.assertrepr_compare

View File

@@ -286,7 +286,19 @@ class DebugInterpreter(ast.NodeVisitor):
source = "__exprinfo_expr.%s" % (attr.attr,)
co = self._compile(source)
try:
result = self.frame.eval(co, __exprinfo_expr=source_result)
try:
result = self.frame.eval(co, __exprinfo_expr=source_result)
except AttributeError:
# Maybe the attribute name needs to be mangled?
if not attr.attr.startswith("__") or attr.attr.endswith("__"):
raise
source = "getattr(__exprinfo_expr.__class__, '__name__', '')"
co = self._compile(source)
class_name = self.frame.eval(co, __exprinfo_expr=source_result)
mangled_attr = "_" + class_name + attr.attr
source = "__exprinfo_expr.%s" % (mangled_attr,)
co = self._compile(source)
result = self.frame.eval(co, __exprinfo_expr=source_result)
except Exception:
raise Failure(explanation)
explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result),

View File

@@ -1,3 +1,5 @@
import traceback
import types
import py
import sys, inspect
from compiler import parse, ast, pycodegen
@@ -55,7 +57,7 @@ class View(object):
def __getattr__(self, attr):
# attributes not found in the normal hierarchy rooted on View
# are looked up in the object's real class
return getattr(self.__obj__, attr)
return getattr(object.__getattribute__(self, '__obj__'), attr)
def __viewkey__(self):
return self.__obj__.__class__
@@ -355,7 +357,18 @@ class Getattr(Interpretable):
expr.eval(frame)
source = '__exprinfo_expr.%s' % self.attrname
try:
self.result = frame.eval(source, __exprinfo_expr=expr.result)
try:
self.result = frame.eval(source, __exprinfo_expr=expr.result)
except AttributeError:
# Maybe the attribute name needs to be mangled?
if (not self.attrname.startswith("__") or
self.attrname.endswith("__")):
raise
source = "getattr(__exprinfo_expr.__class__, '__name__', '')"
class_name = frame.eval(source, __exprinfo_expr=expr.result)
mangled_attr = "_" + class_name + self.attrname
source = "__exprinfo_expr.%s" % (mangled_attr,)
self.result = frame.eval(source, __exprinfo_expr=expr.result)
except passthroughex:
raise
except:
@@ -466,7 +479,7 @@ def check(s, frame=None):
def interpret(source, frame, should_fail=False):
module = Interpretable(parse(source, 'exec').node)
#print "got module", module
if isinstance(frame, py.std.types.FrameType):
if isinstance(frame, types.FrameType):
frame = py.code.Frame(frame)
try:
module.run(frame)
@@ -476,7 +489,6 @@ def interpret(source, frame, should_fail=False):
except passthroughex:
raise
except:
import traceback
traceback.print_exc()
if should_fail:
return ("(assertion failed, but when it was re-run for "

View File

@@ -45,10 +45,8 @@ class AssertionError(BuiltinAssertionError):
if sys.version_info > (3, 0):
AssertionError.__module__ = "builtins"
reinterpret_old = "old reinterpretation not available for py3"
else:
from _pytest.assertion.oldinterpret import interpret as reinterpret_old
if sys.version_info >= (2, 6) or (sys.platform.startswith("java")):
if sys.version_info >= (2, 6) or sys.platform.startswith("java"):
from _pytest.assertion.newinterpret import interpret as reinterpret
else:
reinterpret = reinterpret_old
from _pytest.assertion.oldinterpret import interpret as reinterpret

View File

@@ -131,15 +131,15 @@ class AssertionRewritingHook(object):
pyc = os.path.join(cache_dir, cache_name)
# Notice that even if we're in a read-only directory, I'm going
# to check for a cached pyc. This may not be optimal...
co = _read_pyc(fn_pypath, pyc)
co = _read_pyc(fn_pypath, pyc, state.trace)
if co is None:
state.trace("rewriting %r" % (fn,))
co = _rewrite_test(state, fn_pypath)
source_stat, co = _rewrite_test(state, fn_pypath)
if co is None:
# Probably a SyntaxError in the test.
return None
if write:
_make_rewritten_pyc(state, fn_pypath, pyc, co)
_make_rewritten_pyc(state, source_stat, pyc, co)
else:
state.trace("found cached rewritten pyc for %r" % (fn,))
self.modules[name] = co, pyc
@@ -192,13 +192,12 @@ class AssertionRewritingHook(object):
pkg_resources.register_loader_type(cls, pkg_resources.DefaultProvider)
def _write_pyc(state, co, source_path, pyc):
def _write_pyc(state, co, source_stat, pyc):
# Technically, we don't have to have the same pyc format as
# (C)Python, since these "pycs" should never be seen by builtin
# import. However, there's little reason deviate, and I hope
# sometime to be able to use imp.load_compiled to load them. (See
# the comment in load_module above.)
mtime = int(source_path.mtime())
try:
fp = open(pyc, "wb")
except IOError:
@@ -210,7 +209,9 @@ def _write_pyc(state, co, source_path, pyc):
return False
try:
fp.write(imp.get_magic())
fp.write(struct.pack("<l", mtime))
mtime = int(source_stat.mtime)
size = source_stat.size & 0xFFFFFFFF
fp.write(struct.pack("<ll", mtime, size))
marshal.dump(co, fp)
finally:
fp.close()
@@ -225,9 +226,10 @@ BOM_UTF8 = '\xef\xbb\xbf'
def _rewrite_test(state, fn):
"""Try to read and rewrite *fn* and return the code object."""
try:
stat = fn.stat()
source = fn.read("rb")
except EnvironmentError:
return None
return None, None
if ASCII_IS_DEFAULT_ENCODING:
# ASCII is the default encoding in Python 2. Without a coding
# declaration, Python 2 will complain about any bytes in the file
@@ -246,14 +248,15 @@ def _rewrite_test(state, fn):
cookie_re.match(source[0:end1]) is None and
cookie_re.match(source[end1 + 1:end2]) is None):
if hasattr(state, "_indecode"):
return None # encodings imported us again, we don't rewrite
# encodings imported us again, so don't rewrite.
return None, None
state._indecode = True
try:
try:
source.decode("ascii")
except UnicodeDecodeError:
# Let it fail in real import.
return None
return None, None
finally:
del state._indecode
# On Python versions which are not 2.7 and less than or equal to 3.1, the
@@ -265,7 +268,7 @@ def _rewrite_test(state, fn):
except SyntaxError:
# Let this pop up again in the real import.
state.trace("failed to parse: %r" % (fn,))
return None
return None, None
rewrite_asserts(tree)
try:
co = compile(tree, fn.strpath, "exec")
@@ -273,23 +276,23 @@ def _rewrite_test(state, fn):
# It's possible that this error is from some bug in the
# assertion rewriting, but I don't know of a fast way to tell.
state.trace("failed to compile: %r" % (fn,))
return None
return co
return None, None
return stat, co
def _make_rewritten_pyc(state, fn, pyc, co):
def _make_rewritten_pyc(state, source_stat, pyc, co):
"""Try to dump rewritten code to *pyc*."""
if sys.platform.startswith("win"):
# Windows grants exclusive access to open files and doesn't have atomic
# rename, so just write into the final file.
_write_pyc(state, co, fn, pyc)
_write_pyc(state, co, source_stat, pyc)
else:
# When not on windows, assume rename is atomic. Dump the code object
# into a file specific to this process and atomically replace it.
proc_pyc = pyc + "." + str(os.getpid())
if _write_pyc(state, co, fn, proc_pyc):
if _write_pyc(state, co, source_stat, proc_pyc):
os.rename(proc_pyc, pyc)
def _read_pyc(source, pyc):
def _read_pyc(source, pyc, trace=lambda x: None):
"""Possibly read a pytest pyc containing rewritten code.
Return rewritten code if successful or None if not.
@@ -298,23 +301,28 @@ def _read_pyc(source, pyc):
fp = open(pyc, "rb")
except IOError:
return None
try:
with fp:
try:
mtime = int(source.mtime())
data = fp.read(8)
except EnvironmentError:
size = source.size()
data = fp.read(12)
except EnvironmentError as e:
trace('_read_pyc(%s): EnvironmentError %s' % (source, e))
return None
# Check for invalid or out of date pyc file.
if (len(data) != 8 or data[:4] != imp.get_magic() or
struct.unpack("<l", data[4:])[0] != mtime):
if (len(data) != 12 or data[:4] != imp.get_magic() or
struct.unpack("<ll", data[4:]) != (mtime, size)):
trace('_read_pyc(%s): invalid or out of date pyc' % source)
return None
try:
co = marshal.load(fp)
except Exception as e:
trace('_read_pyc(%s): marshal.load error %s' % (source, e))
return None
co = marshal.load(fp)
if not isinstance(co, types.CodeType):
# That's interesting....
trace('_read_pyc(%s): not a code object' % source)
return None
return co
finally:
fp.close()
def rewrite_asserts(mod):
@@ -322,9 +330,54 @@ def rewrite_asserts(mod):
AssertionRewriter().run(mod)
_saferepr = py.io.saferepr
def _saferepr(obj):
"""Get a safe repr of an object for assertion error messages.
The assertion formatting (util.format_explanation()) requires
newlines to be escaped since they are a special character for it.
Normally assertion.util.format_explanation() does this but for a
custom repr it is possible to contain one of the special escape
sequences, especially '\n{' and '\n}' are likely to be present in
JSON reprs.
"""
repr = py.io.saferepr(obj)
if py.builtin._istext(repr):
t = py.builtin.text
else:
t = py.builtin.bytes
return repr.replace(t("\n"), t("\\n"))
from _pytest.assertion.util import format_explanation as _format_explanation # noqa
def _format_assertmsg(obj):
"""Format the custom assertion message given.
For strings this simply replaces newlines with '\n~' so that
util.format_explanation() will preserve them instead of escaping
newlines. For other objects py.io.saferepr() is used first.
"""
# reprlib appears to have a bug which means that if a string
# contains a newline it gets escaped, however if an object has a
# .__repr__() which contains newlines it does not get escaped.
# However in either case we want to preserve the newline.
if py.builtin._istext(obj) or py.builtin._isbytes(obj):
s = obj
is_repr = False
else:
s = py.io.saferepr(obj)
is_repr = True
if py.builtin._istext(s):
t = py.builtin.text
else:
t = py.builtin.bytes
s = s.replace(t("\n"), t("\n~"))
if is_repr:
s = s.replace(t("\\n"), t("\n~"))
return s
def _should_repr_global_name(obj):
return not hasattr(obj, "__name__") and not py.builtin.callable(obj)
@@ -393,6 +446,56 @@ def set_location(node, lineno, col_offset):
class AssertionRewriter(ast.NodeVisitor):
"""Assertion rewriting implementation.
The main entrypoint is to call .run() with an ast.Module instance,
this will then find all the assert statements and re-write them to
provide intermediate values and a detailed assertion error. See
http://pybites.blogspot.be/2011/07/behind-scenes-of-pytests-new-assertion.html
for an overview of how this works.
The entry point here is .run() which will iterate over all the
statenemts in an ast.Module and for each ast.Assert statement it
finds call .visit() with it. Then .visit_Assert() takes over and
is responsible for creating new ast statements to replace the
original assert statement: it re-writes the test of an assertion
to provide intermediate values and replace it with an if statement
which raises an assertion error with a detailed explanation in
case the expression is false.
For this .visit_Assert() uses the visitor pattern to visit all the
AST nodes of the ast.Assert.test field, each visit call returning
an AST node and the corresponding explanation string. During this
state is kept in several instance attributes:
:statements: All the AST statements which will replace the assert
statement.
:variables: This is populated by .variable() with each variable
used by the statements so that they can all be set to None at
the end of the statements.
:variable_counter: Counter to create new unique variables needed
by statements. Variables are created using .variable() and
have the form of "@py_assert0".
:on_failure: The AST statements which will be executed if the
assertion test fails. This is the code which will construct
the failure message and raises the AssertionError.
:explanation_specifiers: A dict filled by .explanation_param()
with %-formatting placeholders and their corresponding
expressions to use in the building of an assertion message.
This is used by .pop_format_context() to build a message.
:stack: A stack of the explanation_specifiers dicts maintained by
.push_format_context() and .pop_format_context() which allows
to build another %-formatted string while already building one.
This state is reset on every new assert statement visited and used
by the other visitors.
"""
def run(self, mod):
"""Find all assert statements in *mod* and rewrite them."""
@@ -474,15 +577,41 @@ class AssertionRewriter(ast.NodeVisitor):
return ast.Attribute(builtin_name, name, ast.Load())
def explanation_param(self, expr):
"""Return a new named %-formatting placeholder for expr.
This creates a %-formatting placeholder for expr in the
current formatting context, e.g. ``%(py0)s``. The placeholder
and expr are placed in the current format context so that it
can be used on the next call to .pop_format_context().
"""
specifier = "py" + str(next(self.variable_counter))
self.explanation_specifiers[specifier] = expr
return "%(" + specifier + ")s"
def push_format_context(self):
"""Create a new formatting context.
The format context is used for when an explanation wants to
have a variable value formatted in the assertion message. In
this case the value required can be added using
.explanation_param(). Finally .pop_format_context() is used
to format a string of %-formatted values as added by
.explanation_param().
"""
self.explanation_specifiers = {}
self.stack.append(self.explanation_specifiers)
def pop_format_context(self, expl_expr):
"""Format the %-formatted string with current format context.
The expl_expr should be an ast.Str instance constructed from
the %-placeholders created by .explanation_param(). This will
add the required code to format said string to .on_failure and
return the ast.Name instance of the formatted string.
"""
current = self.stack.pop()
if self.stack:
self.explanation_specifiers = self.stack[-1]
@@ -500,11 +629,15 @@ class AssertionRewriter(ast.NodeVisitor):
return res, self.explanation_param(self.display(res))
def visit_Assert(self, assert_):
if assert_.msg:
# There's already a message. Don't mess with it.
return [assert_]
"""Return the AST statements to replace the ast.Assert instance.
This re-writes the test of an assertion to provide
intermediate values and replace it with an if statement which
raises an assertion error with a detailed explanation in case
the expression is false.
"""
self.statements = []
self.cond_chain = ()
self.variables = []
self.variable_counter = itertools.count()
self.stack = []
@@ -516,8 +649,13 @@ class AssertionRewriter(ast.NodeVisitor):
body = self.on_failure
negation = ast.UnaryOp(ast.Not(), top_condition)
self.statements.append(ast.If(negation, body, []))
explanation = "assert " + explanation
template = ast.Str(explanation)
if assert_.msg:
assertmsg = self.helper('format_assertmsg', assert_.msg)
explanation = "\n>assert " + explanation
else:
assertmsg = ast.Str("")
explanation = "assert " + explanation
template = ast.BinOp(assertmsg, ast.Add(), ast.Str(explanation))
msg = self.pop_format_context(template)
fmt = self.helper("format_explanation", msg)
err_name = ast.Name("AssertionError", ast.Load())

View File

@@ -1,4 +1,5 @@
"""Utilities for assertion debugging"""
import pprint
import py
try:
@@ -72,7 +73,7 @@ def _split_explanation(explanation):
raw_lines = (explanation or u('')).split('\n')
lines = [raw_lines[0]]
for l in raw_lines[1:]:
if l.startswith('{') or l.startswith('}') or l.startswith('~'):
if l and l[0] in ['{', '}', '~', '>']:
lines.append(l)
else:
lines[-1] += '\\n' + l
@@ -102,13 +103,14 @@ def _format_lines(lines):
stackcnt.append(0)
result.append(u(' +') + u(' ')*(len(stack)-1) + s + line[1:])
elif line.startswith('}'):
assert line.startswith('}')
stack.pop()
stackcnt.pop()
result[stack[-1]] += line[1:]
else:
assert line.startswith('~')
result.append(u(' ')*len(stack) + line[1:])
assert line[0] in ['~', '>']
stack[-1] += 1
indent = len(stack) if line.startswith('~') else len(stack) - 1
result.append(u(' ')*indent + line[1:])
assert len(stack) == 1
return result
@@ -149,11 +151,10 @@ def assertrepr_compare(config, op, left, right):
if istext(left) and istext(right):
explanation = _notin_text(left, right, verbose)
except Exception:
excinfo = py.code.ExceptionInfo()
explanation = [
u('(pytest_assertion plugin: representation of details failed. '
'Probably an object has a faulty __repr__.)'),
u(excinfo)]
u(py.code.ExceptionInfo())]
if not explanation:
return None
@@ -169,6 +170,7 @@ def _diff_text(left, right, verbose=False):
If the input are bytes they will be safely converted to text.
"""
from difflib import ndiff
explanation = []
if isinstance(left, py.builtin.bytes):
left = u(repr(left)[1:-1]).replace(r'\n', '\n')
@@ -196,8 +198,8 @@ def _diff_text(left, right, verbose=False):
left = left[:-i]
right = right[:-i]
explanation += [line.strip('\n')
for line in py.std.difflib.ndiff(left.splitlines(),
right.splitlines())]
for line in ndiff(left.splitlines(),
right.splitlines())]
return explanation
@@ -215,8 +217,8 @@ def _compare_eq_sequence(left, right, verbose=False):
explanation += [
u('Right contains more items, first extra item: %s') %
py.io.saferepr(right[len(left)],)]
return explanation # + _diff_text(py.std.pprint.pformat(left),
# py.std.pprint.pformat(right))
return explanation # + _diff_text(pprint.pformat(left),
# pprint.pformat(right))
def _compare_eq_set(left, right, verbose=False):
@@ -243,7 +245,7 @@ def _compare_eq_dict(left, right, verbose=False):
len(same)]
elif same:
explanation += [u('Common items:')]
explanation += py.std.pprint.pformat(same).splitlines()
explanation += pprint.pformat(same).splitlines()
diff = set(k for k in common if left[k] != right[k])
if diff:
explanation += [u('Differing items:')]
@@ -253,12 +255,12 @@ def _compare_eq_dict(left, right, verbose=False):
extra_left = set(left) - set(right)
if extra_left:
explanation.append(u('Left contains more items:'))
explanation.extend(py.std.pprint.pformat(
explanation.extend(pprint.pformat(
dict((k, left[k]) for k in extra_left)).splitlines())
extra_right = set(right) - set(left)
if extra_right:
explanation.append(u('Right contains more items:'))
explanation.extend(py.std.pprint.pformat(
explanation.extend(pprint.pformat(
dict((k, right[k]) for k in extra_right)).splitlines())
return explanation

View File

@@ -1,40 +1,18 @@
"""
per-test stdout/stderr capturing mechanisms,
``capsys`` and ``capfd`` function arguments.
per-test stdout/stderr capturing mechanism.
"""
# note: py.io capture was where copied from
# pylib 1.4.20.dev2 (rev 13d9af95547e)
from __future__ import with_statement
import sys
import os
import tempfile
from tempfile import TemporaryFile
import py
import pytest
try:
from io import StringIO
except ImportError:
from StringIO import StringIO
try:
from io import BytesIO
except ImportError:
class BytesIO(StringIO):
def write(self, data):
if isinstance(data, unicode):
raise TypeError("not a byte value: %r" % (data,))
StringIO.write(self, data)
if sys.version_info < (3, 0):
class TextIO(StringIO):
def write(self, data):
if not isinstance(data, unicode):
enc = getattr(self, '_encoding', 'UTF-8')
data = unicode(data, enc, 'replace')
StringIO.write(self, data)
else:
TextIO = StringIO
from py.io import TextIO
unicode = py.builtin.text
patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'}
@@ -42,9 +20,10 @@ patchsysdict = {0: 'stdin', 1: 'stdout', 2: 'stderr'}
def pytest_addoption(parser):
group = parser.getgroup("general")
group._addoption(
'--capture', action="store", default=None,
'--capture', action="store",
default="fd" if hasattr(os, "dup") else "sys",
metavar="method", choices=['fd', 'sys', 'no'],
help="per-test capturing method: one of fd (default)|sys|no.")
help="per-test capturing method: one of fd|sys|no.")
group._addoption(
'-s', action="store_const", const="no", dest="capture",
help="shortcut for --capture=no.")
@@ -52,32 +31,22 @@ def pytest_addoption(parser):
@pytest.mark.tryfirst
def pytest_load_initial_conftests(early_config, parser, args, __multicall__):
ns = parser.parse_known_args(args)
method = ns.capture
if not method:
method = "fd"
if method == "fd" and not hasattr(os, "dup"):
method = "sys"
capman = CaptureManager(method)
early_config.pluginmanager.register(capman, "capturemanager")
ns = early_config.known_args_namespace
pluginmanager = early_config.pluginmanager
capman = CaptureManager(ns.capture)
pluginmanager.register(capman, "capturemanager")
# make sure that capturemanager is properly reset at final shutdown
def teardown():
try:
capman.reset_capturings()
except ValueError:
pass
early_config.pluginmanager.add_shutdown(teardown)
pluginmanager.add_shutdown(capman.reset_capturings)
# make sure logging does not raise exceptions at the end
def silence_logging_at_shutdown():
if "logging" in sys.modules:
sys.modules["logging"].raiseExceptions = False
early_config.pluginmanager.add_shutdown(silence_logging_at_shutdown)
pluginmanager.add_shutdown(silence_logging_at_shutdown)
# finally trigger conftest loading but while capturing (issue93)
capman.resumecapture()
capman.init_capturings()
try:
try:
return __multicall__.execute()
@@ -89,208 +58,143 @@ def pytest_load_initial_conftests(early_config, parser, args, __multicall__):
raise
def addouterr(rep, outerr):
for secname, content in zip(["out", "err"], outerr):
if content:
rep.sections.append(("Captured std%s" % secname, content))
class NoCapture:
def startall(self):
pass
def resume(self):
pass
def reset(self):
pass
def suspend(self):
return "", ""
class CaptureManager:
def __init__(self, defaultmethod=None):
self._method2capture = {}
self._defaultmethod = defaultmethod
def _maketempfile(self):
f = py.std.tempfile.TemporaryFile()
newf = dupfile(f, encoding="UTF-8")
f.close()
return newf
def _makestringio(self):
return TextIO()
def __init__(self, method):
self._method = method
def _getcapture(self, method):
if method == "fd":
return StdCaptureFD(
out=self._maketempfile(),
err=self._maketempfile(),
)
return MultiCapture(out=True, err=True, Capture=FDCapture)
elif method == "sys":
return StdCapture(
out=self._makestringio(),
err=self._makestringio(),
)
return MultiCapture(out=True, err=True, Capture=SysCapture)
elif method == "no":
return NoCapture()
return MultiCapture(out=False, err=False, in_=False)
else:
raise ValueError("unknown capturing method: %r" % method)
def _getmethod(self, config, fspath):
if config.option.capture:
method = config.option.capture
else:
try:
method = config._conftest.rget("option_capture", path=fspath)
except KeyError:
method = "fd"
if method == "fd" and not hasattr(os, 'dup'): # e.g. jython
method = "sys"
return method
def init_capturings(self):
assert not hasattr(self, "_capturing")
self._capturing = self._getcapture(self._method)
self._capturing.start_capturing()
def reset_capturings(self):
for cap in self._method2capture.values():
cap.reset()
cap = self.__dict__.pop("_capturing", None)
if cap is not None:
cap.pop_outerr_to_orig()
cap.stop_capturing()
def resumecapture_item(self, item):
method = self._getmethod(item.config, item.fspath)
if not hasattr(item, 'outerr'):
item.outerr = ('', '') # we accumulate outerr on the item
return self.resumecapture(method)
def resumecapture(self):
self._capturing.resume_capturing()
def resumecapture(self, method=None):
if hasattr(self, '_capturing'):
raise ValueError(
"cannot resume, already capturing with %r" %
(self._capturing,))
if method is None:
method = self._defaultmethod
cap = self._method2capture.get(method)
self._capturing = method
if cap is None:
self._method2capture[method] = cap = self._getcapture(method)
cap.startall()
else:
cap.resume()
def suspendcapture(self, item=None):
def suspendcapture(self, in_=False):
self.deactivate_funcargs()
if hasattr(self, '_capturing'):
method = self._capturing
cap = self._method2capture.get(method)
if cap is not None:
outerr = cap.suspend()
del self._capturing
if item:
outerr = (item.outerr[0] + outerr[0],
item.outerr[1] + outerr[1])
cap = getattr(self, "_capturing", None)
if cap is not None:
outerr = cap.readouterr()
cap.suspend_capturing(in_=in_)
return outerr
if hasattr(item, 'outerr'):
return item.outerr
return "", ""
def activate_funcargs(self, pyfuncitem):
funcargs = getattr(pyfuncitem, "funcargs", None)
if funcargs is not None:
for name, capfuncarg in funcargs.items():
if name in ('capsys', 'capfd'):
assert not hasattr(self, '_capturing_funcarg')
self._capturing_funcarg = capfuncarg
capfuncarg._start()
capfuncarg = pyfuncitem.__dict__.pop("_capfuncarg", None)
if capfuncarg is not None:
capfuncarg._start()
self._capfuncarg = capfuncarg
def deactivate_funcargs(self):
capturing_funcarg = getattr(self, '_capturing_funcarg', None)
if capturing_funcarg:
outerr = capturing_funcarg._finalize()
del self._capturing_funcarg
return outerr
capfuncarg = self.__dict__.pop("_capfuncarg", None)
if capfuncarg is not None:
capfuncarg.close()
@pytest.mark.tryfirst
def pytest_make_collect_report(self, __multicall__, collector):
method = self._getmethod(collector.config, collector.fspath)
try:
self.resumecapture(method)
except ValueError:
# recursive collect, XXX refactor capturing
# to allow for more lightweight recursive capturing
if not isinstance(collector, pytest.File):
return
self.resumecapture()
try:
rep = __multicall__.execute()
finally:
outerr = self.suspendcapture()
addouterr(rep, outerr)
out, err = self.suspendcapture()
if out:
rep.sections.append(("Captured stdout", out))
if err:
rep.sections.append(("Captured stderr", err))
return rep
@pytest.mark.tryfirst
@pytest.mark.hookwrapper
def pytest_runtest_setup(self, item):
self.resumecapture_item(item)
self.resumecapture()
yield
self.suspendcapture_item(item, "setup")
@pytest.mark.tryfirst
@pytest.mark.hookwrapper
def pytest_runtest_call(self, item):
self.resumecapture_item(item)
self.resumecapture()
self.activate_funcargs(item)
yield
#self.deactivate_funcargs() called from suspendcapture()
self.suspendcapture_item(item, "call")
@pytest.mark.tryfirst
@pytest.mark.hookwrapper
def pytest_runtest_teardown(self, item):
self.resumecapture_item(item)
def pytest_keyboard_interrupt(self, excinfo):
if hasattr(self, '_capturing'):
self.suspendcapture()
self.resumecapture()
yield
self.suspendcapture_item(item, "teardown")
@pytest.mark.tryfirst
def pytest_runtest_makereport(self, __multicall__, item, call):
funcarg_outerr = self.deactivate_funcargs()
rep = __multicall__.execute()
outerr = self.suspendcapture(item)
if funcarg_outerr is not None:
outerr = (outerr[0] + funcarg_outerr[0],
outerr[1] + funcarg_outerr[1])
addouterr(rep, outerr)
if not rep.passed or rep.when == "teardown":
outerr = ('', '')
item.outerr = outerr
return rep
def pytest_keyboard_interrupt(self, excinfo):
self.reset_capturings()
@pytest.mark.tryfirst
def pytest_internalerror(self, excinfo):
self.reset_capturings()
def suspendcapture_item(self, item, when):
out, err = self.suspendcapture()
item.add_report_section(when, "out", out)
item.add_report_section(when, "err", err)
error_capsysfderror = "cannot use capsys and capfd at the same time"
def pytest_funcarg__capsys(request):
@pytest.fixture
def capsys(request):
"""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.
"""
if "capfd" in request._funcargs:
raise request.raiseerror(error_capsysfderror)
return CaptureFixture(StdCapture)
request.node._capfuncarg = c = CaptureFixture(SysCapture)
return c
def pytest_funcarg__capfd(request):
@pytest.fixture
def capfd(request):
"""enables capturing of writes to file descriptors 1 and 2 and makes
captured output available via ``capsys.readouterr()`` method calls
captured output available via ``capfd.readouterr()`` method calls
which return a ``(out, err)`` tuple.
"""
if "capsys" in request._funcargs:
request.raiseerror(error_capsysfderror)
if not hasattr(os, 'dup'):
pytest.skip("capfd funcarg needs os.dup")
return CaptureFixture(StdCaptureFD)
request.node._capfuncarg = c = CaptureFixture(FDCapture)
return c
class CaptureFixture:
def __init__(self, captureclass):
self._capture = captureclass()
self.captureclass = captureclass
def _start(self):
self._capture.startall()
self._capture = MultiCapture(out=True, err=True, in_=False,
Capture=self.captureclass)
self._capture.start_capturing()
def _finalize(self):
if hasattr(self, '_capture'):
outerr = self._outerr = self._capture.reset()
del self._capture
return outerr
def close(self):
cap = self.__dict__.pop("_capture", None)
if cap is not None:
self._outerr = cap.pop_outerr_to_orig()
cap.stop_capturing()
def readouterr(self):
try:
@@ -298,295 +202,223 @@ class CaptureFixture:
except AttributeError:
return self._outerr
def close(self):
self._finalize()
class FDCapture:
""" Capture IO to/from a given os-level filedescriptor. """
def __init__(self, targetfd, tmpfile=None, patchsys=False):
""" save targetfd descriptor, and open a new
temporary file there. If no tmpfile is
specified a tempfile.Tempfile() will be opened
in text mode.
"""
self.targetfd = targetfd
if tmpfile is None and targetfd != 0:
f = tempfile.TemporaryFile('wb+')
tmpfile = dupfile(f, encoding="UTF-8")
f.close()
self.tmpfile = tmpfile
self._savefd = os.dup(self.targetfd)
if patchsys:
self._oldsys = getattr(sys, patchsysdict[targetfd])
def start(self):
try:
os.fstat(self._savefd)
except OSError:
raise ValueError(
"saved filedescriptor not valid, "
"did you call start() twice?")
if self.targetfd == 0 and not self.tmpfile:
fd = os.open(os.devnull, os.O_RDONLY)
os.dup2(fd, 0)
os.close(fd)
if hasattr(self, '_oldsys'):
setattr(sys, patchsysdict[self.targetfd], DontReadFromInput())
else:
os.dup2(self.tmpfile.fileno(), self.targetfd)
if hasattr(self, '_oldsys'):
setattr(sys, patchsysdict[self.targetfd], self.tmpfile)
def done(self):
""" unpatch and clean up, returns the self.tmpfile (file object)
"""
os.dup2(self._savefd, self.targetfd)
os.close(self._savefd)
if self.targetfd != 0:
self.tmpfile.seek(0)
if hasattr(self, '_oldsys'):
setattr(sys, patchsysdict[self.targetfd], self._oldsys)
return self.tmpfile
def writeorg(self, data):
""" write a string to the original file descriptor
"""
tempfp = tempfile.TemporaryFile()
try:
os.dup2(self._savefd, tempfp.fileno())
tempfp.write(data)
finally:
tempfp.close()
def dupfile(f, mode=None, buffering=0, raising=False, encoding=None):
""" return a new open file object that's a duplicate of f
mode is duplicated if not given, 'buffering' controls
buffer size (defaulting to no buffering) and 'raising'
defines whether an exception is raised when an incompatible
file object is passed in (if raising is False, the file
object itself will be returned)
def safe_text_dupfile(f, mode, default_encoding="UTF8"):
""" return a open text file object that's a duplicate of f on the
FD-level if possible.
"""
encoding = getattr(f, "encoding", None)
try:
fd = f.fileno()
mode = mode or f.mode
except AttributeError:
if raising:
raise
return f
newfd = os.dup(fd)
if sys.version_info >= (3, 0):
if encoding is not None:
mode = mode.replace("b", "")
buffering = True
return os.fdopen(newfd, mode, buffering, encoding, closefd=True)
except Exception:
if "b" not in getattr(f, "mode", "") and hasattr(f, "encoding"):
# we seem to have a text stream, let's just use it
return f
else:
f = os.fdopen(newfd, mode, buffering)
if encoding is not None:
return EncodedFile(f, encoding)
return f
newfd = os.dup(fd)
if "b" not in mode:
mode += "b"
f = os.fdopen(newfd, mode, 0) # no buffering
return EncodedFile(f, encoding or default_encoding)
class EncodedFile(object):
def __init__(self, _stream, encoding):
self._stream = _stream
errors = "strict" # possibly needed by py3 code (issue555)
def __init__(self, buffer, encoding):
self.buffer = buffer
self.encoding = encoding
def write(self, obj):
if isinstance(obj, unicode):
obj = obj.encode(self.encoding)
self._stream.write(obj)
obj = obj.encode(self.encoding, "replace")
self.buffer.write(obj)
def writelines(self, linelist):
data = ''.join(linelist)
self.write(data)
def __getattr__(self, name):
return getattr(self._stream, name)
return getattr(object.__getattribute__(self, "buffer"), name)
class Capture(object):
def reset(self):
""" reset sys.stdout/stderr and return captured output as strings. """
if hasattr(self, '_reset'):
raise ValueError("was already reset")
self._reset = True
outfile, errfile = self.done(save=False)
out, err = "", ""
if outfile and not outfile.closed:
out = outfile.read()
outfile.close()
if errfile and errfile != outfile and not errfile.closed:
err = errfile.read()
errfile.close()
return out, err
class MultiCapture(object):
out = err = in_ = None
def suspend(self):
""" return current snapshot captures, memorize tempfiles. """
outerr = self.readouterr()
outfile, errfile = self.done()
return outerr
class StdCaptureFD(Capture):
""" This class allows to capture writes to FD1 and FD2
and may connect a NULL file to FD0 (and prevent
reads from sys.stdin). If any of the 0,1,2 file descriptors
is invalid it will not be captured.
"""
def __init__(self, out=True, err=True, in_=True, patchsys=True):
self._options = {
"out": out,
"err": err,
"in_": in_,
"patchsys": patchsys,
}
self._save()
def _save(self):
in_ = self._options['in_']
out = self._options['out']
err = self._options['err']
patchsys = self._options['patchsys']
def __init__(self, out=True, err=True, in_=True, Capture=None):
if in_:
try:
self.in_ = FDCapture(
0, tmpfile=None,
patchsys=patchsys)
except OSError:
pass
self.in_ = Capture(0)
if out:
tmpfile = None
if hasattr(out, 'write'):
tmpfile = out
try:
self.out = FDCapture(
1, tmpfile=tmpfile,
patchsys=patchsys)
self._options['out'] = self.out.tmpfile
except OSError:
pass
self.out = Capture(1)
if err:
if hasattr(err, 'write'):
tmpfile = err
else:
tmpfile = None
try:
self.err = FDCapture(
2, tmpfile=tmpfile,
patchsys=patchsys)
self._options['err'] = self.err.tmpfile
except OSError:
pass
self.err = Capture(2)
def startall(self):
if hasattr(self, 'in_'):
def start_capturing(self):
if self.in_:
self.in_.start()
if hasattr(self, 'out'):
if self.out:
self.out.start()
if hasattr(self, 'err'):
if self.err:
self.err.start()
def resume(self):
""" resume capturing with original temp files. """
self.startall()
def done(self, save=True):
""" return (outfile, errfile) and stop capturing. """
outfile = errfile = None
if hasattr(self, 'out') and not self.out.tmpfile.closed:
outfile = self.out.done()
if hasattr(self, 'err') and not self.err.tmpfile.closed:
errfile = self.err.done()
if hasattr(self, 'in_'):
self.in_.done()
if save:
self._save()
return outfile, errfile
def readouterr(self):
""" return snapshot value of stdout/stderr capturings. """
out = self._readsnapshot('out')
err = self._readsnapshot('err')
def pop_outerr_to_orig(self):
""" pop current snapshot out/err capture and flush to orig streams. """
out, err = self.readouterr()
if out:
self.out.writeorg(out)
if err:
self.err.writeorg(err)
return out, err
def _readsnapshot(self, name):
if hasattr(self, name):
f = getattr(self, name).tmpfile
else:
return ''
def suspend_capturing(self, in_=False):
if self.out:
self.out.suspend()
if self.err:
self.err.suspend()
if in_ and self.in_:
self.in_.suspend()
self._in_suspended = True
def resume_capturing(self):
if self.out:
self.out.resume()
if self.err:
self.err.resume()
if hasattr(self, "_in_suspended"):
self.in_.resume()
del self._in_suspended
def stop_capturing(self):
""" stop capturing and reset capturing streams """
if hasattr(self, '_reset'):
raise ValueError("was already stopped")
self._reset = True
if self.out:
self.out.done()
if self.err:
self.err.done()
if self.in_:
self.in_.done()
def readouterr(self):
""" return snapshot unicode value of stdout/stderr capturings. """
return (self.out.snap() if self.out is not None else "",
self.err.snap() if self.err is not None else "")
class NoCapture:
__init__ = start = done = suspend = resume = lambda *args: None
class FDCapture:
""" Capture IO to/from a given os-level filedescriptor. """
def __init__(self, targetfd, tmpfile=None):
self.targetfd = targetfd
try:
self.targetfd_save = os.dup(self.targetfd)
except OSError:
self.start = lambda: None
self.done = lambda: None
else:
if targetfd == 0:
assert not tmpfile, "cannot set tmpfile with stdin"
tmpfile = open(os.devnull, "r")
self.syscapture = SysCapture(targetfd)
else:
if tmpfile is None:
f = TemporaryFile()
with f:
tmpfile = safe_text_dupfile(f, mode="wb+")
if targetfd in patchsysdict:
self.syscapture = SysCapture(targetfd, tmpfile)
else:
self.syscapture = NoCapture()
self.tmpfile = tmpfile
self.tmpfile_fd = tmpfile.fileno()
def __repr__(self):
return "<FDCapture %s oldfd=%s>" % (self.targetfd, self.targetfd_save)
def start(self):
""" Start capturing on targetfd using memorized tmpfile. """
try:
os.fstat(self.targetfd_save)
except (AttributeError, OSError):
raise ValueError("saved filedescriptor not valid anymore")
os.dup2(self.tmpfile_fd, self.targetfd)
self.syscapture.start()
def snap(self):
f = self.tmpfile
f.seek(0)
res = f.read()
enc = getattr(f, "encoding", None)
if enc:
res = py.builtin._totext(res, enc, "replace")
if res:
enc = getattr(f, "encoding", None)
if enc and isinstance(res, bytes):
res = py.builtin._totext(res, enc, "replace")
f.truncate(0)
f.seek(0)
return res
return ''
def done(self):
""" stop capturing, restore streams, return original capture file,
seeked to position zero. """
targetfd_save = self.__dict__.pop("targetfd_save")
os.dup2(targetfd_save, self.targetfd)
os.close(targetfd_save)
self.syscapture.done()
self.tmpfile.close()
def suspend(self):
self.syscapture.suspend()
os.dup2(self.targetfd_save, self.targetfd)
def resume(self):
self.syscapture.resume()
os.dup2(self.tmpfile_fd, self.targetfd)
def writeorg(self, data):
""" write to original file descriptor. """
if py.builtin._istext(data):
data = data.encode("utf8") # XXX use encoding of original stream
os.write(self.targetfd_save, data)
class SysCapture:
def __init__(self, fd, tmpfile=None):
name = patchsysdict[fd]
self._old = getattr(sys, name)
self.name = name
if tmpfile is None:
if name == "stdin":
tmpfile = DontReadFromInput()
else:
tmpfile = TextIO()
self.tmpfile = tmpfile
def start(self):
setattr(sys, self.name, self.tmpfile)
def snap(self):
f = self.tmpfile
res = f.getvalue()
f.truncate(0)
f.seek(0)
return res
def done(self):
setattr(sys, self.name, self._old)
del self._old
self.tmpfile.close()
class StdCapture(Capture):
""" This class allows to capture writes to sys.stdout|stderr "in-memory"
and will raise errors on tries to read from sys.stdin. It only
modifies sys.stdout|stderr|stdin attributes and does not
touch underlying File Descriptors (use StdCaptureFD for that).
"""
def __init__(self, out=True, err=True, in_=True):
self._oldout = sys.stdout
self._olderr = sys.stderr
self._oldin = sys.stdin
if out and not hasattr(out, 'file'):
out = TextIO()
self.out = out
if err:
if not hasattr(err, 'write'):
err = TextIO()
self.err = err
self.in_ = in_
def startall(self):
if self.out:
sys.stdout = self.out
if self.err:
sys.stderr = self.err
if self.in_:
sys.stdin = self.in_ = DontReadFromInput()
def done(self, save=True):
""" return (outfile, errfile) and stop capturing. """
outfile = errfile = None
if self.out and not self.out.closed:
sys.stdout = self._oldout
outfile = self.out
outfile.seek(0)
if self.err and not self.err.closed:
sys.stderr = self._olderr
errfile = self.err
errfile.seek(0)
if self.in_:
sys.stdin = self._oldin
return outfile, errfile
def suspend(self):
setattr(sys, self.name, self._old)
def resume(self):
""" resume capturing with original temp files. """
self.startall()
setattr(sys, self.name, self.tmpfile)
def readouterr(self):
""" return snapshot value of stdout/stderr capturings. """
out = err = ""
if self.out:
out = self.out.getvalue()
self.out.truncate(0)
self.out.seek(0)
if self.err:
err = self.err.getvalue()
self.err.truncate(0)
self.err.seek(0)
return out, err
def writeorg(self, data):
self._old.write(data)
self._old.flush()
class DontReadFromInput:
@@ -596,6 +428,9 @@ class DontReadFromInput:
because in automated test runs it is better to crash than
hang indefinitely.
"""
encoding = None
def read(self, *args):
raise IOError("reading from stdin while output is captured")
readline = read

View File

@@ -1,4 +1,9 @@
""" command line options, ini-file and conftest.py processing. """
import argparse
import shlex
import traceback
import types
import warnings
import py
# DON't import pytest here because it causes import cycle troubles
@@ -7,6 +12,13 @@ from _pytest import hookspec # the extension point definitions
from _pytest.core import PluginManager
# pytest startup
#
class ConftestImportFailure(Exception):
def __init__(self, path, excinfo):
Exception.__init__(self, path, excinfo)
self.path = path
self.excinfo = excinfo
def main(args=None, plugins=None):
""" return exit code, after performing an in-process test run.
@@ -16,8 +28,17 @@ def main(args=None, plugins=None):
:arg plugins: list of plugin objects to be auto-registered during
initialization.
"""
config = _prepareconfig(args, plugins)
return config.hook.pytest_cmdline_main(config=config)
try:
config = _prepareconfig(args, plugins)
except ConftestImportFailure:
e = sys.exc_info()[1]
tw = py.io.TerminalWriter(sys.stderr)
for line in traceback.format_exception(*e.excinfo):
tw.line(line.rstrip(), red=True)
tw.line("ERROR: could not load %s\n" % (e.path), red=True)
return 4
else:
return config.hook.pytest_cmdline_main(config=config)
class cmdline: # compatibility namespace
main = staticmethod(main)
@@ -54,13 +75,17 @@ def _prepareconfig(args=None, plugins=None):
elif not isinstance(args, (tuple, list)):
if not isinstance(args, str):
raise ValueError("not a string or argument list: %r" % (args,))
args = py.std.shlex.split(args)
args = shlex.split(args)
pluginmanager = get_plugin_manager()
if plugins:
for plugin in plugins:
pluginmanager.register(plugin)
return pluginmanager.hook.pytest_cmdline_parse(
pluginmanager=pluginmanager, args=args)
try:
if plugins:
for plugin in plugins:
pluginmanager.register(plugin)
return pluginmanager.hook.pytest_cmdline_parse(
pluginmanager=pluginmanager, args=args)
except Exception:
pluginmanager.ensure_shutdown()
raise
class PytestPluginManager(PluginManager):
def __init__(self, hookspecs=[hookspec]):
@@ -82,6 +107,8 @@ class PytestPluginManager(PluginManager):
config.addinivalue_line("markers",
"trylast: mark a hook implementation function such that the "
"plugin machinery will try to call it last/as late as possible.")
for warning in self._warnings:
config.warn(code="I1", message=warning)
class Parser:
@@ -94,7 +121,6 @@ class Parser:
self._usage = usage
self._inidict = {}
self._ininames = []
self.hints = []
def processoption(self, option):
if self._processopt:
@@ -159,8 +185,7 @@ class Parser:
a = option.attrs()
arggroup.add_argument(*n, **a)
# bash like autocompletion for dirs (appending '/')
optparser.add_argument(FILE_OR_DIR, nargs='*'
).completer=filescompleter
optparser.add_argument(FILE_OR_DIR, nargs='*').completer=filescompleter
return optparser
def parse_setoption(self, args, option):
@@ -207,7 +232,7 @@ class ArgumentError(Exception):
class Argument:
"""class that mimics the necessary behaviour of py.std.optparse.Option """
"""class that mimics the necessary behaviour of optparse.Option """
_typ_map = {
'int': int,
'string': str,
@@ -225,7 +250,7 @@ class Argument:
try:
help = attrs['help']
if '%default' in help:
py.std.warnings.warn(
warnings.warn(
'pytest now uses argparse. "%default" should be'
' changed to "%(default)s" ',
FutureWarning,
@@ -241,7 +266,7 @@ class Argument:
if isinstance(typ, py.builtin._basestring):
if typ == 'choice':
if self.TYPE_WARN:
py.std.warnings.warn(
warnings.warn(
'type argument to addoption() is a string %r.'
' For parsearg this is optional and when supplied '
' should be a type.'
@@ -253,7 +278,7 @@ class Argument:
attrs['type'] = type(attrs['choices'][0])
else:
if self.TYPE_WARN:
py.std.warnings.warn(
warnings.warn(
'type argument to addoption() is a string %r.'
' For parsearg this should be a type.'
' (options: %s)' % (typ, names),
@@ -373,32 +398,24 @@ class OptionGroup:
self.options.append(option)
class MyOptionParser(py.std.argparse.ArgumentParser):
class MyOptionParser(argparse.ArgumentParser):
def __init__(self, parser):
self._parser = parser
py.std.argparse.ArgumentParser.__init__(self, usage=parser._usage,
argparse.ArgumentParser.__init__(self, usage=parser._usage,
add_help=False, formatter_class=DropShorterLongHelpFormatter)
def format_epilog(self, formatter):
hints = self._parser.hints
if hints:
s = "\n".join(["hint: " + x for x in hints]) + "\n"
s = "\n" + s + "\n"
return s
return ""
def parse_args(self, args=None, namespace=None):
"""allow splitting of positional arguments"""
args, argv = self.parse_known_args(args, namespace)
if argv:
for arg in argv:
if arg and arg[0] == '-':
msg = py.std.argparse._('unrecognized arguments: %s')
msg = argparse._('unrecognized arguments: %s')
self.error(msg % ' '.join(argv))
getattr(args, FILE_OR_DIR).extend(argv)
return args
class DropShorterLongHelpFormatter(py.std.argparse.HelpFormatter):
class DropShorterLongHelpFormatter(argparse.HelpFormatter):
"""shorten help for long options that differ only in extra hyphens
- collapse **long** options that are the same except for extra hyphens
@@ -408,7 +425,7 @@ class DropShorterLongHelpFormatter(py.std.argparse.HelpFormatter):
- cache result on action object as this is called at least 2 times
"""
def _format_action_invocation(self, action):
orgstr = py.std.argparse.HelpFormatter._format_action_invocation(self, action)
orgstr = argparse.HelpFormatter._format_action_invocation(self, action)
if orgstr and orgstr[0] != '-': # only optional arguments
return orgstr
res = getattr(action, '_formatted_action_invocation', None)
@@ -442,7 +459,7 @@ class DropShorterLongHelpFormatter(py.std.argparse.HelpFormatter):
if len(option) == 2 or option[2] == ' ':
return_list.append(option)
if option[2:] == short_long.get(option.replace('-', '')):
return_list.append(option)
return_list.append(option.replace(' ', '='))
action._formatted_action_invocation = ', '.join(return_list)
return action._formatted_action_invocation
@@ -451,38 +468,32 @@ class Conftest(object):
""" the single place for accessing values and interacting
towards conftest modules from pytest objects.
"""
def __init__(self, onimport=None, confcutdir=None):
def __init__(self, onimport=None):
self._path2confmods = {}
self._onimport = onimport
self._conftestpath2mod = {}
self._confcutdir = confcutdir
self._confcutdir = None
def setinitial(self, args):
""" try to find a first anchor path for looking up global values
from conftests. This function is usually called _before_
argument parsing. conftest files may add command line options
and we thus have no completely safe way of determining
which parts of the arguments are actually related to options
and which are file system paths. We just try here to get
bootstrapped ...
def setinitial(self, namespace):
""" load initial conftest files given a preparsed "namespace".
As conftest files may add their own command line options
which have arguments ('--my-opt somepath') we might get some
false positives. All builtin and 3rd party plugins will have
been loaded, however, so common options will not confuse our logic
here.
"""
current = py.path.local()
opt = '--confcutdir'
for i in range(len(args)):
opt1 = str(args[i])
if opt1.startswith(opt):
if opt1 == opt:
if len(args) > i:
p = current.join(args[i+1], abs=True)
elif opt1.startswith(opt + "="):
p = current.join(opt1[len(opt)+1:], abs=1)
self._confcutdir = p
break
self._confcutdir = current.join(namespace.confcutdir, abs=True) \
if namespace.confcutdir else None
testpaths = namespace.file_or_dir
foundanchor = False
for arg in args:
if hasattr(arg, 'startswith') and arg.startswith("--"):
continue
anchor = current.join(arg, abs=1)
for path in testpaths:
path = str(path)
# remove node-id syntax
i = path.find("::")
if i != -1:
path = path[:i]
anchor = current.join(path, abs=1)
if exists(anchor): # we found some file object
self._try_load_conftest(anchor)
foundanchor = True
@@ -490,7 +501,7 @@ class Conftest(object):
self._try_load_conftest(current)
def _try_load_conftest(self, anchor):
self._path2confmods[None] = self.getconftestmodules(anchor)
self.getconftestmodules(anchor)
# let's also consider test* subdirs
if anchor.check(dir=1):
for x in anchor.listdir("test*"):
@@ -499,28 +510,22 @@ class Conftest(object):
def getconftestmodules(self, path):
try:
clist = self._path2confmods[path]
return self._path2confmods[path]
except KeyError:
if path is None:
raise ValueError("missing default conftest.")
clist = []
for parent in path.parts():
if self._confcutdir and self._confcutdir.relto(parent):
continue
conftestpath = parent.join("conftest.py")
if conftestpath.check(file=1):
clist.append(self.importconftest(conftestpath))
mod = self.importconftest(conftestpath)
clist.append(mod)
self._path2confmods[path] = clist
return clist
return clist
def rget(self, name, path=None):
mod, value = self.rget_with_confmod(name, path)
return value
def rget_with_confmod(self, name, path=None):
def rget_with_confmod(self, name, path):
modules = self.getconftestmodules(path)
modules.reverse()
for mod in modules:
for mod in reversed(modules):
try:
return mod, getattr(mod, name)
except AttributeError:
@@ -528,27 +533,27 @@ class Conftest(object):
raise KeyError(name)
def importconftest(self, conftestpath):
assert conftestpath.check(), conftestpath
try:
return self._conftestpath2mod[conftestpath]
except KeyError:
pkgpath = conftestpath.pypkgpath()
if pkgpath is None:
_ensure_removed_sysmodule(conftestpath.purebasename)
self._conftestpath2mod[conftestpath] = mod = conftestpath.pyimport()
try:
mod = conftestpath.pyimport()
except Exception:
raise ConftestImportFailure(conftestpath, sys.exc_info())
self._conftestpath2mod[conftestpath] = mod
dirpath = conftestpath.dirpath()
if dirpath in self._path2confmods:
for path, mods in self._path2confmods.items():
if path and path.relto(dirpath) or path == dirpath:
assert mod not in mods
mods.append(mod)
self._postimport(mod)
if self._onimport:
self._onimport(mod)
return mod
def _postimport(self, mod):
if self._onimport:
self._onimport(mod)
return mod
def _ensure_removed_sysmodule(modname):
try:
@@ -563,6 +568,11 @@ class CmdOptions(object):
def __repr__(self):
return "<CmdOptions %r>" %(self.__dict__,)
class Notset:
def __repr__(self):
return "<NOTSET>"
notset = Notset()
FILE_OR_DIR = 'file_or_dir'
class Config(object):
""" access to configuration values, pluginmanager and plugin hooks. """
@@ -613,6 +623,14 @@ class Config(object):
self.hook.pytest_unconfigure(config=self)
self.pluginmanager.ensure_shutdown()
def warn(self, code, message):
""" generate a warning for this test session. """
self.hook.pytest_logwarning(code=code, message=message,
fslocation=None, nodeid=None)
def get_terminal_writer(self):
return self.pluginmanager.getplugin("terminalreporter")._tw
def pytest_cmdline_parse(self, pluginmanager, args):
assert self == pluginmanager.config, (self, pluginmanager.config)
self.parse(args)
@@ -670,12 +688,20 @@ class Config(object):
plugins += self._conftest.getconftestmodules(fspath)
return plugins
def pytest_load_initial_conftests(self, parser, args):
self._conftest.setinitial(args)
def pytest_load_initial_conftests(self, early_config):
self._conftest.setinitial(early_config.known_args_namespace)
pytest_load_initial_conftests.trylast = True
def _initini(self, args):
self.inicfg = getcfg(args, ["pytest.ini", "tox.ini", "setup.cfg"])
parsed_args = self._parser.parse_known_args(args)
if parsed_args.inifilename:
iniconfig = py.iniconfig.IniConfig(parsed_args.inifilename)
if 'pytest' in iniconfig.sections:
self.inicfg = iniconfig['pytest']
else:
self.inicfg = {}
else:
self.inicfg = getcfg(args, ["pytest.ini", "tox.ini", "setup.cfg"])
self._parser.addini('addopts', 'extra command line options', 'args')
self._parser.addini('minversion', 'minimally required pytest version')
@@ -687,8 +713,19 @@ class Config(object):
self.pluginmanager.consider_preparse(args)
self.pluginmanager.consider_setuptools_entrypoints()
self.pluginmanager.consider_env()
self.hook.pytest_load_initial_conftests(early_config=self,
args=args, parser=self._parser)
self.known_args_namespace = ns = self._parser.parse_known_args(args)
try:
self.hook.pytest_load_initial_conftests(early_config=self,
args=args, parser=self._parser)
except ConftestImportFailure:
e = sys.exc_info()[1]
if ns.help or ns.version:
# we don't want to prevent --help/--version to work
# so just let is pass and print a warning at the end
self.pluginmanager._warnings.append(
"could not load initial conftests (%s)\n" % e.path)
else:
raise
def _checkversion(self):
import pytest
@@ -704,17 +741,15 @@ class Config(object):
def parse(self, args):
# parse given cmdline arguments into this config object.
# Note that this can only be called once per testing process.
assert not hasattr(self, 'args'), (
"can only parse cmdline args at most once per Config object")
self._origargs = args
self._preparse(args)
# XXX deprecated hook:
self.hook.pytest_cmdline_preparse(config=self, args=args)
self._parser.hints.extend(self.pluginmanager._hints)
args = self._parser.parse_setoption(args, self.option)
if not args:
args.append(py.std.os.getcwd())
args.append(os.getcwd())
self.args = args
def addinivalue_line(self, name, line):
@@ -752,18 +787,18 @@ class Config(object):
if type == "pathlist":
dp = py.path.local(self.inicfg.config.path).dirpath()
l = []
for relpath in py.std.shlex.split(value):
for relpath in shlex.split(value):
l.append(dp.join(relpath, abs=True))
return l
elif type == "args":
return py.std.shlex.split(value)
return shlex.split(value)
elif type == "linelist":
return [t for t in map(lambda x: x.strip(), value.split("\n")) if t]
else:
assert type is None
return value
def _getconftest_pathlist(self, name, path=None):
def _getconftest_pathlist(self, name, path):
try:
mod, relroots = self._conftest.rget_with_confmod(name, path)
except KeyError:
@@ -777,47 +812,36 @@ class Config(object):
l.append(relroot)
return l
def _getconftest(self, name, path=None, check=False):
if check:
self._checkconftest(name)
return self._conftest.rget(name, path)
def getoption(self, name):
def getoption(self, name, default=notset, skip=False):
""" return command line option value.
:arg name: name of the option. You may also specify
the literal ``--OPT`` option instead of the "dest" option name.
:arg default: default value if no option of that name exists.
:arg skip: if True raise pytest.skip if option does not exists
or has a None value.
"""
name = self._opt2dest.get(name, name)
try:
return getattr(self.option, name)
val = getattr(self.option, name)
if val is None and skip:
raise AttributeError(name)
return val
except AttributeError:
if default is not notset:
return default
if skip:
import pytest
pytest.skip("no %r option found" %(name,))
raise ValueError("no option named %r" % (name,))
def getvalue(self, name, path=None):
""" return command line option value.
:arg name: name of the command line option
(deprecated) if we can't find the option also lookup
the name in a matching conftest file.
"""
try:
return getattr(self.option, name)
except AttributeError:
return self._getconftest(name, path, check=False)
""" (deprecated, use getoption()) """
return self.getoption(name)
def getvalueorskip(self, name, path=None):
""" (deprecated) return getvalue(name) or call
pytest.skip if no value exists. """
__tracebackhide__ = True
try:
val = self.getvalue(name, path)
if val is None:
raise KeyError(name)
return val
except KeyError:
py.test.skip("no %r value found" %(name,))
""" (deprecated, use getoption(skip=True)) """
return self.getoption(name, skip=True)
def exists(path, ignore=EnvironmentError):
try:
@@ -848,7 +872,7 @@ def setns(obj, dic):
mod = getattr(obj, name, None)
if mod is None:
modname = "pytest.%s" % name
mod = py.std.types.ModuleType(modname)
mod = types.ModuleType(modname)
sys.modules[modname] = mod
mod.__all__ = []
setattr(obj, name, mod)

View File

@@ -1,6 +1,7 @@
"""
pytest PluginManager, basic initialization and tracing.
"""
import os
import sys
import inspect
import py
@@ -71,7 +72,7 @@ class PluginManager(object):
self._name2plugin = {}
self._listattrcache = {}
self._plugins = []
self._hints = []
self._warnings = []
self.trace = TagTracer().get("pluginmanage")
self._plugin_distinfo = []
self._shutdown = []
@@ -137,7 +138,8 @@ class PluginManager(object):
def skipifmissing(self, name):
if not self.hasplugin(name):
py.test.skip("plugin %r is missing" % name)
import pytest
pytest.skip("plugin %r is missing" % name)
def hasplugin(self, name):
return bool(self.getplugin(name))
@@ -153,7 +155,7 @@ class PluginManager(object):
# API for bootstrapping
#
def _envlist(self, varname):
val = py.std.os.environ.get(varname, None)
val = os.environ.get(varname, None)
if val is not None:
return val.split(',')
return ()
@@ -220,12 +222,11 @@ class PluginManager(object):
return self.import_plugin(modname[7:])
raise
except:
e = py.std.sys.exc_info()[1]
if not hasattr(py.test, 'skip'):
e = sys.exc_info()[1]
import pytest
if not hasattr(pytest, 'skip') or not isinstance(e, pytest.skip.Exception):
raise
elif not isinstance(e, py.test.skip.Exception):
raise
self._hints.append("skipped plugin %r: %s" %((modname, e.msg)))
self._warnings.append("skipped plugin %r: %s" %((modname, e.msg)))
else:
self.register(mod, modname)
self.consider_module(mod)
@@ -240,18 +241,22 @@ class PluginManager(object):
pass
l = []
last = []
wrappers = []
for plugin in plugins:
try:
meth = getattr(plugin, attrname)
if hasattr(meth, 'tryfirst'):
last.append(meth)
elif hasattr(meth, 'trylast'):
l.insert(0, meth)
else:
l.append(meth)
except AttributeError:
continue
if hasattr(meth, 'hookwrapper'):
wrappers.append(meth)
elif hasattr(meth, 'tryfirst'):
last.append(meth)
elif hasattr(meth, 'trylast'):
l.insert(0, meth)
else:
l.append(meth)
l.extend(last)
l.extend(wrappers)
self._listattrcache[key] = list(l)
return l
@@ -272,6 +277,14 @@ def importplugin(importspec):
class MultiCall:
""" execute a call into multiple python functions/methods. """
class WrongHookWrapper(Exception):
""" a hook wrapper does not behave correctly. """
def __init__(self, func, message):
Exception.__init__(self, func, message)
self.func = func
self.message = message
def __init__(self, methods, kwargs, firstresult=False):
self.methods = list(methods)
self.kwargs = kwargs
@@ -283,16 +296,39 @@ class MultiCall:
return "<MultiCall %s, kwargs=%r>" %(status, self.kwargs)
def execute(self):
while self.methods:
method = self.methods.pop()
kwargs = self.getkwargs(method)
res = method(**kwargs)
if res is not None:
self.results.append(res)
if self.firstresult:
return res
if not self.firstresult:
return self.results
next_finalizers = []
try:
while self.methods:
method = self.methods.pop()
kwargs = self.getkwargs(method)
if hasattr(method, "hookwrapper"):
it = method(**kwargs)
next = getattr(it, "next", None)
if next is None:
next = getattr(it, "__next__", None)
if next is None:
raise self.WrongHookWrapper(method,
"wrapper does not contain a yield")
res = next()
next_finalizers.append((method, next))
else:
res = method(**kwargs)
if res is not None:
self.results.append(res)
if self.firstresult:
return res
if not self.firstresult:
return self.results
finally:
for method, fin in reversed(next_finalizers):
try:
fin()
except StopIteration:
pass
else:
raise self.WrongHookWrapper(method,
"wrapper contain more than one yield")
def getkwargs(self, method):
kwargs = {}

View File

@@ -1,5 +1,6 @@
""" discover and run doctests in modules and test files."""
from __future__ import absolute_import
import traceback
import pytest, py
from _pytest.python import FixtureRequest, FuncFixtureInfo
from py._code.code import TerminalRepr, ReprFileLocation
@@ -43,7 +44,7 @@ class DoctestItem(pytest.Item):
self.runner.run(self.dtest)
def repr_failure(self, excinfo):
doctest = py.std.doctest
import doctest
if excinfo.errisinstance((doctest.DocTestFailure,
doctest.UnexpectedException)):
doctestfailure = excinfo.value
@@ -56,8 +57,8 @@ class DoctestItem(pytest.Item):
lineno = test.lineno + example.lineno + 1
message = excinfo.type.__name__
reprlocation = ReprFileLocation(filename, lineno, message)
checker = py.std.doctest.OutputChecker()
REPORT_UDIFF = py.std.doctest.REPORT_UDIFF
checker = doctest.OutputChecker()
REPORT_UDIFF = doctest.REPORT_UDIFF
filelines = py.path.local(filename).readlines(cr=0)
lines = []
if lineno is not None:
@@ -78,7 +79,7 @@ class DoctestItem(pytest.Item):
inner_excinfo = py.code.ExceptionInfo(excinfo.value.exc_info)
lines += ["UNEXPECTED EXCEPTION: %s" %
repr(inner_excinfo.value)]
lines += py.std.traceback.format_exception(*excinfo.value.exc_info)
lines += traceback.format_exception(*excinfo.value.exc_info)
return ReprFailDoctest(reprlocation, lines)
else:
return super(DoctestItem, self).repr_failure(excinfo)
@@ -88,7 +89,7 @@ class DoctestItem(pytest.Item):
class DoctestTextfile(DoctestItem, pytest.File):
def runtest(self):
doctest = py.std.doctest
import doctest
# satisfy `FixtureRequest` constructor...
self.funcargs = {}
fm = self.session._fixturemanager
@@ -106,7 +107,7 @@ class DoctestTextfile(DoctestItem, pytest.File):
class DoctestModule(pytest.File):
def collect(self):
doctest = py.std.doctest
import doctest
if self.fspath.basename == "conftest.py":
module = self.config._conftest.importconftest(self.fspath)
else:

View File

@@ -1,9 +1,16 @@
""" generate a single-file self-contained version of pytest """
import py
import os
import sys
import pkgutil
import py
import _pytest
def find_toplevel(name):
for syspath in py.std.sys.path:
for syspath in sys.path:
base = py.path.local(syspath)
lib = base/name
if lib.check(dir=1):
@@ -29,9 +36,10 @@ def pkg_to_mapping(name):
return name2src
def compress_mapping(mapping):
data = py.std.pickle.dumps(mapping, 2)
data = py.std.zlib.compress(data, 9)
data = py.std.base64.encodestring(data)
import base64, pickle, zlib
data = pickle.dumps(mapping, 2)
data = zlib.compress(data, 9)
data = base64.encodestring(data)
data = data.decode('ascii')
return data
@@ -64,11 +72,11 @@ def pytest_cmdline_main(config):
deps = ['py', '_pytest', 'pytest']
if sys.version_info < (2,7):
deps.append("argparse")
tw.line("generated script will run on python2.5-python3.3++")
tw.line("generated script will run on python2.6-python3.3++")
else:
tw.line("WARNING: generated script will not run on python2.6 "
"or below due to 'argparse' dependency. Use python2.6 "
"to generate a python2.5/6 compatible script", red=True)
"due to 'argparse' dependency. Use python2.6 "
"to generate a python2.6 compatible script", red=True)
script = generate_script(
'import pytest; raise SystemExit(pytest.cmdline.main())',
deps,
@@ -78,3 +86,42 @@ def pytest_cmdline_main(config):
tw.line("generated pytest standalone script: %s" % genscript,
bold=True)
return 0
def pytest_namespace():
return {'freeze_includes': freeze_includes}
def freeze_includes():
"""
Returns a list of module names used by py.test that should be
included by cx_freeze.
"""
result = list(_iter_all_modules(py))
result += list(_iter_all_modules(_pytest))
return result
def _iter_all_modules(package, prefix=''):
"""
Iterates over the names of all modules that can be found in the given
package, recursively.
Example:
_iter_all_modules(_pytest) ->
['_pytest.assertion.newinterpret',
'_pytest.capture',
'_pytest.core',
...
]
"""
if type(package) is not str:
path, prefix = package.__path__[0], package.__name__ + '.'
else:
path = package
for _, name, is_package in pkgutil.iter_modules([path]):
if is_package:
for m in _iter_all_modules(os.path.join(path, name), prefix=name + '.'):
yield prefix + m
else:
yield prefix + name

View File

@@ -64,7 +64,6 @@ def pytest_cmdline_main(config):
def showhelp(config):
tw = py.io.TerminalWriter()
tw.write(config._parser.optparser.format_help())
tw.write(config._parser.optparser.format_epilog(None))
tw.line()
tw.line()
#tw.sep( "=", "config file settings")
@@ -86,16 +85,10 @@ def showhelp(config):
tw.line("to see available fixtures type: py.test --fixtures")
tw.line("(shown according to specified file_or_dir or current dir "
"if not specified)")
for warning in config.pluginmanager._warnings:
tw.line("warning: %s" % (warning,), red=True)
return
tw.line("conftest.py options:")
tw.line()
conftestitems = sorted(config._parser._conftestdict.items())
for name, help in conftest_options + conftestitems:
line = " %-15s %s" %(name, help)
tw.line(line[:tw.fullwidth])
tw.line()
#tw.sep( "=")
conftest_options = [
('pytest_plugins', 'list of plugin names to load'),

View File

@@ -53,8 +53,8 @@ def pytest_cmdline_main(config):
pytest_cmdline_main.firstresult = True
def pytest_load_initial_conftests(args, early_config, parser):
""" implements loading initial conftests.
"""
""" implements the loading of initial conftest files ahead
of command line option parsing. """
def pytest_configure(config):
""" called after command line options have been parsed
@@ -152,9 +152,9 @@ def pytest_runtest_protocol(item, nextitem):
:arg item: test item for which the runtest protocol is performed.
:arg nexitem: the scheduled-to-be-next test item (or None if this
is the end my friend). This argument is passed on to
:py:func:`pytest_runtest_teardown`.
:arg nextitem: the scheduled-to-be-next test item (or None if this
is the end my friend). This argument is passed on to
:py:func:`pytest_runtest_teardown`.
:return boolean: True if no further hook implementations should be invoked.
"""
@@ -172,10 +172,10 @@ def pytest_runtest_call(item):
def pytest_runtest_teardown(item, nextitem):
""" called after ``pytest_runtest_call``.
:arg nexitem: the scheduled-to-be-next test item (None if no further
test item is scheduled). This argument can be used to
perform exact teardowns, i.e. calling just enough finalizers
so that nextitem only needs to call setup-functions.
:arg nextitem: the scheduled-to-be-next test item (None if no further
test item is scheduled). This argument can be used to
perform exact teardowns, i.e. calling just enough finalizers
so that nextitem only needs to call setup-functions.
"""
def pytest_runtest_makereport(item, call):
@@ -227,6 +227,11 @@ pytest_report_teststatus.firstresult = True
def pytest_terminal_summary(terminalreporter):
""" add additional section in terminal summary reporting. """
def pytest_logwarning(message, code, nodeid, fslocation):
""" process a warning specified by a message, a code string,
a nodeid and fslocation (both of which may be None
if the warning is not tied to a partilar node/location)."""
# -------------------------------------------------------------------------
# doctest hooks
# -------------------------------------------------------------------------
@@ -257,3 +262,5 @@ def pytest_exception_interact(node, call, report):
that is not an internal exception like "skip.Exception".
"""
def pytest_enter_pdb():
""" called upon pdb.set_trace()"""

View File

@@ -2,7 +2,6 @@
Based on initial code from Ross Lawley.
"""
import py
import os
import re
@@ -10,20 +9,13 @@ import sys
import time
# Python 2.X and 3.X compatibility
try:
unichr(65)
except NameError:
if sys.version_info[0] < 3:
from codecs import open
else:
unichr = chr
try:
unicode('A')
except NameError:
unicode = str
try:
long(1)
except NameError:
long = int
class Junit(py.xml.Namespace):
pass
@@ -108,12 +100,14 @@ class LogXML(object):
))
def _write_captured_output(self, report):
sec = dict(report.sections)
for name in ('out', 'err'):
content = sec.get("Captured std%s" % name)
if content:
tag = getattr(Junit, 'system-'+name)
self.append(tag(bin_xml_escape(content)))
for capname in ('out', 'err'):
allcontent = ""
for name, content in report.get_sections("Captured std%s" %
capname):
allcontent += content
if allcontent:
tag = getattr(Junit, 'system-'+capname)
self.append(tag(bin_xml_escape(allcontent)))
def append(self, obj):
self.tests[-1].append(obj)
@@ -135,10 +129,10 @@ class LogXML(object):
self.failed += 1
self._write_captured_output(report)
def append_collect_failure(self, report):
def append_collect_error(self, report):
#msg = str(report.longrepr.reprtraceback.extraline)
self.append(Junit.failure(bin_xml_escape(report.longrepr),
message="collection failure"))
self.append(Junit.error(bin_xml_escape(report.longrepr),
message="collection failure"))
self.errors += 1
def append_collect_skipped(self, report):
@@ -161,7 +155,7 @@ class LogXML(object):
if skipreason.startswith("Skipped: "):
skipreason = bin_xml_escape(skipreason[9:])
self.append(
Junit.skipped("%s:%s: %s" % report.longrepr,
Junit.skipped("%s:%s: %s" % (filename, lineno, skipreason),
type="pytest.skip",
message=skipreason
))
@@ -187,7 +181,7 @@ class LogXML(object):
if not report.passed:
self._opentestcase(report)
if report.failed:
self.append_collect_failure(report)
self.append_collect_error(report)
else:
self.append_collect_skipped(report)
@@ -204,11 +198,7 @@ class LogXML(object):
self.suite_start_time = time.time()
def pytest_sessionfinish(self):
if py.std.sys.version_info[0] < 3:
logfile = py.std.codecs.open(self.logfile, 'w', encoding='utf-8')
else:
logfile = open(self.logfile, 'w', encoding='utf-8')
logfile = open(self.logfile, 'w', encoding='utf-8')
suite_stop_time = time.time()
suite_time_delta = suite_stop_time - self.suite_start_time
numtests = self.passed + self.failed

View File

@@ -1,4 +1,5 @@
""" core implementation of testing process: init, session, runtest loop. """
import re
import py
import pytest, _pytest
@@ -8,7 +9,7 @@ try:
except ImportError:
from UserDict import DictMixin as MappingMixin
from _pytest.runner import collect_one_node, Skipped
from _pytest.runner import collect_one_node
tracebackcutdir = py.path.local(_pytest.__file__).dirpath()
@@ -19,11 +20,11 @@ EXIT_INTERRUPTED = 2
EXIT_INTERNALERROR = 3
EXIT_USAGEERROR = 4
name_re = py.std.re.compile("^[a-zA-Z_]\w*$")
name_re = re.compile("^[a-zA-Z_]\w*$")
def pytest_addoption(parser):
parser.addini("norecursedirs", "directory patterns to avoid for recursion",
type="args", default=('.*', 'CVS', '_darcs', '{arch}'))
type="args", default=('.*', 'CVS', '_darcs', '{arch}', '*.egg'))
#parser.addini("dirpatterns",
# "patterns specifying possible locations of test files",
# type="linelist", default=["**/test_*.txt",
@@ -38,6 +39,8 @@ def pytest_addoption(parser):
help="exit after first num failures or errors.")
group._addoption('--strict', action="store_true",
help="run pytest in strict mode, warnings become errors.")
group._addoption("-c", metavar="file", type=str, dest="inifilename",
help="load configuration from `file` instead of trying to locate one of the implicit configuration files.")
group = parser.getgroup("collect", "collection")
group.addoption('--collectonly', '--collect-only', action="store_true",
@@ -98,6 +101,7 @@ def wrap_session(config, doit):
if session._testsfailed:
session.exitstatus = EXIT_TESTSFAILED
finally:
excinfo = None # Explicitly break reference cycle.
session.startdir.chdir()
if initstate >= 2:
config.hook.pytest_sessionfinish(
@@ -144,18 +148,19 @@ def pytest_ignore_collect(path, config):
p = path.dirpath()
ignore_paths = config._getconftest_pathlist("collect_ignore", path=p)
ignore_paths = ignore_paths or []
excludeopt = config.getvalue("ignore")
excludeopt = config.getoption("ignore")
if excludeopt:
ignore_paths.extend([py.path.local(x) for x in excludeopt])
return path in ignore_paths
class HookProxy:
class HookProxy(object):
def __init__(self, fspath, config):
self.fspath = fspath
self.config = config
def __getattr__(self, name):
hookmethod = getattr(self.config.hook, name)
config = object.__getattribute__(self, "config")
hookmethod = getattr(config.hook, name)
def call_matching_hooks(**kwargs):
plugins = self.config._getmatchingplugins(self.fspath)
@@ -233,6 +238,7 @@ class Node(object):
# used for storing artificial fixturedefs for direct parametrization
self._name2pseudofixturedef = {}
#self.extrainit()
@property
@@ -263,6 +269,20 @@ class Node(object):
return "<%s %r>" %(self.__class__.__name__,
getattr(self, 'name', None))
def warn(self, code, message):
""" generate a warning with the given code and message for this
item. """
assert isinstance(code, str)
fslocation = getattr(self, "location", None)
if fslocation is None:
fslocation = getattr(self, "fspath", None)
else:
fslocation = "%s:%s" % fslocation[:2]
self.ihook.pytest_logwarning(code=code, message=message,
nodeid=self.nodeid,
fslocation=fslocation)
# methods for ordering nodes
@property
def nodeid(self):
@@ -297,7 +317,7 @@ class Node(object):
except py.builtin._sysex:
raise
except:
failure = py.std.sys.exc_info()
failure = sys.exc_info()
setattr(self, exattrname, failure)
raise
setattr(self, attrname, res)
@@ -372,20 +392,24 @@ class Node(object):
fm = self.session._fixturemanager
if excinfo.errisinstance(fm.FixtureLookupError):
return excinfo.value.formatrepr()
tbfilter = True
if self.config.option.fulltrace:
style="long"
else:
self._prunetraceback(excinfo)
# XXX should excinfo.getrepr record all data and toterminal()
# process it?
tbfilter = False # prunetraceback already does it
if style == "auto":
style = "long"
# XXX should excinfo.getrepr record all data and toterminal() process it?
if style is None:
if self.config.option.tbstyle == "short":
style = "short"
else:
style = "long"
return excinfo.getrepr(funcargs=True,
showlocals=self.config.option.showlocals,
style=style)
style=style, tbfilter=tbfilter)
repr_failure = _repr_failure_py
@@ -394,10 +418,6 @@ class Collector(Node):
and thus iteratively build a tree.
"""
# the set of exceptions to interpret as "Skip the whole module" during
# collection
skip_exceptions = (Skipped,)
class CollectError(Exception):
""" an error during collection, contains a custom message. """
@@ -455,6 +475,14 @@ class Item(Node):
"""
nextitem = None
def __init__(self, name, parent=None, config=None, session=None):
super(Item, self).__init__(name, parent, config, session)
self._report_sections = []
def add_report_section(self, when, key, content):
if content:
self._report_sections.append((when, key, content))
def reportinfo(self):
return self.fspath, None, ""

View File

@@ -59,7 +59,11 @@ def derive_importpath(import_path):
notset = object()
class Notset:
def __repr__(self):
return "<notset>"
notset = Notset()
class monkeypatch:
""" object keeping a record of setattr/item/env/syspath changes. """

View File

@@ -1,17 +1,27 @@
""" run test suites written for nose. """
import pytest, py
import sys
import py
import pytest
from _pytest import unittest
def get_skip_exceptions():
skip_classes = set()
for module_name in ('unittest', 'unittest2', 'nose'):
mod = sys.modules.get(module_name)
if hasattr(mod, 'SkipTest'):
skip_classes.add(mod.SkipTest)
return tuple(skip_classes)
def pytest_runtest_makereport(__multicall__, item, call):
SkipTest = getattr(sys.modules.get('nose', None), 'SkipTest', None)
if SkipTest:
if call.excinfo and call.excinfo.errisinstance(SkipTest):
# let's substitute the excinfo with a pytest.skip one
call2 = call.__class__(lambda:
pytest.skip(str(call.excinfo.value)), call.when)
call.excinfo = call2.excinfo
if call.excinfo and call.excinfo.errisinstance(get_skip_exceptions()):
# let's substitute the excinfo with a pytest.skip one
call2 = call.__class__(lambda:
pytest.skip(str(call.excinfo.value)), call.when)
call.excinfo = call2.excinfo
@pytest.mark.trylast
@@ -38,13 +48,8 @@ def teardown_nose(item):
# #call_optional(item._nosegensetup, 'teardown')
# del item.parent._nosegensetup
def pytest_make_collect_report(collector):
SkipTest = getattr(sys.modules.get('unittest', None), 'SkipTest', None)
if SkipTest is not None:
collector.skip_exceptions += (SkipTest,)
SkipTest = getattr(sys.modules.get('nose', None), 'SkipTest', None)
if SkipTest is not None:
collector.skip_exceptions += (SkipTest,)
if isinstance(collector, pytest.Generator):
call_optional(collector.obj, 'setup')

View File

@@ -1,8 +1,12 @@
""" interactive debugging with PDB, the Python Debugger. """
import pytest, py
from __future__ import absolute_import
import pdb
import sys
import pytest
import py
def pytest_addoption(parser):
group = parser.getgroup("general")
group._addoption('--pdb',
@@ -16,50 +20,38 @@ def pytest_configure(config):
if config.getvalue("usepdb"):
config.pluginmanager.register(PdbInvoke(), 'pdbinvoke')
old_trace = py.std.pdb.set_trace
old = (pdb.set_trace, pytestPDB._pluginmanager)
def fin():
py.std.pdb.set_trace = old_trace
py.std.pdb.set_trace = pytest.set_trace
pdb.set_trace, pytestPDB._pluginmanager = old
pdb.set_trace = pytest.set_trace
pytestPDB._pluginmanager = config.pluginmanager
config._cleanup.append(fin)
class pytestPDB:
""" Pseudo PDB that defers to the real pdb. """
item = None
collector = None
_pluginmanager = None
def set_trace(self):
""" invoke PDB set_trace debugging, dropping any IO capturing. """
frame = sys._getframe().f_back
item = self.item or self.collector
if item is not None:
capman = item.config.pluginmanager.getplugin("capturemanager")
out, err = capman.suspendcapture()
if hasattr(item, 'outerr'):
item.outerr = (item.outerr[0] + out, item.outerr[1] + err)
capman = None
if self._pluginmanager is not None:
capman = self._pluginmanager.getplugin("capturemanager")
if capman:
capman.suspendcapture(in_=True)
tw = py.io.TerminalWriter()
tw.line()
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
py.std.pdb.Pdb().set_trace(frame)
self._pluginmanager.hook.pytest_enter_pdb()
pdb.Pdb().set_trace(frame)
def pdbitem(item):
pytestPDB.item = item
pytest_runtest_setup = pytest_runtest_call = pytest_runtest_teardown = pdbitem
@pytest.mark.tryfirst
def pytest_make_collect_report(__multicall__, collector):
try:
pytestPDB.collector = collector
return __multicall__.execute()
finally:
pytestPDB.collector = None
def pytest_runtest_makereport():
pytestPDB.item = None
class PdbInvoke:
def pytest_exception_interact(self, node, call, report):
return _enter_pdb(node, call.excinfo, report)
capman = node.config.pluginmanager.getplugin("capturemanager")
if capman:
capman.suspendcapture(in_=True)
_enter_pdb(node, call.excinfo, report)
def pytest_internalerror(self, excrepr, excinfo):
for line in str(excrepr).split("\n"):
@@ -87,7 +79,8 @@ def _enter_pdb(node, excinfo, rep):
def _postmortem_traceback(excinfo):
# A doctest.UnexpectedException is not useful for post_mortem.
# Use the underlying exception instead:
if isinstance(excinfo.value, py.std.doctest.UnexpectedException):
from doctest import UnexpectedException
if isinstance(excinfo.value, UnexpectedException):
return excinfo.value.exc_info[2]
else:
return excinfo._excinfo[2]
@@ -101,7 +94,6 @@ def _find_last_non_hidden_frame(stack):
def post_mortem(t):
pdb = py.std.pdb
class Pdb(pdb.Pdb):
def get_stack(self, f, t):
stack, i = pdb.Pdb.get_stack(self, f, t)

View File

@@ -1,15 +1,21 @@
""" (disabled by default) support for testing pytest and pytest plugins. """
import py, pytest
import sys, os
import inspect
import sys
import os
import codecs
import re
import time
import platform
from fnmatch import fnmatch
from _pytest.main import Session, EXIT_OK
import subprocess
import py
import pytest
from py.builtin import print_
from _pytest.core import HookRelay
from _pytest.main import Session, EXIT_OK
def get_public_names(l):
"""Only return names from iterator l without a leading underscore."""
@@ -87,10 +93,10 @@ class HookRecorder:
def _makecallparser(self, method):
name = method.__name__
args, varargs, varkw, default = py.std.inspect.getargspec(method)
args, varargs, varkw, default = inspect.getargspec(method)
if not args or args[0] != "self":
args.insert(0, 'self')
fspec = py.std.inspect.formatargspec(args, varargs, varkw, default)
fspec = inspect.formatargspec(args, varargs, varkw, default)
# we use exec because we want to have early type
# errors on wrong input arguments, using
# *args/**kwargs delays this and gives errors
@@ -122,7 +128,7 @@ class HookRecorder:
__tracebackhide__ = True
i = 0
entries = list(entries)
backlocals = py.std.sys._getframe(1).f_locals
backlocals = sys._getframe(1).f_locals
while entries:
name, check = entries.pop(0)
for ind, call in enumerate(self.calls[i:]):
@@ -210,7 +216,7 @@ class TmpTestdir:
def finalize(self):
for p in self._syspathremove:
py.std.sys.path.remove(p)
sys.path.remove(p)
if hasattr(self, '_olddir'):
self._olddir.chdir()
# delete modules that have been loaded from tmpdir
@@ -246,8 +252,14 @@ class TmpTestdir:
ret = None
for name, value in items:
p = self.tmpdir.join(name).new(ext=ext)
source = py.builtin._totext(py.code.Source(value)).strip()
content = source.encode("utf-8") # + "\n"
source = py.code.Source(value)
def my_totext(s, encoding="utf-8"):
if py.builtin._isbytes(s):
s = py.builtin._totext(s, encoding=encoding)
return s
source_unicode = "\n".join([my_totext(line) for line in source.lines])
source = py.builtin._totext(source_unicode)
content = source.strip().encode("utf-8") # + "\n"
#content = content.rstrip() + "\n"
p.write(content, "wb")
if ret is None:
@@ -277,7 +289,7 @@ class TmpTestdir:
def syspathinsert(self, path=None):
if path is None:
path = self.tmpdir
py.std.sys.path.insert(0, str(path))
sys.path.insert(0, str(path))
self._syspathremove.append(str(path))
def mkdir(self, name):
@@ -420,9 +432,8 @@ class TmpTestdir:
env['PYTHONPATH'] = os.pathsep.join(filter(None, [
str(os.getcwd()), env.get('PYTHONPATH', '')]))
kw['env'] = env
#print "env", env
return py.std.subprocess.Popen(cmdargs,
stdout=stdout, stderr=stderr, **kw)
return subprocess.Popen(cmdargs,
stdout=stdout, stderr=stderr, **kw)
def run(self, *cmdargs):
return self._run(*cmdargs)
@@ -468,9 +479,9 @@ class TmpTestdir:
def _getpybinargs(self, scriptname):
if not self.request.config.getvalue("notoolsonpath"):
# XXX we rely on script referring to the correct environment
# we cannot use "(py.std.sys.executable,script)"
# we cannot use "(sys.executable,script)"
# because on windows the script is e.g. a py.test.exe
return (py.std.sys.executable, _pytest_fullpath,) # noqa
return (sys.executable, _pytest_fullpath,) # noqa
else:
pytest.skip("cannot run %r with --no-tools-on-path" % scriptname)
@@ -490,7 +501,7 @@ class TmpTestdir:
def runpython_c(self, command):
command = self._getsysprepend() + command
return self.run(py.std.sys.executable, "-c", command)
return self.run(sys.executable, "-c", command)
def runpytest(self, *args):
p = py.path.local.make_numbered_dir(prefix="runpytest-",
@@ -517,7 +528,7 @@ class TmpTestdir:
def spawn(self, cmd, expect_timeout=10.0):
pexpect = pytest.importorskip("pexpect", "3.0")
if hasattr(sys, 'pypy_version_info') and '64' in py.std.platform.machine():
if hasattr(sys, 'pypy_version_info') and '64' in platform.machine():
pytest.skip("pypy-64 bit not supported")
if sys.platform == "darwin":
pytest.xfail("pexpect does not work reliably on darwin?!")
@@ -664,7 +675,7 @@ class LineMatcher:
def fnmatch_lines(self, lines2):
def show(arg1, arg2):
py.builtin.print_(arg1, arg2, file=py.std.sys.stderr)
py.builtin.print_(arg1, arg2, file=sys.stderr)
lines2 = self._getlines(lines2)
lines1 = self.lines[:]
nextline = None

View File

@@ -11,7 +11,8 @@ cutdir = py.path.local(_pytest.__file__).dirpath()
NoneType = type(None)
NOTSET = object()
isfunction = inspect.isfunction
isclass = inspect.isclass
callable = py.builtin.callable
def getfslineno(obj):
@@ -44,7 +45,7 @@ class FixtureFunctionMarker:
self.ids = ids
def __call__(self, function):
if inspect.isclass(function):
if isclass(function):
raise ValueError(
"class fixtures not supported (may be in the future)")
function._pytestfixturefunction = self
@@ -213,18 +214,26 @@ def pytest_pycollect_makeitem(__multicall__, collector, name, obj):
res = __multicall__.execute()
if res is not None:
return res
if inspect.isclass(obj):
if isclass(obj):
#if hasattr(collector.obj, 'unittest'):
# return # we assume it's a mixin class for a TestCase derived one
if collector.classnamefilter(name):
Class = collector._getcustomclass("Class")
return Class(name, parent=collector)
elif collector.funcnamefilter(name) and hasattr(obj, '__call__') and \
elif collector.funcnamefilter(name) and hasattr(obj, "__call__") and \
getfixturemarker(obj) is None:
if is_generator(obj):
return Generator(name, parent=collector)
else:
return list(collector._genfunctions(name, obj))
# mock seems to store unbound methods (issue473), let's normalize it
obj = getattr(obj, "__func__", obj)
if not isfunction(obj):
collector.warn(code="C2", message=
"cannot collect %r because it is not a function."
% name, )
return
if getattr(obj, "__test__", True):
if is_generator(obj):
return Generator(name, parent=collector)
else:
return list(collector._genfunctions(name, obj))
def is_generator(func):
try:
@@ -306,6 +315,9 @@ class PyCollector(PyobjMixin, pytest.Collector):
return True
def collect(self):
if not getattr(self.obj, "__test__", True):
return []
# NB. we avoid random getattrs and peek in the __dict__ instead
# (XXX originally introduced from a PyPy need, still true?)
dicts = [getattr(self.obj, '__dict__', {})]
@@ -450,8 +462,8 @@ class Module(pytest.File, PyCollector):
try:
mod = self.fspath.pyimport(ensuresyspath=True)
except SyntaxError:
excinfo = py.code.ExceptionInfo()
raise self.CollectError(excinfo.getrepr(style="short"))
raise self.CollectError(
py.code.ExceptionInfo().getrepr(style="short"))
except self.fspath.ImportMismatchError:
e = sys.exc_info()[1]
raise self.CollectError(
@@ -498,10 +510,9 @@ class Class(PyCollector):
""" Collector for test methods. """
def collect(self):
if hasinit(self.obj):
pytest.skip("class %s.%s with __init__ won't get collected" % (
self.obj.__module__,
self.obj.__name__,
))
self.warn("C1", "cannot collect test class %r because it has a "
"__init__ constructor" % self.obj.__name__)
return []
return [self._getcustomclass("Instance")(name="()", parent=self)]
def setup(self):
@@ -567,6 +578,12 @@ class FunctionMixin(PyobjMixin):
if ntraceback == traceback:
ntraceback = ntraceback.cut(excludepath=cutdir)
excinfo.traceback = ntraceback.filter()
# issue364: mark all but first and last frames to
# only show a single-line message for each frame
if self.config.option.tbstyle == "auto":
if len(excinfo.traceback) > 2:
for entry in excinfo.traceback[1:-1]:
entry.set_repr_style('short')
def _repr_failure_py(self, excinfo, style="long"):
if excinfo.errisinstance(pytest.fail.Exception):
@@ -577,8 +594,10 @@ class FunctionMixin(PyobjMixin):
def repr_failure(self, excinfo, outerr=None):
assert outerr is None, "XXX outerr usage is deprecated"
return self._repr_failure_py(excinfo,
style=self.config.option.tbstyle)
style = self.config.option.tbstyle
if style == "auto":
style = "long"
return self._repr_failure_py(excinfo, style=style)
class Generator(FunctionMixin, PyCollector):
@@ -966,15 +985,16 @@ def raises(ExpectedException, *args, **kwargs):
Performance note:
-----------------
Similar to caught exception objects in Python, explicitly clearing local
references to returned ``py.code.ExceptionInfo`` objects can help the Python
interpreter speed up its garbage collection.
Similar to caught exception objects in Python, explicitly clearing
local references to returned ``py.code.ExceptionInfo`` objects can
help the Python interpreter speed up its garbage collection.
Clearing those references breaks a reference cycle (``ExceptionInfo`` -->
caught exception --> frame stack raising the exception --> current frame
stack --> local variables --> ``ExceptionInfo``) which makes Python keep all
objects referenced from that cycle (including all local variables in the
current frame) alive until the next cyclic garbage collection run. See the
Clearing those references breaks a reference cycle
(``ExceptionInfo`` --> caught exception --> frame stack raising
the exception --> current frame stack --> local variables -->
``ExceptionInfo``) which makes Python keep all objects referenced
from that cycle (including all local variables in the current
frame) alive until the next cyclic garbage collection run. See the
official Python ``try`` statement documentation for more detailed
information.
@@ -984,7 +1004,16 @@ def raises(ExpectedException, *args, **kwargs):
# we want to catch a AssertionError
# replace our subclass with the builtin one
# see https://bitbucket.org/hpk42/pytest/issue/176/pytestraises
from _pytest.assertion.util import BuiltinAssertionError as ExpectedException
from _pytest.assertion.util import BuiltinAssertionError \
as ExpectedException
msg = ("exceptions must be old-style classes or"
" derived from BaseException, not %s")
if isinstance(ExpectedException, tuple):
for exc in ExpectedException:
if not inspect.isclass(exc):
raise TypeError(msg % type(exc))
elif not inspect.isclass(ExpectedException):
raise TypeError(msg % type(ExpectedException))
if not args:
return RaisesContext(ExpectedException)
@@ -1316,7 +1345,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
except FixtureLookupError:
if argname == "request":
class PseudoFixtureDef:
cached_result = (self, [0])
cached_result = (self, [0], None)
return PseudoFixtureDef
raise
result = self._getfuncargvalue(fixturedef)
@@ -1582,10 +1611,15 @@ class FixtureManager:
except AttributeError:
pass
else:
# construct the base nodeid which is later used to check
# what fixtures are visible for particular tests (as denoted
# by their test id)
if p.basename.startswith("conftest.py"):
nodeid = p.dirpath().relto(self.session.fspath)
nodeid = self.session.fspath.bestrelpath(p.dirpath())
if p.sep != "/":
nodeid = nodeid.replace(p.sep, "/")
if nodeid == ".":
nodeid = ""
self.parsefactories(plugin, nodeid)
self._seenplugins.add(plugin)
@@ -1773,13 +1807,15 @@ class FixtureDef:
self._finalizer.append(finalizer)
def finish(self):
while self._finalizer:
func = self._finalizer.pop()
func()
try:
del self.cached_result
except AttributeError:
pass
while self._finalizer:
func = self._finalizer.pop()
func()
finally:
# even if finalization fails, we invalidate
# the cached fixture value
if hasattr(self, "cached_result"):
del self.cached_result
def execute(self, request):
# get required arguments and register our own finish()
@@ -1787,7 +1823,7 @@ class FixtureDef:
kwargs = {}
for argname in self.argnames:
fixturedef = request._get_active_fixturedef(argname)
result, arg_cache_key = fixturedef.cached_result
result, arg_cache_key, exc = fixturedef.cached_result
kwargs[argname] = result
if argname != "request":
fixturedef.addfinalizer(self.finish)
@@ -1795,13 +1831,12 @@ class FixtureDef:
my_cache_key = request.param_index
cached_result = getattr(self, "cached_result", None)
if cached_result is not None:
#print argname, "Found cached_result", cached_result
#print argname, "param_index", param_index
result, cache_key = cached_result
result, cache_key, err = cached_result
if my_cache_key == cache_key:
#print request.fixturename, "CACHE HIT", repr(my_cache_key)
return result
#print request.fixturename, "CACHE MISS"
if err is not None:
py.builtin._reraise(*err)
else:
return result
# we have a previous but differently parametrized fixture instance
# so we need to tear it down before creating a new one
self.finish()
@@ -1818,15 +1853,31 @@ class FixtureDef:
fixturefunc = getimfunc(self.func)
if fixturefunc != self.func:
fixturefunc = fixturefunc.__get__(request.instance)
result = call_fixture_func(fixturefunc, request, kwargs,
self.yieldctx)
self.cached_result = (result, my_cache_key)
try:
result = call_fixture_func(fixturefunc, request, kwargs,
self.yieldctx)
except Exception:
self.cached_result = (None, my_cache_key, sys.exc_info())
raise
self.cached_result = (result, my_cache_key, None)
return result
def __repr__(self):
return ("<FixtureDef name=%r scope=%r baseid=%r >" %
(self.argname, self.scope, self.baseid))
def num_mock_patch_args(function):
""" return number of arguments used up by mock arguments (if any) """
patchings = getattr(function, "patchings", None)
if not patchings:
return 0
mock = sys.modules.get("mock", sys.modules.get("unittest.mock", None))
if mock is not None:
return len([p for p in patchings
if not p.attribute_name and p.new is mock.DEFAULT])
return len(patchings)
def getfuncargnames(function, startindex=None):
# XXX merge with main.py's varnames
#assert not inspect.isclass(function)
@@ -1836,7 +1887,7 @@ def getfuncargnames(function, startindex=None):
if startindex is None:
startindex = inspect.ismethod(function) and 1 or 0
if realfunction != function:
startindex += len(getattr(function, "patchings", []))
startindex += num_mock_patch_args(function)
function = realfunction
argnames = inspect.getargs(py.code.getrawcode(function))[0]
defaults = getattr(function, 'func_defaults',

View File

@@ -1,7 +1,8 @@
""" recording warnings during test function execution. """
import py
import sys
import warnings
def pytest_funcarg__recwarn(request):
"""Return a WarningsRecorder instance that provides these methods:
@@ -13,7 +14,6 @@ def pytest_funcarg__recwarn(request):
on warning categories.
"""
if sys.version_info >= (2,7):
import warnings
oldfilters = warnings.filters[:]
warnings.simplefilter('default')
def reset_filters():
@@ -30,26 +30,24 @@ def deprecated_call(func, *args, **kwargs):
""" assert that calling ``func(*args, **kwargs)``
triggers a DeprecationWarning.
"""
warningmodule = py.std.warnings
l = []
oldwarn_explicit = getattr(warningmodule, 'warn_explicit')
oldwarn_explicit = getattr(warnings, 'warn_explicit')
def warn_explicit(*args, **kwargs):
l.append(args)
oldwarn_explicit(*args, **kwargs)
oldwarn = getattr(warningmodule, 'warn')
oldwarn = getattr(warnings, 'warn')
def warn(*args, **kwargs):
l.append(args)
oldwarn(*args, **kwargs)
warningmodule.warn_explicit = warn_explicit
warningmodule.warn = warn
warnings.warn_explicit = warn_explicit
warnings.warn = warn
try:
ret = func(*args, **kwargs)
finally:
warningmodule.warn_explicit = warn_explicit
warningmodule.warn = warn
warnings.warn_explicit = warn_explicit
warnings.warn = warn
if not l:
#print warningmodule
__tracebackhide__ = True
raise AssertionError("%r did not produce DeprecationWarning" %(func,))
return ret
@@ -65,7 +63,6 @@ class RecordedWarning:
class WarningsRecorder:
def __init__(self):
warningmodule = py.std.warnings
self.list = []
def showwarning(message, category, filename, lineno, line=0):
self.list.append(RecordedWarning(
@@ -76,8 +73,8 @@ class WarningsRecorder:
except TypeError:
# < python2.6
self.old_showwarning(message, category, filename, lineno)
self.old_showwarning = warningmodule.showwarning
warningmodule.showwarning = showwarning
self.old_showwarning = warnings.showwarning
warnings.showwarning = showwarning
def pop(self, cls=Warning):
""" pop the first recorded warning, raise exception if not exists."""
@@ -88,7 +85,6 @@ class WarningsRecorder:
assert 0, "%r not found in %r" %(cls, self.list)
#def resetregistry(self):
# import warnings
# warnings.onceregistry.clear()
# warnings.__warningregistry__.clear()
@@ -96,4 +92,4 @@ class WarningsRecorder:
self.list[:] = []
def finalize(self):
py.std.warnings.showwarning = self.old_showwarning
warnings.showwarning = self.old_showwarning

View File

@@ -1,9 +1,10 @@
""" basic collect and runtest protocol implementations """
import bdb
import sys
from time import time
import py
import pytest
import sys
from time import time
from py._code.code import TerminalRepr
def pytest_namespace():
@@ -118,7 +119,7 @@ def check_interactive_exception(call, report):
return call.excinfo and not (
hasattr(report, "wasxfail") or
call.excinfo.errisinstance(skip.Exception) or
call.excinfo.errisinstance(py.std.bdb.BdbQuit))
call.excinfo.errisinstance(bdb.BdbQuit))
def call_runtest_hook(item, when, **kwds):
hookname = "pytest_runtest_" + when
@@ -135,14 +136,13 @@ class CallInfo:
self.when = when
self.start = time()
try:
try:
self.result = func()
except KeyboardInterrupt:
raise
except:
self.excinfo = py.code.ExceptionInfo()
finally:
self.result = func()
except KeyboardInterrupt:
self.stop = time()
raise
except:
self.excinfo = py.code.ExceptionInfo()
self.stop = time()
def __repr__(self):
if self.excinfo:
@@ -178,6 +178,11 @@ class BaseReport(object):
except UnicodeEncodeError:
out.line("<unprintable longrepr>")
def get_sections(self, prefix):
for name, content in self.sections:
if name.startswith(prefix):
yield prefix, content
passed = property(lambda x: x.outcome == "passed")
failed = property(lambda x: x.outcome == "failed")
skipped = property(lambda x: x.outcome == "skipped")
@@ -191,6 +196,7 @@ def pytest_runtest_makereport(item, call):
duration = call.stop-call.start
keywords = dict([(x,1) for x in item.keywords])
excinfo = call.excinfo
sections = []
if not call.excinfo:
outcome = "passed"
longrepr = None
@@ -209,16 +215,18 @@ def pytest_runtest_makereport(item, call):
else: # exception in setup or teardown
longrepr = item._repr_failure_py(excinfo,
style=item.config.option.tbstyle)
for rwhen, key, content in item._report_sections:
sections.append(("Captured std%s %s" %(key, rwhen), content))
return TestReport(item.nodeid, item.location,
keywords, outcome, longrepr, when,
duration=duration)
sections, duration)
class TestReport(BaseReport):
""" Basic test report object (also used for setup and teardown calls if
they fail).
"""
def __init__(self, nodeid, location,
keywords, outcome, longrepr, when, sections=(), duration=0, **extra):
def __init__(self, nodeid, location, keywords, outcome,
longrepr, when, sections=(), duration=0, **extra):
#: normalized collection node id
self.nodeid = nodeid
@@ -267,7 +275,9 @@ def pytest_make_collect_report(collector):
if not call.excinfo:
outcome = "passed"
else:
if call.excinfo.errisinstance(collector.skip_exceptions):
from _pytest import nose
skip_exceptions = (Skipped,) + nose.get_skip_exceptions()
if call.excinfo.errisinstance(skip_exceptions):
outcome = "skipped"
r = collector._repr_failure_py(call.excinfo, "line").reprcrash
longrepr = (str(r.path), r.lineno, r.message)
@@ -284,7 +294,8 @@ def pytest_make_collect_report(collector):
class CollectReport(BaseReport):
def __init__(self, nodeid, outcome, longrepr, result, sections=(), **extra):
def __init__(self, nodeid, outcome, longrepr, result,
sections=(), **extra):
self.nodeid = nodeid
self.outcome = outcome
self.longrepr = longrepr
@@ -318,7 +329,7 @@ class SetupState(object):
is called at the end of teardown_all().
"""
assert colitem and not isinstance(colitem, tuple)
assert callable(finalizer)
assert py.builtin.callable(finalizer)
#assert colitem in self.stack # some unit tests don't setup stack :/
self._finalizers.setdefault(colitem, []).append(finalizer)

View File

@@ -1,7 +1,10 @@
""" support for skip/xfail functions and markers. """
import py, pytest
import os
import sys
import traceback
import py
import pytest
def pytest_addoption(parser):
group = parser.getgroup("general")
@@ -26,11 +29,13 @@ def pytest_configure(config):
"http://pytest.org/latest/skipping.html"
)
config.addinivalue_line("markers",
"xfail(condition, reason=None, run=True): mark the the test function "
"xfail(condition, reason=None, run=True, raises=None): mark the the test function "
"as an expected failure if eval(condition) has a True value. "
"Optionally specify a reason for better reporting and run=False if "
"you don't even want to execute the test function. See "
"http://pytest.org/latest/skipping.html"
"you don't even want to execute the test function. If only specific "
"exception(s) are expected, you can list them in raises, and if the test fails "
"in other ways, it will be reported as a true failure. "
"See http://pytest.org/latest/skipping.html"
)
def pytest_namespace():
@@ -53,6 +58,7 @@ class MarkEvaluator:
@property
def holder(self):
return self.item.keywords.get(self.name, None)
def __bool__(self):
return bool(self.holder)
__nonzero__ = __bool__
@@ -60,6 +66,12 @@ class MarkEvaluator:
def wasvalid(self):
return not hasattr(self, 'exc')
def invalidraise(self, exc):
raises = self.get('raises')
if not raises:
return
return not isinstance(exc, raises)
def istrue(self):
try:
return self._istrue()
@@ -71,7 +83,7 @@ class MarkEvaluator:
msg = [" " * (self.exc[1].offset + 4) + "^",]
msg.append("SyntaxError: invalid syntax")
else:
msg = py.std.traceback.format_exception_only(*self.exc[:2])
msg = traceback.format_exception_only(*self.exc[:2])
pytest.fail("Error evaluating %r expression\n"
" %s\n"
"%s"
@@ -79,7 +91,7 @@ class MarkEvaluator:
pytrace=False)
def _getglobals(self):
d = {'os': py.std.os, 'sys': py.std.sys, 'config': self.item.config}
d = {'os': os, 'sys': sys, 'config': self.item.config}
func = self.item.obj
try:
d.update(func.__globals__)
@@ -125,8 +137,6 @@ class MarkEvaluator:
@pytest.mark.tryfirst
def pytest_runtest_setup(item):
if not isinstance(item, pytest.Function):
return
evalskip = MarkEvaluator(item, 'skipif')
if evalskip.istrue():
pytest.skip(evalskip.getexplanation())
@@ -144,8 +154,6 @@ def check_xfail_no_run(item):
pytest.xfail("[NOTRUN] " + evalxfail.getexplanation())
def pytest_runtest_makereport(__multicall__, item, call):
if not isinstance(item, pytest.Function):
return
# unitttest special case, see setting of _unexpectedsuccess
if hasattr(item, '_unexpectedsuccess'):
rep = __multicall__.execute()
@@ -171,7 +179,11 @@ def pytest_runtest_makereport(__multicall__, item, call):
if not item.config.option.runxfail:
if evalxfail.wasvalid() and evalxfail.istrue():
if call.excinfo:
rep.outcome = "skipped"
if evalxfail.invalidraise(call.excinfo.value):
rep.outcome = "failed"
return rep
else:
rep.outcome = "skipped"
elif call.when == "call":
rep.outcome = "failed"
else:
@@ -186,7 +198,7 @@ def pytest_report_teststatus(report):
if report.skipped:
return "xfailed", "x", "xfail"
elif report.failed:
return "xpassed", "X", "XPASS"
return "xpassed", "X", ("XPASS", {'yellow': True})
# called by the terminalreporter instance/plugin
def pytest_terminal_summary(terminalreporter):

View File

@@ -5,6 +5,8 @@ This is a good source for looking at the various reporting hooks.
import pytest
import py
import sys
import time
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting", "reporting", after="general")
@@ -15,7 +17,7 @@ def pytest_addoption(parser):
group._addoption('-r',
action="store", dest="reportchars", default=None, metavar="chars",
help="show extra test summary info as specified by chars (f)ailed, "
"(E)error, (s)skipped, (x)failed, (X)passed.")
"(E)error, (s)skipped, (x)failed, (X)passed (w)warnings.")
group._addoption('-l', '--showlocals',
action="store_true", dest="showlocals", default=False,
help="show locals in tracebacks (disabled by default).")
@@ -23,8 +25,8 @@ def pytest_addoption(parser):
action="store", dest="report", default=None, metavar="opts",
help="(deprecated, use -r)")
group._addoption('--tb', metavar="style",
action="store", dest="tbstyle", default='long',
choices=['long', 'short', 'no', 'line', 'native'],
action="store", dest="tbstyle", default='auto',
choices=['auto', 'long', 'short', 'no', 'line', 'native'],
help="traceback print mode (long/short/line/native/no).")
group._addoption('--fulltrace', '--full-trace',
action="store_true", default=False,
@@ -49,7 +51,7 @@ def getreportopt(config):
optvalue = config.option.report
if optvalue:
py.builtin.print_("DEPRECATED: use -r instead of --report option.",
file=py.std.sys.stderr)
file=sys.stderr)
if optvalue:
for setting in optvalue.split(","):
setting = setting.strip()
@@ -75,6 +77,14 @@ def pytest_report_teststatus(report):
letter = "f"
return report.outcome, letter, report.outcome.upper()
class WarningReport:
def __init__(self, code, message, nodeid=None, fslocation=None):
self.code = code
self.message = message
self.nodeid = nodeid
self.fslocation = fslocation
class TerminalReporter:
def __init__(self, config, file=None):
self.config = config
@@ -87,7 +97,7 @@ class TerminalReporter:
self.stats = {}
self.startdir = self.curdir = py.path.local()
if file is None:
file = py.std.sys.stdout
file = sys.stdout
self._tw = self.writer = py.io.TerminalWriter(file)
if self.config.option.color == 'yes':
self._tw.hasmarkup = True
@@ -128,7 +138,8 @@ class TerminalReporter:
self._tw.write(content, **markup)
def write_line(self, line, **markup):
line = str(line)
if not py.builtin._istext(line):
line = py.builtin.text(line, errors="replace")
self.ensure_newline()
self._tw.line(line, **markup)
@@ -147,10 +158,16 @@ class TerminalReporter:
self._tw.line(msg, **kw)
def pytest_internalerror(self, excrepr):
for line in str(excrepr).split("\n"):
for line in py.builtin.text(excrepr).split("\n"):
self.write_line("INTERNALERROR> " + line)
return 1
def pytest_logwarning(self, code, fslocation, message, nodeid):
warnings = self.stats.setdefault("warnings", [])
warning = WarningReport(code=code, fslocation=fslocation,
message=message, nodeid=nodeid)
warnings.append(warning)
def pytest_plugin_registered(self, plugin):
if self.config.option.traceconfig:
msg = "PLUGIN registered: %s" % (plugin,)
@@ -250,7 +267,7 @@ class TerminalReporter:
@pytest.mark.trylast
def pytest_sessionstart(self, session):
self._sessionstarttime = py.std.time.time()
self._sessionstarttime = time.time()
if not self.showheader:
return
self.write_sep("=", "test session starts", bold=True)
@@ -334,7 +351,7 @@ class TerminalReporter:
if exitstatus in (0, 1, 2, 4):
self.summary_errors()
self.summary_failures()
self.summary_hints()
self.summary_warnings()
self.config.hook.pytest_terminal_summary(terminalreporter=self)
if exitstatus == 2:
self._report_keyboardinterrupt()
@@ -365,11 +382,10 @@ class TerminalReporter:
fspath = "%s <- %s" % (collect_fspath, fspath)
if fspath:
line = str(fspath)
if lineno is not None:
lineno += 1
line += ":" + str(lineno)
if domain:
line += ": " + str(domain)
split = str(domain).split('[')
split[0] = split[0].replace('.', '::') # don't replace '.' in params
line += "::" + '['.join(split)
else:
line = "[location]"
return line + " "
@@ -400,10 +416,15 @@ class TerminalReporter:
l.append(x)
return l
def summary_hints(self):
if self.config.option.traceconfig:
for hint in self.config.pluginmanager._hints:
self._tw.line("hint: %s" % hint)
def summary_warnings(self):
if self.hasopt("w"):
warnings = self.stats.get("warnings")
if not warnings:
return
self.write_sep("=", "warning summary")
for w in warnings:
self._tw.line("W%s %s %s" % (w.code,
w.fslocation, w.message))
def summary_failures(self):
if self.config.option.tbstyle != "no":
@@ -447,9 +468,10 @@ class TerminalReporter:
self._tw.line(content)
def summary_stats(self):
session_duration = py.std.time.time() - self._sessionstarttime
session_duration = time.time() - self._sessionstarttime
keys = "failed passed skipped deselected xfailed xpassed".split()
keys = ("failed passed skipped deselected "
"xfailed xpassed warnings").split()
for key in self.stats.keys():
if key not in keys:
keys.append(key)

View File

@@ -1,7 +1,11 @@
""" support for providing temporary directories to test functions. """
import pytest, py
import re
import pytest
import py
from _pytest.monkeypatch import monkeypatch
class TempdirHandler:
def __init__(self, config):
self.config = config
@@ -63,7 +67,7 @@ def tmpdir(request):
path object.
"""
name = request.node.name
name = py.std.re.sub("[\W]", "_", name)
name = re.sub("[\W]", "_", name)
MAXVAL = 30
if len(name) > MAXVAL:
name = name[:MAXVAL]

View File

@@ -1,27 +1,25 @@
""" discovery and running of std-library "unittest" style tests. """
import pytest, py
from __future__ import absolute_import
import traceback
import sys
import pytest
import py
# for transfering markers
from _pytest.python import transfer_markers
def is_unittest(obj):
"""Is obj a subclass of unittest.TestCase?"""
unittest = sys.modules.get('unittest')
if unittest is None:
return # nobody can have derived unittest.TestCase
try:
return issubclass(obj, unittest.TestCase)
except KeyboardInterrupt:
raise
except:
return False
def pytest_pycollect_makeitem(collector, name, obj):
if is_unittest(obj):
return UnitTestCase(name, parent=collector)
# has unittest been imported and is obj a subclass of its TestCase?
try:
if not issubclass(obj, sys.modules["unittest"].TestCase):
return
except Exception:
return
# yes, so let's collect it
return UnitTestCase(name, parent=collector)
class UnitTestCase(pytest.Class):
@@ -41,10 +39,13 @@ class UnitTestCase(pytest.Class):
super(UnitTestCase, self).setup()
def collect(self):
self.session._fixturemanager.parsefactories(self, unittest=True)
loader = py.std.unittest.TestLoader()
module = self.getparent(pytest.Module).obj
from unittest import TestLoader
cls = self.obj
if not getattr(cls, "__test__", True):
return
self.session._fixturemanager.parsefactories(self, unittest=True)
loader = TestLoader()
module = self.getparent(pytest.Module).obj
foundsomething = False
for name in loader.getTestCaseNames(self.obj):
x = getattr(self.obj, name)
@@ -88,7 +89,7 @@ class TestCaseFunction(pytest.Function):
except TypeError:
try:
try:
l = py.std.traceback.format_exception(*rawexcinfo)
l = traceback.format_exception(*rawexcinfo)
l.insert(0, "NOTE: Incompatible Exception Representation, "
"displaying natively:\n\n")
pytest.fail("".join(l), pytrace=False)
@@ -154,7 +155,7 @@ def pytest_runtest_protocol(item, __multicall__):
if isinstance(item, TestCaseFunction):
if 'twisted.trial.unittest' in sys.modules:
ut = sys.modules['twisted.python.failure']
Failure__init__ = ut.Failure.__init__.im_func
Failure__init__ = ut.Failure.__init__
check_testcase_implements_trial_reporter()
def excstore(self, exc_value=None, exc_type=None, exc_tb=None,
captureVars=None):

View File

@@ -4,8 +4,8 @@ if __name__ == '__main__':
import cProfile
import pytest
import pstats
script = sys.argv[1] if len(sys.argv) > 1 else "empty.py"
stats = cProfile.run('pytest.cmdline.main([%r])' % script, 'prof')
script = sys.argv[1:] if len(sys.argv) > 1 else "empty.py"
stats = cProfile.run('pytest.cmdline.main(%r)' % script, 'prof')
p = pstats.Stats("prof")
p.strip_dirs()
p.sort_stats('cumulative')

View File

@@ -4,7 +4,7 @@
<li><a href="{{ pathto('contributing') }}">Contribution Guide</a></li>
<li><a href="https://pypi.python.org/pypi/pytest">pytest @ PyPI</a></li>
<li><a href="https://bitbucket.org/hpk42/pytest/">pytest @ Bitbucket</a></li>
<li><a href="http://pytest.org/latest/plugins_index/index.html">3rd party plugins (beta)</a></li>
<li><a href="http://pytest.org/latest/plugins_index/index.html">3rd party plugins</a></li>
<li><a href="https://bitbucket.org/hpk42/pytest/issues?status=new&status=open">Issue Tracker</a></li>
<li><a href="http://pytest.org/latest/pytest.pdf">PDF Documentation</a>
</ul>

View File

@@ -8,8 +8,9 @@
{% set page_width = '1020px' %}
{% set sidebar_width = '220px' %}
{% set link_color = '#490' %}
{% set link_hover_color = '#9c0' %}
/* orange of logo is #d67c29 but we use black for links for now */
{% set link_color = '#000' %}
{% set link_hover_color = '#000' %}
{% set base_font = 'sans-serif' %}
{% set header_font = 'sans-serif' %}

View File

@@ -5,6 +5,9 @@ Release announcements
.. toctree::
:maxdepth: 2
release-2.6.2
release-2.6.1
release-2.6.0
release-2.5.2
release-2.5.1
release-2.5.0

View File

@@ -0,0 +1,153 @@
pytest-2.6.0: shorter tracebacks, new warning system, test runner compat
===========================================================================
pytest is a mature Python testing tool with more than a 1000 tests
against itself, passing on many different interpreters and platforms.
The 2.6.0 release should be drop-in backward compatible to 2.5.2 and
fixes a number of bugs and brings some new features, mainly:
- shorter tracebacks by default: only the first (test function) entry
and the last (failure location) entry are shown, the ones between
only in "short" format. Use ``--tb=long`` to get back the old
behaviour of showing "long" entries everywhere.
- a new warning system which reports oddities during collection
and execution. For example, ignoring collecting Test* classes with an
``__init__`` now produces a warning.
- various improvements to nose/mock/unittest integration
Note also that 2.6.0 departs with the "zero reported bugs" policy
because it has been too hard to keep up with it, unfortunately.
Instead we are for now rather bound to work on "upvoted" issues in
the https://bitbucket.org/hpk42/pytest/issues?status=new&status=open&sort=-votes
issue tracker.
See docs at:
http://pytest.org
As usual, you can upgrade from pypi via::
pip install -U pytest
Thanks to all who contributed, among them:
Benjamin Peterson
Jurko Gospodnetić
Floris Bruynooghe
Marc Abramowitz
Marc Schlaich
Trevor Bekolay
Bruno Oliveira
Alex Groenholm
have fun,
holger krekel
2.6.0
-----------------------------------
- fix issue537: Avoid importing old assertion reinterpretation code by default.
Thanks Benjamin Peterson.
- fix issue364: shorten and enhance tracebacks representation by default.
The new "--tb=auto" option (default) will only display long tracebacks
for the first and last entry. You can get the old behaviour of printing
all entries as long entries with "--tb=long". Also short entries by
default are now printed very similarly to "--tb=native" ones.
- fix issue514: teach assertion reinterpretation about private class attributes
Thanks Benjamin Peterson.
- change -v output to include full node IDs of tests. Users can copy
a node ID from a test run, including line number, and use it as a
positional argument in order to run only a single test.
- fix issue 475: fail early and comprehensible if calling
pytest.raises with wrong exception type.
- fix issue516: tell in getting-started about current dependencies.
- cleanup setup.py a bit and specify supported versions. Thanks Jurko
Gospodnetic for the PR.
- change XPASS colour to yellow rather then red when tests are run
with -v.
- fix issue473: work around mock putting an unbound method into a class
dict when double-patching.
- fix issue498: if a fixture finalizer fails, make sure that
the fixture is still invalidated.
- fix issue453: the result of the pytest_assertrepr_compare hook now gets
it's newlines escaped so that format_exception does not blow up.
- internal new warning system: pytest will now produce warnings when
it detects oddities in your test collection or execution.
Warnings are ultimately sent to a new pytest_logwarning hook which is
currently only implemented by the terminal plugin which displays
warnings in the summary line and shows more details when -rw (report on
warnings) is specified.
- change skips into warnings for test classes with an __init__ and
callables in test modules which look like a test but are not functions.
- fix issue436: improved finding of initial conftest files from command
line arguments by using the result of parse_known_args rather than
the previous flaky heuristics. Thanks Marc Abramowitz for tests
and initial fixing approaches in this area.
- fix issue #479: properly handle nose/unittest(2) SkipTest exceptions
during collection/loading of test modules. Thanks to Marc Schlaich
for the complete PR.
- fix issue490: include pytest_load_initial_conftests in documentation
and improve docstring.
- fix issue472: clarify that ``pytest.config.getvalue()`` cannot work
if it's triggered ahead of command line parsing.
- merge PR123: improved integration with mock.patch decorator on tests.
- fix issue412: messing with stdout/stderr FD-level streams is now
captured without crashes.
- fix issue483: trial/py33 works now properly. Thanks Daniel Grana for PR.
- improve example for pytest integration with "python setup.py test"
which now has a generic "-a" or "--pytest-args" option where you
can pass additional options as a quoted string. Thanks Trevor Bekolay.
- simplified internal capturing mechanism and made it more robust
against tests or setups changing FD1/FD2, also better integrated
now with pytest.pdb() in single tests.
- improvements to pytest's own test-suite leakage detection, courtesy of PRs
from Marc Abramowitz
- fix issue492: avoid leak in test_writeorg. Thanks Marc Abramowitz.
- fix issue493: don't run tests in doc directory with ``python setup.py test``
(use tox -e doctesting for that)
- fix issue486: better reporting and handling of early conftest loading failures
- some cleanup and simplification of internal conftest handling.
- work a bit harder to break reference cycles when catching exceptions.
Thanks Jurko Gospodnetic.
- fix issue443: fix skip examples to use proper comparison. Thanks Alex
Groenholm.
- support nose-style ``__test__`` attribute on modules, classes and
functions, including unittest-style Classes. If set to False, the
test will not be collected.
- fix issue512: show "<notset>" for arguments which might not be set
in monkeypatch plugin. Improves output in documentation.
- avoid importing "py.test" (an old alias module for "pytest")

View File

@@ -0,0 +1,59 @@
pytest-2.6.1: fixes and new xfail feature
===========================================================================
pytest is a mature Python testing tool with more than a 1100 tests
against itself, passing on many different interpreters and platforms.
The 2.6.1 release is drop-in compatible to 2.5.2 and actually fixes some
regressions introduced with 2.6.0. It also brings a little feature
to the xfail marker which now recognizes expected exceptions,
see the CHANGELOG below.
See docs at:
http://pytest.org
As usual, you can upgrade from pypi via::
pip install -U pytest
Thanks to all who contributed, among them:
Floris Bruynooghe
Bruno Oliveira
Nicolas Delaby
have fun,
holger krekel
Changes 2.6.1
=================
- No longer show line numbers in the --verbose output, the output is now
purely the nodeid. The line number is still shown in failure reports.
Thanks Floris Bruynooghe.
- fix issue437 where assertion rewriting could cause pytest-xdist slaves
to collect different tests. Thanks Bruno Oliveira.
- fix issue555: add "errors" attribute to capture-streams to satisfy
some distutils and possibly other code accessing sys.stdout.errors.
- fix issue547 capsys/capfd also work when output capturing ("-s") is disabled.
- address issue170: allow pytest.mark.xfail(...) to specify expected exceptions via
an optional "raises=EXC" argument where EXC can be a single exception
or a tuple of exception classes. Thanks David Mohr for the complete
PR.
- fix integration of pytest with unittest.mock.patch decorator when
it uses the "new" argument. Thanks Nicolas Delaby for test and PR.
- fix issue with detecting conftest files if the arguments contain
"::" node id specifications (copy pasted from "-v" output)
- fix issue544 by only removing "@NUM" at the end of "::" separated parts
and if the part has an ".py" extension
- don't use py.std import helper, rather import things directly.
Thanks Bruno Oliveira.

View File

@@ -0,0 +1,52 @@
pytest-2.6.2: few fixes and cx_freeze support
===========================================================================
pytest is a mature Python testing tool with more than a 1100 tests
against itself, passing on many different interpreters and platforms.
This release is drop-in compatible to 2.5.2 and 2.6.X. It also
brings support for including pytest with cx_freeze or similar
freezing tools into your single-file app distribution. For details
see the CHANGELOG below.
See docs at:
http://pytest.org
As usual, you can upgrade from pypi via::
pip install -U pytest
Thanks to all who contributed, among them:
Floris Bruynooghe
Benjamin Peterson
Bruno Oliveira
have fun,
holger krekel
2.6.2
-----------
- Added function pytest.freeze_includes(), which makes it easy to embed
pytest into executables using tools like cx_freeze.
See docs for examples and rationale. Thanks Bruno Oliveira.
- Improve assertion rewriting cache invalidation precision.
- fixed issue561: adapt autouse fixture example for python3.
- fixed issue453: assertion rewriting issue with __repr__ containing
"\n{", "\n}" and "\n~".
- fix issue560: correctly display code if an "else:" or "finally:" is
followed by statements on the same line.
- Fix example in monkeypatch documentation, thanks t-8ch.
- fix issue572: correct tmpdir doc example for python3.
- Do not mark as universal wheel because Python 2.6 is different from
other builds due to the extra argparse dependency. Fixes issue566.
Thanks sontek.

View File

@@ -0,0 +1,52 @@
pytest-2.6.3: fixes and little improvements
===========================================================================
pytest is a mature Python testing tool with more than a 1100 tests
against itself, passing on many different interpreters and platforms.
This release is drop-in compatible to 2.5.2 and 2.6.X.
See below for the changes and see docs at:
http://pytest.org
As usual, you can upgrade from pypi via::
pip install -U pytest
Thanks to all who contributed, among them:
Floris Bruynooghe
Oleg Sinyavskiy
Uwe Schmitt
Charles Cloud
Wolfgang Schnerring
have fun,
holger krekel
Changes 2.6.3
======================
- fix issue575: xunit-xml was reporting collection errors as failures
instead of errors, thanks Oleg Sinyavskiy.
- fix issue582: fix setuptools example, thanks Laszlo Papp and Ronny
Pfannschmidt.
- Fix infinite recursion bug when pickling capture.EncodedFile, thanks
Uwe Schmitt.
- fix issue589: fix bad interaction with numpy and others when showing
exceptions. Check for precise "maximum recursion depth exceed" exception
instead of presuming any RuntimeError is that one (implemented in py
dep). Thanks Charles Cloud for analysing the issue.
- fix conftest related fixture visibility issue: when running with a
CWD outside a test package pytest would get fixture discovery wrong.
Thanks to Wolfgang Schnerring for figuring out a reproducable example.
- Introduce pytest_enter_pdb hook (needed e.g. by pytest_timeout to cancel the
timeout when interactively entering pdb). Thanks Wolfgang Schnerring.
- check xfail/skip also with non-python function test items. Thanks
Floris Bruynooghe.

View File

@@ -26,7 +26,7 @@ you will see the return value of the function call::
$ py.test test_assert1.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 1 items
test_assert1.py F
@@ -66,20 +66,23 @@ 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
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
and if you need to have access to the actual exception info you may use::
with pytest.raises(RuntimeError) as excinfo:
def f():
def test_recursion_depth():
with pytest.raises(RuntimeError) as excinfo:
def f():
f()
f()
f()
# do checks related to excinfo.type, excinfo.value, excinfo.traceback
assert 'maximum recursion' in str(excinfo.value)
``excinfo`` is a `py.code.ExceptionInfo`_ instance, which is a wrapper around
the actual exception raised.
the actual exception raised. The main attributes of interest are
``.type``, ``.value`` and ``.traceback``.
.. _py.code.ExceptionInfo:
http://pylib.readthedocs.org/en/latest/code.html#py-code-exceptioninfo
@@ -95,6 +98,22 @@ asserts that the given ``ExpectedException`` is raised. The reporter will
provide you with helpful output in case of failures such as *no
exception* or *wrong exception*.
Note that it is also possible to specify a "raises" argument to
``pytest.mark.xfail``, which checks that the test is failing in a more
specific way than just having any exception raised::
@pytest.mark.xfail(raises=IndexError)
def test_f():
f()
Using ``pytest.raises`` is likely to be better for cases where you are testing
exceptions your own code is deliberately raising, whereas using
``@pytest.mark.xfail`` with a check function is probably better for something
like documenting unfixed bugs (where the test describes what "should" happen)
or bugs in dependencies.
.. _newreport:
Making use of context-sensitive comparisons
@@ -116,7 +135,7 @@ if you run this module::
$ py.test test_assert2.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 1 items
test_assert2.py F

View File

@@ -1,188 +0,0 @@
**Test classes, modules or whole projects can make use of
one or more fixtures**. All required fixture functions will execute
before a test from the specifying context executes. As You can use this
to make tests operate from a pre-initialized directory or with
certain environment variables or with pre-configured global application
settings.
For example, the Django_ project requires database
initialization to be able to import from and use its model objects.
For that, the `pytest-django`_ plugin provides fixtures which your
project can then easily depend or extend on, simply by referencing the
name of the particular fixture.
Fixture functions have limited visilibity which depends on where they
are defined. If they are defined on a test class, only its test methods
may use it. A fixture defined in a module can only be used
from that test module. A fixture defined in a conftest.py file
can only be used by the tests below the directory of that file.
Lastly, plugins can define fixtures which are available across all
projects.
Python, Java and many other languages support a so called xUnit_ style
for providing a fixed state, `test fixtures`_, for running tests. It
typically involves calling a autouse function ahead and a teardown
function after test execute. In 2005 pytest introduced a scope-specific
model of automatically detecting and calling autouse and teardown
functions on a per-module, class or function basis. The Python unittest
package and nose have subsequently incorporated them. This model
remains supported by pytest as :ref:`classic xunit`.
One property of xunit fixture functions is that they work implicitely
by preparing global state or setting attributes on TestCase objects.
By contrast, pytest provides :ref:`funcargs` which allow to
dependency-inject application test state into test functions or
methods as function arguments. If your application is sufficiently modular
or if you are creating a new project, we recommend you now rather head over to
:ref:`funcargs` instead because many pytest users agree that using this
paradigm leads to better application and test organisation.
However, not all programs and frameworks work and can be tested in
a fully modular way. They rather require preparation of global state
like database autouse on which further fixtures like preparing application
specific tables or wrapping tests in transactions can take place. For those
needs, pytest-2.3 now supports new **fixture functions** which come with
a ton of improvements over classic xunit fixture writing. Fixture functions:
- allow to separate different autouse concerns into multiple modular functions
- can receive and fully interoperate with :ref:`funcargs <resources>`,
- are called multiple times if its funcargs are parametrized,
- don't need to be defined directly in your test classes or modules,
they can also be defined in a plugin or :ref:`conftest.py <conftest.py>` files and get called
- are called on a per-session, per-module, per-class or per-function basis
by means of a simple "scope" declaration.
- can access the :ref:`request <request>` object which allows to
introspect and interact with the (scoped) testcontext.
- can add cleanup functions which will be invoked when the last test
of the fixture test context has finished executing.
All of these features are now demonstrated by little examples.
test modules accessing a global resource
-------------------------------------------------------
.. note::
Relying on `global state is considered bad programming practise <http://en.wikipedia.org/wiki/Global_variable>`_ but when you work with an application
that relies on it you often have no choice.
If you want test modules to access a global resource,
you can stick the resource to the module globals in
a per-module autouse function. We use a :ref:`resource factory
<@pytest.fixture>` to create our global resource::
# content of conftest.py
import pytest
class GlobalResource:
def __init__(self):
pass
@pytest.fixture(scope="session")
def globresource():
return GlobalResource()
@pytest.fixture(scope="module")
def setresource(request, globresource):
request.module.globresource = globresource
Now any test module can access ``globresource`` as a module global::
# content of test_glob.py
def test_1():
print ("test_1 %s" % globresource)
def test_2():
print ("test_2 %s" % globresource)
Let's run this module without output-capturing::
$ py.test -qs test_glob.py
FF
================================= FAILURES =================================
__________________________________ test_1 __________________________________
def test_1():
> print ("test_1 %s" % globresource)
E NameError: global name 'globresource' is not defined
test_glob.py:3: NameError
__________________________________ test_2 __________________________________
def test_2():
> print ("test_2 %s" % globresource)
E NameError: global name 'globresource' is not defined
test_glob.py:5: NameError
2 failed in 0.01 seconds
The two tests see the same global ``globresource`` object.
Parametrizing the global resource
+++++++++++++++++++++++++++++++++++++++++++++++++
We extend the previous example and add parametrization to the globresource
factory and also add a finalizer::
# content of conftest.py
import pytest
class GlobalResource:
def __init__(self, param):
self.param = param
@pytest.fixture(scope="session", params=[1,2])
def globresource(request):
g = GlobalResource(request.param)
def fin():
print "finalizing", g
request.addfinalizer(fin)
return g
@pytest.fixture(scope="module")
def setresource(request, globresource):
request.module.globresource = globresource
And then re-run our test module::
$ py.test -qs test_glob.py
FF
================================= FAILURES =================================
__________________________________ test_1 __________________________________
def test_1():
> print ("test_1 %s" % globresource)
E NameError: global name 'globresource' is not defined
test_glob.py:3: NameError
__________________________________ test_2 __________________________________
def test_2():
> print ("test_2 %s" % globresource)
E NameError: global name 'globresource' is not defined
test_glob.py:5: NameError
2 failed in 0.01 seconds
We are now running the two tests twice with two different global resource
instances. Note that the tests are ordered such that only
one instance is active at any given time: the finalizer of
the first globresource instance is called before the second
instance is created and sent to the autouse functions.

View File

@@ -80,7 +80,7 @@ You can ask for available builtin or project-custom
capfd
enables capturing of writes to file descriptors 1 and 2 and makes
captured output available via ``capsys.readouterr()`` method calls
captured output available via ``capfd.readouterr()`` method calls
which return a ``(out, err)`` tuple.
monkeypatch

View File

@@ -64,7 +64,7 @@ of the failing function and hide the other one::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 2 items
test_module.py .F
@@ -77,18 +77,16 @@ of the failing function and hide the other one::
E assert False
test_module.py:9: AssertionError
----------------------------- Captured stdout ------------------------------
setting up <function test_func2 at 0x1ec25f0>
-------------------------- Captured stdout setup ---------------------------
setting up <function test_func2 at 0x2b3173d7fbf8>
==================== 1 failed, 1 passed in 0.01 seconds ====================
Accessing captured output from a test function
---------------------------------------------------
The :ref:`funcarg mechanism` allows test function a very easy
way to access the captured output by simply using the names
``capsys`` or ``capfd`` in the test function signature. Here
is an example test function that performs some output related
checks::
The ``capsys`` and ``capfd`` fixtures allow to access stdout/stderr
output created during test execution. Here is an example test function
that performs some output related checks::
def test_myoutput(capsys): # or use "capfd" for fd-level
print ("hello")
@@ -108,8 +106,10 @@ test from having to care about setting/resetting
output streams and also interacts well with pytest's
own per-test capturing.
If you want to capture on ``fd`` level you can use
If you want to capture on filedescriptor level you can use
the ``capfd`` function argument which offers the exact
same interface.
same interface but allows to also capture output from
libraries or subprocesses that directly write to operating
system level output streams (FD1 and FD2).
.. include:: links.inc

View File

@@ -17,8 +17,8 @@
#
# The full version, including alpha/beta/rc tags.
# The short X.Y version.
version = "2.5.2"
release = "2.5.2"
version = "2.6"
release = "2.6.3"
import sys, os
@@ -54,7 +54,7 @@ master_doc = 'contents'
# General information about the project.
project = u'pytest'
copyright = u'2013, holger krekel'
copyright = u'2014, holger krekel'
@@ -131,12 +131,12 @@ html_short_title = "pytest-%s" % release
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
html_logo = "img/pytest1.png"
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
html_favicon = "img/pytest1favi.ico"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -225,7 +225,7 @@ latex_documents = [
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
latex_logo = 'img/pytest1.png'
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.

View File

@@ -1,4 +1,10 @@
.. note::
`improving your automated testing with pytest <https://ep2014.europython.eu/en/schedule/sessions/92/>`_, July 25th 2014, Berlin, Germany
`professional testing with pytest and tox <http://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_, 24-26th November 2014, Freiburg, Germany
.. _toc:
Full pytest documentation

View File

@@ -97,9 +97,9 @@ Builtin configuration file options
[seq] matches any character in seq
[!seq] matches any char not in seq
Default patterns are ``.* _darcs CVS {args}``. Setting a ``norecursedir``
replaces the default. Here is an example of how to avoid
certain directories::
Default patterns are ``'.*', 'CVS', '_darcs', '{arch}', '*.egg'``.
Setting a ``norecursedirs`` replaces the default. Here is an example of
how to avoid certain directories::
# content of setup.cfg
[pytest]

View File

@@ -44,12 +44,12 @@ then you can just invoke ``py.test`` without command line options::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 1 items
mymodule.py .
========================= 1 passed in 0.01 seconds =========================
========================= 1 passed in 0.05 seconds =========================
It is possible to use fixtures using the ``getfixture`` helper::

View File

@@ -211,3 +211,27 @@ class TestMoreErrors:
finally:
x = 0
class TestCustomAssertMsg:
def test_single_line(self):
class A:
a = 1
b = 2
assert A.a == b, "A.a appears not to be b"
def test_multiline(self):
class A:
a = 1
b = 2
assert A.a == b, "A.a appears not to be b\n" \
"or does not appear to be b\none of those"
def test_custom_repr(self):
class JSON:
a = 1
def __repr__(self):
return "This is JSON\n{\n 'foo': 'bar'\n}"
a = JSON()
b = 2
assert a.a == b, a

View File

@@ -9,6 +9,6 @@ def test_failure_demo_fails_properly(testdir):
failure_demo.copy(testdir.tmpdir.join(failure_demo.basename))
result = testdir.runpytest(target)
result.stdout.fnmatch_lines([
"*39 failed*"
"*42 failed*"
])
assert result.ret != 0

View File

@@ -21,6 +21,9 @@ You can "mark" a test function with custom metadata like this::
pass
def test_another():
pass
class TestClass:
def test_method(self):
pass
.. versionadded:: 2.2
@@ -28,26 +31,82 @@ You can then restrict a test run to only run tests marked with ``webtest``::
$ py.test -v -m webtest
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 3 items
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4
collecting ... collected 4 items
test_server.py:3: test_send_http PASSED
test_server.py::test_send_http PASSED
=================== 2 tests deselected by "-m 'webtest'" ===================
================== 1 passed, 2 deselected in 0.01 seconds ==================
=================== 3 tests deselected by "-m 'webtest'" ===================
================== 1 passed, 3 deselected in 0.01 seconds ==================
Or the inverse, running all tests except the webtest ones::
$ py.test -v -m "not webtest"
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 3 items
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4
collecting ... collected 4 items
test_server.py:6: test_something_quick PASSED
test_server.py:8: test_another PASSED
test_server.py::test_something_quick PASSED
test_server.py::test_another PASSED
test_server.py::TestClass::test_method PASSED
================= 1 tests deselected by "-m 'not webtest'" =================
================== 2 passed, 1 deselected in 0.01 seconds ==================
================== 3 passed, 1 deselected in 0.01 seconds ==================
Selecing tests based on their node ID
-------------------------------------
You can provide one or more :ref:`node IDs <node-id>` as positional
arguments to select only specified tests. This makes it easy to select
tests based on their module, class, method, or function name::
$ py.test -v test_server.py::TestClass::test_method
=========================== test session starts ============================
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4
collecting ... collected 5 items
test_server.py::TestClass::test_method PASSED
========================= 1 passed in 0.01 seconds =========================
You can also select on the class::
$ py.test -v test_server.py::TestClass
=========================== test session starts ============================
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4
collecting ... collected 4 items
test_server.py::TestClass::test_method PASSED
========================= 1 passed in 0.01 seconds =========================
Or select multiple nodes::
$ py.test -v test_server.py::TestClass test_server.py::test_send_http
=========================== test session starts ============================
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4
collecting ... collected 8 items
test_server.py::TestClass::test_method PASSED
test_server.py::test_send_http PASSED
========================= 2 passed in 0.01 seconds =========================
.. _node-id:
.. note::
Node IDs are of the form ``module.py::class::method`` or
``module.py::function``. Node IDs control which tests are
collected, so ``module.py::class`` will select all test methods
on the class. Nodes are also created for each parameter of a
parametrized fixture or test, so selecting a parametrized test
must include the parameter value, e.g.
``module.py::function[param]``.
Node IDs for failing tests are displayed in the test summary info
when running py.test with the ``-rf`` option. You can also
construct Node IDs from the output of ``py.test --collectonly``.
Using ``-k expr`` to select tests based on their name
-------------------------------------------------------
@@ -61,39 +120,40 @@ select tests based on their names::
$ py.test -v -k http # running with the above defined example module
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 3 items
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4
collecting ... collected 4 items
test_server.py:3: test_send_http PASSED
test_server.py::test_send_http PASSED
====================== 2 tests deselected by '-khttp' ======================
================== 1 passed, 2 deselected in 0.01 seconds ==================
====================== 3 tests deselected by '-khttp' ======================
================== 1 passed, 3 deselected in 0.01 seconds ==================
And you can also run all tests except the ones that match the keyword::
$ py.test -k "not send_http" -v
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 3 items
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4
collecting ... collected 4 items
test_server.py:6: test_something_quick PASSED
test_server.py:8: test_another PASSED
test_server.py::test_something_quick PASSED
test_server.py::test_another PASSED
test_server.py::TestClass::test_method PASSED
================= 1 tests deselected by '-knot send_http' ==================
================== 2 passed, 1 deselected in 0.01 seconds ==================
================== 3 passed, 1 deselected in 0.02 seconds ==================
Or to select "http" and "quick" tests::
$ py.test -k "http or quick" -v
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
collecting ... collected 3 items
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4
collecting ... collected 4 items
test_server.py:3: test_send_http PASSED
test_server.py:6: test_something_quick PASSED
test_server.py::test_send_http PASSED
test_server.py::test_something_quick PASSED
================= 1 tests deselected by '-khttp or quick' ==================
================== 2 passed, 1 deselected in 0.01 seconds ==================
================= 2 tests deselected by '-khttp or quick' ==================
================== 2 passed, 2 deselected in 0.01 seconds ==================
.. note::
@@ -127,7 +187,7 @@ You can ask which markers exist for your test suite - the list includes our just
@pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html
@pytest.mark.xfail(condition, reason=None, run=True): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. See http://pytest.org/latest/skipping.html
@pytest.mark.xfail(condition, reason=None, run=True, raises=None): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples.
@@ -266,7 +326,7 @@ the test needs::
$ py.test -E stage2
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 1 items
test_someenv.py s
@@ -277,7 +337,7 @@ and here is one that specifies exactly the environment needed::
$ py.test -E stage1
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 1 items
test_someenv.py .
@@ -291,7 +351,7 @@ The ``--markers`` option always gives you a list of available markers::
@pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html
@pytest.mark.xfail(condition, reason=None, run=True): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. See http://pytest.org/latest/skipping.html
@pytest.mark.xfail(condition, reason=None, run=True, raises=None): mark the the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples.
@@ -395,26 +455,26 @@ then you will see two test skipped and two executed tests as expected::
$ py.test -rs # this option reports skip reasons
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 4 items
test_plat.py s.s.
test_plat.py sss.
========================= short test summary info ==========================
SKIP [2] /tmp/doc-exec-65/conftest.py:12: cannot run on platform linux2
SKIP [3] /tmp/doc-exec-224/conftest.py:12: cannot run on platform linux
=================== 2 passed, 2 skipped in 0.01 seconds ====================
=================== 1 passed, 3 skipped in 0.01 seconds ====================
Note that if you specify a platform via the marker-command line option like this::
$ py.test -m linux2
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 4 items
test_plat.py .
test_plat.py s
=================== 3 tests deselected by "-m 'linux2'" ====================
================== 1 passed, 3 deselected in 0.01 seconds ==================
================= 1 skipped, 3 deselected in 0.01 seconds ==================
then the unmarked-tests will not be run. It is thus a way to restrict the run to the specific tests.
@@ -459,7 +519,7 @@ We can now use the ``-m option`` to select one set::
$ py.test -m interface --tb=short
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 4 items
test_module.py FF
@@ -467,12 +527,12 @@ We can now use the ``-m option`` to select one set::
================================= FAILURES =================================
__________________________ test_interface_simple ___________________________
test_module.py:3: in test_interface_simple
> assert 0
E assert 0
assert 0
E assert 0
__________________________ test_interface_complex __________________________
test_module.py:6: in test_interface_complex
> assert 0
E assert 0
assert 0
E assert 0
================== 2 tests deselected by "-m 'interface'" ==================
================== 2 failed, 2 deselected in 0.01 seconds ==================
@@ -480,7 +540,7 @@ or to select both "event" and "interface" tests::
$ py.test -m "interface or event" --tb=short
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 4 items
test_module.py FFF
@@ -488,15 +548,15 @@ or to select both "event" and "interface" tests::
================================= FAILURES =================================
__________________________ test_interface_simple ___________________________
test_module.py:3: in test_interface_simple
> assert 0
E assert 0
assert 0
E assert 0
__________________________ test_interface_complex __________________________
test_module.py:6: in test_interface_complex
> assert 0
E assert 0
assert 0
E assert 0
____________________________ test_event_simple _____________________________
test_module.py:9: in test_event_simple
> assert 0
E assert 0
assert 0
E assert 0
============= 1 tests deselected by "-m 'interface or event'" ==============
================== 3 failed, 1 deselected in 0.01 seconds ==================

View File

@@ -5,7 +5,7 @@ serialization via the pickle module.
import py
import pytest
pythonlist = ['python2.4', 'python2.5', 'python2.6', 'python2.7', 'python2.8']
pythonlist = ['python2.6', 'python2.7', 'python3.4']
@pytest.fixture(params=pythonlist)
def python1(request, tmpdir):
picklefile = tmpdir.join("data.pickle")

View File

@@ -27,10 +27,10 @@ now execute the test specification::
nonpython $ py.test test_simple.yml
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 2 items
test_simple.yml F.
test_simple.yml .F
================================= FAILURES =================================
______________________________ usecase: hello ______________________________
@@ -56,11 +56,11 @@ consulted when reporting in ``verbose`` mode::
nonpython $ py.test -v
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4
collecting ... collected 2 items
test_simple.yml:1: usecase: hello FAILED
test_simple.yml:1: usecase: ok PASSED
test_simple.yml::usecase: ok PASSED
test_simple.yml::usecase: hello FAILED
================================= FAILURES =================================
______________________________ usecase: hello ______________________________
@@ -74,10 +74,10 @@ interesting to just look at the collection tree::
nonpython $ py.test --collect-only
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 2 items
<YamlFile 'test_simple.yml'>
<YamlItem 'hello'>
<YamlItem 'ok'>
<YamlItem 'hello'>
============================= in 0.02 seconds =============================
============================= in 0.03 seconds =============================

View File

@@ -106,7 +106,7 @@ this is a fully self-contained example which you can run with::
$ py.test test_scenarios.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 4 items
test_scenarios.py ....
@@ -118,7 +118,7 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia
$ py.test --collect-only test_scenarios.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 4 items
<Module 'test_scenarios.py'>
<Class 'TestSampleWithScenarios'>
@@ -182,7 +182,7 @@ Let's first see how it looks like at collection time::
$ py.test test_backends.py --collect-only
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 2 items
<Module 'test_backends.py'>
<Function 'test_db_initialized[d1]'>
@@ -197,7 +197,7 @@ And then when we run the test::
================================= FAILURES =================================
_________________________ test_db_initialized[d2] __________________________
db = <conftest.DB2 instance at 0x1e5f050>
db = <conftest.DB2 object at 0x2b24a8545390>
def test_db_initialized(db):
# a dummy test
@@ -206,7 +206,7 @@ And then when we run the test::
E Failed: deliberately failing for demo purposes
test_backends.py:6: Failed
1 failed, 1 passed in 0.01 seconds
1 failed, 1 passed in 0.02 seconds
The first invocation with ``db == "DB1"`` passed while the second with ``db == "DB2"`` failed. Our ``db`` fixture function has instantiated each of the DB values during the setup phase while the ``pytest_generate_tests`` generated two according calls to the ``test_db_initialized`` during the collection phase.
@@ -253,14 +253,14 @@ argument sets to use for each test function. Let's run it::
================================= FAILURES =================================
________________________ TestClass.test_equals[1-2] ________________________
self = <test_parametrize.TestClass instance at 0x246c4d0>, a = 1, b = 2
self = <test_parametrize.TestClass object at 0x2b0ed5d8cdd8>, a = 1, b = 2
def test_equals(self, a, b):
> assert a == b
E assert 1 == 2
test_parametrize.py:18: AssertionError
1 failed, 2 passed in 0.01 seconds
1 failed, 2 passed in 0.02 seconds
Indirect parametrization with multiple fixtures
--------------------------------------------------------------
@@ -279,10 +279,345 @@ is to be run with different sets of arguments for its three arguments:
Running it results in some skips if we don't have all the python interpreters installed and otherwise runs all combinations (5 interpreters times 5 interpreters times 3 objects to serialize/deserialize)::
. $ py.test -rs -q multipython.py
............sss............sss............sss............ssssssssssssssssss
========================= short test summary info ==========================
SKIP [27] /home/hpk/p/pytest/doc/en/example/multipython.py:22: 'python2.8' not found
48 passed, 27 skipped in 1.30 seconds
..................FFFFFF...
================================= FAILURES =================================
________________ test_basic_objects[python3.4-python2.6-42] ________________
python1 = <multipython.Python object at 0x2b02a1bc79b0>
python2 = <multipython.Python object at 0x2b02a1bc7630>, obj = 42
@pytest.mark.parametrize("obj", [42, {}, {1:3},])
def test_basic_objects(python1, python2, obj):
python1.dumps(obj)
> python2.load_and_is_true("obj == %s" % obj)
multipython.py:51:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
multipython.py:46: in load_and_is_true
py.process.cmdexec("%s %s" %(self.pythonpath, loadfile))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cmd = '/home/hpk/bin/python2.6 /tmp/pytest-21/test_basic_objects_python3_4_p0/load.py'
def cmdexec(cmd):
""" return unicode output of executing 'cmd' in a separate process.
raise cmdexec.Error exeception if the command failed.
the exception will provide an 'err' attribute containing
the error-output from the command.
if the subprocess module does not provide a proper encoding/unicode strings
sys.getdefaultencoding() will be used, if that does not exist, 'UTF-8'.
"""
process = subprocess.Popen(cmd, shell=True,
universal_newlines=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate()
if sys.version_info[0] < 3: # on py3 we get unicode strings, on py2 not
try:
default_encoding = sys.getdefaultencoding() # jython may not have it
except AttributeError:
default_encoding = sys.stdout.encoding or 'UTF-8'
out = unicode(out, process.stdout.encoding or default_encoding)
err = unicode(err, process.stderr.encoding or default_encoding)
status = process.poll()
if status:
> raise ExecutionFailed(status, status, cmd, out, err)
E py.process.cmdexec.Error: ExecutionFailed: 1 /home/hpk/bin/python2.6 /tmp/pytest-21/test_basic_objects_python3_4_p0/load.py
E Traceback (most recent call last):
E File "/tmp/pytest-21/test_basic_objects_python3_4_p0/load.py", line 4, in <module>
E obj = pickle.load(f)
E File "/usr/lib/python2.6/pickle.py", line 1370, in load
E return Unpickler(file).load()
E File "/usr/lib/python2.6/pickle.py", line 858, in load
E dispatch[key](self)
E File "/usr/lib/python2.6/pickle.py", line 886, in load_proto
E raise ValueError, "unsupported pickle protocol: %d" % proto
E ValueError: unsupported pickle protocol: 3
../../../.tox/regen/lib/python3.4/site-packages/py/_process/cmdexec.py:28: Error
--------------------------- Captured stdout call ---------------------------
/tmp/pytest-21/test_basic_objects_python3_4_p0/load.py
_______________ test_basic_objects[python3.4-python2.6-obj1] _______________
python1 = <multipython.Python object at 0x2b02a1b66f28>
python2 = <multipython.Python object at 0x2b02a1b66198>, obj = {}
@pytest.mark.parametrize("obj", [42, {}, {1:3},])
def test_basic_objects(python1, python2, obj):
python1.dumps(obj)
> python2.load_and_is_true("obj == %s" % obj)
multipython.py:51:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
multipython.py:46: in load_and_is_true
py.process.cmdexec("%s %s" %(self.pythonpath, loadfile))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cmd = '/home/hpk/bin/python2.6 /tmp/pytest-21/test_basic_objects_python3_4_p1/load.py'
def cmdexec(cmd):
""" return unicode output of executing 'cmd' in a separate process.
raise cmdexec.Error exeception if the command failed.
the exception will provide an 'err' attribute containing
the error-output from the command.
if the subprocess module does not provide a proper encoding/unicode strings
sys.getdefaultencoding() will be used, if that does not exist, 'UTF-8'.
"""
process = subprocess.Popen(cmd, shell=True,
universal_newlines=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate()
if sys.version_info[0] < 3: # on py3 we get unicode strings, on py2 not
try:
default_encoding = sys.getdefaultencoding() # jython may not have it
except AttributeError:
default_encoding = sys.stdout.encoding or 'UTF-8'
out = unicode(out, process.stdout.encoding or default_encoding)
err = unicode(err, process.stderr.encoding or default_encoding)
status = process.poll()
if status:
> raise ExecutionFailed(status, status, cmd, out, err)
E py.process.cmdexec.Error: ExecutionFailed: 1 /home/hpk/bin/python2.6 /tmp/pytest-21/test_basic_objects_python3_4_p1/load.py
E Traceback (most recent call last):
E File "/tmp/pytest-21/test_basic_objects_python3_4_p1/load.py", line 4, in <module>
E obj = pickle.load(f)
E File "/usr/lib/python2.6/pickle.py", line 1370, in load
E return Unpickler(file).load()
E File "/usr/lib/python2.6/pickle.py", line 858, in load
E dispatch[key](self)
E File "/usr/lib/python2.6/pickle.py", line 886, in load_proto
E raise ValueError, "unsupported pickle protocol: %d" % proto
E ValueError: unsupported pickle protocol: 3
../../../.tox/regen/lib/python3.4/site-packages/py/_process/cmdexec.py:28: Error
--------------------------- Captured stdout call ---------------------------
/tmp/pytest-21/test_basic_objects_python3_4_p1/load.py
_______________ test_basic_objects[python3.4-python2.6-obj2] _______________
python1 = <multipython.Python object at 0x2b02a1bcd320>
python2 = <multipython.Python object at 0x2b02a1bcd358>, obj = {1: 3}
@pytest.mark.parametrize("obj", [42, {}, {1:3},])
def test_basic_objects(python1, python2, obj):
python1.dumps(obj)
> python2.load_and_is_true("obj == %s" % obj)
multipython.py:51:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
multipython.py:46: in load_and_is_true
py.process.cmdexec("%s %s" %(self.pythonpath, loadfile))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cmd = '/home/hpk/bin/python2.6 /tmp/pytest-21/test_basic_objects_python3_4_p2/load.py'
def cmdexec(cmd):
""" return unicode output of executing 'cmd' in a separate process.
raise cmdexec.Error exeception if the command failed.
the exception will provide an 'err' attribute containing
the error-output from the command.
if the subprocess module does not provide a proper encoding/unicode strings
sys.getdefaultencoding() will be used, if that does not exist, 'UTF-8'.
"""
process = subprocess.Popen(cmd, shell=True,
universal_newlines=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate()
if sys.version_info[0] < 3: # on py3 we get unicode strings, on py2 not
try:
default_encoding = sys.getdefaultencoding() # jython may not have it
except AttributeError:
default_encoding = sys.stdout.encoding or 'UTF-8'
out = unicode(out, process.stdout.encoding or default_encoding)
err = unicode(err, process.stderr.encoding or default_encoding)
status = process.poll()
if status:
> raise ExecutionFailed(status, status, cmd, out, err)
E py.process.cmdexec.Error: ExecutionFailed: 1 /home/hpk/bin/python2.6 /tmp/pytest-21/test_basic_objects_python3_4_p2/load.py
E Traceback (most recent call last):
E File "/tmp/pytest-21/test_basic_objects_python3_4_p2/load.py", line 4, in <module>
E obj = pickle.load(f)
E File "/usr/lib/python2.6/pickle.py", line 1370, in load
E return Unpickler(file).load()
E File "/usr/lib/python2.6/pickle.py", line 858, in load
E dispatch[key](self)
E File "/usr/lib/python2.6/pickle.py", line 886, in load_proto
E raise ValueError, "unsupported pickle protocol: %d" % proto
E ValueError: unsupported pickle protocol: 3
../../../.tox/regen/lib/python3.4/site-packages/py/_process/cmdexec.py:28: Error
--------------------------- Captured stdout call ---------------------------
/tmp/pytest-21/test_basic_objects_python3_4_p2/load.py
________________ test_basic_objects[python3.4-python2.7-42] ________________
python1 = <multipython.Python object at 0x2b02a1bc78d0>
python2 = <multipython.Python object at 0x2b02a1bc7128>, obj = 42
@pytest.mark.parametrize("obj", [42, {}, {1:3},])
def test_basic_objects(python1, python2, obj):
python1.dumps(obj)
> python2.load_and_is_true("obj == %s" % obj)
multipython.py:51:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
multipython.py:46: in load_and_is_true
py.process.cmdexec("%s %s" %(self.pythonpath, loadfile))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cmd = '/home/hpk/bin/python2.7 /tmp/pytest-21/test_basic_objects_python3_4_p3/load.py'
def cmdexec(cmd):
""" return unicode output of executing 'cmd' in a separate process.
raise cmdexec.Error exeception if the command failed.
the exception will provide an 'err' attribute containing
the error-output from the command.
if the subprocess module does not provide a proper encoding/unicode strings
sys.getdefaultencoding() will be used, if that does not exist, 'UTF-8'.
"""
process = subprocess.Popen(cmd, shell=True,
universal_newlines=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate()
if sys.version_info[0] < 3: # on py3 we get unicode strings, on py2 not
try:
default_encoding = sys.getdefaultencoding() # jython may not have it
except AttributeError:
default_encoding = sys.stdout.encoding or 'UTF-8'
out = unicode(out, process.stdout.encoding or default_encoding)
err = unicode(err, process.stderr.encoding or default_encoding)
status = process.poll()
if status:
> raise ExecutionFailed(status, status, cmd, out, err)
E py.process.cmdexec.Error: ExecutionFailed: 1 /home/hpk/bin/python2.7 /tmp/pytest-21/test_basic_objects_python3_4_p3/load.py
E Traceback (most recent call last):
E File "/tmp/pytest-21/test_basic_objects_python3_4_p3/load.py", line 4, in <module>
E obj = pickle.load(f)
E File "/usr/lib/python2.7/pickle.py", line 1378, in load
E return Unpickler(file).load()
E File "/usr/lib/python2.7/pickle.py", line 858, in load
E dispatch[key](self)
E File "/usr/lib/python2.7/pickle.py", line 886, in load_proto
E raise ValueError, "unsupported pickle protocol: %d" % proto
E ValueError: unsupported pickle protocol: 3
../../../.tox/regen/lib/python3.4/site-packages/py/_process/cmdexec.py:28: Error
--------------------------- Captured stdout call ---------------------------
/tmp/pytest-21/test_basic_objects_python3_4_p3/load.py
_______________ test_basic_objects[python3.4-python2.7-obj1] _______________
python1 = <multipython.Python object at 0x2b02a1bd2550>
python2 = <multipython.Python object at 0x2b02a1bd23c8>, obj = {}
@pytest.mark.parametrize("obj", [42, {}, {1:3},])
def test_basic_objects(python1, python2, obj):
python1.dumps(obj)
> python2.load_and_is_true("obj == %s" % obj)
multipython.py:51:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
multipython.py:46: in load_and_is_true
py.process.cmdexec("%s %s" %(self.pythonpath, loadfile))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cmd = '/home/hpk/bin/python2.7 /tmp/pytest-21/test_basic_objects_python3_4_p4/load.py'
def cmdexec(cmd):
""" return unicode output of executing 'cmd' in a separate process.
raise cmdexec.Error exeception if the command failed.
the exception will provide an 'err' attribute containing
the error-output from the command.
if the subprocess module does not provide a proper encoding/unicode strings
sys.getdefaultencoding() will be used, if that does not exist, 'UTF-8'.
"""
process = subprocess.Popen(cmd, shell=True,
universal_newlines=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate()
if sys.version_info[0] < 3: # on py3 we get unicode strings, on py2 not
try:
default_encoding = sys.getdefaultencoding() # jython may not have it
except AttributeError:
default_encoding = sys.stdout.encoding or 'UTF-8'
out = unicode(out, process.stdout.encoding or default_encoding)
err = unicode(err, process.stderr.encoding or default_encoding)
status = process.poll()
if status:
> raise ExecutionFailed(status, status, cmd, out, err)
E py.process.cmdexec.Error: ExecutionFailed: 1 /home/hpk/bin/python2.7 /tmp/pytest-21/test_basic_objects_python3_4_p4/load.py
E Traceback (most recent call last):
E File "/tmp/pytest-21/test_basic_objects_python3_4_p4/load.py", line 4, in <module>
E obj = pickle.load(f)
E File "/usr/lib/python2.7/pickle.py", line 1378, in load
E return Unpickler(file).load()
E File "/usr/lib/python2.7/pickle.py", line 858, in load
E dispatch[key](self)
E File "/usr/lib/python2.7/pickle.py", line 886, in load_proto
E raise ValueError, "unsupported pickle protocol: %d" % proto
E ValueError: unsupported pickle protocol: 3
../../../.tox/regen/lib/python3.4/site-packages/py/_process/cmdexec.py:28: Error
--------------------------- Captured stdout call ---------------------------
/tmp/pytest-21/test_basic_objects_python3_4_p4/load.py
_______________ test_basic_objects[python3.4-python2.7-obj2] _______________
python1 = <multipython.Python object at 0x2b02a1bcdeb8>
python2 = <multipython.Python object at 0x2b02a1bcdf98>, obj = {1: 3}
@pytest.mark.parametrize("obj", [42, {}, {1:3},])
def test_basic_objects(python1, python2, obj):
python1.dumps(obj)
> python2.load_and_is_true("obj == %s" % obj)
multipython.py:51:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
multipython.py:46: in load_and_is_true
py.process.cmdexec("%s %s" %(self.pythonpath, loadfile))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cmd = '/home/hpk/bin/python2.7 /tmp/pytest-21/test_basic_objects_python3_4_p5/load.py'
def cmdexec(cmd):
""" return unicode output of executing 'cmd' in a separate process.
raise cmdexec.Error exeception if the command failed.
the exception will provide an 'err' attribute containing
the error-output from the command.
if the subprocess module does not provide a proper encoding/unicode strings
sys.getdefaultencoding() will be used, if that does not exist, 'UTF-8'.
"""
process = subprocess.Popen(cmd, shell=True,
universal_newlines=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate()
if sys.version_info[0] < 3: # on py3 we get unicode strings, on py2 not
try:
default_encoding = sys.getdefaultencoding() # jython may not have it
except AttributeError:
default_encoding = sys.stdout.encoding or 'UTF-8'
out = unicode(out, process.stdout.encoding or default_encoding)
err = unicode(err, process.stderr.encoding or default_encoding)
status = process.poll()
if status:
> raise ExecutionFailed(status, status, cmd, out, err)
E py.process.cmdexec.Error: ExecutionFailed: 1 /home/hpk/bin/python2.7 /tmp/pytest-21/test_basic_objects_python3_4_p5/load.py
E Traceback (most recent call last):
E File "/tmp/pytest-21/test_basic_objects_python3_4_p5/load.py", line 4, in <module>
E obj = pickle.load(f)
E File "/usr/lib/python2.7/pickle.py", line 1378, in load
E return Unpickler(file).load()
E File "/usr/lib/python2.7/pickle.py", line 858, in load
E dispatch[key](self)
E File "/usr/lib/python2.7/pickle.py", line 886, in load_proto
E raise ValueError, "unsupported pickle protocol: %d" % proto
E ValueError: unsupported pickle protocol: 3
../../../.tox/regen/lib/python3.4/site-packages/py/_process/cmdexec.py:28: Error
--------------------------- Captured stdout call ---------------------------
/tmp/pytest-21/test_basic_objects_python3_4_p5/load.py
6 failed, 21 passed in 1.36 seconds
Indirect parametrization of optional implementations/imports
--------------------------------------------------------------------
@@ -329,12 +664,12 @@ If you run this with reporting for skips enabled::
$ py.test -rs test_module.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 2 items
test_module.py .s
========================= short test summary info ==========================
SKIP [1] /tmp/doc-exec-67/conftest.py:10: could not import 'opt2'
SKIP [1] /tmp/doc-exec-226/conftest.py:10: could not import 'opt2'
=================== 1 passed, 1 skipped in 0.01 seconds ====================

View File

@@ -43,7 +43,7 @@ then the test collection looks like this::
$ py.test --collect-only
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 2 items
<Module 'check_myapp.py'>
<Class 'CheckMyApp'>
@@ -88,7 +88,7 @@ You can always peek at the collection tree without running tests like this::
. $ py.test --collect-only pythoncollection.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 3 items
<Module 'pythoncollection.py'>
<Function 'test_function'>
@@ -141,10 +141,8 @@ interpreters and will leave out the setup.py file::
$ py.test --collect-only
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
collected 1 items
<Module 'pkg/module_py2.py'>
<Function 'test_only_on_python2'>
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 0 items
============================= in 0.01 seconds =============================

View File

@@ -13,10 +13,10 @@ get on the terminal - we are working on that):
assertion $ py.test failure_demo.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
collected 39 items
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 42 items
failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
================================= FAILURES =================================
____________________________ test_generative[0] ____________________________
@@ -30,7 +30,7 @@ get on the terminal - we are working on that):
failure_demo.py:15: AssertionError
_________________________ TestFailing.test_simple __________________________
self = <failure_demo.TestFailing object at 0x29e5210>
self = <failure_demo.TestFailing object at 0x2adb9885cfd0>
def test_simple(self):
def f():
@@ -40,13 +40,13 @@ get on the terminal - we are working on that):
> assert f() == g()
E assert 42 == 43
E + where 42 = <function f at 0x296a9b0>()
E + and 43 = <function g at 0x296aa28>()
E + where 42 = <function TestFailing.test_simple.<locals>.f at 0x2adb9887e6a8>()
E + and 43 = <function TestFailing.test_simple.<locals>.g at 0x2adb9887e598>()
failure_demo.py:28: AssertionError
____________________ TestFailing.test_simple_multiline _____________________
self = <failure_demo.TestFailing object at 0x29cef50>
self = <failure_demo.TestFailing object at 0x2adb98841518>
def test_simple_multiline(self):
otherfunc_multi(
@@ -66,19 +66,19 @@ get on the terminal - we are working on that):
failure_demo.py:11: AssertionError
___________________________ TestFailing.test_not ___________________________
self = <failure_demo.TestFailing object at 0x29be250>
self = <failure_demo.TestFailing object at 0x2adb98813278>
def test_not(self):
def f():
return 42
> assert not f()
E assert not 42
E + where 42 = <function f at 0x296ac08>()
E + where 42 = <function TestFailing.test_not.<locals>.f at 0x2adb9887e840>()
failure_demo.py:38: AssertionError
_________________ TestSpecialisedExplanations.test_eq_text _________________
self = <failure_demo.TestSpecialisedExplanations object at 0x29c3990>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb987a9588>
def test_eq_text(self):
> assert 'spam' == 'eggs'
@@ -89,7 +89,7 @@ get on the terminal - we are working on that):
failure_demo.py:42: AssertionError
_____________ TestSpecialisedExplanations.test_eq_similar_text _____________
self = <failure_demo.TestSpecialisedExplanations object at 0x2acef90>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb9881fe80>
def test_eq_similar_text(self):
> assert 'foo 1 bar' == 'foo 2 bar'
@@ -102,7 +102,7 @@ get on the terminal - we are working on that):
failure_demo.py:45: AssertionError
____________ TestSpecialisedExplanations.test_eq_multiline_text ____________
self = <failure_demo.TestSpecialisedExplanations object at 0x29f1f50>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb98894b38>
def test_eq_multiline_text(self):
> assert 'foo\nspam\nbar' == 'foo\neggs\nbar'
@@ -115,7 +115,7 @@ get on the terminal - we are working on that):
failure_demo.py:48: AssertionError
______________ TestSpecialisedExplanations.test_eq_long_text _______________
self = <failure_demo.TestSpecialisedExplanations object at 0x29e58d0>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb98812fd0>
def test_eq_long_text(self):
a = '1'*100 + 'a' + '2'*100
@@ -132,7 +132,7 @@ get on the terminal - we are working on that):
failure_demo.py:53: AssertionError
_________ TestSpecialisedExplanations.test_eq_long_text_multiline __________
self = <failure_demo.TestSpecialisedExplanations object at 0x29cee50>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb987ce240>
def test_eq_long_text_multiline(self):
a = '1\n'*100 + 'a' + '2\n'*100
@@ -156,7 +156,7 @@ get on the terminal - we are working on that):
failure_demo.py:58: AssertionError
_________________ TestSpecialisedExplanations.test_eq_list _________________
self = <failure_demo.TestSpecialisedExplanations object at 0x29c3810>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb98841a58>
def test_eq_list(self):
> assert [0, 1, 2] == [0, 1, 3]
@@ -166,7 +166,7 @@ get on the terminal - we are working on that):
failure_demo.py:61: AssertionError
______________ TestSpecialisedExplanations.test_eq_list_long _______________
self = <failure_demo.TestSpecialisedExplanations object at 0x29e50d0>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb987e4e48>
def test_eq_list_long(self):
a = [0]*100 + [1] + [3]*100
@@ -178,7 +178,7 @@ get on the terminal - we are working on that):
failure_demo.py:66: AssertionError
_________________ TestSpecialisedExplanations.test_eq_dict _________________
self = <failure_demo.TestSpecialisedExplanations object at 0x29c5dd0>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb98843d30>
def test_eq_dict(self):
> assert {'a': 0, 'b': 1, 'c': 0} == {'a': 0, 'b': 2, 'd': 0}
@@ -194,7 +194,7 @@ get on the terminal - we are working on that):
failure_demo.py:69: AssertionError
_________________ TestSpecialisedExplanations.test_eq_set __________________
self = <failure_demo.TestSpecialisedExplanations object at 0x29e2690>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb98822b38>
def test_eq_set(self):
> assert set([0, 10, 11, 12]) == set([0, 20, 21])
@@ -210,7 +210,7 @@ get on the terminal - we are working on that):
failure_demo.py:72: AssertionError
_____________ TestSpecialisedExplanations.test_eq_longer_list ______________
self = <failure_demo.TestSpecialisedExplanations object at 0x29ceb50>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb987a96d8>
def test_eq_longer_list(self):
> assert [1,2] == [1,2,3]
@@ -220,7 +220,7 @@ get on the terminal - we are working on that):
failure_demo.py:75: AssertionError
_________________ TestSpecialisedExplanations.test_in_list _________________
self = <failure_demo.TestSpecialisedExplanations object at 0x29c3050>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb987b72e8>
def test_in_list(self):
> assert 1 in [0, 2, 3, 4, 5]
@@ -229,7 +229,7 @@ get on the terminal - we are working on that):
failure_demo.py:78: AssertionError
__________ TestSpecialisedExplanations.test_not_in_text_multiline __________
self = <failure_demo.TestSpecialisedExplanations object at 0x29e5b10>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb98894908>
def test_not_in_text_multiline(self):
text = 'some multiline\ntext\nwhich\nincludes foo\nand a\ntail'
@@ -247,7 +247,7 @@ get on the terminal - we are working on that):
failure_demo.py:82: AssertionError
___________ TestSpecialisedExplanations.test_not_in_text_single ____________
self = <failure_demo.TestSpecialisedExplanations object at 0x29f1610>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb9885c898>
def test_not_in_text_single(self):
text = 'single foo line'
@@ -260,7 +260,7 @@ get on the terminal - we are working on that):
failure_demo.py:86: AssertionError
_________ TestSpecialisedExplanations.test_not_in_text_single_long _________
self = <failure_demo.TestSpecialisedExplanations object at 0x29cea50>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb987cc9e8>
def test_not_in_text_single_long(self):
text = 'head ' * 50 + 'foo ' + 'tail ' * 20
@@ -273,7 +273,7 @@ get on the terminal - we are working on that):
failure_demo.py:90: AssertionError
______ TestSpecialisedExplanations.test_not_in_text_single_long_term _______
self = <failure_demo.TestSpecialisedExplanations object at 0x29e2a10>
self = <failure_demo.TestSpecialisedExplanations object at 0x2adb987d2748>
def test_not_in_text_single_long_term(self):
text = 'head ' * 50 + 'f'*70 + 'tail ' * 20
@@ -292,7 +292,7 @@ get on the terminal - we are working on that):
i = Foo()
> assert i.b == 2
E assert 1 == 2
E + where 1 = <failure_demo.Foo object at 0x29c77d0>.b
E + where 1 = <failure_demo.test_attribute.<locals>.Foo object at 0x2adb987b5470>.b
failure_demo.py:101: AssertionError
_________________________ test_attribute_instance __________________________
@@ -302,8 +302,8 @@ get on the terminal - we are working on that):
b = 1
> assert Foo().b == 2
E assert 1 == 2
E + where 1 = <failure_demo.Foo object at 0x29e5f10>.b
E + where <failure_demo.Foo object at 0x29e5f10> = <class 'failure_demo.Foo'>()
E + where 1 = <failure_demo.test_attribute_instance.<locals>.Foo object at 0x2adb987d0390>.b
E + where <failure_demo.test_attribute_instance.<locals>.Foo object at 0x2adb987d0390> = <class 'failure_demo.test_attribute_instance.<locals>.Foo'>()
failure_demo.py:107: AssertionError
__________________________ test_attribute_failure __________________________
@@ -319,7 +319,7 @@ get on the terminal - we are working on that):
failure_demo.py:116:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <failure_demo.Foo object at 0x29e6b10>
self = <failure_demo.test_attribute_failure.<locals>.Foo object at 0x2adb98822cf8>
def _get_b(self):
> raise Exception('Failed to get attrib')
@@ -335,15 +335,15 @@ get on the terminal - we are working on that):
b = 2
> assert Foo().b == Bar().b
E assert 1 == 2
E + where 1 = <failure_demo.Foo object at 0x29c3b10>.b
E + where <failure_demo.Foo object at 0x29c3b10> = <class 'failure_demo.Foo'>()
E + and 2 = <failure_demo.Bar object at 0x29c3350>.b
E + where <failure_demo.Bar object at 0x29c3350> = <class 'failure_demo.Bar'>()
E + where 1 = <failure_demo.test_attribute_multiple.<locals>.Foo object at 0x2adb98841dd8>.b
E + where <failure_demo.test_attribute_multiple.<locals>.Foo object at 0x2adb98841dd8> = <class 'failure_demo.test_attribute_multiple.<locals>.Foo'>()
E + and 2 = <failure_demo.test_attribute_multiple.<locals>.Bar object at 0x2adb98841a90>.b
E + where <failure_demo.test_attribute_multiple.<locals>.Bar object at 0x2adb98841a90> = <class 'failure_demo.test_attribute_multiple.<locals>.Bar'>()
failure_demo.py:124: AssertionError
__________________________ TestRaises.test_raises __________________________
self = <failure_demo.TestRaises instance at 0x2aec878>
self = <failure_demo.TestRaises object at 0x2adb98854668>
def test_raises(self):
s = 'qwe'
@@ -355,10 +355,10 @@ get on the terminal - we are working on that):
> int(s)
E ValueError: invalid literal for int() with base 10: 'qwe'
<0-codegen /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:999>:1: ValueError
<0-codegen /home/hpk/p/pytest/.tox/regen/lib/python3.4/site-packages/_pytest/python.py:1028>:1: ValueError
______________________ TestRaises.test_raises_doesnt _______________________
self = <failure_demo.TestRaises instance at 0x2aafef0>
self = <failure_demo.TestRaises object at 0x2adb988818d0>
def test_raises_doesnt(self):
> raises(IOError, "int('3')")
@@ -367,7 +367,7 @@ get on the terminal - we are working on that):
failure_demo.py:136: Failed
__________________________ TestRaises.test_raise ___________________________
self = <failure_demo.TestRaises instance at 0x2ae5758>
self = <failure_demo.TestRaises object at 0x2adb9885cc50>
def test_raise(self):
> raise ValueError("demo error")
@@ -376,7 +376,7 @@ get on the terminal - we are working on that):
failure_demo.py:139: ValueError
________________________ TestRaises.test_tupleerror ________________________
self = <failure_demo.TestRaises instance at 0x29cf4d0>
self = <failure_demo.TestRaises object at 0x2adb988430b8>
def test_tupleerror(self):
> a,b = [1]
@@ -385,7 +385,7 @@ get on the terminal - we are working on that):
failure_demo.py:142: ValueError
______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______
self = <failure_demo.TestRaises instance at 0x29cf9e0>
self = <failure_demo.TestRaises object at 0x2adb9881fa20>
def test_reinterpret_fails_with_print_for_the_fun_of_it(self):
l = [1,2,3]
@@ -394,15 +394,15 @@ get on the terminal - we are working on that):
E TypeError: 'int' object is not iterable
failure_demo.py:147: TypeError
----------------------------- Captured stdout ------------------------------
--------------------------- Captured stdout call ---------------------------
l is [1, 2, 3]
________________________ TestRaises.test_some_error ________________________
self = <failure_demo.TestRaises instance at 0x29d9ea8>
self = <failure_demo.TestRaises object at 0x2adb98894a90>
def test_some_error(self):
> if namenotexi:
E NameError: global name 'namenotexi' is not defined
E NameError: name 'namenotexi' is not defined
failure_demo.py:150: NameError
____________________ test_dynamic_compile_shows_nicely _____________________
@@ -426,7 +426,7 @@ get on the terminal - we are working on that):
<2-codegen 'abc-123' /home/hpk/p/pytest/doc/en/example/assertion/failure_demo.py:162>:2: AssertionError
____________________ TestMoreErrors.test_complex_error _____________________
self = <failure_demo.TestMoreErrors instance at 0x29ca8c0>
self = <failure_demo.TestMoreErrors object at 0x2adb98812da0>
def test_complex_error(self):
def f():
@@ -437,13 +437,8 @@ get on the terminal - we are working on that):
failure_demo.py:175:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
x = 44, y = 43
def somefunc(x,y):
> otherfunc(x,y)
failure_demo.py:8:
failure_demo.py:8: in somefunc
otherfunc(x,y)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
a = 44, b = 43
@@ -455,7 +450,7 @@ get on the terminal - we are working on that):
failure_demo.py:5: AssertionError
___________________ TestMoreErrors.test_z1_unpack_error ____________________
self = <failure_demo.TestMoreErrors instance at 0x2ae2ea8>
self = <failure_demo.TestMoreErrors object at 0x2adb9884d4a8>
def test_z1_unpack_error(self):
l = []
@@ -465,7 +460,7 @@ get on the terminal - we are working on that):
failure_demo.py:179: ValueError
____________________ TestMoreErrors.test_z2_type_error _____________________
self = <failure_demo.TestMoreErrors instance at 0x29da518>
self = <failure_demo.TestMoreErrors object at 0x2adb987b52b0>
def test_z2_type_error(self):
l = 3
@@ -475,19 +470,19 @@ get on the terminal - we are working on that):
failure_demo.py:183: TypeError
______________________ TestMoreErrors.test_startswith ______________________
self = <failure_demo.TestMoreErrors instance at 0x29b8440>
self = <failure_demo.TestMoreErrors object at 0x2adb988224e0>
def test_startswith(self):
s = "123"
g = "456"
> assert s.startswith(g)
E assert <built-in method startswith of str object at 0x29ea328>('456')
E + where <built-in method startswith of str object at 0x29ea328> = '123'.startswith
E assert <built-in method startswith of str object at 0x2adb987a9ca8>('456')
E + where <built-in method startswith of str object at 0x2adb987a9ca8> = '123'.startswith
failure_demo.py:188: AssertionError
__________________ TestMoreErrors.test_startswith_nested ___________________
self = <failure_demo.TestMoreErrors instance at 0x2ae4e18>
self = <failure_demo.TestMoreErrors object at 0x2adb98836898>
def test_startswith_nested(self):
def f():
@@ -495,15 +490,15 @@ get on the terminal - we are working on that):
def g():
return "456"
> assert f().startswith(g())
E assert <built-in method startswith of str object at 0x29ea328>('456')
E + where <built-in method startswith of str object at 0x29ea328> = '123'.startswith
E + where '123' = <function f at 0x29595f0>()
E + and '456' = <function g at 0x2ab5320>()
E assert <built-in method startswith of str object at 0x2adb987a9ca8>('456')
E + where <built-in method startswith of str object at 0x2adb987a9ca8> = '123'.startswith
E + where '123' = <function TestMoreErrors.test_startswith_nested.<locals>.f at 0x2adb9887e9d8>()
E + and '456' = <function TestMoreErrors.test_startswith_nested.<locals>.g at 0x2adb9887e7b8>()
failure_demo.py:195: AssertionError
_____________________ TestMoreErrors.test_global_func ______________________
self = <failure_demo.TestMoreErrors instance at 0x2abf320>
self = <failure_demo.TestMoreErrors object at 0x2adb987b77f0>
def test_global_func(self):
> assert isinstance(globf(42), float)
@@ -513,18 +508,18 @@ get on the terminal - we are working on that):
failure_demo.py:198: AssertionError
_______________________ TestMoreErrors.test_instance _______________________
self = <failure_demo.TestMoreErrors instance at 0x2aaf050>
self = <failure_demo.TestMoreErrors object at 0x2adb988729b0>
def test_instance(self):
self.x = 6*7
> assert self.x != 42
E assert 42 != 42
E + where 42 = <failure_demo.TestMoreErrors instance at 0x2aaf050>.x
E + where 42 = <failure_demo.TestMoreErrors object at 0x2adb988729b0>.x
failure_demo.py:202: AssertionError
_______________________ TestMoreErrors.test_compare ________________________
self = <failure_demo.TestMoreErrors instance at 0x2aedbd8>
self = <failure_demo.TestMoreErrors object at 0x2adb98812f98>
def test_compare(self):
> assert globf(10) < 5
@@ -534,7 +529,7 @@ get on the terminal - we are working on that):
failure_demo.py:205: AssertionError
_____________________ TestMoreErrors.test_try_finally ______________________
self = <failure_demo.TestMoreErrors instance at 0x29f2098>
self = <failure_demo.TestMoreErrors object at 0x2adb987d0198>
def test_try_finally(self):
x = 1
@@ -543,4 +538,55 @@ get on the terminal - we are working on that):
E assert 1 == 0
failure_demo.py:210: AssertionError
======================== 39 failed in 0.20 seconds =========================
___________________ TestCustomAssertMsg.test_single_line ___________________
self = <failure_demo.TestCustomAssertMsg object at 0x2adb98894cc0>
def test_single_line(self):
class A:
a = 1
b = 2
> assert A.a == b, "A.a appears not to be b"
E AssertionError: A.a appears not to be b
E assert 1 == 2
E + where 1 = <class 'failure_demo.TestCustomAssertMsg.test_single_line.<locals>.A'>.a
failure_demo.py:221: AssertionError
____________________ TestCustomAssertMsg.test_multiline ____________________
self = <failure_demo.TestCustomAssertMsg object at 0x2adb988414e0>
def test_multiline(self):
class A:
a = 1
b = 2
> assert A.a == b, "A.a appears not to be b\n" \
"or does not appear to be b\none of those"
E AssertionError: A.a appears not to be b
E or does not appear to be b
E one of those
E assert 1 == 2
E + where 1 = <class 'failure_demo.TestCustomAssertMsg.test_multiline.<locals>.A'>.a
failure_demo.py:227: AssertionError
___________________ TestCustomAssertMsg.test_custom_repr ___________________
self = <failure_demo.TestCustomAssertMsg object at 0x2adb9885c668>
def test_custom_repr(self):
class JSON:
a = 1
def __repr__(self):
return "This is JSON\n{\n 'foo': 'bar'\n}"
a = JSON()
b = 2
> assert a.a == b, a
E AssertionError: This is JSON
E {
E 'foo': 'bar'
E }
E assert 1 == 2
E + where 1 = This is JSON\n{\n 'foo': 'bar'\n}.a
failure_demo.py:237: AssertionError
======================== 42 failed in 0.29 seconds =========================

View File

@@ -41,9 +41,9 @@ Let's run this without supplying our new option::
F
================================= FAILURES =================================
_______________________________ test_answer ________________________________
cmdopt = 'type1'
def test_answer(cmdopt):
if cmdopt == "type1":
print ("first")
@@ -51,11 +51,11 @@ Let's run this without supplying our new option::
print ("second")
> assert 0 # to see what was printed
E assert 0
test_sample.py:6: AssertionError
----------------------------- Captured stdout ------------------------------
--------------------------- Captured stdout call ---------------------------
first
1 failed in 0.01 seconds
1 failed in 0.02 seconds
And now with supplying a command line option::
@@ -75,7 +75,7 @@ And now with supplying a command line option::
E assert 0
test_sample.py:6: AssertionError
----------------------------- Captured stdout ------------------------------
--------------------------- Captured stdout call ---------------------------
second
1 failed in 0.01 seconds
@@ -108,9 +108,9 @@ directory with the above conftest.py::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 0 items
============================= in 0.00 seconds =============================
.. _`excontrolskip`:
@@ -152,12 +152,12 @@ and when running it will see a skipped "slow" test::
$ py.test -rs # "-rs" means report details on the little 's'
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 2 items
test_module.py .s
========================= short test summary info ==========================
SKIP [1] /tmp/doc-exec-70/conftest.py:9: need --runslow option to run
SKIP [1] /tmp/doc-exec-229/conftest.py:9: need --runslow option to run
=================== 1 passed, 1 skipped in 0.01 seconds ====================
@@ -165,11 +165,11 @@ Or run it including the ``slow`` marked test::
$ py.test --runslow
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 2 items
test_module.py ..
========================= 2 passed in 0.01 seconds =========================
Writing well integrated assertion helpers
@@ -256,10 +256,10 @@ which will add the string to the test header accordingly::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
project deps: mylib-1.1
collected 0 items
============================= in 0.00 seconds =============================
.. regendoc:wipe
@@ -279,20 +279,20 @@ which will add info only when run with "--v"::
$ py.test -v
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4
info1: did you know that ...
did you?
collecting ... collected 0 items
============================= in 0.00 seconds =============================
and nothing when run plainly::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 0 items
============================= in 0.00 seconds =============================
profiling test duration
@@ -322,7 +322,7 @@ Now we can profile which test functions execute the slowest::
$ py.test --durations=3
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 3 items
test_some_are_slow.py ...
@@ -330,8 +330,8 @@ Now we can profile which test functions execute the slowest::
========================= slowest 3 test durations =========================
0.20s call test_some_are_slow.py::test_funcslow2
0.10s call test_some_are_slow.py::test_funcslow1
0.00s setup test_some_are_slow.py::test_funcfast
========================= 3 passed in 0.31 seconds =========================
0.00s teardown test_some_are_slow.py::test_funcslow1
========================= 3 passed in 0.32 seconds =========================
incremental testing - test steps
---------------------------------------------------
@@ -383,7 +383,7 @@ If we run this::
$ py.test -rx
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 4 items
test_step.py .Fx.
@@ -391,7 +391,7 @@ If we run this::
================================= FAILURES =================================
____________________ TestUserHandling.test_modification ____________________
self = <test_step.TestUserHandling instance at 0x2768dd0>
self = <test_step.TestUserHandling object at 0x2af9f0d94470>
def test_modification(self):
> assert 0
@@ -453,7 +453,7 @@ We can run this::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 7 items
test_step.py .Fx.
@@ -463,17 +463,17 @@ We can run this::
================================== ERRORS ==================================
_______________________ ERROR at setup of test_root ________________________
file /tmp/doc-exec-70/b/test_error.py, line 1
file /tmp/doc-exec-229/b/test_error.py, line 1
def test_root(db): # no db here, will error out
fixture 'db' not found
available fixtures: pytestconfig, capfd, monkeypatch, capsys, recwarn, tmpdir
available fixtures: capsys, pytestconfig, monkeypatch, tmpdir, recwarn, capfd
use 'py.test --fixtures [testpath]' for help on them.
/tmp/doc-exec-70/b/test_error.py:1
/tmp/doc-exec-229/b/test_error.py:1
================================= FAILURES =================================
____________________ TestUserHandling.test_modification ____________________
self = <test_step.TestUserHandling instance at 0x238fdd0>
self = <test_step.TestUserHandling object at 0x2b0f0e2ff0b8>
def test_modification(self):
> assert 0
@@ -482,23 +482,25 @@ We can run this::
test_step.py:9: AssertionError
_________________________________ test_a1 __________________________________
db = <conftest.DB instance at 0x23f9998>
db = <conftest.DB object at 0x2b0f0e2ff630>
def test_a1(db):
> assert 0, db # to show value
E AssertionError: <conftest.DB instance at 0x23f9998>
E AssertionError: <conftest.DB object at 0x2b0f0e2ff630>
E assert 0
a/test_db.py:2: AssertionError
_________________________________ test_a2 __________________________________
db = <conftest.DB instance at 0x23f9998>
db = <conftest.DB object at 0x2b0f0e2ff630>
def test_a2(db):
> assert 0, db # to show value
E AssertionError: <conftest.DB instance at 0x23f9998>
E AssertionError: <conftest.DB object at 0x2b0f0e2ff630>
E assert 0
a/test_db2.py:2: AssertionError
========== 3 failed, 2 passed, 1 xfailed, 1 error in 0.03 seconds ==========
========== 3 failed, 2 passed, 1 xfailed, 1 error in 0.04 seconds ==========
The two test modules in the ``a`` directory see the same ``db`` fixture instance
while the one test in the sister-directory ``b`` doesn't see it. We could of course
@@ -553,7 +555,7 @@ and run them::
$ py.test test_module.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 2 items
test_module.py FF
@@ -561,7 +563,7 @@ and run them::
================================= FAILURES =================================
________________________________ test_fail1 ________________________________
tmpdir = local('/tmp/pytest-1012/test_fail10')
tmpdir = local('/tmp/pytest-22/test_fail10')
def test_fail1(tmpdir):
> assert 0
@@ -580,7 +582,7 @@ and run them::
you will have a "failures" file which contains the failing test ids::
$ cat failures
test_module.py::test_fail1 (/tmp/pytest-1012/test_fail10)
test_module.py::test_fail1 (/tmp/pytest-22/test_fail10)
test_module.py::test_fail2
Making test result information available in fixtures
@@ -613,10 +615,10 @@ here is a little example implemented via a local plugin::
# request.node is an "item" because we use the default
# "function" scope
if request.node.rep_setup.failed:
print "setting up a test failed!", request.node.nodeid
print ("setting up a test failed!", request.node.nodeid)
elif request.node.rep_setup.passed:
if request.node.rep_call.failed:
print "executing test failed", request.node.nodeid
print ("executing test failed", request.node.nodeid)
request.addfinalizer(fin)
@@ -643,7 +645,7 @@ and run it::
$ py.test -s test_module.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 3 items
test_module.py Esetting up a test failed! test_module.py::test_setup_fails
@@ -681,3 +683,54 @@ and run it::
You'll see that the fixture finalizers could use the precise reporting
information.
Integrating pytest runner and cx_freeze
-----------------------------------------------------------
If you freeze your application using a tool like
`cx_freeze <http://cx-freeze.readthedocs.org>`_ in order to distribute it
to your end-users, it is a good idea to also package your test runner and run
your tests using the frozen application.
This way packaging errors such as dependencies not being
included into the executable can be detected early while also allowing you to
send test files to users so they can run them in their machines, which can be
invaluable to obtain more information about a hard to reproduce bug.
Unfortunately ``cx_freeze`` can't discover them
automatically because of ``pytest``'s use of dynamic module loading, so you
must declare them explicitly by using ``pytest.freeze_includes()``::
# contents of setup.py
from cx_Freeze import setup, Executable
import pytest
setup(
name="app_main",
executables=[Executable("app_main.py")],
options={"build_exe":
{
'includes': pytest.freeze_includes()}
},
# ... other options
)
If you don't want to ship a different executable just in order to run your tests,
you can make your program check for a certain flag and pass control
over to ``pytest`` instead. For example::
# contents of app_main.py
import sys
if len(sys.argv) > 1 and sys.argv[1] == '--pytest':
import pytest
sys.exit(pytest.main(sys.argv[2:]))
else:
# normal application execution: at this point argv can be parsed
# by your argument-parsing library of choice as usual
...
This makes it convenient to execute your tests from within your frozen
application, using standard ``py.test`` command-line options::
$ ./app_main --pytest --verbose --tb=long --junit-xml=results.xml test-suite/
/bin/sh: 1: ./app_main: not found

View File

@@ -1,7 +1,7 @@
A session-fixture which can look at all collected tests
----------------------------------------------------------------
A session-scoped fixture effectively has access to all
A session-scoped fixture effectively has access to all
collected test items. Here is an example of a fixture
function which walks all collected tests and looks
if their test class defines a ``callme`` method and
@@ -13,7 +13,7 @@ calls it::
@pytest.fixture(scope="session", autouse=True)
def callattr_ahead_of_alltests(request):
print "callattr_ahead_of_alltests called"
print ("callattr_ahead_of_alltests called")
seen = set([None])
session = request.node
for item in session.items:
@@ -31,35 +31,35 @@ will be called ahead of running any tests::
class TestHello:
@classmethod
def callme(cls):
print "callme called!"
print ("callme called!")
def test_method1(self):
print "test_method1 called"
print ("test_method1 called")
def test_method2(self):
print "test_method1 called"
print ("test_method1 called")
class TestOther:
@classmethod
def callme(cls):
print "callme other called"
print ("callme other called")
def test_other(self):
print "test other"
print ("test other")
# works with unittest as well ...
import unittest
class SomeTest(unittest.TestCase):
@classmethod
def callme(self):
print "SomeTest callme called"
print ("SomeTest callme called")
def test_unit1(self):
print "test_unit1 method called"
print ("test_unit1 method called")
If you run this without output capturing::
$ py.test -q -s test_module.py
$ py.test -q -s test_module.py
callattr_ahead_of_alltests called
callme called!
callme other called
@@ -69,4 +69,4 @@ If you run this without output capturing::
.test other
.test_unit1 method called
.
4 passed in 0.01 seconds
4 passed in 0.05 seconds

View File

@@ -23,3 +23,8 @@ def test_hello5():
def test_hello6():
pytest.xfail("reason")
@xfail(raises=IndexError)
def test_hello7():
x = []
x[1] = 1

View File

@@ -76,7 +76,7 @@ marked ``smtp`` fixture function. Running the test looks like this::
$ py.test test_smtpsimple.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 1 items
test_smtpsimple.py F
@@ -84,17 +84,16 @@ marked ``smtp`` fixture function. Running the test looks like this::
================================= FAILURES =================================
________________________________ test_ehlo _________________________________
smtp = <smtplib.SMTP instance at 0x15cc0e0>
smtp = <smtplib.SMTP object at 0x2b040fa62128>
def test_ehlo(smtp):
response, msg = smtp.ehlo()
assert response == 250
assert "merlinux" in msg
> assert 0 # for demo purposes
E assert 0
> assert "merlinux" in msg
E TypeError: Type str doesn't support the buffer API
test_smtpsimple.py:12: AssertionError
========================= 1 failed in 0.21 seconds =========================
test_smtpsimple.py:11: TypeError
========================= 1 failed in 0.20 seconds =========================
In the failure traceback we see that the test function was called with a
``smtp`` argument, the ``smtplib.SMTP()`` instance created by the fixture
@@ -194,7 +193,7 @@ inspect what is going on and can now run the tests::
$ py.test test_module.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 2 items
test_module.py FF
@@ -202,19 +201,18 @@ inspect what is going on and can now run the tests::
================================= FAILURES =================================
________________________________ test_ehlo _________________________________
smtp = <smtplib.SMTP instance at 0x237b638>
smtp = <smtplib.SMTP object at 0x2abe3c757208>
def test_ehlo(smtp):
response = smtp.ehlo()
assert response[0] == 250
assert "merlinux" in response[1]
> assert 0 # for demo purposes
E assert 0
> assert "merlinux" in response[1]
E TypeError: Type str doesn't support the buffer API
test_module.py:6: AssertionError
test_module.py:5: TypeError
________________________________ test_noop _________________________________
smtp = <smtplib.SMTP instance at 0x237b638>
smtp = <smtplib.SMTP object at 0x2abe3c757208>
def test_noop(smtp):
response = smtp.noop()
@@ -223,7 +221,7 @@ inspect what is going on and can now run the tests::
E assert 0
test_module.py:11: AssertionError
========================= 2 failed in 0.23 seconds =========================
========================= 2 failed in 0.17 seconds =========================
You see the two ``assert 0`` failing and more importantly you can also see
that the same (module-scoped) ``smtp`` object was passed into the two
@@ -271,7 +269,7 @@ Let's execute it::
$ py.test -s -q --tb=no
FFteardown smtp
2 failed in 0.21 seconds
2 failed in 0.16 seconds
We see that the ``smtp`` instance is finalized after the two
tests finished execution. Note that if we decorated our fixture
@@ -312,7 +310,7 @@ again, nothing much has changed::
$ py.test -s -q --tb=no
FF
2 failed in 0.59 seconds
2 failed in 0.16 seconds
Let's quickly create another test module that actually sets the
server URL in its module namespace::
@@ -331,8 +329,9 @@ Running it::
================================= FAILURES =================================
______________________________ test_showhelo _______________________________
test_anothersmtp.py:5: in test_showhelo
> assert 0, smtp.helo()
E AssertionError: (250, 'mail.python.org')
assert 0, smtp.helo()
E AssertionError: (250, b'mail.python.org')
E assert 0
voila! The ``smtp`` fixture function picked up our mail server name
from the module namespace.
@@ -379,19 +378,18 @@ So let's just do another run::
================================= FAILURES =================================
__________________________ test_ehlo[merlinux.eu] __________________________
smtp = <smtplib.SMTP instance at 0x21f3e60>
smtp = <smtplib.SMTP object at 0x2afbf4496828>
def test_ehlo(smtp):
response = smtp.ehlo()
assert response[0] == 250
assert "merlinux" in response[1]
> assert 0 # for demo purposes
E assert 0
> assert "merlinux" in response[1]
E TypeError: Type str doesn't support the buffer API
test_module.py:6: AssertionError
test_module.py:5: TypeError
__________________________ test_noop[merlinux.eu] __________________________
smtp = <smtplib.SMTP instance at 0x21f3e60>
smtp = <smtplib.SMTP object at 0x2afbf4496828>
def test_noop(smtp):
response = smtp.noop()
@@ -402,20 +400,20 @@ So let's just do another run::
test_module.py:11: AssertionError
________________________ test_ehlo[mail.python.org] ________________________
smtp = <smtplib.SMTP instance at 0x22047e8>
smtp = <smtplib.SMTP object at 0x2afbf4496d68>
def test_ehlo(smtp):
response = smtp.ehlo()
assert response[0] == 250
> assert "merlinux" in response[1]
E assert 'merlinux' in 'mail.python.org\nSIZE 25600000\nETRN\nSTARTTLS\nENHANCEDSTATUSCODES\n8BITMIME\nDSN'
E TypeError: Type str doesn't support the buffer API
test_module.py:5: AssertionError
----------------------------- Captured stdout ------------------------------
finalizing <smtplib.SMTP instance at 0x21f3e60>
test_module.py:5: TypeError
-------------------------- Captured stdout setup ---------------------------
finalizing <smtplib.SMTP object at 0x2afbf4496828>
________________________ test_noop[mail.python.org] ________________________
smtp = <smtplib.SMTP instance at 0x22047e8>
smtp = <smtplib.SMTP object at 0x2afbf4496d68>
def test_noop(smtp):
response = smtp.noop()
@@ -424,7 +422,7 @@ So let's just do another run::
E assert 0
test_module.py:11: AssertionError
4 failed in 6.06 seconds
4 failed in 6.02 seconds
We see that our two test functions each ran twice, against the different
``smtp`` instances. Note also, that with the ``mail.python.org``
@@ -464,13 +462,13 @@ Here we declare an ``app`` fixture which receives the previously defined
$ py.test -v test_appsetup.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4
collecting ... collected 2 items
test_appsetup.py:12: test_smtp_exists[merlinux.eu] PASSED
test_appsetup.py:12: test_smtp_exists[mail.python.org] PASSED
test_appsetup.py::test_smtp_exists[merlinux.eu] PASSED
test_appsetup.py::test_smtp_exists[mail.python.org] PASSED
========================= 2 passed in 6.42 seconds =========================
========================= 2 passed in 5.45 seconds =========================
Due to the parametrization of ``smtp`` the test will run twice with two
different ``App`` instances and respective smtp servers. There is no
@@ -508,7 +506,7 @@ to show the setup/teardown flow::
@pytest.fixture(scope="module", params=["mod1", "mod2"])
def modarg(request):
param = request.param
print "create", param
print ("create", param)
def fin():
print ("fin %s" % param)
return param
@@ -518,36 +516,36 @@ to show the setup/teardown flow::
return request.param
def test_0(otherarg):
print " test0", otherarg
print (" test0", otherarg)
def test_1(modarg):
print " test1", modarg
print (" test1", modarg)
def test_2(otherarg, modarg):
print " test2", otherarg, modarg
print (" test2", otherarg, modarg)
Let's run the tests in verbose mode and with looking at the print-output::
$ py.test -v -s test_module.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2 -- /home/hpk/p/pytest/.tox/regen/bin/python
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3 -- /home/hpk/p/pytest/.tox/regen/bin/python3.4
collecting ... collected 8 items
test_module.py:15: test_0[1] test0 1
test_module.py::test_0[1] test0 1
PASSED
test_module.py:15: test_0[2] test0 2
test_module.py::test_0[2] test0 2
PASSED
test_module.py:17: test_1[mod1] create mod1
test_module.py::test_1[mod1] create mod1
test1 mod1
PASSED
test_module.py:19: test_2[1-mod1] test2 1 mod1
test_module.py::test_2[1-mod1] test2 1 mod1
PASSED
test_module.py:19: test_2[2-mod1] test2 2 mod1
test_module.py::test_2[2-mod1] test2 2 mod1
PASSED
test_module.py:17: test_1[mod2] create mod2
test_module.py::test_1[mod2] create mod2
test1 mod2
PASSED
test_module.py:19: test_2[1-mod2] test2 1 mod2
test_module.py::test_2[1-mod2] test2 1 mod2
PASSED
test_module.py:19: test_2[2-mod2] test2 2 mod2
test_module.py::test_2[2-mod2] test2 2 mod2
PASSED
========================= 8 passed in 0.01 seconds =========================

View File

@@ -1,12 +1,16 @@
Installation and Getting Started
===================================
**Pythons**: Python 2.5-3.3, Jython, PyPy
**Pythons**: Python 2.6-3.4, Jython, PyPy-2.3
**Platforms**: Unix/Posix and Windows
**PyPI package name**: `pytest <http://pypi.python.org/pypi/pytest>`_
**dependencies**: `py <http://pypi.python.org/pypi/py>`_,
`colorama (Windows) <http://pypi.python.org/pypi/colorama>`_,
`argparse (py26) <http://pypi.python.org/pypi/argparse>`_.
**documentation as PDF**: `download latest <http://pytest.org/latest/pytest.pdf>`_
.. _`getstarted`:
@@ -23,7 +27,7 @@ Installation options::
To check your installation has installed the correct version::
$ py.test --version
This is pytest version 2.5.2, imported from /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/pytest.pyc
This is pytest version 2.6.3, imported from /home/hpk/p/pytest/.tox/regen/lib/python3.4/site-packages/pytest.py
If you get an error checkout :ref:`installation issues`.
@@ -45,7 +49,7 @@ That's it. You can execute the test function now::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 1 items
test_sample.py F
@@ -93,7 +97,7 @@ Running it with, this time in "quiet" reporting mode::
$ py.test -q test_sysexit.py
.
1 passed in 0.01 seconds
1 passed in 0.00 seconds
.. todo:: For further ways to assert exceptions see the `raises`
@@ -123,7 +127,7 @@ run the module by passing its filename::
================================= FAILURES =================================
____________________________ TestClass.test_two ____________________________
self = <test_class.TestClass instance at 0x255a0e0>
self = <test_class.TestClass object at 0x2b39478f7438>
def test_two(self):
x = "hello"
@@ -147,7 +151,7 @@ resources, for example a unique temporary directory::
# content of test_tmpdir.py
def test_needsfiles(tmpdir):
print tmpdir
print (tmpdir)
assert 0
We list the name ``tmpdir`` in the test function signature and
@@ -159,16 +163,16 @@ before performing the test function call. Let's just run it::
================================= FAILURES =================================
_____________________________ test_needsfiles ______________________________
tmpdir = local('/tmp/pytest-1008/test_needsfiles0')
tmpdir = local('/tmp/pytest-18/test_needsfiles0')
def test_needsfiles(tmpdir):
print tmpdir
print (tmpdir)
> assert 0
E assert 0
test_tmpdir.py:3: AssertionError
----------------------------- Captured stdout ------------------------------
/tmp/pytest-1008/test_needsfiles0
--------------------------- Captured stdout call ---------------------------
/tmp/pytest-18/test_needsfiles0
1 failed in 0.01 seconds
Before the test runs, a unique-per-test-invocation temporary directory

View File

@@ -1,4 +1,3 @@
.. highlightlang:: python
.. _`goodpractises`:
@@ -69,7 +68,7 @@ Important notes relating to both schemes:
- **avoid "__init__.py" files in your test directories**.
This way your tests can run easily against an installed version
of ``mypkg``, independently from if the installed package contains
of ``mypkg``, independently from the installed package if it contains
the tests or not.
- With inlined tests you might put ``__init__.py`` into test
@@ -190,12 +189,16 @@ this to your ``setup.py`` file::
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
import sys,subprocess
errno = subprocess.call([sys.executable, 'runtests.py'])
raise SystemExit(errno)
setup(
#...,
cmdclass = {'test': PyTest},
@@ -220,20 +223,30 @@ Setuptools supports writing our own Test command for invoking pytest.
Most often it is better to use tox_ instead, but here is how you can
get started with setuptools integration::
from setuptools.command.test import test as TestCommand
import sys
from setuptools.command.test import test as TestCommand
class PyTest(TestCommand):
user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")]
def initialize_options(self):
TestCommand.initialize_options(self)
self.pytest_args = []
def finalize_options(self):
TestCommand.finalize_options(self)
self.test_args = []
self.test_suite = True
def run_tests(self):
#import here, cause outside the eggs aren't loaded
import pytest
errno = pytest.main(self.test_args)
errno = pytest.main(self.pytest_args)
sys.exit(errno)
setup(
#...,
tests_require=['pytest'],
@@ -245,7 +258,12 @@ Now if you run::
python setup.py test
this will download ``pytest`` if needed and then run your tests
as you would expect it to.
as you would expect it to. You can pass a single string of arguments
using the ``--pytest-args`` or ``-a`` command-line option. For example::
python setup.py test -a "--durations=5"
is equivalent to running ``py.test --durations=5``.
.. _`test discovery`:
.. _`Python test discovery`:
@@ -258,7 +276,7 @@ Conventions for Python test discovery
* 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_*.py`` or ``*_test.py`` files, imported by their `test package name`_.
* ``Test`` prefixed test classes (without an ``__init__`` method)
* ``test_`` prefixed test functions or methods are test items

BIN
doc/en/img/pytest1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
doc/en/img/pytest1favi.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -1,24 +1,27 @@
.. _features:
.. second training: `professional testing with Python <http://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_ , 25-27th November 2013, Leipzig.
.. note::
next training: `professional testing with pytest and tox <http://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_, 24-26th November 2014, Freiburg, Germany
pytest: helps you write better programs
=============================================
**a mature full-featured Python testing tool**
- runs on Posix/Windows, Python 2.5-3.3, PyPy and Jython-2.5.1
- **zero-reported-bugs** policy with >1000 tests against itself
- runs on Posix/Windows, Python 2.6-3.4, PyPy and (possibly still) Jython-2.5.1
- **well tested** with more than a thousand tests against itself
- **strict backward compatibility policy** for safe pytest upgrades
- :ref:`comprehensive online <toc>` and `PDF documentation <pytest.pdf>`_
- many :ref:`third party plugins <extplugins>` and :ref:`builtin helpers <pytest helpers>`,
- many :ref:`third party plugins <extplugins>` and :ref:`builtin helpers <pytest helpers>`,
- used in :ref:`many small and large projects and organisations <projects>`
- comes with many :ref:`tested examples <examples>`
**provides easy no-boilerplate testing**
- makes it :ref:`easy to get started <getstarted>`,
- makes it :ref:`easy to get started <getstarted>`,
has many :ref:`usage options <usage>`
- :ref:`assert with the assert statement`
- helpful :ref:`traceback and failing assertion reporting <tbreportdemo>`
@@ -38,7 +41,7 @@ pytest: helps you write better programs
**integrates with other testing methods and tools**:
- multi-paradigm: pytest can run ``nose``, ``unittest`` and
- multi-paradigm: pytest can run ``nose``, ``unittest`` and
``doctest`` style test suites, including running testcases made for
Django and trial
- supports :ref:`good integration practises <goodpractises>`

View File

@@ -18,4 +18,4 @@
.. _hudson: http://hudson-ci.org/
.. _jenkins: http://jenkins-ci.org/
.. _tox: http://testrun.org/tox
.. _pylib: http://pylib.org
.. _pylib: http://py.readthedocs.org/en/latest/

View File

@@ -48,7 +48,7 @@ requests in all your tests, you can do::
import pytest
@pytest.fixture(autouse=True)
def no_requests(monkeypatch):
monkeypatch.delattr("requests.session.Session.request")
monkeypatch.delattr("requests.sessions.Session.request")
This autouse fixture will be executed for each test function and it
will delete the method ``request.session.Session.request``

View File

@@ -25,6 +25,7 @@ Supported nose Idioms
* SkipTest exceptions and markers
* setup/teardown decorators
* yield-based tests and their setup
* ``__test__`` attribute on modules/classes/functions
* general usage of nose utilities
Unsupported idioms / known issues

View File

@@ -53,7 +53,7 @@ them in turn::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 3 items
test_expectation.py ..F
@@ -100,12 +100,12 @@ Let's run this::
$ py.test
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 3 items
test_expectation.py ..x
=================== 2 passed, 1 xfailed in 0.01 seconds ====================
=================== 2 passed, 1 xfailed in 0.02 seconds ====================
The one parameter set which caused a failure previously now
shows up as an "xfailed (expected to fail)" test.
@@ -170,8 +170,8 @@ Let's also run with a stringinput that will lead to a failing test::
def test_valid_string(stringinput):
> assert stringinput.isalpha()
E assert <built-in method isalpha of str object at 0x2b869b32b148>()
E + where <built-in method isalpha of str object at 0x2b869b32b148> = '!'.isalpha
E assert <built-in method isalpha of str object at 0x2b1c6de5bb20>()
E + where <built-in method isalpha of str object at 0x2b1c6de5bb20> = '!'.isalpha
test_strings.py:3: AssertionError
1 failed in 0.01 seconds
@@ -185,7 +185,7 @@ listlist::
$ py.test -q -rs test_strings.py
s
========================= short test summary info ==========================
SKIP [1] /home/hpk/p/pytest/.tox/regen/local/lib/python2.7/site-packages/_pytest/python.py:1110: got empty parameter set, function test_valid_string at /tmp/doc-exec-24/test_strings.py:1
SKIP [1] /home/hpk/p/pytest/.tox/regen/lib/python3.4/site-packages/_pytest/python.py:1139: got empty parameter set, function test_valid_string at /tmp/doc-exec-180/test_strings.py:1
1 skipped in 0.01 seconds
For further examples, you might want to look at :ref:`more

View File

@@ -64,9 +64,10 @@ tool, for example::
pip uninstall pytest-NAME
If a plugin is installed, ``pytest`` automatically finds and integrates it,
there is no need to activate it. We have a :doc:`beta page listing
all 3rd party plugins and their status <plugins_index/index>` and here
is a little annotated list for some popular plugins:
there is no need to activate it. We have a :doc:`page listing
all 3rd party plugins and their status against the latest py.test version
<plugins_index/index>` and here is a little annotated list
for some popular plugins:
.. _`django`: https://www.djangoproject.com/
@@ -109,7 +110,11 @@ is a little annotated list for some popular plugins:
* `oejskit <http://pypi.python.org/pypi/oejskit>`_:
a plugin to run javascript unittests in life browsers
You may discover more plugins through a `pytest- pypi.python.org search`_.
To see a complete list of all plugins with their latest testing
status against different py.test and Python versions, please visit
`pytest-plugs <http://pytest-plugs.herokuapp.com/>`_.
You may also discover more plugins through a `pytest- pypi.python.org search`_.
.. _`available installable plugins`:
.. _`pytest- pypi.python.org search`: http://pypi.python.org/pypi?%3Aaction=search&term=pytest-&submit=search
@@ -304,6 +309,7 @@ Initialization, command line and configuration hooks
.. currentmodule:: _pytest.hookspec
.. autofunction:: pytest_load_initial_conftests
.. autofunction:: pytest_cmdline_preparse
.. autofunction:: pytest_cmdline_parse
.. autofunction:: pytest_namespace
@@ -315,7 +321,7 @@ Initialization, command line and configuration hooks
Generic "runtest" hooks
------------------------------
All all runtest related hooks receive a :py:class:`pytest.Item` object.
All runtest related hooks receive a :py:class:`pytest.Item` object.
.. autofunction:: pytest_runtest_protocol
.. autofunction:: pytest_runtest_setup

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

View File

@@ -3,110 +3,163 @@
List of Third-Party Plugins
===========================
========================================================================================== ======================================================================================================== ======================================================================================================== ============================================================= =============================================================================================================================================
Name Py27 Py33 Repository Summary
========================================================================================== ======================================================================================================== ======================================================================================================== ============================================================= =============================================================================================================================================
`pytest-bdd-0.6.8 <http://pypi.python.org/pypi/pytest-bdd/0.6.8>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bdd-0.6.8?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bdd-0.6.8?py=py33&pytest=2.5.1 https://github.com/olegpidsadnyi/pytest-bdd BDD for pytest
:target: http://pytest-plugs.herokuapp.com/output/pytest-bdd-0.6.8?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-bdd-0.6.8?py=py33&pytest=2.5.1
`pytest-bdd-splinter-0.5.98 <http://pypi.python.org/pypi/pytest-bdd-splinter/0.5.98>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bdd-splinter-0.5.98?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bdd-splinter-0.5.98?py=py33&pytest=2.5.1 https://github.com/olegpidsadnyi/pytest-bdd-splinter Splinter subplugin for Pytest BDD plugin
:target: http://pytest-plugs.herokuapp.com/output/pytest-bdd-splinter-0.5.98?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-bdd-splinter-0.5.98?py=py33&pytest=2.5.1
`pytest-bench-0.2.5 <http://pypi.python.org/pypi/pytest-bench/0.2.5>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bench-0.2.5?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bench-0.2.5?py=py33&pytest=2.5.1 http://github.com/concordusapps/pytest-bench Benchmark utility that plugs into pytest.
:target: http://pytest-plugs.herokuapp.com/output/pytest-bench-0.2.5?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-bench-0.2.5?py=py33&pytest=2.5.1
`pytest-blockage-0.1 <http://pypi.python.org/pypi/pytest-blockage/0.1>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-blockage-0.1?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-blockage-0.1?py=py33&pytest=2.5.1 https://github.com/rob-b/pytest-blockage Disable network requests during a test run.
:target: http://pytest-plugs.herokuapp.com/output/pytest-blockage-0.1?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-blockage-0.1?py=py33&pytest=2.5.1
`pytest-browsermob-proxy-0.1 <http://pypi.python.org/pypi/pytest-browsermob-proxy/0.1>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-browsermob-proxy-0.1?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-browsermob-proxy-0.1?py=py33&pytest=2.5.1 https://github.com/davehunt/pytest-browsermob-proxy BrowserMob proxy plugin for py.test.
:target: http://pytest-plugs.herokuapp.com/output/pytest-browsermob-proxy-0.1?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-browsermob-proxy-0.1?py=py33&pytest=2.5.1
`pytest-bugzilla-0.2 <http://pypi.python.org/pypi/pytest-bugzilla/0.2>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bugzilla-0.2?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bugzilla-0.2?py=py33&pytest=2.5.1 http://github.com/nibrahim/pytest_bugzilla py.test bugzilla integration plugin
:target: http://pytest-plugs.herokuapp.com/output/pytest-bugzilla-0.2?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-bugzilla-0.2?py=py33&pytest=2.5.1
`pytest-cache-1.0 <http://pypi.python.org/pypi/pytest-cache/1.0>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cache-1.0?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cache-1.0?py=py33&pytest=2.5.1 http://bitbucket.org/hpk42/pytest-cache/ pytest plugin with mechanisms for caching across test runs
:target: http://pytest-plugs.herokuapp.com/output/pytest-cache-1.0?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-cache-1.0?py=py33&pytest=2.5.1
`pytest-capturelog-0.7 <http://pypi.python.org/pypi/pytest-capturelog/0.7>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-capturelog-0.7?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-capturelog-0.7?py=py33&pytest=2.5.1 http://bitbucket.org/memedough/pytest-capturelog/overview py.test plugin to capture log messages
:target: http://pytest-plugs.herokuapp.com/output/pytest-capturelog-0.7?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-capturelog-0.7?py=py33&pytest=2.5.1
`pytest-codecheckers-0.2 <http://pypi.python.org/pypi/pytest-codecheckers/0.2>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-codecheckers-0.2?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-codecheckers-0.2?py=py33&pytest=2.5.1 http://bitbucket.org/RonnyPfannschmidt/pytest-codecheckers/ pytest plugin to add source code sanity checks (pep8 and friends)
:target: http://pytest-plugs.herokuapp.com/output/pytest-codecheckers-0.2?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-codecheckers-0.2?py=py33&pytest=2.5.1
`pytest-contextfixture-0.1.1 <http://pypi.python.org/pypi/pytest-contextfixture/0.1.1>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-contextfixture-0.1.1?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-contextfixture-0.1.1?py=py33&pytest=2.5.1 http://github.com/pelme/pytest-contextfixture/ Define pytest fixtures as context managers.
:target: http://pytest-plugs.herokuapp.com/output/pytest-contextfixture-0.1.1?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-contextfixture-0.1.1?py=py33&pytest=2.5.1
`pytest-couchdbkit-0.5.1 <http://pypi.python.org/pypi/pytest-couchdbkit/0.5.1>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-couchdbkit-0.5.1?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-couchdbkit-0.5.1?py=py33&pytest=2.5.1 http://bitbucket.org/RonnyPfannschmidt/pytest-couchdbkit py.test extension for per-test couchdb databases using couchdbkit
:target: http://pytest-plugs.herokuapp.com/output/pytest-couchdbkit-0.5.1?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-couchdbkit-0.5.1?py=py33&pytest=2.5.1
`pytest-cov-1.6 <http://pypi.python.org/pypi/pytest-cov/1.6>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cov-1.6?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cov-1.6?py=py33&pytest=2.5.1 http://bitbucket.org/memedough/pytest-cov/overview py.test plugin for coverage reporting with support for both centralised and distributed testing, including subprocesses and multiprocessing
:target: http://pytest-plugs.herokuapp.com/output/pytest-cov-1.6?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-cov-1.6?py=py33&pytest=2.5.1
`pytest-dbfixtures-0.4.3 <http://pypi.python.org/pypi/pytest-dbfixtures/0.4.3>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-dbfixtures-0.4.3?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-dbfixtures-0.4.3?py=py33&pytest=2.5.1 https://github.com/clearcode/pytest-dbfixtures dbfixtures plugin for py.test.
:target: http://pytest-plugs.herokuapp.com/output/pytest-dbfixtures-0.4.3?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-dbfixtures-0.4.3?py=py33&pytest=2.5.1
`pytest-django-2.5 <http://pypi.python.org/pypi/pytest-django/2.5>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-2.5?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-2.5?py=py33&pytest=2.5.1 http://pytest-django.readthedocs.org/ A Django plugin for py.test.
:target: http://pytest-plugs.herokuapp.com/output/pytest-django-2.5?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-django-2.5?py=py33&pytest=2.5.1
`pytest-django-lite-0.1.0 <http://pypi.python.org/pypi/pytest-django-lite/0.1.0>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-lite-0.1.0?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-lite-0.1.0?py=py33&pytest=2.5.1 UNKNOWN The bare minimum to integrate py.test with Django.
:target: http://pytest-plugs.herokuapp.com/output/pytest-django-lite-0.1.0?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-django-lite-0.1.0?py=py33&pytest=2.5.1
`pytest-figleaf-1.0 <http://pypi.python.org/pypi/pytest-figleaf/1.0>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-figleaf-1.0?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-figleaf-1.0?py=py33&pytest=2.5.1 http://bitbucket.org/hpk42/pytest-figleaf py.test figleaf coverage plugin
:target: http://pytest-plugs.herokuapp.com/output/pytest-figleaf-1.0?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-figleaf-1.0?py=py33&pytest=2.5.1
`pytest-flakes-0.2 <http://pypi.python.org/pypi/pytest-flakes/0.2>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-flakes-0.2?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-flakes-0.2?py=py33&pytest=2.5.1 https://github.com/fschulze/pytest-flakes pytest plugin to check source code with pyflakes
:target: http://pytest-plugs.herokuapp.com/output/pytest-flakes-0.2?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-flakes-0.2?py=py33&pytest=2.5.1
`pytest-greendots-0.2 <http://pypi.python.org/pypi/pytest-greendots/0.2>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-greendots-0.2?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-greendots-0.2?py=py33&pytest=2.5.1 UNKNOWN Green progress dots
:target: http://pytest-plugs.herokuapp.com/output/pytest-greendots-0.2?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-greendots-0.2?py=py33&pytest=2.5.1
`pytest-growl-0.2 <http://pypi.python.org/pypi/pytest-growl/0.2>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-growl-0.2?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-growl-0.2?py=py33&pytest=2.5.1 UNKNOWN Growl notifications for pytest results.
:target: http://pytest-plugs.herokuapp.com/output/pytest-growl-0.2?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-growl-0.2?py=py33&pytest=2.5.1
`pytest-incremental-0.3.0 <http://pypi.python.org/pypi/pytest-incremental/0.3.0>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-incremental-0.3.0?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-incremental-0.3.0?py=py33&pytest=2.5.1 https://bitbucket.org/schettino72/pytest-incremental an incremental test runner (pytest plugin)
:target: http://pytest-plugs.herokuapp.com/output/pytest-incremental-0.3.0?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-incremental-0.3.0?py=py33&pytest=2.5.1
`pytest-instafail-0.1.1 <http://pypi.python.org/pypi/pytest-instafail/0.1.1>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-instafail-0.1.1?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-instafail-0.1.1?py=py33&pytest=2.5.1 https://github.com/jpvanhal/pytest-instafail py.test plugin to show failures instantly
:target: http://pytest-plugs.herokuapp.com/output/pytest-instafail-0.1.1?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-instafail-0.1.1?py=py33&pytest=2.5.1
`pytest-ipdb-0.1-prerelease <http://pypi.python.org/pypi/pytest-ipdb/0.1-prerelease>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-ipdb-0.1-prerelease?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-ipdb-0.1-prerelease?py=py33&pytest=2.5.1 https://github.com/mverteuil/pytest-ipdb A py.test plug-in to enable drop to ipdb debugger on test failure.
:target: http://pytest-plugs.herokuapp.com/output/pytest-ipdb-0.1-prerelease?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-ipdb-0.1-prerelease?py=py33&pytest=2.5.1
`pytest-jira-0.01 <http://pypi.python.org/pypi/pytest-jira/0.01>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-jira-0.01?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-jira-0.01?py=py33&pytest=2.5.1 http://github.com/jlaska/pytest_jira py.test JIRA integration plugin, using markers
:target: http://pytest-plugs.herokuapp.com/output/pytest-jira-0.01?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-jira-0.01?py=py33&pytest=2.5.1
`pytest-konira-0.2 <http://pypi.python.org/pypi/pytest-konira/0.2>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-konira-0.2?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-konira-0.2?py=py33&pytest=2.5.1 http://github.com/alfredodeza/pytest-konira Run Konira DSL tests with py.test
:target: http://pytest-plugs.herokuapp.com/output/pytest-konira-0.2?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-konira-0.2?py=py33&pytest=2.5.1
`pytest-localserver-0.3.2 <http://pypi.python.org/pypi/pytest-localserver/0.3.2>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-localserver-0.3.2?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-localserver-0.3.2?py=py33&pytest=2.5.1 http://bitbucket.org/basti/pytest-localserver/ py.test plugin to test server connections locally.
:target: http://pytest-plugs.herokuapp.com/output/pytest-localserver-0.3.2?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-localserver-0.3.2?py=py33&pytest=2.5.1
`pytest-marker-bugzilla-0.06 <http://pypi.python.org/pypi/pytest-marker-bugzilla/0.06>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-marker-bugzilla-0.06?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-marker-bugzilla-0.06?py=py33&pytest=2.5.1 http://github.com/eanxgeek/pytest_marker_bugzilla py.test bugzilla integration plugin, using markers
:target: http://pytest-plugs.herokuapp.com/output/pytest-marker-bugzilla-0.06?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-marker-bugzilla-0.06?py=py33&pytest=2.5.1
`pytest-markfiltration-0.8 <http://pypi.python.org/pypi/pytest-markfiltration/0.8>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-markfiltration-0.8?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-markfiltration-0.8?py=py33&pytest=2.5.1 https://github.com/adamgoucher/pytest-markfiltration UNKNOWN
:target: http://pytest-plugs.herokuapp.com/output/pytest-markfiltration-0.8?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-markfiltration-0.8?py=py33&pytest=2.5.1
`pytest-marks-0.4 <http://pypi.python.org/pypi/pytest-marks/0.4>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-marks-0.4?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-marks-0.4?py=py33&pytest=2.5.1 https://github.com/adamgoucher/pytest-marks UNKNOWN
:target: http://pytest-plugs.herokuapp.com/output/pytest-marks-0.4?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-marks-0.4?py=py33&pytest=2.5.1
`pytest-monkeyplus-1.1.0 <http://pypi.python.org/pypi/pytest-monkeyplus/1.1.0>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-monkeyplus-1.1.0?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-monkeyplus-1.1.0?py=py33&pytest=2.5.1 http://bitbucket.org/hsoft/pytest-monkeyplus/ pytest's monkeypatch subclass with extra functionalities
:target: http://pytest-plugs.herokuapp.com/output/pytest-monkeyplus-1.1.0?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-monkeyplus-1.1.0?py=py33&pytest=2.5.1
`pytest-mozwebqa-1.1.1 <http://pypi.python.org/pypi/pytest-mozwebqa/1.1.1>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-mozwebqa-1.1.1?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-mozwebqa-1.1.1?py=py33&pytest=2.5.1 https://github.com/davehunt/pytest-mozwebqa Mozilla WebQA plugin for py.test.
:target: http://pytest-plugs.herokuapp.com/output/pytest-mozwebqa-1.1.1?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-mozwebqa-1.1.1?py=py33&pytest=2.5.1
`pytest-oerp-0.2.0 <http://pypi.python.org/pypi/pytest-oerp/0.2.0>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-oerp-0.2.0?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-oerp-0.2.0?py=py33&pytest=2.5.1 http://github.com/santagada/pytest-oerp/ pytest plugin to test OpenERP modules
:target: http://pytest-plugs.herokuapp.com/output/pytest-oerp-0.2.0?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-oerp-0.2.0?py=py33&pytest=2.5.1
`pytest-osxnotify-0.1.4 <http://pypi.python.org/pypi/pytest-osxnotify/0.1.4>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-osxnotify-0.1.4?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-osxnotify-0.1.4?py=py33&pytest=2.5.1 https://github.com/dbader/pytest-osxnotify OS X notifications for py.test results.
:target: http://pytest-plugs.herokuapp.com/output/pytest-osxnotify-0.1.4?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-osxnotify-0.1.4?py=py33&pytest=2.5.1
`pytest-paste-config-0.1 <http://pypi.python.org/pypi/pytest-paste-config/0.1>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-paste-config-0.1?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-paste-config-0.1?py=py33&pytest=2.5.1 UNKNOWN Allow setting the path to a paste config file
:target: http://pytest-plugs.herokuapp.com/output/pytest-paste-config-0.1?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-paste-config-0.1?py=py33&pytest=2.5.1
`pytest-pep8-1.0.5 <http://pypi.python.org/pypi/pytest-pep8/1.0.5>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pep8-1.0.5?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pep8-1.0.5?py=py33&pytest=2.5.1 http://bitbucket.org/hpk42/pytest-pep8/ pytest plugin to check PEP8 requirements
:target: http://pytest-plugs.herokuapp.com/output/pytest-pep8-1.0.5?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-pep8-1.0.5?py=py33&pytest=2.5.1
`pytest-poo-0.2 <http://pypi.python.org/pypi/pytest-poo/0.2>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-poo-0.2?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-poo-0.2?py=py33&pytest=2.5.1 http://github.com/pelme/pytest-poo Visualize your crappy tests
:target: http://pytest-plugs.herokuapp.com/output/pytest-poo-0.2?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-poo-0.2?py=py33&pytest=2.5.1
`pytest-pydev-0.1 <http://pypi.python.org/pypi/pytest-pydev/0.1>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pydev-0.1?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pydev-0.1?py=py33&pytest=2.5.1 http://bitbucket.org/basti/pytest-pydev/ py.test plugin to connect to a remote debug server with PyDev or PyCharm.
:target: http://pytest-plugs.herokuapp.com/output/pytest-pydev-0.1?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-pydev-0.1?py=py33&pytest=2.5.1
`pytest-qt-1.0.2 <http://pypi.python.org/pypi/pytest-qt/1.0.2>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-qt-1.0.2?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-qt-1.0.2?py=py33&pytest=2.5.1 http://github.com/nicoddemus/pytest-qt pytest plugin that adds fixtures for testing Qt (PyQt and PySide) applications.
:target: http://pytest-plugs.herokuapp.com/output/pytest-qt-1.0.2?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-qt-1.0.2?py=py33&pytest=2.5.1
`pytest-quickcheck-0.8 <http://pypi.python.org/pypi/pytest-quickcheck/0.8>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-quickcheck-0.8?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-quickcheck-0.8?py=py33&pytest=2.5.1 http://bitbucket.org/t2y/pytest-quickcheck/ pytest plugin to generate random data inspired by QuickCheck
:target: http://pytest-plugs.herokuapp.com/output/pytest-quickcheck-0.8?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-quickcheck-0.8?py=py33&pytest=2.5.1
`pytest-rage-0.1 <http://pypi.python.org/pypi/pytest-rage/0.1>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-rage-0.1?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-rage-0.1?py=py33&pytest=2.5.1 http://github.com/santagada/pytest-rage/ pytest plugin to implement PEP712
:target: http://pytest-plugs.herokuapp.com/output/pytest-rage-0.1?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-rage-0.1?py=py33&pytest=2.5.1
`pytest-random-0.02 <http://pypi.python.org/pypi/pytest-random/0.02>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-random-0.02?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-random-0.02?py=py33&pytest=2.5.1 https://github.com/klrmn/pytest-random py.test plugin to randomize tests
:target: http://pytest-plugs.herokuapp.com/output/pytest-random-0.02?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-random-0.02?py=py33&pytest=2.5.1
`pytest-rerunfailures-0.03 <http://pypi.python.org/pypi/pytest-rerunfailures/0.03>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-rerunfailures-0.03?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-rerunfailures-0.03?py=py33&pytest=2.5.1 https://github.com/klrmn/pytest-rerunfailures py.test plugin to re-run tests to eliminate flakey failures
:target: http://pytest-plugs.herokuapp.com/output/pytest-rerunfailures-0.03?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-rerunfailures-0.03?py=py33&pytest=2.5.1
`pytest-runfailed-0.3 <http://pypi.python.org/pypi/pytest-runfailed/0.3>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-runfailed-0.3?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-runfailed-0.3?py=py33&pytest=2.5.1 http://github.com/dmerejkowsky/pytest-runfailed implement a --failed option for pytest
:target: http://pytest-plugs.herokuapp.com/output/pytest-runfailed-0.3?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-runfailed-0.3?py=py33&pytest=2.5.1
`pytest-runner-2.0 <http://pypi.python.org/pypi/pytest-runner/2.0>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-runner-2.0?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-runner-2.0?py=py33&pytest=2.5.1 https://bitbucket.org/jaraco/pytest-runner UNKNOWN
:target: http://pytest-plugs.herokuapp.com/output/pytest-runner-2.0?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-runner-2.0?py=py33&pytest=2.5.1
`pytest-sugar-0.2.2 <http://pypi.python.org/pypi/pytest-sugar/0.2.2>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-sugar-0.2.2?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-sugar-0.2.2?py=py33&pytest=2.5.1 http://pivotfinland.com/pytest-sugar/ py.test plugin that adds instafail, ETA and neat graphics
:target: http://pytest-plugs.herokuapp.com/output/pytest-sugar-0.2.2?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-sugar-0.2.2?py=py33&pytest=2.5.1
`pytest-timeout-0.3 <http://pypi.python.org/pypi/pytest-timeout/0.3>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-timeout-0.3?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-timeout-0.3?py=py33&pytest=2.5.1 http://bitbucket.org/flub/pytest-timeout/ pytest plugin to abort tests after a timeout
:target: http://pytest-plugs.herokuapp.com/output/pytest-timeout-0.3?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-timeout-0.3?py=py33&pytest=2.5.1
`pytest-twisted-1.4 <http://pypi.python.org/pypi/pytest-twisted/1.4>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-twisted-1.4?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-twisted-1.4?py=py33&pytest=2.5.1 https://github.com/schmir/pytest-twisted A twisted plugin for py.test.
:target: http://pytest-plugs.herokuapp.com/output/pytest-twisted-1.4?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-twisted-1.4?py=py33&pytest=2.5.1
`pytest-xdist-1.9 <http://pypi.python.org/pypi/pytest-xdist/1.9>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-xdist-1.9?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-xdist-1.9?py=py33&pytest=2.5.1 http://bitbucket.org/hpk42/pytest-xdist py.test xdist plugin for distributed testing and loop-on-failing modes
:target: http://pytest-plugs.herokuapp.com/output/pytest-xdist-1.9?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-xdist-1.9?py=py33&pytest=2.5.1
`pytest-xprocess-0.8 <http://pypi.python.org/pypi/pytest-xprocess/0.8>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-xprocess-0.8?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-xprocess-0.8?py=py33&pytest=2.5.1 http://bitbucket.org/hpk42/pytest-xprocess/ pytest plugin to manage external processes across test runs
:target: http://pytest-plugs.herokuapp.com/output/pytest-xprocess-0.8?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-xprocess-0.8?py=py33&pytest=2.5.1
`pytest-yamlwsgi-0.6 <http://pypi.python.org/pypi/pytest-yamlwsgi/0.6>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-yamlwsgi-0.6?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-yamlwsgi-0.6?py=py33&pytest=2.5.1 UNKNOWN Run tests against wsgi apps defined in yaml
:target: http://pytest-plugs.herokuapp.com/output/pytest-yamlwsgi-0.6?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-yamlwsgi-0.6?py=py33&pytest=2.5.1
`pytest-zap-0.1 <http://pypi.python.org/pypi/pytest-zap/0.1>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-zap-0.1?py=py27&pytest=2.5.1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-zap-0.1?py=py33&pytest=2.5.1 https://github.com/davehunt/pytest-zap OWASP ZAP plugin for py.test.
:target: http://pytest-plugs.herokuapp.com/output/pytest-zap-0.1?py=py27&pytest=2.5.1 :target: http://pytest-plugs.herokuapp.com/output/pytest-zap-0.1?py=py33&pytest=2.5.1
The table below contains a listing of plugins found in PyPI and
their status when tested using py.test **2.6.2.dev1** and python 2.7 and
3.3.
========================================================================================== ======================================================================================================== ======================================================================================================== ============================================================= =============================================================================================================================================
A complete listing can also be found at
`pytest-plugs <http://pytest-plugs.herokuapp.com/>`_, which contains tests
status against other py.test releases.
*(Updated on 2014-01-15)*
========================================================================================== ================================================================================================================= ================================================================================================================= ======================================================================================== =============================================================================================================================================
Name Py27 Py34 Repo Summary
========================================================================================== ================================================================================================================= ================================================================================================================= ======================================================================================== =============================================================================================================================================
`pytest-allure-adaptor-1.4.0 <http://pypi.python.org/pypi/pytest-allure-adaptor>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-allure-adaptor-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-allure-adaptor-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Plugin for py.test to generate allure xml reports
:target: http://pytest-plugs.herokuapp.com/output/pytest-allure-adaptor-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-allure-adaptor-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/allure-framework/allure-python
`pytest-bdd-2.3.1 <http://pypi.python.org/pypi/pytest-bdd>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bdd-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bdd-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png BDD for pytest
:target: http://pytest-plugs.herokuapp.com/output/pytest-bdd-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-bdd-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/olegpidsadnyi/pytest-bdd
`pytest-beds-0.0.1 <http://pypi.python.org/pypi/pytest-beds>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-beds-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-beds-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Fixtures for testing Google Appengine (GAE) apps
:target: http://pytest-plugs.herokuapp.com/output/pytest-beds-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-beds-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/kaste/pytest-beds
`pytest-bench-0.3.0 <http://pypi.python.org/pypi/pytest-bench>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bench-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bench-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Benchmark utility that plugs into pytest.
:target: http://pytest-plugs.herokuapp.com/output/pytest-bench-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-bench-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/concordusapps/pytest-bench
`pytest-blockage-0.1 <http://pypi.python.org/pypi/pytest-blockage>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-blockage-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-blockage-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Disable network requests during a test run.
:target: http://pytest-plugs.herokuapp.com/output/pytest-blockage-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-blockage-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/rob-b/pytest-blockage
`pytest-browsermob-proxy-0.1 <http://pypi.python.org/pypi/pytest-browsermob-proxy>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-browsermob-proxy-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-browsermob-proxy-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png BrowserMob proxy plugin for py.test.
:target: http://pytest-plugs.herokuapp.com/output/pytest-browsermob-proxy-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-browsermob-proxy-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/davehunt/pytest-browsermob-proxy
`pytest-bugzilla-0.2 <http://pypi.python.org/pypi/pytest-bugzilla>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bugzilla-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-bugzilla-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png py.test bugzilla integration plugin
:target: http://pytest-plugs.herokuapp.com/output/pytest-bugzilla-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-bugzilla-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/nibrahim/pytest_bugzilla
`pytest-cache-1.0 <http://pypi.python.org/pypi/pytest-cache>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cache-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cache-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png pytest plugin with mechanisms for caching across test runs
:target: http://pytest-plugs.herokuapp.com/output/pytest-cache-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-cache-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/hpk42/pytest-cache/
`pytest-capturelog-0.7 <http://pypi.python.org/pypi/pytest-capturelog>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-capturelog-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-capturelog-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png py.test plugin to capture log messages
:target: http://pytest-plugs.herokuapp.com/output/pytest-capturelog-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-capturelog-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/memedough/pytest-capturelog/overview
`pytest-codecheckers-0.2 <http://pypi.python.org/pypi/pytest-codecheckers>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-codecheckers-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-codecheckers-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png pytest plugin to add source code sanity checks (pep8 and friends)
:target: http://pytest-plugs.herokuapp.com/output/pytest-codecheckers-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-codecheckers-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/RonnyPfannschmidt/pytest-codecheckers/
`pytest-config-0.0.10 <http://pypi.python.org/pypi/pytest-config>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-config-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-config-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Base configurations and utilities for developing your Python project test suite with pytest.
:target: http://pytest-plugs.herokuapp.com/output/pytest-config-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-config-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/buzzfeed/pytest_config
`pytest-contextfixture-0.1.1 <http://pypi.python.org/pypi/pytest-contextfixture>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-contextfixture-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-contextfixture-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Define pytest fixtures as context managers.
:target: http://pytest-plugs.herokuapp.com/output/pytest-contextfixture-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-contextfixture-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/pelme/pytest-contextfixture/
`pytest-couchdbkit-0.5.1 <http://pypi.python.org/pypi/pytest-couchdbkit>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-couchdbkit-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-couchdbkit-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png py.test extension for per-test couchdb databases using couchdbkit
:target: http://pytest-plugs.herokuapp.com/output/pytest-couchdbkit-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-couchdbkit-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/RonnyPfannschmidt/pytest-couchdbkit
`pytest-cov-1.8.0 <http://pypi.python.org/pypi/pytest-cov>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cov-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cov-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png py.test plugin for coverage reporting with support for both centralised and distributed testing, including subprocesses and multiprocessing
:target: http://pytest-plugs.herokuapp.com/output/pytest-cov-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-cov-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/schlamar/pytest-cov
`pytest-cpp-0.3.0 <http://pypi.python.org/pypi/pytest-cpp>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cpp-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-cpp-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Use pytest's runner to discover and execute C++ tests
:target: http://pytest-plugs.herokuapp.com/output/pytest-cpp-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-cpp-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/nicoddemus/pytest-cpp
`pytest-dbfixtures-0.5.1 <http://pypi.python.org/pypi/pytest-dbfixtures>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-dbfixtures-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-dbfixtures-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Databases fixtures plugin for py.test.
:target: http://pytest-plugs.herokuapp.com/output/pytest-dbfixtures-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-dbfixtures-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/ClearcodeHQ/pytest-dbfixtures
`pytest-dbus-notification-1.0.1 <http://pypi.python.org/pypi/pytest-dbus-notification>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-dbus-notification-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-dbus-notification-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png D-BUS notifications for pytest results.
:target: http://pytest-plugs.herokuapp.com/output/pytest-dbus-notification-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-dbus-notification-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/bmathieu33/pytest-dbus-notification
`pytest-diffeo-0.1.8.dev1 <http://pypi.python.org/pypi/pytest-diffeo>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-diffeo-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-diffeo-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Common py.test support for Diffeo packages
:target: http://pytest-plugs.herokuapp.com/output/pytest-diffeo-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-diffeo-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/diffeo/pytest-diffeo
`pytest-django-2.6.2 <http://pypi.python.org/pypi/pytest-django>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-latest?py=py34&pytest=2.6.2.dev1 `http://pytest-django.readthedocs.org/ <http://pytest-django.readthedocs.org/>`_ A Django plugin for py.test.
:target: http://pytest-plugs.herokuapp.com/output/pytest-django-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-django-latest?py=py34&pytest=2.6.2.dev1
`pytest-django-haystack-0.1.1 <http://pypi.python.org/pypi/pytest-django-haystack>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-haystack-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-haystack-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Cleanup your Haystack indexes between tests
:target: http://pytest-plugs.herokuapp.com/output/pytest-django-haystack-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-django-haystack-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/rouge8/pytest-django-haystack
`pytest-django-lite-0.1.1 <http://pypi.python.org/pypi/pytest-django-lite>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-lite-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-django-lite-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png The bare minimum to integrate py.test with Django.
:target: http://pytest-plugs.herokuapp.com/output/pytest-django-lite-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-django-lite-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/dcramer/pytest-django-lite
`pytest-echo-1.3 <http://pypi.python.org/pypi/pytest-echo>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-echo-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-echo-latest?py=py34&pytest=2.6.2.dev1 `http://pypi.python.org/pypi/pytest-echo/ <http://pypi.python.org/pypi/pytest-echo/>`_ pytest plugin with mechanisms for echoing environment variables, package version and generic attributes
:target: http://pytest-plugs.herokuapp.com/output/pytest-echo-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-echo-latest?py=py34&pytest=2.6.2.dev1
`pytest-eradicate-0.0.2 <http://pypi.python.org/pypi/pytest-eradicate>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-eradicate-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-eradicate-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png pytest plugin to check for commented out code
:target: http://pytest-plugs.herokuapp.com/output/pytest-eradicate-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-eradicate-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/spil-johan/pytest-eradicate
`pytest-figleaf-1.0 <http://pypi.python.org/pypi/pytest-figleaf>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-figleaf-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-figleaf-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png py.test figleaf coverage plugin
:target: http://pytest-plugs.herokuapp.com/output/pytest-figleaf-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-figleaf-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/hpk42/pytest-figleaf
`pytest-fixture-tools-1.0.0 <http://pypi.python.org/pypi/pytest-fixture-tools>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-fixture-tools-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-fixture-tools-latest?py=py34&pytest=2.6.2.dev1 ? Plugin for pytest which provides tools for fixtures
:target: http://pytest-plugs.herokuapp.com/output/pytest-fixture-tools-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-fixture-tools-latest?py=py34&pytest=2.6.2.dev1
`pytest-flakes-0.2 <http://pypi.python.org/pypi/pytest-flakes>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-flakes-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-flakes-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png pytest plugin to check source code with pyflakes
:target: http://pytest-plugs.herokuapp.com/output/pytest-flakes-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-flakes-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/fschulze/pytest-flakes
`pytest-greendots-0.3 <http://pypi.python.org/pypi/pytest-greendots>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-greendots-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-greendots-latest?py=py34&pytest=2.6.2.dev1 ? Green progress dots
:target: http://pytest-plugs.herokuapp.com/output/pytest-greendots-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-greendots-latest?py=py34&pytest=2.6.2.dev1
`pytest-growl-0.2 <http://pypi.python.org/pypi/pytest-growl>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-growl-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-growl-latest?py=py34&pytest=2.6.2.dev1 ? Growl notifications for pytest results.
:target: http://pytest-plugs.herokuapp.com/output/pytest-growl-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-growl-latest?py=py34&pytest=2.6.2.dev1
`pytest-httpbin-0.0.2 <http://pypi.python.org/pypi/pytest-httpbin>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-httpbin-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-httpbin-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Easily test your HTTP library against a local copy of httpbin
:target: http://pytest-plugs.herokuapp.com/output/pytest-httpbin-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-httpbin-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/kevin1024/pytest-httpbin
`pytest-httpretty-0.2.0 <http://pypi.python.org/pypi/pytest-httpretty>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-httpretty-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-httpretty-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png A thin wrapper of HTTPretty for pytest
:target: http://pytest-plugs.herokuapp.com/output/pytest-httpretty-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-httpretty-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/papaeye/pytest-httpretty
`pytest-incremental-0.3.0 <http://pypi.python.org/pypi/pytest-incremental>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-incremental-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-incremental-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png an incremental test runner (pytest plugin)
:target: http://pytest-plugs.herokuapp.com/output/pytest-incremental-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-incremental-latest?py=py34&pytest=2.6.2.dev1 :target: https://bitbucket.org/schettino72/pytest-incremental
`pytest-instafail-0.2.0 <http://pypi.python.org/pypi/pytest-instafail>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-instafail-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-instafail-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png py.test plugin to show failures instantly
:target: http://pytest-plugs.herokuapp.com/output/pytest-instafail-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-instafail-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/jpvanhal/pytest-instafail
`pytest-ipdb-0.1-prerelease <http://pypi.python.org/pypi/pytest-ipdb>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-ipdb-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-ipdb-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png A py.test plug-in to enable drop to ipdb debugger on test failure.
:target: http://pytest-plugs.herokuapp.com/output/pytest-ipdb-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-ipdb-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/mverteuil/pytest-ipdb
`pytest-jira-0.01 <http://pypi.python.org/pypi/pytest-jira>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-jira-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-jira-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png py.test JIRA integration plugin, using markers
:target: http://pytest-plugs.herokuapp.com/output/pytest-jira-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-jira-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/jlaska/pytest_jira
`pytest-knows-0.1.5 <http://pypi.python.org/pypi/pytest-knows>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-knows-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-knows-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png A pytest plugin that can automaticly skip test case based on dependence info calculated by trace
:target: http://pytest-plugs.herokuapp.com/output/pytest-knows-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-knows-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/mapix/ptknows
`pytest-konira-0.2 <http://pypi.python.org/pypi/pytest-konira>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-konira-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-konira-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Run Konira DSL tests with py.test
:target: http://pytest-plugs.herokuapp.com/output/pytest-konira-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-konira-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/alfredodeza/pytest-konira
`pytest-localserver-0.3.2 <http://pypi.python.org/pypi/pytest-localserver>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-localserver-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-localserver-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png py.test plugin to test server connections locally.
:target: http://pytest-plugs.herokuapp.com/output/pytest-localserver-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-localserver-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/basti/pytest-localserver/
`pytest-marker-bugzilla-0.06 <http://pypi.python.org/pypi/pytest-marker-bugzilla>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-marker-bugzilla-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-marker-bugzilla-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png py.test bugzilla integration plugin, using markers
:target: http://pytest-plugs.herokuapp.com/output/pytest-marker-bugzilla-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-marker-bugzilla-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/eanxgeek/pytest_marker_bugzilla
`pytest-markfiltration-0.8 <http://pypi.python.org/pypi/pytest-markfiltration>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-markfiltration-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-markfiltration-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png UNKNOWN
:target: http://pytest-plugs.herokuapp.com/output/pytest-markfiltration-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-markfiltration-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/adamgoucher/pytest-markfiltration
`pytest-marks-0.4 <http://pypi.python.org/pypi/pytest-marks>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-marks-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-marks-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png UNKNOWN
:target: http://pytest-plugs.herokuapp.com/output/pytest-marks-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-marks-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/adamgoucher/pytest-marks
`pytest-mock-0.3.0 <http://pypi.python.org/pypi/pytest-mock>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-mock-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-mock-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Thin-wrapper around the mock package for easier use with py.test
:target: http://pytest-plugs.herokuapp.com/output/pytest-mock-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-mock-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/nicoddemus/pytest-mock/
`pytest-monkeyplus-1.1.0 <http://pypi.python.org/pypi/pytest-monkeyplus>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-monkeyplus-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-monkeyplus-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png pytest's monkeypatch subclass with extra functionalities
:target: http://pytest-plugs.herokuapp.com/output/pytest-monkeyplus-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-monkeyplus-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/hsoft/pytest-monkeyplus/
`pytest-mozwebqa-1.1.1 <http://pypi.python.org/pypi/pytest-mozwebqa>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-mozwebqa-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-mozwebqa-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Mozilla WebQA plugin for py.test.
:target: http://pytest-plugs.herokuapp.com/output/pytest-mozwebqa-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-mozwebqa-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/davehunt/pytest-mozwebqa
`pytest-oerp-0.2.0 <http://pypi.python.org/pypi/pytest-oerp>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-oerp-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-oerp-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png pytest plugin to test OpenERP modules
:target: http://pytest-plugs.herokuapp.com/output/pytest-oerp-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-oerp-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/santagada/pytest-oerp/
`pytest-ordering-0.3 <http://pypi.python.org/pypi/pytest-ordering>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-ordering-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-ordering-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png pytest plugin to run your tests in a specific order
:target: http://pytest-plugs.herokuapp.com/output/pytest-ordering-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-ordering-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/ftobia/pytest-ordering
`pytest-osxnotify-0.1.4 <http://pypi.python.org/pypi/pytest-osxnotify>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-osxnotify-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-osxnotify-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png OS X notifications for py.test results.
:target: http://pytest-plugs.herokuapp.com/output/pytest-osxnotify-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-osxnotify-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/dbader/pytest-osxnotify
`pytest-paste-config-0.1 <http://pypi.python.org/pypi/pytest-paste-config>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-paste-config-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-paste-config-latest?py=py34&pytest=2.6.2.dev1 ? Allow setting the path to a paste config file
:target: http://pytest-plugs.herokuapp.com/output/pytest-paste-config-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-paste-config-latest?py=py34&pytest=2.6.2.dev1
`pytest-pep8-1.0.6 <http://pypi.python.org/pypi/pytest-pep8>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pep8-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pep8-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png pytest plugin to check PEP8 requirements
:target: http://pytest-plugs.herokuapp.com/output/pytest-pep8-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-pep8-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/hpk42/pytest-pep8/
`pytest-pipeline-0.1.0 <http://pypi.python.org/pypi/pytest-pipeline>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pipeline-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pipeline-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Pytest plugin for functional testing of data analysis pipelines
:target: http://pytest-plugs.herokuapp.com/output/pytest-pipeline-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-pipeline-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/bow/pytest_pipeline
`pytest-poo-0.2 <http://pypi.python.org/pypi/pytest-poo>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-poo-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-poo-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Visualize your crappy tests
:target: http://pytest-plugs.herokuapp.com/output/pytest-poo-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-poo-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/pelme/pytest-poo
`pytest-pycharm-0.1.0 <http://pypi.python.org/pypi/pytest-pycharm>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pycharm-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pycharm-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Plugin for py.test to enter PyCharm debugger on uncaught exceptions
:target: http://pytest-plugs.herokuapp.com/output/pytest-pycharm-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-pycharm-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/jlubcke/pytest-pycharm
`pytest-pydev-0.1 <http://pypi.python.org/pypi/pytest-pydev>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pydev-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pydev-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png py.test plugin to connect to a remote debug server with PyDev or PyCharm.
:target: http://pytest-plugs.herokuapp.com/output/pytest-pydev-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-pydev-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/basti/pytest-pydev/
`pytest-pythonpath-0.3 <http://pypi.python.org/pypi/pytest-pythonpath>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pythonpath-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-pythonpath-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png pytest plugin for adding to the PYTHONPATH from command line or configs.
:target: http://pytest-plugs.herokuapp.com/output/pytest-pythonpath-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-pythonpath-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/bigsassy/pytest-pythonpath
`pytest-qt-1.2.0 <http://pypi.python.org/pypi/pytest-qt>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-qt-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-qt-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png pytest support for PyQt and PySide applications
:target: http://pytest-plugs.herokuapp.com/output/pytest-qt-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-qt-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/nicoddemus/pytest-qt
`pytest-quickcheck-0.8 <http://pypi.python.org/pypi/pytest-quickcheck>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-quickcheck-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-quickcheck-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png pytest plugin to generate random data inspired by QuickCheck
:target: http://pytest-plugs.herokuapp.com/output/pytest-quickcheck-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-quickcheck-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/t2y/pytest-quickcheck/
`pytest-rage-0.1 <http://pypi.python.org/pypi/pytest-rage>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-rage-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-rage-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png pytest plugin to implement PEP712
:target: http://pytest-plugs.herokuapp.com/output/pytest-rage-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-rage-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/santagada/pytest-rage/
`pytest-raisesregexp-1.0 <http://pypi.python.org/pypi/pytest-raisesregexp>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-raisesregexp-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-raisesregexp-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Simple pytest plugin to look for regex in Exceptions
:target: http://pytest-plugs.herokuapp.com/output/pytest-raisesregexp-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-raisesregexp-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/Walkman/pytest_raisesregexp
`pytest-random-0.02 <http://pypi.python.org/pypi/pytest-random>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-random-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-random-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png py.test plugin to randomize tests
:target: http://pytest-plugs.herokuapp.com/output/pytest-random-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-random-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/klrmn/pytest-random
`pytest-rerunfailures-0.05 <http://pypi.python.org/pypi/pytest-rerunfailures>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-rerunfailures-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-rerunfailures-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png py.test plugin to re-run tests to eliminate flakey failures
:target: http://pytest-plugs.herokuapp.com/output/pytest-rerunfailures-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-rerunfailures-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/klrmn/pytest-rerunfailures
`pytest-runfailed-0.3 <http://pypi.python.org/pypi/pytest-runfailed>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-runfailed-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-runfailed-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png implement a --failed option for pytest
:target: http://pytest-plugs.herokuapp.com/output/pytest-runfailed-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-runfailed-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/dmerejkowsky/pytest-runfailed
`pytest-runner-2.1 <http://pypi.python.org/pypi/pytest-runner>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-runner-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-runner-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png UNKNOWN
:target: http://pytest-plugs.herokuapp.com/output/pytest-runner-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-runner-latest?py=py34&pytest=2.6.2.dev1 :target: https://bitbucket.org/jaraco/pytest-runner
`pytest-sftpserver-1.0.2 <http://pypi.python.org/pypi/pytest-sftpserver>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-sftpserver-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-sftpserver-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png py.test plugin to locally test sftp server connections.
:target: http://pytest-plugs.herokuapp.com/output/pytest-sftpserver-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-sftpserver-latest?py=py34&pytest=2.6.2.dev1 :target: http://github.com/ulope/pytest-sftpserver/
`pytest-spec-0.2.22 <http://pypi.python.org/pypi/pytest-spec>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-spec-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-spec-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png pytest plugin to display test execution output like a SPECIFICATION
:target: http://pytest-plugs.herokuapp.com/output/pytest-spec-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-spec-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/pchomik/pytest-spec
`pytest-splinter-1.0.3 <http://pypi.python.org/pypi/pytest-splinter>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-splinter-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-splinter-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Splinter subplugin for Pytest BDD plugin
:target: http://pytest-plugs.herokuapp.com/output/pytest-splinter-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-splinter-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/paylogic/pytest-splinter
`pytest-stepwise-0.2 <http://pypi.python.org/pypi/pytest-stepwise>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-stepwise-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-stepwise-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png Run a test suite one failing test at a time.
:target: http://pytest-plugs.herokuapp.com/output/pytest-stepwise-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-stepwise-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/nip3o/pytest-stepwise
`pytest-sugar-0.3.4 <http://pypi.python.org/pypi/pytest-sugar>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-sugar-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-sugar-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png py.test is a plugin for py.test that changes the default look and feel of py.test (e.g. progressbar, show tests that fail instantly).
:target: http://pytest-plugs.herokuapp.com/output/pytest-sugar-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-sugar-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/Frozenball/pytest-sugar
`pytest-timeout-0.4 <http://pypi.python.org/pypi/pytest-timeout>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-timeout-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-timeout-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png py.test plugin to abort hanging tests
:target: http://pytest-plugs.herokuapp.com/output/pytest-timeout-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-timeout-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/flub/pytest-timeout/
`pytest-twisted-1.5 <http://pypi.python.org/pypi/pytest-twisted>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-twisted-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-twisted-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png A twisted plugin for py.test.
:target: http://pytest-plugs.herokuapp.com/output/pytest-twisted-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-twisted-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/schmir/pytest-twisted
`pytest-xdist-1.10 <http://pypi.python.org/pypi/pytest-xdist>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-xdist-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-xdist-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png py.test xdist plugin for distributed testing and loop-on-failing modes
:target: http://pytest-plugs.herokuapp.com/output/pytest-xdist-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-xdist-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/hpk42/pytest-xdist
`pytest-xprocess-0.8 <http://pypi.python.org/pypi/pytest-xprocess>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-xprocess-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-xprocess-latest?py=py34&pytest=2.6.2.dev1 .. image:: bitbucket.png pytest plugin to manage external processes across test runs
:target: http://pytest-plugs.herokuapp.com/output/pytest-xprocess-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-xprocess-latest?py=py34&pytest=2.6.2.dev1 :target: http://bitbucket.org/hpk42/pytest-xprocess/
`pytest-yamlwsgi-0.6 <http://pypi.python.org/pypi/pytest-yamlwsgi>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-yamlwsgi-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-yamlwsgi-latest?py=py34&pytest=2.6.2.dev1 ? Run tests against wsgi apps defined in yaml
:target: http://pytest-plugs.herokuapp.com/output/pytest-yamlwsgi-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-yamlwsgi-latest?py=py34&pytest=2.6.2.dev1
`pytest-zap-0.2 <http://pypi.python.org/pypi/pytest-zap>`_ .. image:: http://pytest-plugs.herokuapp.com/status/pytest-zap-latest?py=py27&pytest=2.6.2.dev1 .. image:: http://pytest-plugs.herokuapp.com/status/pytest-zap-latest?py=py34&pytest=2.6.2.dev1 .. image:: github.png OWASP ZAP plugin for py.test.
:target: http://pytest-plugs.herokuapp.com/output/pytest-zap-latest?py=py27&pytest=2.6.2.dev1 :target: http://pytest-plugs.herokuapp.com/output/pytest-zap-latest?py=py34&pytest=2.6.2.dev1 :target: https://github.com/davehunt/pytest-zap
========================================================================================== ================================================================================================================= ================================================================================================================= ======================================================================================== =============================================================================================================================================
*(Updated on 2014-08-26)*

View File

@@ -1,6 +1,13 @@
"""
Script to generate the file `index.txt` with information about
pytest plugins taken directly from a live PyPI server.
pytest plugins taken directly from PyPI.
Usage:
python plugins_index.py
This command will update `index.txt` in the same directory found as this script.
This should be issued before every major documentation release to obtain latest
versions from PyPI.
Also includes plugin compatibility between different python and pytest versions,
obtained from http://pytest-plugs.herokuapp.com.
@@ -66,9 +73,39 @@ def obtain_plugins_table(plugins, client):
:param plugins: list of (name, version)
:param client: ServerProxy
"""
def get_repo_markup(repo):
"""
obtains appropriate markup for the given repository, as two lines
that should be output in the same table row. We use this to display an icon
for known repository hosts (github, etc), just a "?" char when
repository is not registered in pypi or a simple link otherwise.
"""
target = repo
if 'github.com' in repo:
image = 'github.png'
elif 'bitbucket.org' in repo:
image = 'bitbucket.png'
elif repo.lower() == 'unknown':
return '?', ''
else:
image = None
if image is not None:
image_markup = '.. image:: %s' % image
target_markup = ' :target: %s' % repo
pad_right = ('%-' + str(len(target_markup)) + 's')
return pad_right % image_markup, target_markup
else:
return ('`%s <%s>`_' % (target, target)), ''
def sanitize_summary(summary):
"""Make sure summaries don't break our table formatting.
"""
return summary.replace('\n', ' ')
rows = []
ColumnData = namedtuple('ColumnData', 'text link')
headers = ['Name', 'Py27', 'Py33', 'Repository', 'Summary']
headers = ['Name', 'Py27', 'Py34', 'Repo', 'Summary']
pytest_version = pytest.__version__
repositories = obtain_override_repositories()
print('*** pytest-{0} ***'.format(pytest_version))
@@ -83,27 +120,29 @@ def obtain_plugins_table(plugins, client):
name=package_name,
version=version)
repository = repositories.get(package_name, release_data['home_page'])
repo_markup_1, repo_markup_2 = get_repo_markup(repository)
# first row: name, images and simple links
url = '.. image:: {site}/status/{name}-{version}'
url = '.. image:: {site}/status/{name}-latest'
image_url = url.format(**common_params)
image_url += '?py={py}&pytest={pytest}'
row = (
ColumnData(package_name + '-' + version,
release_data['release_url']),
ColumnData(package_name + "-" + version, release_data['package_url']),
ColumnData(image_url.format(py='py27', pytest=pytest_version),
None),
ColumnData(image_url.format(py='py33', pytest=pytest_version),
ColumnData(image_url.format(py='py34', pytest=pytest_version),
None),
ColumnData(
repositories.get(package_name, release_data['home_page']),
repo_markup_1,
None),
ColumnData(release_data['summary'], None),
ColumnData(sanitize_summary(release_data['summary']), None),
)
assert len(row) == len(headers)
rows.append(row)
# second row: links for images (they should be in their own line)
url = ' :target: {site}/output/{name}-{version}'
url = ' :target: {site}/output/{name}-latest'
output_url = url.format(**common_params)
output_url += '?py={py}&pytest={pytest}'
@@ -111,10 +150,11 @@ def obtain_plugins_table(plugins, client):
ColumnData('', None),
ColumnData(output_url.format(py='py27', pytest=pytest_version),
None),
ColumnData(output_url.format(py='py33', pytest=pytest_version),
ColumnData(output_url.format(py='py34', pytest=pytest_version),
None),
ColumnData(repo_markup_2, None),
ColumnData('', None),
ColumnData('', None),
)
assert len(row) == len(headers)
rows.append(row)
@@ -135,6 +175,7 @@ def obtain_override_repositories():
return {
'pytest-blockage': 'https://github.com/rob-b/pytest-blockage',
'pytest-konira': 'http://github.com/alfredodeza/pytest-konira',
'pytest-sugar': 'https://github.com/Frozenball/pytest-sugar',
}
@@ -168,11 +209,9 @@ def generate_plugins_index_from_table(filename, headers, rows):
return ' '.join(char * length for length in column_lengths)
with open(filename, 'w') as f:
# write welcome
print('.. _plugins_index:', file=f)
print(file=f)
print('List of Third-Party Plugins', file=f)
print('===========================', file=f)
# header
header_text = HEADER.format(pytest_version=pytest.__version__)
print(header_text, file=f)
print(file=f)
# table
@@ -233,5 +272,21 @@ def main(argv):
return 0
# header for the plugins_index page
HEADER = '''.. _plugins_index:
List of Third-Party Plugins
===========================
The table below contains a listing of plugins found in PyPI and
their status when tested using py.test **{pytest_version}** and python 2.7 and
3.3.
A complete listing can also be found at
`pytest-plugs <http://pytest-plugs.herokuapp.com/>`_, which contains tests
status against other py.test releases.
'''
if __name__ == '__main__':
sys.exit(main(sys.argv))

View File

@@ -35,7 +35,7 @@ Here is an example of marking a test function to be skipped
when run on a Python3.3 interpreter::
import sys
@pytest.mark.skipif(sys.version_info >= (3,3),
@pytest.mark.skipif(sys.version_info < (3,3),
reason="requires python3.3")
def test_function():
...
@@ -51,7 +51,7 @@ You can share skipif markers between modules. Consider this test module::
# content of test_mymodule.py
import mymodule
minversion = pytest.mark.skipif(mymodule.__versioninfo__ >= (1,1),
minversion = pytest.mark.skipif(mymodule.__versioninfo__ < (1,1),
reason="at least mymodule-1.1 required")
@minversion
def test_function():
@@ -149,6 +149,11 @@ on a particular platform::
def test_function():
...
If you want to be more specific as to why the test is failing, you can specify
a single exception, or a list of exceptions, in the ``raises`` argument. Then
the test will be reported as a regular failure if it fails with an
exception not mentioned in ``raises``.
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 the several usages:
@@ -159,10 +164,10 @@ Running it with the report-on-xfail option gives this output::
example $ py.test -rx xfail_demo.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
collected 6 items
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 7 items
xfail_demo.py xxxxxx
xfail_demo.py xxxxxxx
========================= short test summary info ==========================
XFAIL xfail_demo.py::test_hello
XFAIL xfail_demo.py::test_hello2
@@ -175,8 +180,9 @@ Running it with the report-on-xfail option gives this output::
condition: pytest.__version__[0] != "17"
XFAIL xfail_demo.py::test_hello6
reason: reason
XFAIL xfail_demo.py::test_hello7
======================== 6 xfailed in 0.04 seconds =========================
======================== 7 xfailed in 0.05 seconds =========================
.. _`skip/xfail with parametrize`:
@@ -286,4 +292,9 @@ The equivalent with "boolean conditions" is::
def test_function(...):
pass
.. note::
You cannot use ``pytest.config.getvalue()`` in code
imported before py.test's argument parsing takes place. For example,
``conftest.py`` files are imported before command line parsing and thus
``config.getvalue()`` will not execute correctly.

View File

@@ -2,34 +2,50 @@
Talks and Tutorials
==========================
.. sidebar:: Next Open Trainings
`professional testing with pytest and tox <http://www.python-academy.com/courses/specialtopics/python_course_testing.html>`_, 24-26th November 2014, Freiburg, Germany
.. _`funcargs`: funcargs.html
Tutorial examples and blog postings
Talks and blog postings
---------------------------------------------
.. _`tutorial1 repository`: http://bitbucket.org/hpk42/pytest-tutorial1/
.. _`pycon 2010 tutorial PDF`: http://bitbucket.org/hpk42/pytest-tutorial1/raw/tip/pytest-basic.pdf
Basic usage and fixtures:
- `Introduction to pytest, Andreas Pelme, EuroPython 2014
<https://www.youtube.com/watch?v=LdVJj65ikRY>`_.
- `pytest feature and release highlights (GERMAN, October 2013)
- `Advanced Uses of py.test Fixtures, Floris Bruynooghe, EuroPython
2014 <https://www.youtube.com/watch?v=IBC_dxr-4ps>`_.
- `Why i use py.test and maybe you should too, Andy Todd, Pycon AU 2013
<https://www.youtube.com/watch?v=P-AhpukDIik>`_
- `3-part blog series about pytest from @pydanny alias Daniel Greenfeld (January
2014) <http://pydanny.com/pytest-no-boilerplate-testing.html>`_
- `pytest: helps you write better Django apps, Andreas Pelme, DjangoCon
Europe 2014 <https://www.youtube.com/watch?v=aaArYVh6XSM>`_.
- :ref:`fixtures`
- `Testing Django Applications with pytest, Andreas Pelme, EuroPython
2013 <https://www.youtube.com/watch?v=aUf8Fkb7TaY>`_.
- `Testes pythonics com py.test, Vinicius Belchior Assef Neto, Plone
Conf 2013, Brazil <https://www.youtube.com/watch?v=QUKoq2K7bis>`_.
- `Introduction to py.test fixtures, FOSDEM 2013, Floris Bruynooghe
<https://www.youtube.com/watch?v=bJhRW4eZMco>`_.
- `pytest feature and release highlights, Holger Krekel (GERMAN, October 2013)
<http://pyvideo.org/video/2429/pytest-feature-and-new-release-highlights>`_
- `pytest introduction from Brian Okken (January 2013)
<http://pythontesting.net/framework/pytest-introduction/>`_
- `3-part blog series about pytest from Daniel Greenfeld (January
2014) <http://pydanny.com/pytest-no-boilerplate-testing.html>`_
- `pycon australia 2012 pytest talk from Brianna Laugher
<http://2012.pycon-au.org/schedule/52/view_talk?day=sunday>`_ (`video <http://www.youtube.com/watch?v=DTNejE9EraI>`_, `slides <http://www.slideshare.net/pfctdayelise/funcargs-other-fun-with-pytest>`_, `code <https://gist.github.com/3386951>`_)
- `pycon 2012 US talk video from Holger Krekel <http://www.youtube.com/watch?v=9LVqBQcFmyw>`_
- `pycon 2010 tutorial PDF`_ and `tutorial1 repository`_
Fixtures and Function arguments:
- :ref:`fixtures`
- `monkey patching done right`_ (blog post, consult `monkeypatch
plugin`_ for up-to-date API)
@@ -69,6 +85,11 @@ Plugin specific examples:
Older conference talks and tutorials
----------------------------------------
- `pycon australia 2012 pytest talk from Brianna Laugher
<http://2012.pycon-au.org/schedule/52/view_talk?day=sunday>`_ (`video <http://www.youtube.com/watch?v=DTNejE9EraI>`_, `slides <http://www.slideshare.net/pfctdayelise/funcargs-other-fun-with-pytest>`_, `code <https://gist.github.com/3386951>`_)
- `pycon 2012 US talk video from Holger Krekel <http://www.youtube.com/watch?v=9LVqBQcFmyw>`_
- `pycon 2010 tutorial PDF`_ and `tutorial1 repository`_
- `ep2009-rapidtesting.pdf`_ tutorial slides (July 2009):
- testing terminology

View File

@@ -29,7 +29,7 @@ Running this would result in a passed test except for the last
$ py.test test_tmpdir.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 1 items
test_tmpdir.py F
@@ -37,7 +37,7 @@ Running this would result in a passed test except for the last
================================= FAILURES =================================
_____________________________ test_create_file _____________________________
tmpdir = local('/tmp/pytest-1009/test_create_file0')
tmpdir = local('/tmp/pytest-19/test_create_file0')
def test_create_file(tmpdir):
p = tmpdir.mkdir("sub").join("hello.txt")

View File

@@ -88,7 +88,7 @@ the ``self.db`` values in the traceback::
$ py.test test_unittest_db.py
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
platform linux -- Python 3.4.0 -- py-1.4.25 -- pytest-2.6.3
collected 2 items
test_unittest_db.py FF
@@ -101,7 +101,8 @@ the ``self.db`` values in the traceback::
def test_method1(self):
assert hasattr(self, "db")
> assert 0, self.db # fail for demo purposes
E AssertionError: <conftest.DummyDB instance at 0x12124d0>
E AssertionError: <conftest.db_class.<locals>.DummyDB object at 0x2b938b865208>
E assert 0
test_unittest_db.py:9: AssertionError
___________________________ MyTest.test_method2 ____________________________
@@ -110,10 +111,11 @@ the ``self.db`` values in the traceback::
def test_method2(self):
> assert 0, self.db # fail for demo purposes
E AssertionError: <conftest.DummyDB instance at 0x12124d0>
E AssertionError: <conftest.db_class.<locals>.DummyDB object at 0x2b938b865208>
E assert 0
test_unittest_db.py:12: AssertionError
========================= 2 failed in 0.01 seconds =========================
========================= 2 failed in 0.05 seconds =========================
This default pytest traceback shows that the two test methods
share the same ``self.db`` instance which was our intention
@@ -160,7 +162,7 @@ Running this test module ...::
$ py.test -q test_unittest_cleandir.py
.
1 passed in 0.01 seconds
1 passed in 0.05 seconds
... gives us one passed test because the ``initdir`` fixture function
was executed ahead of the ``test_method``.

View File

@@ -49,6 +49,9 @@ Several test run options::
# the "string expression", e.g. "MyClass and not method"
# will select TestMyClass.test_something
# but not TestMyClass.test_method_simple
py.test test_mod.py::test_func # only run tests that match the "node ID",
# e.g "test_mod.py::test_func" will select
# only test_func in test_mod.py
Import 'pkg' and use its filesystem location to find and run tests::
@@ -67,13 +70,13 @@ Examples for modifying traceback printing::
py.test --tb=short # a shorter traceback format
py.test --tb=line # only one line per failure
Dropping to PDB (Python Debugger) on failures
----------------------------------------------
Dropping to PDB_ (Python Debugger) on failures
-----------------------------------------------
.. _PDB: http://docs.python.org/library/pdb.html
Python comes with a builtin Python debugger called PDB_. ``pytest``
allows one to drop into the PDB prompt via a command line option::
allows one to drop into the PDB_ prompt via a command line option::
py.test --pdb
@@ -82,7 +85,7 @@ only want to do this for the first failing test to understand a certain
failure situation::
py.test -x --pdb # drop to PDB on first failure, then end test session
py.test --pdb --maxfail=3 # drop to PDB for the first three failures
py.test --pdb --maxfail=3 # drop to PDB for first three failures
Setting a breakpoint / aka ``set_trace()``
@@ -98,8 +101,24 @@ can use a helper::
.. versionadded: 2.0.0
In previous versions you could only enter PDB tracing if
you disabled capturing on the command line via ``py.test -s``.
Prior to pytest version 2.0.0 you could only enter PDB_ tracing if you disabled
capturing on the command line via ``py.test -s``. In later versions, pytest
automatically disables its output capture when you enter PDB_ tracing:
* Output capture in other tests is not affected.
* Any prior test output that has already been captured and will be processed as
such.
* Any later output produced within the same test will not be captured and will
instead get sent directly to ``sys.stdout``. Note that this holds true even
for test output occuring after you exit the interactive PDB_ tracing session
and continue with the regular test run.
.. versionadded: 2.4.0
Since pytest version 2.4.0 you can also use the native Python
``import pdb;pdb.set_trace()`` call to enter PDB_ tracing without having to use
the ``pytest.set_trace()`` wrapper or explicitly disable pytest's output
capturing via ``py.test -s``.
.. _durations:

View File

@@ -1,4 +1,3 @@
.. _yieldfixture:
Fixture functions using "yield" / context manager integration
@@ -52,9 +51,9 @@ Let's run it with output capturing disabled::
test called
.teardown after yield
1 passed in 0.00 seconds
1 passed in 0.01 seconds
We can also seemlessly use the new syntax with ``with`` statements.
We can also seamlessly use the new syntax with ``with`` statements.
Let's simplify the above ``passwd`` fixture::
# content of test_yield2.py

View File

@@ -1,10 +1,8 @@
#!/usr/bin/env python
import subprocess
import sys
if __name__ == "__main__":
subprocess.call(["tox",
import subprocess
import sys
subprocess.call([sys.executable, "-m", "tox",
"-i", "ALL=https://devpi.net/hpk/dev/",
"--develop",] + sys.argv[1:])
"--develop"] + sys.argv[1:])

View File

@@ -5,4 +5,3 @@ all_files = 1
[upload_sphinx]
upload-dir = doc/en/build/html

View File

@@ -1,41 +1,41 @@
import os, sys
from setuptools import setup, Command
classifiers=['Development Status :: 6 - Mature',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: POSIX',
'Operating System :: Microsoft :: Windows',
'Operating System :: MacOS :: MacOS X',
'Topic :: Software Development :: Testing',
'Topic :: Software Development :: Libraries',
'Topic :: Utilities',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3'] + [
("Programming Language :: Python :: %s" % x) for x in
"2.6 2.7 3.0 3.1 3.2 3.3".split()]
classifiers = ['Development Status :: 6 - Mature',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: POSIX',
'Operating System :: Microsoft :: Windows',
'Operating System :: MacOS :: MacOS X',
'Topic :: Software Development :: Testing',
'Topic :: Software Development :: Libraries',
'Topic :: Utilities'] + [
('Programming Language :: Python :: %s' % x) for x in
'2 2.6 2.7 3 3.2 3.3 3.4'.split()]
long_description = open('README.rst').read()
long_description = open("README.rst").read()
def main():
install_requires = ["py>=1.4.20"]
if sys.version_info < (2,7):
install_requires.append("argparse")
if sys.platform == "win32":
install_requires.append("colorama")
install_requires = ['py>=1.4.25']
if sys.version_info < (2, 7) or (3,) <= sys.version_info < (3, 2):
install_requires.append('argparse')
if sys.platform == 'win32':
install_requires.append('colorama')
setup(
name='pytest',
description='pytest: simple powerful testing with Python',
long_description = long_description,
version='2.5.2',
long_description=long_description,
version='2.6.3',
url='http://pytest.org',
license='MIT license',
platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'],
author='Holger Krekel, Benjamin Peterson, Ronny Pfannschmidt, Floris Bruynooghe and others',
author_email='holger at merlinux.eu',
entry_points= make_entry_points(),
entry_points=make_entry_points(),
classifiers=classifiers,
cmdclass = {'test': PyTest},
cmdclass={'test': PyTest},
# the following should be enabled for release
install_requires=install_requires,
packages=['_pytest', '_pytest.assertion'],
@@ -43,24 +43,26 @@ def main():
zip_safe=False,
)
def cmdline_entrypoints(versioninfo, platform, basename):
target = 'pytest:main'
if platform.startswith('java'):
points = {'py.test-jython': target}
else:
if basename.startswith("pypy"):
if basename.startswith('pypy'):
points = {'py.test-%s' % basename: target}
else: # cpython
points = {'py.test-%s.%s' % versioninfo[:2] : target,}
points = {'py.test-%s.%s' % versioninfo[:2] : target}
points['py.test'] = target
return points
def make_entry_points():
basename = os.path.basename(sys.executable)
points = cmdline_entrypoints(sys.version_info, sys.platform, basename)
keys = list(points.keys())
keys.sort()
l = ["%s = %s" % (x, points[x]) for x in keys]
l = ['%s = %s' % (x, points[x]) for x in keys]
return {'console_scripts': l}
@@ -71,12 +73,13 @@ class PyTest(Command):
def finalize_options(self):
pass
def run(self):
import sys,subprocess
PPATH=[x for x in os.environ.get("PYTHONPATH", "").split(":") if x]
import subprocess
PPATH = [x for x in os.environ.get('PYTHONPATH', '').split(':') if x]
PPATH.insert(0, os.getcwd())
os.environ["PYTHONPATH"] = ":".join(PPATH)
errno = subprocess.call([sys.executable, 'pytest.py'])
os.environ['PYTHONPATH'] = ':'.join(PPATH)
errno = subprocess.call([sys.executable, 'pytest.py', '--ignore=doc'])
raise SystemExit(errno)
if __name__ == '__main__':
main()

View File

@@ -124,6 +124,18 @@ class TestGeneralUsage:
"*ERROR: not found:*%s" %(p2.basename,)
])
def test_issue486_better_reporting_on_conftest_load_failure(self, testdir):
testdir.makepyfile("")
testdir.makeconftest("import qwerty")
result = testdir.runpytest("--help")
result.stdout.fnmatch_lines("""
*--version*
*warning*conftest.py*
""")
result = testdir.runpytest()
result.stderr.fnmatch_lines("""
*ERROR*could not load*conftest.py*
""")
def test_early_skip(self, testdir):
@@ -335,6 +347,12 @@ class TestGeneralUsage:
res = testdir.runpytest(p.basename)
assert res.ret == 0
def test_unknown_option(self, testdir):
result = testdir.runpytest("--qwlkej")
result.stderr.fnmatch_lines("""
*unrecognized*
""")
class TestInvocationVariants:
def test_earlyinit(self, testdir):

View File

@@ -4,48 +4,71 @@ import sys
pytest_plugins = "pytester",
import os, py
pid = os.getpid()
class LsofFdLeakChecker(object):
def get_open_files(self):
out = self._exec_lsof()
open_files = self._parse_lsof_output(out)
return open_files
def _exec_lsof(self):
pid = os.getpid()
return py.process.cmdexec("lsof -Ffn0 -p %d" % pid)
def _parse_lsof_output(self, out):
def isopen(line):
return line.startswith('f') and (
"deleted" not in line and 'mem' not in line and "txt" not in line and 'cwd' not in line)
open_files = []
for line in out.split("\n"):
if isopen(line):
fields = line.split('\0')
fd = fields[0][1:]
filename = fields[1][1:]
if filename.startswith('/'):
open_files.append((fd, filename))
return open_files
def pytest_addoption(parser):
parser.addoption('--lsof',
action="store_true", dest="lsof", default=False,
help=("run FD checks if lsof is available"))
def pytest_configure(config):
def pytest_runtest_setup(item):
config = item.config
config._basedir = py.path.local()
if config.getvalue("lsof"):
try:
out = py.process.cmdexec("lsof -p %d" % pid)
config._fd_leak_checker = LsofFdLeakChecker()
config._openfiles = config._fd_leak_checker.get_open_files()
except py.process.cmdexec.Error:
pass
else:
config._numfiles = len(getopenfiles(out))
#def pytest_report_header():
# return "pid: %s" % os.getpid()
def getopenfiles(out):
def isopen(line):
return ("REG" in line or "CHR" in line) and (
"deleted" not in line and 'mem' not in line and "txt" not in line)
return [x for x in out.split("\n") if isopen(x)]
def check_open_files(config):
out2 = py.process.cmdexec("lsof -p %d" % pid)
lines2 = getopenfiles(out2)
if len(lines2) > config._numfiles + 3:
lines2 = config._fd_leak_checker.get_open_files()
new_fds = set([t[0] for t in lines2]) - set([t[0] for t in config._openfiles])
open_files = [t for t in lines2 if t[0] in new_fds]
if open_files:
error = []
error.append("***** %s FD leackage detected" %
(len(lines2)-config._numfiles))
error.extend(lines2)
error.append("***** %s FD leakage detected" % len(open_files))
error.extend([str(f) for f in open_files])
error.append("*** Before:")
error.extend([str(f) for f in config._openfiles])
error.append("*** After:")
error.extend([str(f) for f in lines2])
error.append(error[0])
# update numfile so that the overall test run continuess
config._numfiles = len(lines2)
raise AssertionError("\n".join(error))
def pytest_runtest_teardown(item, __multicall__):
item.config._basedir.chdir()
if hasattr(item.config, '_numfiles'):
if hasattr(item.config, '_openfiles'):
x = __multicall__.execute()
check_open_files(item.config)
return x
@@ -54,12 +77,11 @@ def pytest_runtest_teardown(item, __multicall__):
winpymap = {
'python2.7': r'C:\Python27\python.exe',
'python2.6': r'C:\Python26\python.exe',
'python2.5': r'C:\Python25\python.exe',
'python2.4': r'C:\Python24\python.exe',
'python3.1': r'C:\Python31\python.exe',
'python3.2': r'C:\Python32\python.exe',
'python3.3': r'C:\Python33\python.exe',
'python3.4': r'C:\Python34\python.exe',
'python3.5': r'C:\Python35\python.exe',
}
def getexecutable(name, cache={}):
@@ -80,9 +102,8 @@ def getexecutable(name, cache={}):
cache[name] = executable
return executable
@pytest.fixture(params=['python2.5', 'python2.6',
'python2.7', 'python3.2', "python3.3",
'pypy', 'jython'])
@pytest.fixture(params=['python2.6', 'python2.7', 'python3.3', "python3.4",
'pypy', 'pypy3'])
def anypython(request):
name = request.param
executable = getexecutable(name)

View File

@@ -0,0 +1,9 @@
"""
This is the script that is actually frozen into an executable: simply executes
py.test main().
"""
if __name__ == '__main__':
import sys
import pytest
sys.exit(pytest.main())

View File

@@ -0,0 +1,15 @@
"""
Sample setup.py script that generates an executable with pytest runner embedded.
"""
if __name__ == '__main__':
from cx_Freeze import setup, Executable
import pytest
setup(
name="runtests",
version="0.1",
description="exemple of how embedding py.test into an executable using cx_freeze",
executables=[Executable("runtests_script.py")],
options={"build_exe": {'includes': pytest.freeze_includes()}},
)

View File

@@ -0,0 +1,6 @@
Testing doctest::
>>> 1 + 1
2

View File

@@ -0,0 +1,6 @@
def test_upper():
assert 'foo'.upper() == 'FOO'
def test_lower():
assert 'FOO'.lower() == 'foo'

View File

@@ -0,0 +1,15 @@
"""
Called by tox.ini: uses the generated executable to run the tests in ./tests/
directory.
.. note:: somehow calling "build/runtests_script" directly from tox doesn't
seem to work (at least on Windows).
"""
if __name__ == '__main__':
import os
import sys
executable = os.path.join(os.getcwd(), 'build', 'runtests_script')
if sys.platform.startswith('win'):
executable += '.exe'
sys.exit(os.system('%s tests' % executable))

View File

@@ -33,8 +33,8 @@ class TestModule:
pytest.raises(ImportError, lambda: modcol.obj)
class TestClass:
def test_class_with_init_skip_collect(self, testdir):
modcol = testdir.getmodulecol("""
def test_class_with_init_warning(self, testdir):
testdir.makepyfile("""
class TestClass1:
def __init__(self):
pass
@@ -42,11 +42,11 @@ class TestClass:
def __init__(self):
pass
""")
l = modcol.collect()
assert len(l) == 2
for classcol in l:
pytest.raises(pytest.skip.Exception, classcol.collect)
result = testdir.runpytest("-rw")
result.stdout.fnmatch_lines("""
WC1*test_class_with_init_warning.py*__init__*
*2 warnings*
""")
def test_class_subclassobject(self, testdir):
testdir.getmodulecol("""
@@ -276,6 +276,17 @@ class TestFunction:
assert isinstance(modcol, pytest.Module)
assert hasattr(modcol.obj, 'test_func')
def test_function_as_object_instance_ignored(self, testdir):
testdir.makepyfile("""
class A:
def __call__(self, tmpdir):
0/0
test_a = A()
""")
reprec = testdir.inline_run()
reprec.assertoutcome()
def test_function_equality(self, testdir, tmpdir):
from _pytest.python import FixtureManager
config = testdir.parseconfigure()
@@ -630,7 +641,7 @@ class TestTracebackCutting:
assert "x = 1" not in out
assert "x = 2" not in out
result.stdout.fnmatch_lines([
">*asd*",
" *asd*",
"E*NameError*",
])
result = testdir.runpytest("--fulltrace")

View File

@@ -1001,6 +1001,40 @@ class TestFixtureManagerParseFactories:
reprec = testdir.inline_run("-s")
reprec.assertoutcome(passed=1)
def test_parsefactories_relative_node_ids(self, testdir):
# example mostly taken from:
# https://mail.python.org/pipermail/pytest-dev/2014-September/002617.html
runner = testdir.mkdir("runner")
package = testdir.mkdir("package")
package.join("conftest.py").write(dedent("""\
import pytest
@pytest.fixture
def one():
return 1
"""))
package.join("test_x.py").write(dedent("""\
def test_x(one):
assert one == 1
"""))
sub = package.mkdir("sub")
sub.join("__init__.py").ensure()
sub.join("conftest.py").write(dedent("""\
import pytest
@pytest.fixture
def one():
return 2
"""))
sub.join("test_y.py").write(dedent("""\
def test_x(one):
assert one == 2
"""))
reprec = testdir.inline_run()
reprec.assertoutcome(passed=2)
with runner.as_cwd():
reprec = testdir.inline_run("..")
reprec.assertoutcome(passed=2)
class TestAutouseDiscovery:
def pytest_funcarg__testdir(self, testdir):
testdir.makeconftest("""
@@ -1430,6 +1464,78 @@ class TestFixtureMarker:
reprec = testdir.inline_run()
reprec.assertoutcome(passed=3)
def test_scope_session_exc(self, testdir):
testdir.makepyfile("""
import pytest
l = []
@pytest.fixture(scope="session")
def fix():
l.append(1)
pytest.skip('skipping')
def test_1(fix):
pass
def test_2(fix):
pass
def test_last():
assert l == [1]
""")
reprec = testdir.inline_run()
reprec.assertoutcome(skipped=2, passed=1)
def test_scope_session_exc_two_fix(self, testdir):
testdir.makepyfile("""
import pytest
l = []
m = []
@pytest.fixture(scope="session")
def a():
l.append(1)
pytest.skip('skipping')
@pytest.fixture(scope="session")
def b(a):
m.append(1)
def test_1(b):
pass
def test_2(b):
pass
def test_last():
assert l == [1]
assert m == []
""")
reprec = testdir.inline_run()
reprec.assertoutcome(skipped=2, passed=1)
def test_scope_exc(self, testdir):
testdir.makepyfile(
test_foo="""
def test_foo(fix):
pass
""",
test_bar="""
def test_bar(fix):
pass
""",
conftest="""
import pytest
reqs = []
@pytest.fixture(scope="session")
def fix(request):
reqs.append(1)
pytest.skip()
@pytest.fixture
def req_list():
return reqs
""",
test_real="""
def test_last(req_list):
assert req_list == [1]
"""
)
reprec = testdir.inline_run()
reprec.assertoutcome(skipped=2, passed=1)
def test_scope_module_uses_session(self, testdir):
testdir.makepyfile("""
import pytest
@@ -1620,22 +1726,22 @@ class TestFixtureMarker:
""")
result = testdir.runpytest("-v")
result.stdout.fnmatch_lines("""
test_mod1.py:1: test_func[s1] PASSED
test_mod2.py:1: test_func2[s1] PASSED
test_mod2.py:3: test_func3[s1-m1] PASSED
test_mod2.py:5: test_func3b[s1-m1] PASSED
test_mod2.py:3: test_func3[s1-m2] PASSED
test_mod2.py:5: test_func3b[s1-m2] PASSED
test_mod1.py:1: test_func[s2] PASSED
test_mod2.py:1: test_func2[s2] PASSED
test_mod2.py:3: test_func3[s2-m1] PASSED
test_mod2.py:5: test_func3b[s2-m1] PASSED
test_mod2.py:7: test_func4[m1] PASSED
test_mod2.py:3: test_func3[s2-m2] PASSED
test_mod2.py:5: test_func3b[s2-m2] PASSED
test_mod2.py:7: test_func4[m2] PASSED
test_mod1.py:3: test_func1[m1] PASSED
test_mod1.py:3: test_func1[m2] PASSED
test_mod1.py::test_func[s1] PASSED
test_mod2.py::test_func2[s1] PASSED
test_mod2.py::test_func3[s1-m1] PASSED
test_mod2.py::test_func3b[s1-m1] PASSED
test_mod2.py::test_func3[s1-m2] PASSED
test_mod2.py::test_func3b[s1-m2] PASSED
test_mod1.py::test_func[s2] PASSED
test_mod2.py::test_func2[s2] PASSED
test_mod2.py::test_func3[s2-m1] PASSED
test_mod2.py::test_func3b[s2-m1] PASSED
test_mod2.py::test_func4[m1] PASSED
test_mod2.py::test_func3[s2-m2] PASSED
test_mod2.py::test_func3b[s2-m2] PASSED
test_mod2.py::test_func4[m2] PASSED
test_mod1.py::test_func1[m1] PASSED
test_mod1.py::test_func1[m2] PASSED
""")
def test_class_ordering(self, testdir):
@@ -1672,18 +1778,18 @@ class TestFixtureMarker:
""")
result = testdir.runpytest("-vs")
result.stdout.fnmatch_lines("""
test_class_ordering.py:4: TestClass2.test_1[1-a] PASSED
test_class_ordering.py:4: TestClass2.test_1[2-a] PASSED
test_class_ordering.py:6: TestClass2.test_2[1-a] PASSED
test_class_ordering.py:6: TestClass2.test_2[2-a] PASSED
test_class_ordering.py:4: TestClass2.test_1[1-b] PASSED
test_class_ordering.py:4: TestClass2.test_1[2-b] PASSED
test_class_ordering.py:6: TestClass2.test_2[1-b] PASSED
test_class_ordering.py:6: TestClass2.test_2[2-b] PASSED
test_class_ordering.py:9: TestClass.test_3[1-a] PASSED
test_class_ordering.py:9: TestClass.test_3[2-a] PASSED
test_class_ordering.py:9: TestClass.test_3[1-b] PASSED
test_class_ordering.py:9: TestClass.test_3[2-b] PASSED
test_class_ordering.py::TestClass2::test_1[1-a] PASSED
test_class_ordering.py::TestClass2::test_1[2-a] PASSED
test_class_ordering.py::TestClass2::test_2[1-a] PASSED
test_class_ordering.py::TestClass2::test_2[2-a] PASSED
test_class_ordering.py::TestClass2::test_1[1-b] PASSED
test_class_ordering.py::TestClass2::test_1[2-b] PASSED
test_class_ordering.py::TestClass2::test_2[1-b] PASSED
test_class_ordering.py::TestClass2::test_2[2-b] PASSED
test_class_ordering.py::TestClass::test_3[1-a] PASSED
test_class_ordering.py::TestClass::test_3[2-a] PASSED
test_class_ordering.py::TestClass::test_3[1-b] PASSED
test_class_ordering.py::TestClass::test_3[2-b] PASSED
""")
def test_parametrize_separated_order_higher_scope_first(self, testdir):
@@ -2087,6 +2193,35 @@ class TestErrors:
"*1 error*",
])
def test_issue498_fixture_finalizer_failing(self, testdir):
testdir.makepyfile("""
import pytest
@pytest.fixture
def fix1(request):
def f():
raise KeyError
request.addfinalizer(f)
return object()
l = []
def test_1(fix1):
l.append(fix1)
def test_2(fix1):
l.append(fix1)
def test_3():
assert l[0] != l[1]
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines("""
*ERROR*teardown*test_1*
*KeyError*
*ERROR*teardown*test_2*
*KeyError*
*3 pass*2 error*
""")
def test_setupfunc_missing_funcarg(self, testdir):
testdir.makepyfile("""
import pytest

View File

@@ -112,6 +112,26 @@ class TestMockDecoration:
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_unittest_mock_and_fixture(self, testdir):
pytest.importorskip("unittest.mock")
testdir.makepyfile("""
import os.path
import unittest.mock
import pytest
@pytest.fixture
def inject_me():
pass
@unittest.mock.patch.object(os.path, "abspath",
new=unittest.mock.MagicMock)
def test_hello(inject_me):
import os
os.path.abspath("hello")
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_mock(self, testdir):
pytest.importorskip("mock", "1.0.1")
testdir.makepyfile("""
@@ -124,12 +144,16 @@ class TestMockDecoration:
def test_hello(self, abspath):
os.path.abspath("hello")
abspath.assert_any_call("hello")
def mock_basename(path):
return "mock_basename"
@mock.patch("os.path.abspath")
@mock.patch("os.path.normpath")
@mock.patch("os.path.basename", new=mock_basename)
def test_someting(normpath, abspath, tmpdir):
abspath.return_value = "this"
os.path.normpath(os.path.abspath("hello"))
normpath.assert_any_call("this")
assert os.path.basename("123") == "mock_basename"
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=2)
@@ -160,6 +184,22 @@ class TestMockDecoration:
names = [x.nodeid.split("::")[-1] for x in calls]
assert names == ["test_one", "test_two", "test_three"]
def test_mock_double_patch_issue473(self, testdir):
pytest.importorskip("mock", "1.0.1")
testdir.makepyfile("""
from mock import patch
from pytest import mark
@patch('os.getcwd')
@patch('os.path')
@mark.slow
class TestSimple:
def test_simple_thing(self, mock_path, mock_getcwd):
pass
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
class TestReRunTests:
def test_rerun(self, testdir):
@@ -195,3 +235,52 @@ class TestReRunTests:
def test_pytestconfig_is_session_scoped():
from _pytest.python import pytestconfig
assert pytestconfig._pytestfixturefunction.scope == "session"
class TestNoselikeTestAttribute:
def test_module(self, testdir):
testdir.makepyfile("""
__test__ = False
def test_hello():
pass
""")
reprec = testdir.inline_run()
assert not reprec.getfailedcollections()
calls = reprec.getreports("pytest_runtest_logreport")
assert not calls
def test_class_and_method(self, testdir):
testdir.makepyfile("""
__test__ = True
def test_func():
pass
test_func.__test__ = False
class TestSome:
__test__ = False
def test_method(self):
pass
""")
reprec = testdir.inline_run()
assert not reprec.getfailedcollections()
calls = reprec.getreports("pytest_runtest_logreport")
assert not calls
def test_unittest_class(self, testdir):
testdir.makepyfile("""
import unittest
class TC(unittest.TestCase):
def test_1(self):
pass
class TC2(unittest.TestCase):
__test__ = False
def test_2(self):
pass
""")
reprec = testdir.inline_run()
assert not reprec.getfailedcollections()
call = reprec.getcalls("pytest_collection_modifyitems")[0]
assert len(call.items) == 1
assert call.items[0].cls.__name__ == "TC"

View File

@@ -62,3 +62,10 @@ class TestRaises:
'*3 passed*',
])
def test_noclass(self):
with pytest.raises(TypeError):
pytest.raises('wrong', lambda: None)
def test_tuple(self):
with pytest.raises((KeyError, ValueError)):
raise KeyError('oops')

View File

@@ -131,6 +131,18 @@ def test_assert_keyword_arg():
e = exvalue()
assert "x=5" in e.msg
def test_private_class_variable():
class X:
def __init__(self):
self.__v = 41
def m(self):
assert self.__v == 42
try:
X().m()
except AssertionError:
e = exvalue()
assert "== 42" in e.msg
# These tests should both fail, but should fail nicely...
class WeirdRepr:
def __repr__(self):

View File

@@ -4,6 +4,7 @@ import sys
import py, pytest
import _pytest.assertion as plugin
from _pytest.assertion import reinterpret
from _pytest.assertion import util
needsnewassert = pytest.mark.skipif("sys.version_info < (2,6)")
@@ -199,6 +200,98 @@ class TestAssert_reprcompare:
assert msg
class TestFormatExplanation:
def test_special_chars_full(self, testdir):
# Issue 453, for the bug this would raise IndexError
testdir.makepyfile("""
def test_foo():
assert '\\n}' == ''
""")
result = testdir.runpytest()
assert result.ret == 1
result.stdout.fnmatch_lines([
"*AssertionError*",
])
def test_fmt_simple(self):
expl = 'assert foo'
assert util.format_explanation(expl) == 'assert foo'
def test_fmt_where(self):
expl = '\n'.join(['assert 1',
'{1 = foo',
'} == 2'])
res = '\n'.join(['assert 1 == 2',
' + where 1 = foo'])
assert util.format_explanation(expl) == res
def test_fmt_and(self):
expl = '\n'.join(['assert 1',
'{1 = foo',
'} == 2',
'{2 = bar',
'}'])
res = '\n'.join(['assert 1 == 2',
' + where 1 = foo',
' + and 2 = bar'])
assert util.format_explanation(expl) == res
def test_fmt_where_nested(self):
expl = '\n'.join(['assert 1',
'{1 = foo',
'{foo = bar',
'}',
'} == 2'])
res = '\n'.join(['assert 1 == 2',
' + where 1 = foo',
' + where foo = bar'])
assert util.format_explanation(expl) == res
def test_fmt_newline(self):
expl = '\n'.join(['assert "foo" == "bar"',
'~- foo',
'~+ bar'])
res = '\n'.join(['assert "foo" == "bar"',
' - foo',
' + bar'])
assert util.format_explanation(expl) == res
def test_fmt_newline_escaped(self):
expl = '\n'.join(['assert foo == bar',
'baz'])
res = 'assert foo == bar\\nbaz'
assert util.format_explanation(expl) == res
def test_fmt_newline_before_where(self):
expl = '\n'.join(['the assertion message here',
'>assert 1',
'{1 = foo',
'} == 2',
'{2 = bar',
'}'])
res = '\n'.join(['the assertion message here',
'assert 1 == 2',
' + where 1 = foo',
' + and 2 = bar'])
assert util.format_explanation(expl) == res
def test_fmt_multi_newline_before_where(self):
expl = '\n'.join(['the assertion',
'~message here',
'>assert 1',
'{1 = foo',
'} == 2',
'{2 = bar',
'}'])
res = '\n'.join(['the assertion',
' message here',
'assert 1 == 2',
' + where 1 = foo',
' + and 2 = bar'])
assert util.format_explanation(expl) == res
def test_python25_compile_issue257(testdir):
testdir.makepyfile("""
def test_rewritten():
@@ -354,7 +447,7 @@ def test_traceback_failure(testdir):
def test_onefails():
f(3)
""")
result = testdir.runpytest(p1)
result = testdir.runpytest(p1, "--tb=long")
result.stdout.fnmatch_lines([
"*test_traceback_failure.py F",
"====* FAILURES *====",
@@ -374,6 +467,25 @@ def test_traceback_failure(testdir):
"*test_traceback_failure.py:4: AssertionError"
])
result = testdir.runpytest(p1) # "auto"
result.stdout.fnmatch_lines([
"*test_traceback_failure.py F",
"====* FAILURES *====",
"____*____",
"",
" def test_onefails():",
"> f(3)",
"",
"*test_*.py:6: ",
"",
" def f(x):",
"> assert x == g()",
"E assert 3 == 2",
"E + where 2 = g()",
"",
"*test_traceback_failure.py:4: AssertionError"
])
@pytest.mark.skipif("sys.version_info < (2,5) or '__pypy__' in sys.builtin_module_names or sys.platform.startswith('java')" )
def test_warn_missing(testdir):
testdir.makepyfile("")

View File

@@ -121,7 +121,56 @@ class TestAssertionRewrite:
def test_assert_already_has_message(self):
def f():
assert False, "something bad!"
assert getmsg(f) == "AssertionError: something bad!"
assert getmsg(f) == "AssertionError: something bad!\nassert False"
def test_assertion_message(self, testdir):
testdir.makepyfile("""
def test_foo():
assert 1 == 2, "The failure message"
""")
result = testdir.runpytest()
assert result.ret == 1
result.stdout.fnmatch_lines([
"*AssertionError*The failure message*",
"*assert 1 == 2*",
])
def test_assertion_message_multiline(self, testdir):
testdir.makepyfile("""
def test_foo():
assert 1 == 2, "A multiline\\nfailure message"
""")
result = testdir.runpytest()
assert result.ret == 1
result.stdout.fnmatch_lines([
"*AssertionError*A multiline*",
"*failure message*",
"*assert 1 == 2*",
])
def test_assertion_message_tuple(self, testdir):
testdir.makepyfile("""
def test_foo():
assert 1 == 2, (1, 2)
""")
result = testdir.runpytest()
assert result.ret == 1
result.stdout.fnmatch_lines([
"*AssertionError*%s*" % repr((1, 2)),
"*assert 1 == 2*",
])
def test_assertion_message_expr(self, testdir):
testdir.makepyfile("""
def test_foo():
assert 1 == 2, 1 + 2
""")
result = testdir.runpytest()
assert result.ret == 1
result.stdout.fnmatch_lines([
"*AssertionError*3*",
"*assert 1 == 2*",
])
def test_boolop(self):
def f():
@@ -313,6 +362,17 @@ class TestAssertionRewrite:
assert "%test" == "test"
assert getmsg(f).startswith("assert '%test' == 'test'")
def test_custom_repr(self):
def f():
class Foo(object):
a = 1
def __repr__(self):
return "\n{ \n~ \n}"
f = Foo()
assert 0 == f.a
assert r"where 1 = \n{ \n~ \n}.a" in util._format_lines([getmsg(f)])[0]
class TestRewriteOnImport:
@@ -458,28 +518,35 @@ class TestAssertionRewriteHookDetails(object):
@pytest.mark.skipif("sys.version_info[0] >= 3")
def test_detect_coding_cookie(self, testdir):
testdir.tmpdir.join("test_cookie.py").write("""# -*- coding: utf-8 -*-
u"St\xc3\xa4d"
def test_rewritten():
assert "@py_builtins" in globals()""", "wb")
testdir.makepyfile(test_cookie="""
# -*- coding: utf-8 -*-
u"St\xc3\xa4d"
def test_rewritten():
assert "@py_builtins" in globals()""")
assert testdir.runpytest().ret == 0
@pytest.mark.skipif("sys.version_info[0] >= 3")
def test_detect_coding_cookie_second_line(self, testdir):
testdir.tmpdir.join("test_cookie.py").write("""#!/usr/bin/env python
# -*- coding: utf-8 -*-
u"St\xc3\xa4d"
def test_rewritten():
assert "@py_builtins" in globals()""", "wb")
testdir.makepyfile(test_cookie="""
# -*- coding: utf-8 -*-
u"St\xc3\xa4d"
def test_rewritten():
assert "@py_builtins" in globals()""")
assert testdir.runpytest().ret == 0
@pytest.mark.skipif("sys.version_info[0] >= 3")
def test_detect_coding_cookie_crlf(self, testdir):
testdir.tmpdir.join("test_cookie.py").write("""#!/usr/bin/env python
# -*- coding: utf-8 -*-
u"St\xc3\xa4d"
def test_rewritten():
assert "@py_builtins" in globals()""".replace("\n", "\r\n"), "wb")
testdir.makepyfile(test_cookie="""
# -*- coding: utf-8 -*-
u"St\xc3\xa4d"
def test_rewritten():
assert "@py_builtins" in globals()""")
assert testdir.runpytest().ret == 0
def test_sys_meta_path_munged(self, testdir):
testdir.makepyfile("""
def test_meta_path():
import sys; sys.meta_path = []""")
assert testdir.runpytest().ret == 0
def test_write_pyc(self, testdir, tmpdir, monkeypatch):
@@ -493,13 +560,13 @@ def test_rewritten():
state = AssertionState(config, "rewrite")
source_path = tmpdir.ensure("source.py")
pycpath = tmpdir.join("pyc").strpath
assert _write_pyc(state, [1], source_path, pycpath)
assert _write_pyc(state, [1], source_path.stat(), pycpath)
def open(*args):
e = IOError()
e.errno = 10
raise e
monkeypatch.setattr(b, "open", open)
assert not _write_pyc(state, [1], source_path, pycpath)
assert not _write_pyc(state, [1], source_path.stat(), pycpath)
def test_resources_provider_for_loader(self, testdir):
"""
@@ -532,3 +599,25 @@ def test_rewritten():
result.stdout.fnmatch_lines([
'* 1 passed*',
])
def test_read_pyc(self, tmpdir):
"""
Ensure that the `_read_pyc` can properly deal with corrupted pyc files.
In those circumstances it should just give up instead of generating
an exception that is propagated to the caller.
"""
import py_compile
from _pytest.assertion.rewrite import _read_pyc
source = tmpdir.join('source.py')
pyc = source + 'c'
source.write('def test(): pass')
py_compile.compile(str(source), str(pyc))
contents = pyc.read(mode='rb')
strip_bytes = 20 # header is around 8 bytes, strip a little more
assert len(contents) > strip_bytes
pyc.write(contents[:strip_bytes], mode='wb')
assert _read_pyc(source, str(pyc)) is None # no error

View File

@@ -1,6 +1,7 @@
# note: py.io capture tests where copied from
# pylib 1.4.20.dev2 (rev 13d9af95547e)
from __future__ import with_statement
import pickle
import os
import sys
import py
@@ -44,82 +45,64 @@ def oswritebytes(fd, obj):
def StdCaptureFD(out=True, err=True, in_=True):
return capture.MultiCapture(out, err, in_, Capture=capture.FDCapture)
def StdCapture(out=True, err=True, in_=True):
return capture.MultiCapture(out, err, in_, Capture=capture.SysCapture)
class TestCaptureManager:
def test_getmethod_default_no_fd(self, testdir, monkeypatch):
config = testdir.parseconfig(testdir.tmpdir)
assert config.getvalue("capture") is None
capman = CaptureManager()
def test_getmethod_default_no_fd(self, monkeypatch):
from _pytest.capture import pytest_addoption
from _pytest.config import Parser
parser = Parser()
pytest_addoption(parser)
default = parser._groups[0].options[0].default
assert default == "fd" if hasattr(os, "dup") else "sys"
parser = Parser()
monkeypatch.delattr(os, 'dup', raising=False)
try:
assert capman._getmethod(config, None) == "sys"
finally:
monkeypatch.undo()
@pytest.mark.parametrize("mode", "no fd sys".split())
def test_configure_per_fspath(self, testdir, mode):
config = testdir.parseconfig(testdir.tmpdir)
capman = CaptureManager()
hasfd = hasattr(os, 'dup')
if hasfd:
assert capman._getmethod(config, None) == "fd"
else:
assert capman._getmethod(config, None) == "sys"
if not hasfd and mode == 'fd':
return
sub = testdir.tmpdir.mkdir("dir" + mode)
sub.ensure("__init__.py")
sub.join("conftest.py").write('option_capture = %r' % mode)
assert capman._getmethod(config, sub.join("test_hello.py")) == mode
pytest_addoption(parser)
assert parser._groups[0].options[0].default == "sys"
@needsosdup
@pytest.mark.parametrize("method", ['no', 'fd', 'sys'])
@pytest.mark.parametrize("method",
['no', 'sys', pytest.mark.skipif('not hasattr(os, "dup")', 'fd')])
def test_capturing_basic_api(self, method):
capouter = capture.StdCaptureFD()
capouter = StdCaptureFD()
old = sys.stdout, sys.stderr, sys.stdin
try:
capman = CaptureManager()
# call suspend without resume or start
outerr = capman.suspendcapture()
capman = CaptureManager(method)
capman.init_capturings()
outerr = capman.suspendcapture()
assert outerr == ("", "")
outerr = capman.suspendcapture()
assert outerr == ("", "")
capman.resumecapture(method)
print ("hello")
out, err = capman.suspendcapture()
if method == "no":
assert old == (sys.stdout, sys.stderr, sys.stdin)
else:
assert out == "hello\n"
capman.resumecapture(method)
assert not out
capman.resumecapture()
print ("hello")
out, err = capman.suspendcapture()
assert not out and not err
if method != "no":
assert out == "hello\n"
capman.reset_capturings()
finally:
capouter.reset()
capouter.stop_capturing()
@needsosdup
def test_juggle_capturings(self, testdir):
capouter = capture.StdCaptureFD()
def test_init_capturing(self):
capouter = StdCaptureFD()
try:
#config = testdir.parseconfig(testdir.tmpdir)
capman = CaptureManager()
try:
capman.resumecapture("fd")
pytest.raises(ValueError, 'capman.resumecapture("fd")')
pytest.raises(ValueError, 'capman.resumecapture("sys")')
os.write(1, "hello\n".encode('ascii'))
out, err = capman.suspendcapture()
assert out == "hello\n"
capman.resumecapture("sys")
os.write(1, "hello\n".encode('ascii'))
py.builtin.print_("world", file=sys.stderr)
out, err = capman.suspendcapture()
assert not out
assert err == "world\n"
finally:
capman.reset_capturings()
capman = CaptureManager("fd")
capman.init_capturings()
pytest.raises(AssertionError, "capman.init_capturings()")
capman.reset_capturings()
finally:
capouter.reset()
capouter.stop_capturing()
@pytest.mark.parametrize("method", ['fd', 'sys'])
@@ -282,9 +265,9 @@ class TestPerTestCapturing:
"====* FAILURES *====",
"____*____",
"*test_capturing_outerr.py:8: ValueError",
"*--- Captured stdout ---*",
"*--- Captured stdout *call*",
"1",
"*--- Captured stderr ---*",
"*--- Captured stderr *call*",
"2",
])
@@ -410,13 +393,14 @@ class TestLoggingInteraction:
class TestCaptureFixture:
def test_std_functional(self, testdir):
@pytest.mark.parametrize("opt", [[], ["-s"]])
def test_std_functional(self, testdir, opt):
reprec = testdir.inline_runsource("""
def test_hello(capsys):
print (42)
out, err = capsys.readouterr()
assert out.startswith("42")
""")
""", *opt)
reprec.assertoutcome(passed=1)
def test_capsyscapfd(self, testdir):
@@ -533,6 +517,24 @@ def test_capture_conftest_runtest_setup(testdir):
assert 'hello19' not in result.stdout.str()
def test_capture_badoutput_issue412(testdir):
testdir.makepyfile("""
import os
def test_func():
omg = bytearray([1,129,1])
os.write(1, omg)
assert 0
""")
result = testdir.runpytest('--cap=fd')
result.stdout.fnmatch_lines('''
*def test_func*
*assert 0*
*Captured*
*1 failed*
''')
def test_capture_early_option_parsing(testdir):
testdir.makeconftest("""
def pytest_runtest_setup():
@@ -544,8 +546,6 @@ def test_capture_early_option_parsing(testdir):
assert 'hello19' in result.stdout.str()
@pytest.mark.xfail(sys.version_info >= (3, 0), reason='encoding issues')
@pytest.mark.xfail(sys.version_info < (2, 6), reason='test not run on py25')
def test_capture_binary_output(testdir):
testdir.makepyfile(r"""
import pytest
@@ -590,7 +590,7 @@ class TestTextIO:
def test_bytes_io():
f = capture.BytesIO()
f = py.io.BytesIO()
f.write(tobytes("hello"))
pytest.raises(TypeError, "f.write(totext('hello'))")
s = f.getvalue()
@@ -619,7 +619,7 @@ def tmpfile(testdir):
def test_dupfile(tmpfile):
flist = []
for i in range(5):
nf = capture.dupfile(tmpfile, encoding="utf-8")
nf = capture.safe_text_dupfile(tmpfile, "wb")
assert nf != tmpfile
assert nf.fileno() != tmpfile.fileno()
assert nf not in flist
@@ -633,19 +633,17 @@ def test_dupfile(tmpfile):
assert "01234" in repr(s)
tmpfile.close()
def test_dupfile_on_bytesio():
io = py.io.BytesIO()
f = capture.safe_text_dupfile(io, "wb")
f.write("hello")
assert io.getvalue() == b"hello"
def test_dupfile_no_mode():
"""
dupfile should trap an AttributeError and return f if no mode is supplied.
"""
class SomeFileWrapper(object):
"An object with a fileno method but no mode attribute"
def fileno(self):
return 1
tmpfile = SomeFileWrapper()
assert capture.dupfile(tmpfile) is tmpfile
with pytest.raises(AttributeError):
capture.dupfile(tmpfile, raising=True)
def test_dupfile_on_textio():
io = py.io.TextIO()
f = capture.safe_text_dupfile(io, "wb")
f.write("hello")
assert io.getvalue() == "hello"
@contextlib.contextmanager
@@ -670,17 +668,15 @@ class TestFDCapture:
cap = capture.FDCapture(fd)
data = tobytes("hello")
os.write(fd, data)
f = cap.done()
s = f.read()
f.close()
s = cap.snap()
cap.done()
assert not s
cap = capture.FDCapture(fd)
cap.start()
os.write(fd, data)
f = cap.done()
s = f.read()
s = cap.snap()
cap.done()
assert s == "hello"
f.close()
def test_simple_many(self, tmpfile):
for i in range(10):
@@ -694,155 +690,179 @@ class TestFDCapture:
def test_simple_fail_second_start(self, tmpfile):
fd = tmpfile.fileno()
cap = capture.FDCapture(fd)
f = cap.done()
cap.done()
pytest.raises(ValueError, cap.start)
f.close()
def test_stderr(self):
cap = capture.FDCapture(2, patchsys=True)
cap = capture.FDCapture(2)
cap.start()
print_("hello", file=sys.stderr)
f = cap.done()
s = f.read()
s = cap.snap()
cap.done()
assert s == "hello\n"
def test_stdin(self, tmpfile):
tmpfile.write(tobytes("3"))
tmpfile.seek(0)
cap = capture.FDCapture(0, tmpfile=tmpfile)
cap = capture.FDCapture(0)
cap.start()
# check with os.read() directly instead of raw_input(), because
# sys.stdin itself may be redirected (as pytest now does by default)
x = os.read(0, 100).strip()
cap.done()
assert x == tobytes("3")
assert x == tobytes('')
def test_writeorg(self, tmpfile):
data1, data2 = tobytes("foo"), tobytes("bar")
try:
cap = capture.FDCapture(tmpfile.fileno())
cap.start()
tmpfile.write(data1)
cap.writeorg(data2)
finally:
tmpfile.close()
f = cap.done()
scap = f.read()
cap = capture.FDCapture(tmpfile.fileno())
cap.start()
tmpfile.write(data1)
tmpfile.flush()
cap.writeorg(data2)
scap = cap.snap()
cap.done()
assert scap == totext(data1)
stmp = open(tmpfile.name, 'rb').read()
assert stmp == data2
with open(tmpfile.name, 'rb') as stmp_file:
stmp = stmp_file.read()
assert stmp == data2
def test_simple_resume_suspend(self, tmpfile):
with saved_fd(1):
cap = capture.FDCapture(1)
cap.start()
data = tobytes("hello")
os.write(1, data)
sys.stdout.write("whatever")
s = cap.snap()
assert s == "hellowhatever"
cap.suspend()
os.write(1, tobytes("world"))
sys.stdout.write("qlwkej")
assert not cap.snap()
cap.resume()
os.write(1, tobytes("but now"))
sys.stdout.write(" yes\n")
s = cap.snap()
assert s == "but now yes\n"
cap.suspend()
cap.done()
pytest.raises(AttributeError, cap.suspend)
@contextlib.contextmanager
def saved_fd(fd):
new_fd = os.dup(fd)
try:
yield
finally:
os.dup2(new_fd, fd)
os.close(new_fd)
class TestStdCapture:
captureclass = staticmethod(StdCapture)
@contextlib.contextmanager
def getcapture(self, **kw):
cap = capture.StdCapture(**kw)
cap.startall()
return cap
cap = self.__class__.captureclass(**kw)
cap.start_capturing()
try:
yield cap
finally:
cap.stop_capturing()
def test_capturing_done_simple(self):
cap = self.getcapture()
sys.stdout.write("hello")
sys.stderr.write("world")
outfile, errfile = cap.done()
s = outfile.read()
assert s == "hello"
s = errfile.read()
assert s == "world"
with self.getcapture() as cap:
sys.stdout.write("hello")
sys.stderr.write("world")
out, err = cap.readouterr()
assert out == "hello"
assert err == "world"
def test_capturing_reset_simple(self):
cap = self.getcapture()
print("hello world")
sys.stderr.write("hello error\n")
out, err = cap.reset()
with self.getcapture() as cap:
print("hello world")
sys.stderr.write("hello error\n")
out, err = cap.readouterr()
assert out == "hello world\n"
assert err == "hello error\n"
def test_capturing_readouterr(self):
cap = self.getcapture()
try:
with self.getcapture() as cap:
print ("hello world")
sys.stderr.write("hello error\n")
out, err = cap.readouterr()
assert out == "hello world\n"
assert err == "hello error\n"
sys.stderr.write("error2")
finally:
out, err = cap.reset()
out, err = cap.readouterr()
assert err == "error2"
def test_capturing_readouterr_unicode(self):
cap = self.getcapture()
try:
with self.getcapture() as cap:
print ("hx\xc4\x85\xc4\x87")
out, err = cap.readouterr()
finally:
cap.reset()
assert out == py.builtin._totext("hx\xc4\x85\xc4\x87\n", "utf8")
@pytest.mark.skipif('sys.version_info >= (3,)',
reason='text output different for bytes on python3')
def test_capturing_readouterr_decode_error_handling(self):
cap = self.getcapture()
# triggered a internal error in pytest
print('\xa6')
out, err = cap.readouterr()
with self.getcapture() as cap:
# triggered a internal error in pytest
print('\xa6')
out, err = cap.readouterr()
assert out == py.builtin._totext('\ufffd\n', 'unicode-escape')
def test_reset_twice_error(self):
cap = self.getcapture()
print ("hello")
out, err = cap.reset()
pytest.raises(ValueError, cap.reset)
with self.getcapture() as cap:
print ("hello")
out, err = cap.readouterr()
pytest.raises(ValueError, cap.stop_capturing)
assert out == "hello\n"
assert not err
def test_capturing_modify_sysouterr_in_between(self):
oldout = sys.stdout
olderr = sys.stderr
cap = self.getcapture()
sys.stdout.write("hello")
sys.stderr.write("world")
sys.stdout = capture.TextIO()
sys.stderr = capture.TextIO()
print ("not seen")
sys.stderr.write("not seen\n")
out, err = cap.reset()
with self.getcapture() as cap:
sys.stdout.write("hello")
sys.stderr.write("world")
sys.stdout = capture.TextIO()
sys.stderr = capture.TextIO()
print ("not seen")
sys.stderr.write("not seen\n")
out, err = cap.readouterr()
assert out == "hello"
assert err == "world"
assert sys.stdout == oldout
assert sys.stderr == olderr
def test_capturing_error_recursive(self):
cap1 = self.getcapture()
print ("cap1")
cap2 = self.getcapture()
print ("cap2")
out2, err2 = cap2.reset()
out1, err1 = cap1.reset()
with self.getcapture() as cap1:
print ("cap1")
with self.getcapture() as cap2:
print ("cap2")
out2, err2 = cap2.readouterr()
out1, err1 = cap1.readouterr()
assert out1 == "cap1\n"
assert out2 == "cap2\n"
def test_just_out_capture(self):
cap = self.getcapture(out=True, err=False)
sys.stdout.write("hello")
sys.stderr.write("world")
out, err = cap.reset()
with self.getcapture(out=True, err=False) as cap:
sys.stdout.write("hello")
sys.stderr.write("world")
out, err = cap.readouterr()
assert out == "hello"
assert not err
def test_just_err_capture(self):
cap = self.getcapture(out=False, err=True)
sys.stdout.write("hello")
sys.stderr.write("world")
out, err = cap.reset()
with self.getcapture(out=False, err=True) as cap:
sys.stdout.write("hello")
sys.stderr.write("world")
out, err = cap.readouterr()
assert err == "world"
assert not out
def test_stdin_restored(self):
old = sys.stdin
cap = self.getcapture(in_=True)
newstdin = sys.stdin
out, err = cap.reset()
with self.getcapture(in_=True):
newstdin = sys.stdin
assert newstdin != sys.stdin
assert sys.stdin is old
@@ -850,68 +870,47 @@ class TestStdCapture:
print ("XXX this test may well hang instead of crashing")
print ("XXX which indicates an error in the underlying capturing")
print ("XXX mechanisms")
cap = self.getcapture()
pytest.raises(IOError, "sys.stdin.read()")
out, err = cap.reset()
def test_suspend_resume(self):
cap = self.getcapture(out=True, err=False, in_=False)
try:
print ("hello")
sys.stderr.write("error\n")
out, err = cap.suspend()
assert out == "hello\n"
assert not err
print ("in between")
sys.stderr.write("in between\n")
cap.resume()
print ("after")
sys.stderr.write("error_after\n")
finally:
out, err = cap.reset()
assert out == "after\n"
assert not err
with self.getcapture():
pytest.raises(IOError, "sys.stdin.read()")
class TestStdCaptureFD(TestStdCapture):
pytestmark = needsosdup
captureclass = staticmethod(StdCaptureFD)
def getcapture(self, **kw):
cap = capture.StdCaptureFD(**kw)
cap.startall()
return cap
def test_simple_only_fd(self, testdir):
testdir.makepyfile("""
import os
def test_x():
os.write(1, "hello\\n".encode("ascii"))
assert 0
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines("""
*test_x*
*assert 0*
*Captured stdout*
""")
def test_intermingling(self):
cap = self.getcapture()
oswritebytes(1, "1")
sys.stdout.write(str(2))
sys.stdout.flush()
oswritebytes(1, "3")
oswritebytes(2, "a")
sys.stderr.write("b")
sys.stderr.flush()
oswritebytes(2, "c")
out, err = cap.reset()
with self.getcapture() as cap:
oswritebytes(1, "1")
sys.stdout.write(str(2))
sys.stdout.flush()
oswritebytes(1, "3")
oswritebytes(2, "a")
sys.stderr.write("b")
sys.stderr.flush()
oswritebytes(2, "c")
out, err = cap.readouterr()
assert out == "123"
assert err == "abc"
def test_many(self, capfd):
with lsof_check():
for i in range(10):
cap = capture.StdCaptureFD()
cap.reset()
@needsosdup
def test_stdcapture_fd_tmpfile(tmpfile):
capfd = capture.StdCaptureFD(out=tmpfile)
try:
os.write(1, "hello".encode("ascii"))
os.write(2, "world".encode("ascii"))
outf, errf = capfd.done()
finally:
capfd.reset()
assert outf == tmpfile
cap = StdCaptureFD()
cap.stop_capturing()
class TestStdCaptureFDinvalidFD:
@@ -920,19 +919,22 @@ class TestStdCaptureFDinvalidFD:
def test_stdcapture_fd_invalid_fd(self, testdir):
testdir.makepyfile("""
import os
from _pytest.capture import StdCaptureFD
from _pytest import capture
def StdCaptureFD(out=True, err=True, in_=True):
return capture.MultiCapture(out, err, in_,
Capture=capture.FDCapture)
def test_stdout():
os.close(1)
cap = StdCaptureFD(out=True, err=False, in_=False)
cap.done()
cap.stop_capturing()
def test_stderr():
os.close(2)
cap = StdCaptureFD(out=False, err=True, in_=False)
cap.done()
cap.stop_capturing()
def test_stdin():
os.close(0)
cap = StdCaptureFD(out=False, err=False, in_=True)
cap.done()
cap.stop_capturing()
""")
result = testdir.runpytest("--capture=fd")
assert result.ret == 0
@@ -940,27 +942,8 @@ class TestStdCaptureFDinvalidFD:
def test_capture_not_started_but_reset():
capsys = capture.StdCapture()
capsys.done()
capsys.done()
capsys.reset()
@needsosdup
def test_capture_no_sys():
capsys = capture.StdCapture()
try:
cap = capture.StdCaptureFD(patchsys=False)
cap.startall()
sys.stdout.write("hello")
sys.stderr.write("world")
oswritebytes(1, "1")
oswritebytes(2, "2")
out, err = cap.reset()
assert out == "1"
assert err == "2"
finally:
capsys.reset()
capsys = StdCapture()
capsys.stop_capturing()
@needsosdup
@@ -968,19 +951,37 @@ def test_capture_no_sys():
def test_fdcapture_tmpfile_remains_the_same(tmpfile, use):
if not use:
tmpfile = True
cap = capture.StdCaptureFD(out=False, err=tmpfile)
cap = StdCaptureFD(out=False, err=tmpfile)
try:
cap.startall()
cap.start_capturing()
capfile = cap.err.tmpfile
cap.suspend()
cap.resume()
cap.readouterr()
finally:
cap.reset()
cap.stop_capturing()
capfile2 = cap.err.tmpfile
assert capfile2 == capfile
@needsosdup
def test_close_and_capture_again(testdir):
testdir.makepyfile("""
import os
def test_close():
os.close(1)
def test_capture_again():
os.write(1, b"hello\\n")
assert 0
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines("""
*test_capture_again*
*assert 0*
*stdout*
*hello*
""")
@pytest.mark.parametrize('method', ['StdCapture', 'StdCaptureFD'])
@pytest.mark.parametrize('method', ['SysCapture', 'FDCapture'])
def test_capturing_and_logging_fundamentals(testdir, method):
if method == "StdCaptureFD" and not hasattr(os, 'dup'):
pytest.skip("need os.dup")
@@ -989,23 +990,59 @@ def test_capturing_and_logging_fundamentals(testdir, method):
import sys, os
import py, logging
from _pytest import capture
cap = capture.%s(out=False, in_=False)
cap.startall()
cap = capture.MultiCapture(out=False, in_=False,
Capture=capture.%s)
cap.start_capturing()
logging.warn("hello1")
outerr = cap.suspend()
outerr = cap.readouterr()
print ("suspend, captured %%s" %%(outerr,))
logging.warn("hello2")
cap.resume()
cap.pop_outerr_to_orig()
logging.warn("hello3")
outerr = cap.suspend()
outerr = cap.readouterr()
print ("suspend2, captured %%s" %% (outerr,))
""" % (method,))
result = testdir.runpython(p)
result.stdout.fnmatch_lines([
"suspend, captured*hello1*",
"suspend2, captured*hello2*WARNING:root:hello3*",
])
result.stdout.fnmatch_lines("""
suspend, captured*hello1*
suspend2, captured*WARNING:root:hello3*
""")
result.stderr.fnmatch_lines("""
WARNING:root:hello2
""")
assert "atexit" not in result.stderr.str()
def test_error_attribute_issue555(testdir):
testdir.makepyfile("""
import sys
def test_capattr():
assert sys.stdout.errors == "strict"
assert sys.stderr.errors == "strict"
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_dontreadfrominput_has_encoding(testdir):
testdir.makepyfile("""
import sys
def test_capattr():
# should not raise AttributeError
assert sys.stdout.encoding
assert sys.stderr.encoding
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_pickling_and_unpickling_enocded_file():
# See https://bitbucket.org/hpk42/pytest/pull-request/194
# pickle.loads() raises infinite recursion if
# EncodedFile.__getattr__ is not implemented properly
ef = capture.EncodedFile(None, None)
ef_as_str = pickle.dumps(ef)
pickle.loads(ef_as_str)

Some files were not shown because too many files have changed in this diff Show More