Compare commits

...

286 Commits
2.8.0 ... 2.8.5

Author SHA1 Message Date
Bruno Oliveira
855b115dab Remove plugins_index generation from HOWTORELEASE 2015-12-11 22:35:44 -02:00
Bruno Oliveira
4263b8b407 Restore regen-doc result 2015-12-11 22:34:16 -02:00
Florian Bruhin
7d150c20cf Regenerate 2.8.5 docs. 2015-12-11 22:28:23 -02:00
Bruno Oliveira
a124163425 Prepare for 2.8.5: bump version, CHANGELOG, announce 2015-12-11 19:20:07 -02:00
Ronny Pfannschmidt
2382546112 Merge pull request #1252 from nicoddemus/optimize-app-veyor
Optimize appveyor build
2015-12-11 16:10:45 +01:00
Bruno Oliveira
946bb08da5 Tyding up the CHANGELOG 2015-12-11 00:36:26 -02:00
Bruno Oliveira
85d1f0404a Merge pull request #1243 from aselus-hub/master
Update python.py
2015-12-11 00:33:46 -02:00
Bruno Oliveira
1d60f61ba8 Optimize appveyor build
- AppVeyor does not run matrix builds in parallel, so creating a matrix with the intent to
  speed up the build will actually result in longer build times, as each matrix will execute
  in a brand new VM.
- tox does not detect 64 bit installations in AppVeyor, it always installs interpreters
  from C:\PythonX.Y, so there's no point to have 64bit builds
- No need for the auxiliary script "install.ps1" because all python versions we are interested
  in are already pre-installed in AppVeyor
2015-12-11 00:20:20 -02:00
aselus-hub
ad05cbe6da fixed meesage. 2015-12-10 15:39:31 -08:00
aselus-hub
1216a27b44 added docstrign to inection collection test. 2015-12-10 15:19:08 -08:00
aselus-hub
2b2240e904 added myself to authors, added changelog entry. 2015-12-10 15:15:09 -08:00
aselus-hub
74f7efd2a3 added line comparison that is pytest-sugar agnostic. 2015-12-10 15:10:55 -08:00
aselus-hub
34db8aed34 added verification that test actually passed. 2015-12-10 15:02:57 -08:00
aselus-hub
af54e09759 nit: fixed newline 2015-12-10 14:46:51 -08:00
aselus-hub
dfaeefd692 added test to verify injection. 2015-12-10 14:45:36 -08:00
Bruno Oliveira
46c85bc352 Merge pull request #1249 from nicoddemus/remove-plugins-index
Remove plugins_index from the docs
2015-12-10 19:11:32 -02:00
Bruno Oliveira
139c97930b Remove plugins_index from the docs
Fix #1229
2015-12-10 19:00:01 -02:00
Ronny Pfannschmidt
9cfee82f9b Merge pull request #1247 from alex/patch-1
Use https for images in readme
2015-12-10 00:02:47 +01:00
Alex Gaynor
c0a5f3df10 Use https for images in readme 2015-12-09 18:01:36 -05:00
Bruno Oliveira
8220c05b01 Merge pull request #1245 from RonnyPfannschmidt/howtorelease
add a reminder of the features branch merge to HOWTORELEASE.rst
2015-12-09 18:34:41 -02:00
Ronny Pfannschmidt
d0f5f6676b add a reminder of the features branch merge to HOWTORELEASE.rst 2015-12-09 21:20:54 +01:00
aselus-hub
ec02f694ef Update python.py
updated dictionary itteration to create a list for generation, so that tests can be added in the generator functions under python3. This works fine as-is in python2 because python 2 already creates a list, whereas python3 returns an itterator. Forcing a list format for the return fixes python3 to work the same way as python2
2015-12-09 11:32:19 -08:00
Ronny Pfannschmidt
1c70827f33 Merge pull request #1241 from nicoddemus/fix-deprecated-call-args
Fix deprecated_call regression introduced in 2.8.4
2015-12-09 06:48:43 +01:00
Bruno Oliveira
1c46462991 Fix deprecated_call regression introduced in 2.8.4
Fix #1238
2015-12-08 22:40:05 -02:00
Ronny Pfannschmidt
ffa572531a Merge pull request #1091 from RonnyPfannschmidt/fix-1074
fix issue 1074 and clean up junitxml
2015-12-07 22:13:16 +01:00
Ronny Pfannschmidt
fde2a6f5fd add changelog entry 2015-12-07 21:58:34 +01:00
Ronny Pfannschmidt
7b7737bf96 handle duplicate test ids via collection and xdist each reporting 2015-12-07 21:54:25 +01:00
Ronny Pfannschmidt
04e9ae75c8 add xfailing test for double test id failure 2015-12-07 21:54:25 +01:00
Ronny Pfannschmidt
9ea7826427 Junitxml: correct node reporter attribute names 2015-12-07 21:54:25 +01:00
Ronny Pfannschmidt
09cc45b0c5 junitxml: correct docstring of make_properties_node 2015-12-07 21:54:25 +01:00
Ronny Pfannschmidt
0aa54101c9 junitxml: follow Bruno's attribute/method naming hint from the review 2015-12-07 21:54:25 +01:00
Ronny Pfannschmidt
5eef6a2821 junitxml: fix python3 compat of the tests 2015-12-07 21:54:25 +01:00
Ronny Pfannschmidt
518c88f149 finalize nodereporters by throwing away the intermediate xml nodes, fixes issue #1074 2015-12-07 21:54:25 +01:00
Ronny Pfannschmidt
5f5a7995b9 reintroduce junitxml report order and debug cleanups 2015-12-07 21:54:24 +01:00
Ronny Pfannschmidt
0528e5b45f junitxml: intermediate, move testcase generation to NodeReporter 2015-12-07 21:54:24 +01:00
Ronny Pfannschmidt
9b04958303 junitxml: keep track of custom property insert order
+ review: should we allow the same key multile times
2015-12-07 21:54:24 +01:00
Ronny Pfannschmidt
faed54d6c7 junitxml: use node.warn to ensure fslocations 2015-12-07 21:54:24 +01:00
Ronny Pfannschmidt
1f609f96e6 junitxml: introduce nodereporter and track durations/properties there 2015-12-07 21:54:24 +01:00
Ronny Pfannschmidt
0664ae137c junitxml: remove debug print 2015-12-07 21:54:24 +01:00
Ronny Pfannschmidt
d0107c898e junitxml restrucutre stat generation - use node tags 2015-12-07 21:54:24 +01:00
Ronny Pfannschmidt
9128fec4c4 junitxml: simplify the api used for testing junitml 2015-12-07 21:54:24 +01:00
Ronny Pfannschmidt
80bcf8d624 junitxml: simplify tests by creating a api wrapper 2015-12-07 21:54:24 +01:00
Ronny Pfannschmidt
b8df5446c0 junitxml: yapf clean the tests 2015-12-07 21:54:24 +01:00
Ronny Pfannschmidt
2a31df072b junitxml: reverse the if/else logic for failure appending 2015-12-07 21:54:24 +01:00
Ronny Pfannschmidt
02f5defd89 yapf junitxml 2015-12-07 21:54:24 +01:00
Bruno Oliveira
efb5332023 Merge pull request #1186 from RonnyPfannschmidt/fix-manifest
fix #1185 - ensure MANIFEST.in exactly matches what should go to a sdist
2015-12-07 13:48:39 -02:00
Ronny Pfannschmidt
b9908cc036 Merge pull request #1228 from pytest-dev/pytest-2.8.4
finish the release process of pytest 2.8.4
2015-12-06 20:32:52 +01:00
Ronny Pfannschmidt
c727860241 bump to 2.8.5.dev 2015-12-06 20:31:14 +01:00
Ronny Pfannschmidt
8c17c7cd12 correct copy&paste error in the release announcement version number 2015-12-06 17:44:08 +01:00
Ronny Pfannschmidt
b7459b8a64 finish release announcement 2015-12-06 16:46:44 +01:00
Ronny Pfannschmidt
b920f09a95 doc regen for release 2.8.4 2015-12-06 16:14:23 +01:00
Ronny Pfannschmidt
a3353c49fd prepare release 2.8.4 - changelog updates + version bump 2015-12-06 16:13:55 +01:00
Ronny Pfannschmidt
a4a12b8356 Merge pull request #1227 from nicoddemus/warn-deprecated-call
Add a note about how DeprecationWarning and PendingDeprecationWarning are treated differently
2015-12-06 10:52:58 +01:00
Ronny Pfannschmidt
13ae2fe28b adopt review comment of #1186 2015-12-06 10:24:24 +01:00
Ronny Pfannschmidt
141a463fed fix #1185 - ensure MANIFEST.in exactly matches what should go to a sdist 2015-12-06 10:24:24 +01:00
Ronny Pfannschmidt
f508a52ca9 Merge pull request #1225 from pytest-dev/skipping-docs-inconsistency
Fix inconsistency in skipif example
2015-12-05 20:44:01 +01:00
Bruno Oliveira
b48a02fdb1 Add a note about how DeprecationWarning and PendingDeprecationWarning are treated differently
Fix #1026
2015-12-05 13:53:58 -02:00
Bruno Oliveira
382efc6363 Fix same inconsistency in next example 2015-12-05 00:43:06 -02:00
Bruno Oliveira
1bed514eb6 Fix inconsistency in skipif example
Fix #1224
2015-12-05 00:35:31 -02:00
Bruno Oliveira
41f19796e8 Merge pull request #1212 from nicoddemus/goodpractices
Goodpractises docs reorganization/review
2015-12-05 00:27:28 -02:00
Ronny Pfannschmidt
427e6c3b4d Merge pull request #1222 from nicoddemus/pastebin-unicode
Fix #1222 - pastebin when captured output contains non-ascii characters
2015-12-04 07:10:49 +01:00
Bruno Oliveira
14bc3c4009 Fix pastebin when captured output contains non-ascii characters
Fix #1219
2015-12-03 20:07:18 -02:00
Florian Bruhin
7e063eec08 Merge pull request #1221 from jeffwidman/patch-1
Fix typo: previosuly --> previously
2015-12-03 21:25:40 +01:00
Jeff Widman
61934ae82d Fix typo: previosuly --> previously 2015-12-03 11:56:18 -08:00
Bruno Oliveira
8c74bb0d25 Improve description on how pytest starts test collection in goodpractises 2015-12-03 01:01:34 -02:00
Bruno Oliveira
bb4771cedf Remove promise about documenting how to create a zipped pytest 2015-12-03 00:13:16 -02:00
Bruno Oliveira
9475cd3fb8 Replace "--assertmode=off" by "--assert=plain"
Fix #1214
2015-12-02 18:39:32 -02:00
Bruno Oliveira
464e16deca Removed incorrect note about genscript requiring wheels 2015-12-02 18:33:53 -02:00
Bruno Oliveira
d9b78f2a95 Remove reference to distutils 2015-12-02 18:30:12 -02:00
Ronny Pfannschmidt
7232b45f25 Merge pull request #1213 from nicoddemus/pastebin-py3
merge Pastebin py3 support

 also closes #1202 and fixes #1198
2015-12-02 09:08:50 +01:00
Bruno Oliveira
a54e4e64cd Merge remote-tracking branch 'upstream/master' into pastebin-py3 2015-12-01 23:51:14 -02:00
Bruno Oliveira
edfb567091 Add #1198 fix to CHANGELOG 2015-12-01 23:37:16 -02:00
Bruno Oliveira
6a2ebddc7c Decode urlopen response in pastebin
Fix #1198
2015-12-01 23:33:37 -02:00
Bruno Oliveira
5040dde0c5 Fix genscript deprecation version and document reasons for such 2015-12-01 23:09:15 -02:00
Bruno Oliveira
095abfd035 Fix formatting errors 2015-12-01 22:52:22 -02:00
Bruno Oliveira
69ef0ab189 Merged virtual env into the Tox section
Nowadays virtualenv use is widespread so we don't need to
devote a how-to section in pytest's docs
2015-12-01 22:47:36 -02:00
Bruno Oliveira
d851a8fd07 Fixed some formatting 2015-12-01 22:43:11 -02:00
Bruno Oliveira
0704fcacd7 Removed setuptools/genscript session 2015-12-01 22:32:07 -02:00
Bruno Oliveira
4f17d56ecb Move deprecated genscript method to the bottom of the document 2015-12-01 22:30:08 -02:00
Bruno Oliveira
b1f6dc23da Moved "conventions for Python test discovery to the top" 2015-12-01 22:28:20 -02:00
Bruno Oliveira
c6f90c25e3 Remove finalize_options override from goodpractices
This is not required in latest versions of `setuptools`, and
`self.test_args` is a read-only attribute in some of the
versions of the 18.X series.

Fix #1134
2015-12-01 22:20:40 -02:00
Florian Bruhin
f0e5cb362e Merge pull request #1211 from nchammas/patch-1
Update xdist newhooks.py link; BitBucket -> GitHub
2015-12-01 20:15:40 +01:00
Nicholas Chammas
c7cf4adfd0 Update xdist link; BitBucket -> GitHub
xdist is now hosted on GitHub.
2015-12-01 13:20:55 -05:00
Ronny Pfannschmidt
def543924b Merge pull request #1209 from jeffwidman/master
Fix spelling: explicitely --> explicitly
2015-12-01 10:51:26 +01:00
Jeff Widman
6be6798cdf Fix spelling: explicitely --> explicitly 2015-12-01 01:41:47 -08:00
Ronny Pfannschmidt
ce4eb51ee0 Merge pull request #1208 from The-Compiler/no-tests-run-spelling
Fix spelling mistake in #1207.
2015-11-30 17:40:26 +01:00
Florian Bruhin
0d2668017d Fix spelling mistake in #1207. 2015-11-30 17:33:34 +01:00
Ronny Pfannschmidt
e7e4860ded Merge pull request #1207 from The-Compiler/no-tests-run
Fix terminal output if no tests were run.
2015-11-30 17:26:47 +01:00
Florian Bruhin
aba55a0fb2 Fix terminal output if no tests were run.
Before:
====  in 0.00 seconds ====

After:
==== no tests run in 0.00 seconds ====
2015-11-30 17:24:40 +01:00
Ronny Pfannschmidt
b5d65e5139 Merge pull request #1206 from The-Compiler/collect-getattr
Don't collect classes with truthy __getattr__.
2015-11-30 17:23:47 +01:00
Ronny Pfannschmidt
3a3f0f5c56 Merge pull request #1205 from The-Compiler/reportinfo-getattr
Fix getting line number with nasty __getattr__. fixes #1204
2015-11-30 17:23:05 +01:00
Florian Bruhin
ba9146c131 Don't collect classes with truthy __getattr__.
When we have a metaclass which returns something truthy (like a method) in its
__getattr__, we collected the class because pytest thought its __test__
attribute was set to True.

We can work around this to some degree by assuming __test__ will always be set
to an explicit True if that's what the user has intended, and if it's something
other than that, this is probably a mistake.

Fixes #1204.
2015-11-30 16:41:13 +01:00
Florian Bruhin
c790f7475e Fix getting line number with nasty __getattr__.
When an object has a custom __getattr__ which always returns a non-int, we
tried to get compat_co_firstlineno from it and checked it was a integer, which
caused an exception if such a class is mistakenly collected.

If we still mistakenly collect such a class (which is likely to be something
other than a test), we now skip it with a warning (because it probably has an
__init__) instead of producing an error.

See #1204.
2015-11-30 16:13:15 +01:00
mehdy
f9b1e39b8a fix #1198 - decoding monkeypatched data to unicode 2015-11-29 19:42:50 +03:30
mehdy
81ad1689b9 fix #1198 - removed docoding the result 2015-11-29 19:20:37 +03:30
mehdy
44f60ba141 fixed #1198 issue by encoding the unicode parameters to bytes and decoding the
bytes response to unicode
2015-11-29 18:27:05 +03:30
Ronny Pfannschmidt
bced5a3f81 Merge pull request #1200 from macrotim/master
Merge #1200 - correct various documentation spelling misstakes
2015-11-28 08:00:24 +01:00
Tim Chan
a8d7e513f4 Fixed docs 2015-11-27 22:46:45 -08:00
Ronny Pfannschmidt
604a021a2a Merge pull request #1196 from nicoddemus/deprecated-call-1190
Make deprecated_call() use monkey-patching again , fixes #1190
2015-11-27 22:09:09 +01:00
Bruno Oliveira
603d81ef2f deprecated_call now uses monkey patching strategy to capture warnings
similar to what we had in 2.7, with a few enhancements

Fix #1190
2015-11-26 16:48:58 -02:00
Bruno Oliveira
6378cdf7a9 Restored 2.7 implentation of deprecated_call 2015-11-26 15:54:57 -02:00
Bruno Oliveira
320c95ca43 Fix formatting in HOWTORELEASE.rst 2015-11-24 12:05:41 -02:00
Bruno Oliveira
b20803f0a6 Mention pytest_enter_pdb in the docs 2015-11-23 18:00:02 -02:00
Ronny Pfannschmidt
af46ffe021 bump to 2.8.4.dev 2015-11-19 22:01:34 +01:00
Ronny Pfannschmidt
e4a000bb00 refer more explicit to osx el cap in the changelogs 2015-11-18 17:57:41 +01:00
Ronny Pfannschmidt
d04505553e update authors list for 2.8.3 and add a log command to the howto 2015-11-18 17:55:18 +01:00
Ronny Pfannschmidt
2b5c46b2ab correct drop in version in announcement 2015-11-18 17:48:35 +01:00
Ronny Pfannschmidt
063f90f0d2 run regendoc 2015-11-18 17:47:17 +01:00
Ronny Pfannschmidt
6096cae3dd release announcements for 2.8.3 2015-11-18 17:38:31 +01:00
Ronny Pfannschmidt
3dc57d99f2 Changelog groming and release preps for 2.8.3 2015-11-18 17:34:30 +01:00
Florian Bruhin
3cc5a4ecb0 Merge pull request #1175 from gabehollombe/add-pyconsg2015-talk
Add 'Improve your testing with Pytest and Mock' video from PyCon SG 2015
2015-11-11 06:16:46 +01:00
Gabe Hollombe
ac0b7b9803 Add 'Improve your testing with Pytest and Mock' video from PyCon SG 2015 2015-11-11 11:28:59 +08:00
Bruno Oliveira
a1d226b751 Merge pull request #1168 from hackebrot/write-docs-on-ignore-cli-option
Write docs on ignore cli option
2015-11-07 12:38:21 -02:00
Raphael Pierzina
d667259e31 Change pytest ignore invocation as suggested by @nicoddemus 2015-11-04 23:45:29 +01:00
Bruno Oliveira
98668c943d Merge pull request #1171 from nicoddemus/fix-1169
Allow @unittest.skip decorators in Python 2.7
2015-11-04 20:27:00 -02:00
Bruno Oliveira
a7a470b56f Give credit where it is due 2015-11-04 19:55:05 -02:00
Bruno Oliveira
7d6edb9ca5 Fix unittest.skip decorator test and separate the fix into a different, self-doc function 2015-11-04 19:54:18 -02:00
Lee Kamentsky
313050b15b Suggested edits by Bruno.
Moved fix to TestCaseFunction.setup. Added myself to AUTHORS and added entry to CHANGELOG
2015-11-04 15:30:16 -05:00
Lee Kamentsky
1833547936 Added test for issue #1169
(I undid my fix, checked for failure, redid my fix and it passes)
2015-11-04 14:24:22 -05:00
LeeKamentsky
8de2c035e2 Fixes #1169
The unittest.skip decorator runs @functools.wraps on self._testcase. functools.wraps expects a "__name__" attribute and this patch adds one. It might not be the correct fix, but it works for me.
2015-11-04 13:52:40 -05:00
Raphael Pierzina
a2d07bfa93 Add pytest invocation along with result 2015-11-04 15:34:18 +01:00
Raphael Pierzina
586fdbcbbd Add example tests directory structure 2015-11-04 15:00:37 +01:00
Raphael Pierzina
04079f9ae5 Start doc section on `--ignore` in pytestcollection.rst 2015-11-04 14:49:02 +01:00
Bruno Oliveira
af2d391903 Merge pull request #1166 from Toilal/pytest-runner
Use pytest-runner for setuptools integration
2015-11-02 12:50:21 -02:00
Toilal
8abf85e96c Use pytest-runner for setuptools integration 2015-11-02 12:22:40 +01:00
Ronny Pfannschmidt
9013cb1b4c Merge pull request #1144 from The-Compiler/elcapitan-sip
Handle EPERM when writing rewritten bytecode.
2015-11-01 08:20:00 +01:00
Florian Bruhin
2eb345f9b7 Merge pull request #1159 from zoidbergwill/patch-1
Fix typo in parametrize.rst
2015-10-30 09:02:29 +01:00
William Martin Stewart
1376d75fbe Fix typo in parametrize.rst 2015-10-30 09:58:41 +02:00
Bruno Oliveira
4fe7cca44e Merge pull request #1157 from gabrielcnr/master
Color highlight on the name of the failed tests
2015-10-28 17:36:47 -02:00
gabriel.reis
a83d5c0f08 Updated entries on CHANGELOG and AUTHORS. Ref: #1157 2015-10-28 19:35:04 +00:00
Gabriel Reis
f3f61fb5d1 Color highlight on the name of the failed tests 2015-10-28 08:12:57 +00:00
Bruno Oliveira
8e54d07c40 Fix link in FAQ about parametrizing tests
Fix #1154
2015-10-26 22:46:35 -02:00
Florian Bruhin
bd36e00174 Merge pull request #1153 from b-jazz/patch-2
Update usage.rst
2015-10-24 15:41:24 +02:00
Ronny Pfannschmidt
da6b1557f0 Merge pull request #1152 from b-jazz/patch-1
Update CONTRIBUTING.rst
2015-10-24 12:00:33 +02:00
b-jazz
f174026f53 Update usage.rst
Remove double "the" in usage comments
2015-10-24 02:36:02 -07:00
b-jazz
390e1c93ed Update CONTRIBUTING.rst
Clean up the grammar of one of the lines.
2015-10-24 02:21:22 -07:00
Bruno Oliveira
8f31a1a64b Merge pull request #1147 from jayvdb/remove-extrainit
Remove commented out extrainit
2015-10-20 10:25:54 -02:00
John Vandenberg
9a04879129 Remove commented out extrainit
Unused since 2012, and the docstring syntax is incorrect with
four quotes.
2015-10-20 21:08:21 +11:00
Bruno Oliveira
7469b5591e Update plugins_index.rst 2015-10-17 13:37:38 -03:00
Bruno Oliveira
75932a92d0 Make pytest-version mandatory
Fix #1118
2015-10-17 13:37:01 -03:00
Bruno Oliveira
cf56f59f58 Merge pull request #1145 from htgoebel/patch-1
Add link to unittest2pytest
2015-10-17 13:16:55 -03:00
Hartmut Goebel
4fba20e544 Add link to unittest2pytest
Closes #991.
2015-10-17 18:14:52 +02:00
Florian Bruhin
2956627b8b Handle EPERM when writing rewritten bytecode.
Fixes #1143.
2015-10-17 11:55:55 +02:00
Ronny Pfannschmidt
3404d2a99b Merge pull request #1142 from nicoddemus/issue-1133-str-relto
Fix situation where a traceback entry "path" returns a str object
2015-10-17 08:58:48 +02:00
Bruno Oliveira
311b0a9683 Fix situation where a traceback entry "path" returns a str object
Fix #1133
2015-10-16 20:18:14 -03:00
Ronny Pfannschmidt
3b11995dbe Merge pull request #1053 from mbirtwell/issue_331_failure_for_test_with_no_name
Prevent non-function callables from being collected
2015-10-13 23:35:32 +02:00
Michael Birtwell
a3bda59a30 collection: Prevent non-function callables from being collected
Fixes issue 331
previously to this change the collection code would issue a warning for
when ever it encountered a variable that looked like a test but wasn't a
function saying that it wouldn't collect it because it wasn't a function.
This fixes the logic so that if that warning is issued it really isn't
collected.
However previously special cases existed to support tests that were
created using functools.wraps and functools.partial. So the condition for
issuing that warning has been updated to take that in to account

Also try the old way of detecting functions just for proper integration
with mock.path in python 2.7 the get_real_func returned the unbound method
2015-10-12 22:23:18 +01:00
Bruno Oliveira
0c21533cc5 Merge pull request #1130 from The-Compiler/pytest_doc_fix
Use a string for pytest_plugins in docs.
2015-10-12 10:58:39 -03:00
Florian Bruhin
dadf03baea Use a string for pytest_plugins in docs. 2015-10-12 06:57:43 +02:00
Ronny Pfannschmidt
1525cc78f6 Merge pull request #1127 from michael-k/indentation
[doc] Fixed indentation
2015-10-10 14:22:18 +02:00
Ronny Pfannschmidt
db077555f6 Merge pull request #1102 from nicoddemus/doctest-fixtures-fix
Fix autouse fixtures and doctest modules
2015-10-10 14:21:53 +02:00
Michael K
37e96c9335 [doc] Fixed indentation 2015-10-10 13:29:22 +02:00
Bruno Oliveira
b052becba9 Merge pull request #1121 from tomviner/issue1035-getattr
Issue1035 getattr
2015-10-09 16:45:52 -03:00
TomV
88c8dd96f9 issue1035 Override inspect.isclass for python 2.6 2015-10-09 19:44:47 +01:00
TomV
707226298a issue1035 add test for classes setting __getattr__ 2015-10-08 09:08:32 +01:00
Florian Bruhin
1f6988bdec Add empty 2.8.3.dev section to CHANGELOG. 2015-10-07 22:47:22 +02:00
Florian Bruhin
ec74a8deb8 Fix contents.rst.
This was broken in 787c866191.
2015-10-07 18:10:13 +02:00
Florian Bruhin
b5b53b6aec start 2.8.3 development 2015-10-07 17:56:05 +02:00
Florian Bruhin
7c529e0afe Merge branch '2.8.2-release' 2015-10-07 17:51:34 +02:00
Florian Bruhin
b955473533 Add 2.8.2 release annoucement. 2015-10-06 22:37:59 +02:00
Florian Bruhin
2026ce0ed2 Update plugin_index. 2015-10-06 22:35:16 +02:00
Florian Bruhin
42937d4bb6 Prepare 2.8.2 release. 2015-10-06 21:06:25 +02:00
Bruno Oliveira
cfd259ae6f Merge pull request #1113 from demianbrecht/typo_fix
typo fix, changed position of context manager notes
2015-10-05 17:21:59 -03:00
Demian Brecht
493530ec6d typo fix, changed position of context manager notes 2015-10-05 12:13:25 -07:00
Florian Bruhin
4dea0892cb Merge pull request #1108 from nicoddemus/plugins_index
plugins_index was still generating ".txt" files, so it was effectively being ignored
2015-10-05 09:37:31 -07:00
Bruno Oliveira
a14c77aeba Fix problems when mixing autouse fixtures and doctest modules
The main problem was that previously DoctestModule was setting
up its fixtures during collection, instead of letting
each DoctestItem make its own fixture setup

Fix #1100
Fix #1057
2015-10-03 16:07:14 -03:00
Bruno Oliveira
9deab6c0fd Add a reminder on HOWTORELEASE to update plugins_index 2015-10-02 19:44:00 -03:00
Bruno Oliveira
f9e9413f52 plugins_index was still generating ".txt" files, so it was effectively being ignored
Fix #1105
2015-10-02 19:21:55 -03:00
Bruno Oliveira
5171d167ce Move "note" to the end of the main text
Fix #1097
2015-10-02 18:14:17 -03:00
Demian Brecht
2981bece55 pyflakes fix 2015-10-02 13:03:43 -07:00
Demian Brecht
fd211bf490 Add a note about usage of the context manager
Addesses #1097
2015-10-02 12:40:58 -07:00
Ronny Pfannschmidt
9263b3a051 Merge pull request #1096 from hackebrot/update-docs-skip-with-cli-option
Update docs skip with cli option
2015-10-01 18:31:55 +02:00
holger krekel
88209c6ac6 Merge pull request #1092 from nicoddemus/param-ids-fix
Param ids fix
2015-10-01 15:09:11 +02:00
Ronny Pfannschmidt
688f955f5e Merge pull request #1058 from nicoddemus/doc-how-disable-cache
Add docs on how to disable cache provider
2015-10-01 13:06:02 +02:00
Bruno Oliveira
f3cee8f0b5 Merge remote-tracking branch 'upstream/master' into param-ids-fix 2015-10-01 07:58:55 -03:00
Ronny Pfannschmidt
b7fd3f0031 Merge pull request #1093 from nicoddemus/relto-bug
Fix internal error when filtering tracebacks where one entry was generated by an exec() statement
Fixes #995
2015-10-01 06:00:40 +02:00
Bruno Oliveira
d1e00f6e19 Detect dynamic code explicitly in filter_traceback 2015-09-30 17:32:49 -03:00
Bruno Oliveira
c9480c5b8b Move imports outside _escape_bytes as suggested in review 2015-09-30 17:02:19 -03:00
Raphael Pierzina
4829eac1e1 Use a variable for the skipif marker as suggested by @nicoddemus 2015-09-30 21:53:34 +02:00
Raphael Pierzina
a10da0e540 Implement skipif marker for slow test based on pytest.config 2015-09-30 19:41:47 +02:00
Raphael Pierzina
7ac8a88a05 Remove pytest_runtest_setup from conftest.py 2015-09-30 19:25:57 +02:00
Bruno Oliveira
639ae0cfe0 Merge pull request #1095 from ionelmc/fix-hook-docs
Correct hook examples in docs.
2015-09-30 11:28:43 -03:00
Ionel Cristian Mărieș
c8f5a40fd9 Edit examples again to use hookimpl. 2015-09-30 16:58:12 +03:00
Ionel Cristian Mărieș
f4f23e8e09 Correct hook examples in docs. 2015-09-30 16:12:33 +03:00
Florian Bruhin
dc9ad12182 Merge pull request #1094 from nicoddemus/cache-fixture-docstring-fix
fix docstring for cache fixture regarding ``/`` on keys
2015-09-30 06:02:38 +02:00
Bruno Oliveira
a808e09204 fix docstring for cache fixture regarding `/` on keys 2015-09-30 00:27:52 -03:00
Bruno Oliveira
6ae16eba36 add entries for #1085 and #1087 to the CHANGELOG 2015-09-29 22:37:11 -03:00
Bruno Oliveira
11f100813e Fix internal error when filtering tracebacks where one entry was generated by an exec() statement
Fix #995
2015-09-29 22:29:43 -03:00
Bruno Oliveira
b64470443f Fix SystemError when using unicode_escape on Python 3
Fix #1087
2015-09-29 18:20:30 -03:00
Bruno Oliveira
8633c4cefd Fix encoding errors for parametrized tests with unicode parameters in py2
Fix #1085
2015-09-29 17:57:49 -03:00
Florian Bruhin
e9240f7eee Merge pull request #1090 from RonnyPfannschmidt/fix-flaky-getusertest
fix flaky get_user fallback tests
2015-09-29 21:35:45 +02:00
Ronny Pfannschmidt
04deea3c6d fix flaky get_user fallback tests 2015-09-29 21:00:12 +02:00
Bruno Oliveira
6ca8923ec7 Merge pull request #1088 from hpk42/docfix
remove unclear todo that irritates in the online docs
2015-09-29 13:26:54 -03:00
holger krekel
e3562be530 remove unclear todo that irritates in the online docs 2015-09-29 18:23:44 +02:00
holger krekel
c5fd42b699 start 2.8.2 development 2015-09-29 15:32:33 +02:00
holger krekel
afdbb6b17a Merge pull request #1084 from hpk42/branch-281
2.8.1 release
2015-09-29 15:19:07 +02:00
holger krekel
a0076460db avoid pullrequest picture and fix bugfix/feature target info.
I could not get the pullrequest picture to be included correctly
in both latex and html sphinx builders due to the "include" directive
from doc/en/contributing.rst
2015-09-29 13:48:38 +02:00
holger krekel
787c866191 hide some parts from generating latexpdf 2015-09-29 13:37:30 +02:00
holger krekel
95245b935c - fix a flaky test on py35-xdist by calling
importlib.invalidate_caches()

- bump version to 2.8.1

- regen docs

- amend changelog, authors
2015-09-29 13:10:59 +02:00
holger krekel
f61f39efdd Merge pull request #1052 from The-Compiler/no-std-prefix
Don't hardcode 'std' for captured stdout/stderr.
2015-09-29 09:19:40 +02:00
holger krekel
a73d517bee Merge pull request #1080 from vodik/master
fix #1034: Add missing nodeid on pytest_logwarning call in addhook.  Thanks Simon Gomizelj for the PR.
2015-09-29 09:07:43 +02:00
Simon Gomizelj
b3727438d6 Add missing nodeid on pytest_logwarning call in addhook.
Otherwise KeyError: 'nodeid' gets thrown, killing pytest. This may fix
issue 1034, but the details of it may be caused by something similar
somewhere else.
2015-09-28 20:23:54 -04:00
Bruno Oliveira
b184f391c6 Show known environment variables in py.test --help 2015-09-28 18:34:16 -03:00
Bruno Oliveira
5f860181b6 Remove print left by accident 2015-09-28 18:25:20 -03:00
Bruno Oliveira
6caa7083db Moved more detailed options on how to disable a plugin to plugins.rst 2015-09-28 18:23:08 -03:00
holger krekel
839909f3f6 Merge pull request #1081 from hunse/fix-pendingdep
`deprecated_call` detects pending warnings again
2015-09-28 19:05:44 +02:00
Eric Hunsberger
4194c9cce2 Check deprecated_call specific to deprecation
`deprecated_call` used to accept any warning. As of #897, it
is now specific to DeprecationWarnings, and another commit in
this PR extends this to PendingDeprecationWarnings. This commit
makes sure this stays the case.
2015-09-28 12:35:24 -04:00
Eric Hunsberger
e8261e0c77 deprecated_call detects pending warnings again
`deprecated_call` now looks for PendingDeprecationWarnings,
as it did previously but was broken by #897. Fixes #1037.

Also added a test so this does not happen again.
2015-09-28 12:11:52 -04:00
Ronny Pfannschmidt
22e1f4946e Merge pull request #1079 from hpk42/issue1073
fix issue #1073 -- shortcut plugin hook lookup if the attrname is not prefixed with pytest_.
2015-09-28 16:15:42 +02:00
holger krekel
971ebcbd77 simplify by removing the single-call "exclude_pytest_names" function 2015-09-28 15:43:55 +02:00
holger krekel
03aca9ea79 add changelog entry for fix #1073 2015-09-28 14:17:58 +02:00
holger krekel
1c0ffc5caf seems like pypy's callable builtin calls __getattr__ so we do the check
later.
2015-09-28 14:02:30 +02:00
holger krekel
4e3a807733 fix issue #1073 -- shortcut plugin hook lookup if the attrname is not
prefixed with pytest_.
2015-09-28 13:34:28 +02:00
holger krekel
d29084ec2c add changelog note for fix #704 2015-09-28 11:45:51 +02:00
holger krekel
c5faa00ace Merge pull request #1077 from nicoddemus/pluggy-0.3.1
Vendor pluggy-0.3.1
2015-09-28 11:44:07 +02:00
Bruno Oliveira
910b25d416 Vendor pluggy-0.3.1
Fix #704
2015-09-27 16:04:29 -03:00
Ronny Pfannschmidt
cb4b5bd684 Merge pull request #1072 from nicoddemus/use-more-py35-tox
Use py35 as preferred py3 interpreter for special test environments
2015-09-26 09:26:16 +02:00
Ronny Pfannschmidt
842aa5746f Merge pull request #1069 from nicoddemus/docs-contents-reorg
Reorganize "Contents" page
2015-09-26 09:18:42 +02:00
Ronny Pfannschmidt
c2c2451788 Merge pull request #1071 from nicoddemus/xml-xdist
Wrong xml report when used with pytest-xdist
2015-09-26 09:05:25 +02:00
Bruno Oliveira
cd7ca3de68 Test py27-xdist and py35 environments on AppVeyor 2015-09-26 03:46:03 -03:00
Bruno Oliveira
d52d0251b2 Test py35 on AppVeyor 2015-09-26 03:44:12 -03:00
Bruno Oliveira
cdead1a991 Update travis with new tox environments 2015-09-26 03:43:37 -03:00
Bruno Oliveira
031a20699c Use py35 as preferred py3 interpreter for special test environments 2015-09-26 03:37:21 -03:00
Bruno Oliveira
e4b18ea5c3 Update CHANGELOG 2015-09-26 03:28:30 -03:00
Bruno Oliveira
b72c3310bc Add note on docs about record_xml_property not working with xdist 2015-09-26 03:24:07 -03:00
Bruno Oliveira
748da0e5d7 Fix xml generation when used with pytest-xdist
pytest_runtest_logreport must be careful to not depend on setup/call/teardown
being called sequentially in that order, as xdist will call them as they are reported
from the slaves

Fix #1064
2015-09-26 03:21:24 -03:00
Bruno Oliveira
bc501a28af Merge pull request #1070 from oleg-alexandrov/master
Documentation clarification
2015-09-26 03:16:44 -03:00
Oleg Alexandrov
9d2d2d17af Clarify documentation
Fix doc markup
2015-09-25 21:46:06 -07:00
Bruno Oliveira
b403395cdb Reorganize "Contents" page
Change the organization in a more logical way to a newcomer
2015-09-26 01:09:50 -03:00
Bruno Oliveira
fbce3bb48f Small format fixes in HOWTORELEASE 2015-09-25 23:10:35 -03:00
Ronny Pfannschmidt
bf23a0f4b8 Merge pull request #1065 from The-Compiler/doc-fixes
Doc fixes
2015-09-25 19:18:09 +02:00
Florian Bruhin
448ec8b740 Mark sources correctly in parametrize.rst.
Sphinx didn't pick this up as monospace text.
2015-09-25 18:43:33 +02:00
Florian Bruhin
272f987b0c Fix test_time in parametrize doc.
The source was indented with a mixture of tabs and spaces, causing syntax
errors when executed.
2015-09-25 18:42:06 +02:00
Florian Bruhin
0ebac22bb2 Regenerate fixture list doc with cache docstring. 2015-09-25 18:41:07 +02:00
Bruno Oliveira
c55e42f856 Merge pull request #1063 from timstaley/docs-module-level-fixtures-pytestmark
Docs: Fixtures page - clarify usage of module-level pytestmark.
2015-09-25 12:42:35 -03:00
Tim Staley
eb2caa554c Docs: Fixtures page - clarify usage of module-level pytestmark.
It certainly wasn't clear to me that the variable assigned by
pytest.mark.usefixtures should also be called pytestmark,
so I was confused when::

  foo = pytest.mark.usefixtures('fixture_bar')

wasn't behaving as expected; correct usage is of course::

  pytestmark = pytest.mark.usefixtures('fixture_bar')

I assume this is by design, otherwise that's a separate issue, at
least current behaviour should be documented.
2015-09-25 14:57:08 +01:00
Florian Bruhin
7c5d2ea81d Merge pull request #1046 from RonnyPfannschmidt/docs
fix documentation regeneration, kill Makefile
2015-09-25 08:35:18 +02:00
Bruno Oliveira
b09d3724a0 Add docs on how to disable cache provider 2015-09-23 19:15:44 -03:00
Ronny Pfannschmidt
acb6b186f2 Merge pull request #1056 from icemac/patch-1
Remove duplicate line.
2015-09-23 09:10:20 +02:00
Ronny Pfannschmidt
a3fdcd9b17 Merge pull request #1031 from pytest-dev/unmarshable-parametrize
Parametrized values containing non-ascii bytes break cache
2015-09-23 09:03:51 +02:00
Ronny Pfannschmidt
e5c76cb22d Merge pull request #1054 from nicoddemus/cache-fixture-docstring
Add docstring to cache fixture
2015-09-23 09:00:01 +02:00
Michael Howitz
730114d088 Remove duplicate line. 2015-09-23 08:53:13 +02:00
Florian Bruhin
c0c685a5de Merge pull request #1055 from nicoddemus/fix-help-pytest-warnings
(w)warnings -> (w)pytest-warnings in "-r chars" help
2015-09-23 06:53:46 +02:00
Bruno Oliveira
79ebca3f30 (w)warnings -> (w)pytest-warnings in "-r chars" help 2015-09-23 01:09:09 -03:00
Bruno Oliveira
25d2cc4604 Add docstring to cache fixture
Fixes #1049
2015-09-22 23:46:05 -03:00
Bruno Oliveira
716fa97fa1 Update CHANGELOG 2015-09-22 23:21:36 -03:00
Bruno Oliveira
e1063678f1 escape bytes when creating ids for parametrized values 2015-09-22 23:18:09 -03:00
Bruno Oliveira
661495e5c5 Write failing test for parametrized tests with unmarshable parameters
Related to #1030; committing directly to pytest repository to
get feedback from others on how to proceed.
2015-09-22 23:18:07 -03:00
Bruno Oliveira
9d1ae0a149 Merge pull request #1048 from RonnyPfannschmidt/pytest-1029
fixes #1029 by handling access errors for cache dirs as pytest warning
2015-09-22 19:04:04 -03:00
Ronny Pfannschmidt
7f776fe19a skip chmod using cache access warning tests on windows 2015-09-22 20:49:11 +02:00
Florian Bruhin
c10f483b9f Don't hardcode 'std' for captured stdout/stderr.
This will make Item.add_report_sect more usable for plugins.
See https://github.com/eisensheng/pytest-catchlog/pull/7
2015-09-22 20:29:16 +02:00
Ronny Pfannschmidt
ea9a491fb3 add an acceptance test for cache write errors 2015-09-22 20:24:37 +02:00
holger krekel
ca460e11e6 Merge pull request #1051 from Akasurde/issue_1027
Added minor documentation change in python.py
2015-09-22 17:09:25 +02:00
Ronny Pfannschmidt
c3588b545f generate docs on python3.4 2015-09-22 16:52:35 +02:00
Abhijeet Kasurde
dc1ce51ac2 Added minor documentation change
Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2015-09-22 20:15:49 +05:30
Ronny Pfannschmidt
6e51918353 update changelog 2015-09-22 16:33:27 +02:00
Bruno Oliveira
1d2afada83 Minor typo in CHANGELOG 2015-09-22 11:30:00 -03:00
Ronny Pfannschmidt
29f4da93d4 handle access errors when writing cache files silently as pytest warning, fixes #1039 2015-09-22 16:28:19 +02:00
Bruno Oliveira
5acbd7bc86 Fix git checkout command in CONTRIBUTING.rst 2015-09-22 10:54:37 -03:00
Ronny Pfannschmidt
5ff75a41ea fix erroring doc example 2015-09-22 15:05:56 +02:00
Ronny Pfannschmidt
89badfec0c update regendoc, substitutes PYTHON_PREFIX 2015-09-22 14:48:04 +02:00
Ronny Pfannschmidt
662d755974 fix documentation gegeneration, kill Makefile 2015-09-22 14:22:37 +02:00
holger krekel
bf9b94595c fix changelog 2015-09-22 11:18:19 +02:00
holger krekel
41d61ed221 Merge pull request #1023 from RonnyPfannschmidt/fix-877
Fix 877
2015-09-22 11:17:02 +02:00
holger krekel
e2f72ffed8 start bugfix changelog on master 2015-09-22 10:59:23 +02:00
Florian Bruhin
79c2abf531 Merge pull request #1038 from hpk42/newbranching
adapt contributing to new versioning and to python3.5 as latest.
2015-09-22 10:55:30 +02:00
holger krekel
a5ff345f7b fix another occurence of "macro" to "major" 2015-09-22 10:45:55 +02:00
holger krekel
f19ba6c2b1 fix naming 2015-09-22 10:29:12 +02:00
holger krekel
745cd26850 Merge branch 'master' into newbranching 2015-09-22 10:22:05 +02:00
holger krekel
71c5883d52 update according to discussion on pytest-dev and in PR 2015-09-22 10:21:01 +02:00
Floris Bruynooghe
c30eafa254 Update changelog for merged PR. 2015-09-21 14:59:48 +01:00
Floris Bruynooghe
7c3be72ac7 Merge pull request #1042 from Bjwebb/issue411
Add __eq__ method to assertion comparison example
2015-09-21 14:57:59 +01:00
Ben Webb
622e64320a Add __eq__ method to assertion comparison example
This makes the example make more sense, because now Foo(1) == Foo(1) is
true. Fixes #411
2015-09-21 14:23:26 +01:00
holger krekel
0efcfeed17 adapt contributing to new versioning and to python3.5 as latest. 2015-09-21 14:04:30 +02:00
Floris Bruynooghe
65de43e67d Mention fix for issue 766 in changelog
Fixes issue #766.
2015-09-21 12:21:24 +01:00
Floris Bruynooghe
cd4557cce8 Merge pull request #1036 from russel/rlw_766
Remove references to distutils as per Issue 766.
2015-09-21 12:19:14 +01:00
Russel Winder
714a97e452 Remove references to distutils as per Issue 766. 2015-09-21 12:00:48 +01:00
Floris Bruynooghe
80897f62a6 Merge pull request #974 from nicoddemus/addoption-conftest
Add warning about implementing pytest_addoption in conftest files
2015-09-21 11:28:31 +01:00
Floris Bruynooghe
dfd83b59f8 Merge pull request #1033 from mbirtwell/changes_to_contributing_rst
contributing: Add instructions from PyCon
2015-09-21 11:13:14 +01:00
Michael Birtwell
bb42e43ee7 contributing: Add instructions from PyCon
At PyCon we realised that the virtualenv created in the make file wasn't
used in the subsequent steps in CONTRIBUTING.rst. This change removes the
reference the make and suggesting installing tox directly.
Also changed the explanation that follows to make more sense with this
change
2015-09-21 10:56:05 +01:00
Bruno Oliveira
8fe5c704e3 Merge pull request #1024 from rouge8/tmpdir-uid-not-found
Make tmpdir resiliant to user ids that do not exist
2015-09-18 22:53:17 -03:00
Andy Freeland
b1c9b8b415 Make tmpdir resiliant to user ids that do not exist
Previously, the tmpdir fixture would fail if the current process's user
id does not correspond to a valid user (e.g. running pytest in a Docker
container with 'docker run -u').
2015-09-18 21:26:19 -04:00
Ronny Pfannschmidt
7658f60146 #877 - reencoding causes typeerrors on python2 2015-09-19 00:30:01 +02:00
Ronny Pfannschmidt
49c99a41ea reencode non-ascii python2 assertion reprs, fixes #877
i decided against using a warning since the problem goes away with python3
the support code can be removed once we drop python2 in 10 years or so
2015-09-19 00:30:01 +02:00
Bruno Oliveira
f02d9425f9 Bump version to 2.8.0 2015-09-18 19:04:20 -03:00
Bruno Oliveira
ccf7584fac Add warning about implementing pytest_addoption from conftest files 2015-08-27 19:14:56 -03:00
93 changed files with 2405 additions and 1822 deletions

View File

@@ -21,10 +21,9 @@ env:
- TESTENV=py33
- TESTENV=py33
- TESTENV=py34
- TESTENV=py34-pexpect
- TESTENV=py34-trial
- TESTENV=py34-trial
- TESTENV=py34-xdist
- TESTENV=py35-pexpect
- TESTENV=py35-trial
- TESTENV=py35-xdist
- TESTENV=py35
- TESTENV=pypy

View File

@@ -33,6 +33,7 @@ Eric Hunsberger
Eric Siegerman
Florian Bruhin
Floris Bruynooghe
Gabriel Reis
Graham Horler
Grig Gheorghiu
Guido Wesdorp
@@ -45,12 +46,14 @@ Jason R. Coombs
Jurko Gospodnetić
Katarzyna Jachim
Kevin Cox
Lee Kamentsky
Maciek Fijalkowski
Maho
Marc Schlaich
Mark Abramowitz
Markus Unterwaditzer
Martijn Faassen
Michael Birtwell
Michael Droettboom
Nicolas Delaby
Pieter Mulder
@@ -64,3 +67,8 @@ Tom Viner
Trevor Bekolay
Wouter van Ackooy
David Díaz-Barquero
Eric Hunsberger
Simon Gomizelj
Russel Winder
Ben Webb
Alexei Kozlenok

148
CHANGELOG
View File

@@ -1,8 +1,142 @@
2.8.0.dev (compared to 2.7.X)
2.8.5
-----
- fix #1243: fixed issue where class attributes injected during collection could break pytest.
PR by Alexei Kozlenok, thanks Ronny Pfannschmidt and Bruno Oliveira for the review and help.
- fix #1074: precompute junitxml chunks instead of storing the whole tree in objects
Thanks Bruno Oliveira for the report and Ronny Pfannschmidt for the PR
- fix #1238: fix ``pytest.deprecated_call()`` receiving multiple arguments
(Regression introduced in 2.8.4). Thanks Alex Gaynor for the report and
Bruno Oliveira for the PR.
2.8.4
-----
- fix #1190: ``deprecated_call()`` now works when the deprecated
function has been already called by another test in the same
module. Thanks Mikhail Chernykh for the report and Bruno Oliveira for the
PR.
- fix #1198: ``--pastebin`` option now works on Python 3. Thanks
Mehdy Khoshnoody for the PR.
- fix #1219: ``--pastebin`` now works correctly when captured output contains
non-ascii characters. Thanks Bruno Oliveira for the PR.
- fix #1204: another error when collecting with a nasty __getattr__().
Thanks Florian Bruhin for the PR.
- fix the summary printed when no tests did run.
Thanks Florian Bruhin for the PR.
- fix #1185 - ensure MANIFEST.in exactly matches what should go to a sdist
- a number of documentation modernizations wrt good practices.
Thanks Bruno Oliveira for the PR.
2.8.3
-----
- fix #1169: add __name__ attribute to testcases in TestCaseFunction to
support the @unittest.skip decorator on functions and methods.
Thanks Lee Kamentsky for the PR.
- fix #1035: collecting tests if test module level obj has __getattr__().
Thanks Suor for the report and Bruno Oliveira / Tom Viner for the PR.
- fix #331: don't collect tests if their failure cannot be reported correctly
e.g. they are a callable instance of a class.
- fix #1133: fixed internal error when filtering tracebacks where one entry
belongs to a file which is no longer available.
Thanks Bruno Oliveira for the PR.
- enhancement made to highlight in red the name of the failing tests so
they stand out in the output.
Thanks Gabriel Reis for the PR.
- add more talks to the documentation
- extend documentation on the --ignore cli option
- use pytest-runner for setuptools integration
- minor fixes for interaction with OS X El Capitan
system integrity protection (thanks Florian)
2.8.2
-----
- fix #1085: proper handling of encoding errors when passing encoded byte
strings to pytest.parametrize in Python 2.
Thanks Themanwithoutaplan for the report and Bruno Oliveira for the PR.
- fix #1087: handling SystemError when passing empty byte strings to
pytest.parametrize in Python 3.
Thanks Paul Kehrer for the report and Bruno Oliveira for the PR.
- fix #995: fixed internal error when filtering tracebacks where one entry
was generated by an exec() statement.
Thanks Daniel Hahler, Ashley C Straw, Philippe Gauthier and Pavel Savchenko
for contributing and Bruno Oliveira for the PR.
- fix #1100 and #1057: errors when using autouse fixtures and doctest modules.
Thanks Sergey B Kirpichev and Vital Kudzelka for contributing and Bruno
Oliveira for the PR.
2.8.1
-----
- fix #1034: Add missing nodeid on pytest_logwarning call in
addhook. Thanks Simon Gomizelj for the PR.
- 'deprecated_call' is now only satisfied with a DeprecationWarning or
PendingDeprecationWarning. Before 2.8.0, it accepted any warning, and 2.8.0
made it accept only DeprecationWarning (but not PendingDeprecationWarning).
Thanks Alex Gaynor for the issue and Eric Hunsberger for the PR.
- fix issue #1073: avoid calling __getattr__ on potential plugin objects.
This fixes an incompatibility with pytest-django. Thanks Andreas Pelme,
Bruno Oliveira and Ronny Pfannschmidt for contributing and Holger Krekel
for the fix.
- Fix issue #704: handle versionconflict during plugin loading more
gracefully. Thanks Bruno Oliveira for the PR.
- Fix issue #1064: ""--junitxml" regression when used with the
"pytest-xdist" plugin, with test reports being assigned to the wrong tests.
Thanks Daniel Grunwald for the report and Bruno Oliveira for the PR.
- (experimental) adapt more SEMVER style versioning and change meaning of
master branch in git repo: "master" branch now keeps the bugfixes, changes
aimed for micro releases. "features" branch will only be be released
with minor or major pytest releases.
- Fix issue #766 by removing documentation references to distutils.
Thanks Russel Winder.
- Fix issue #1030: now byte-strings are escaped to produce item node ids
to make them always serializable.
Thanks Andy Freeland for the report and Bruno Oliveira for the PR.
- Python 2: if unicode parametrized values are convertible to ascii, their
ascii representation is used for the node id.
- Fix issue #411: Add __eq__ method to assertion comparison example.
Thanks Ben Webb.
- fix issue 877: properly handle assertion explanations with non-ascii repr
Thanks Mathieu Agopian for the report and Ronny Pfannschmidt for the PR.
- fix issue 1029: transform errors when writing cache values into pytest-warnings
2.8.0
-----------------------------
- new ``--lf`` and ``-ff`` options to run only the last failing tests or
"failing tests first" from the last run. This functionality is provided
"failing tests first" from the last run. This functionality is provided
through porting the formerly external pytest-cache plugin into pytest core.
BACKWARD INCOMPAT: if you used pytest-cache's functionality to persist
data between test runs be aware that we don't serialize sets anymore.
@@ -108,9 +242,9 @@
- fix issue735: assertion failures on debug versions of Python 3.4+
- new option ``--import-mode`` to allow to change test module importing
behaviour to append to sys.path instead of prepending. This better allows
to run test modules against installated versions of a package even if the
- new option ``--import-mode`` to allow to change test module importing
behaviour to append to sys.path instead of prepending. This better allows
to run test modules against installated versions of a package even if the
package under test has the same import root. In this example::
testing/__init__.py
@@ -118,7 +252,7 @@
pkg_under_test/
the tests will run against the installed version
of pkg_under_test when ``--import-mode=append`` is used whereas
of pkg_under_test when ``--import-mode=append`` is used whereas
by default they would always pick up the local version. Thanks Holger Krekel.
- pytester: add method ``TmpTestdir.delete_loaded_modules()``, and call it
@@ -174,8 +308,6 @@
- fix issue714: add ability to apply indirect=True parameter on particular argnames.
Thanks Elizaveta239.
- fix issue714: add ability to apply indirect=True parameter on particular argnames.
- fix issue890: changed extension of all documentation files from ``txt`` to
``rst``. Thanks to Abhijeet for the PR.

View File

@@ -118,7 +118,7 @@ pytest could always use more documentation. What exactly is needed?
* More complementary documentation. Have you perhaps found something unclear?
* Documentation translations. We currently have only English.
* Docstrings. There's never too much of them.
* Docstrings. There can never be too many of them.
* Blog posts, articles and such -- they're all very appreciated.
You can also edit documentation files directly in the Github web interface
@@ -151,40 +151,54 @@ but here is a simple overview:
$ git clone git@github.com:YOUR_GITHUB_USERNAME/pytest.git
$ cd pytest
$ git checkout pytest-2.7 # if you want to fix a bug for the pytest-2.7 series
$ git checkout master # if you want to add a feature bound for the next minor release
$ git branch your-branch-name # your feature/bugfix branch
# now, to fix a bug create your own branch off "master":
$ git checkout -b your-bugfix-branch-name master
# or to instead add a feature create your own branch off "features":
$ git checkout -b your-feature-branch-name features
Given we have "major.minor.micro" version numbers, bugfixes will usually
be released in micro releases whereas features will be released in
minor releases and incompatible changes in major releases.
If you need some help with Git, follow this quick start
guide: https://git.wiki.kernel.org/index.php/QuickStart
#. Create a development environment
#. Install tox
Tox is used to run all the tests and will automatically setup virtualenvs
to run the tests in.
(will implicitly use http://www.virtualenv.org/en/latest/)::
$ make develop
$ source .env/bin/activate
$ pip install tox
#. You can now edit your local working copy.
#. Run all the tests
You need to have Python 2.7 and 3.4 available in your system. Now
You need to have Python 2.7 and 3.5 available in your system. Now
running tests is as simple as issuing this command::
$ python runtox.py -e py27,py34,flakes
$ python runtox.py -e py27,py35,flakes
This command will run tests via the "tox" tool against Python 2.7 and 3.4
This command will run tests via the "tox" tool against Python 2.7 and 3.5
and also perform "flakes" coding-style checks. ``runtox.py`` is
a thin wrapper around ``tox`` which installs from a development package
index where newer (not yet released to pypi) versions of dependencies
(especially ``py``) might be present.
To run tests on py27 and pass options (e.g. enter pdb on failure)
#. You can now edit your local working copy.
You can now make the changes you want and run the tests again as necessary.
To run tests on py27 and pass options to pytest (e.g. enter pdb on failure)
to pytest you can do::
$ python runtox.py -e py27 -- --pdb
or to only run tests in a particular test module on py34::
or to only run tests in a particular test module on py35::
$ python runtox.py -e py34 -- testing/test_config.py
$ python runtox.py -e py35 -- testing/test_config.py
#. Commit and push once your tests pass and you are happy with your change(s)::
@@ -195,19 +209,13 @@ but here is a simple overview:
are unsure about either of these steps, submit your pull request and we'll
help you fix it up.
#. Finally, submit a pull request through the GitHub website:
.. image:: doc/en/img/pullrequest.png
:width: 700px
:align: center
::
#. Finally, submit a pull request through the GitHub website using this data::
head-fork: YOUR_GITHUB_USERNAME/pytest
compare: your-branch-name
base-fork: pytest-dev/pytest
base: master # if it's a feature
base: pytest-VERSION # if it's a bugfix
base: master # if it's a bugfix
base: feature # if it's a feature

View File

@@ -8,21 +8,23 @@ Note: this assumes you have already registered on pypi.
2. Check and finalize CHANGELOG
3. Write doc/en/announce/release-VERSION.txt and include
it in doc/en/announce/index.txt
it in doc/en/announce/index.txt::
4. Use devpi for uploading a release tarball to a staging area:
git log 2.8.2..HEAD --format='%aN' | sort -u # lists the names of authors involved
``devpi use https://devpi.net/USER/dev``
``devpi upload --formats sdist,bdist_wheel``
4. Use devpi for uploading a release tarball to a staging area::
5. Run from multiple machines:
devpi use https://devpi.net/USER/dev
devpi upload --formats sdist,bdist_wheel
``devpi use https://devpi.net/USER/dev``
``devpi test pytest==VERSION``
5. Run from multiple machines::
6. Check that tests pass for relevant combinations with
devpi use https://devpi.net/USER/dev
devpi test pytest==VERSION
``devpi list pytest``
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
@@ -39,7 +41,7 @@ Note: this assumes you have already registered on pypi.
8. Build the docs, you need a virtualenv with py and sphinx
installed::
cd doc/en
cd doc/en
make html
Commit any changes before tagging the release.
@@ -54,25 +56,25 @@ Note: this assumes you have already registered on pypi.
cd doc/en
make install # or "installall" if you have LaTeX installed for PDF
This requires ssh-login permission 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.
This requires ssh-login permission 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.
If you are making a minor release (e.g. 5.4), you also need to manually
create a symlink for "latest"::
If you are making a minor release (e.g. 5.4), you also need to manually
create a symlink for "latest"::
ssh pytest-dev@pytest.org
ln -s 5.4 latest
ssh pytest-dev@pytest.org
ln -s 5.4 latest
Browse to pytest.org to verify.
Browse to pytest.org to verify.
11. Publish to pypi::
devpi push pytest-VERSION pypi:NAME
where NAME is the name of pypi.python.org as configured in your
~/.pypirc file `for devpi <http://doc.devpi.net/latest/quickstart-releaseprocess.html?highlight=pypirc#devpi-push-releasing-to-an-external-index>`_.
where NAME is the name of pypi.python.org as configured in your ``~/.pypirc``
file `for devpi <http://doc.devpi.net/latest/quickstart-releaseprocess.html?highlight=pypirc#devpi-push-releasing-to-an-external-index>`_.
12. Send release announcement to mailing lists:
@@ -85,3 +87,5 @@ Note: this assumes you have already registered on pypi.
13. **after the release** Bump the version number in ``_pytest/__init__.py``,
to the next Minor release version (i.e. if you released ``pytest-2.8.0``,
set it to ``pytest-2.9.0.dev1``).
14. merge the actual release into the features branch and do a pull request against it

View File

@@ -115,7 +115,7 @@ tags: feature
- introduce pytest.mark.nocollect for not considering a function for
test collection at all. maybe also introduce a pytest.mark.test to
explicitely mark a function to become a tested one. Lookup JUnit ways
explicitly mark a function to become a tested one. Lookup JUnit ways
of tagging tests.
introduce pytest.mark.importorskip

View File

@@ -1,7 +1,34 @@
include CHANGELOG
include README.rst
include setup.py
include tox.ini
include LICENSE
graft doc
include AUTHORS
include README.rst
include CONTRIBUTING.rst
include tox.ini
include setup.py
include .coveragerc
include plugin-test.sh
include requirements-docs.txt
include runtox.py
recursive-include bench *.py
recursive-include extra *.py
graft testing
graft doc
exclude _pytest/impl
graft _pytest/vendored_packages
recursive-exclude * *.pyc *.pyo
exclude appveyor/install.ps1
exclude appveyor.yml
exclude appveyor
exclude ISSUES.txt
exclude HOWTORELEASE.rst

View File

@@ -1,31 +0,0 @@
# Set of targets useful for development/release process
PYTHON = python2.7
PATH := $(PWD)/.env/bin:$(PATH)
REGENDOC_ARGS := \
--normalize "/={8,} (.*) ={8,}/======= \1 ========/" \
--normalize "/_{8,} (.*) _{8,}/_______ \1 ________/" \
--normalize "/in \d+.\d+ seconds/in 0.12 seconds/" \
--normalize "@/tmp/pytest-\d+/@/tmp/pytest-NaN/@"
# prepare virtual python environment
.env:
virtualenv .env -p $(PYTHON)
# install all needed for development
develop: .env
pip install -e . tox -r requirements-docs.txt
# clean the development envrironment
clean:
-rm -rf .env
# generate documentation
docs: develop
find doc/en -name '*.rst' -not -path 'doc/en/_build/*' | xargs .env/bin/regendoc ${REGENDOC_ARGS}
cd doc/en; make html
# upload documentation
upload-docs: develop
find doc/en -name '*.rst' -not -path 'doc/en/_build/*' | xargs .env/bin/regendoc ${REGENDOC_ARGS} --update
#cd doc/en; make install

View File

@@ -5,9 +5,9 @@ pytest
The ``pytest`` testing tool makes it easy to write small tests, yet
scales to support complex functional testing.
.. image:: http://img.shields.io/pypi/v/pytest.svg
.. image:: https://img.shields.io/pypi/v/pytest.svg
:target: https://pypi.python.org/pypi/pytest
.. image:: http://img.shields.io/coveralls/pytest-dev/pytest/master.svg
.. image:: https://img.shields.io/coveralls/pytest-dev/pytest/master.svg
:target: https://coveralls.io/r/pytest-dev/pytest
.. image:: https://travis-ci.org/pytest-dev/pytest.svg?branch=master
:target: https://travis-ci.org/pytest-dev/pytest

View File

@@ -1,2 +1,2 @@
#
__version__ = '2.8.0.dev6'
__version__ = '2.8.5'

View File

@@ -128,7 +128,7 @@ class AssertionRewritingHook(object):
# One of the path components was not a directory, likely
# because we're in a zip file.
write = False
elif e in [errno.EACCES, errno.EROFS]:
elif e in [errno.EACCES, errno.EROFS, errno.EPERM]:
state.trace("read only directory: %r" % fn_pypath.dirname)
write = False
else:

View File

@@ -129,7 +129,16 @@ def assertrepr_compare(config, op, left, right):
width = 80 - 15 - len(op) - 2 # 15 chars indentation, 1 space around op
left_repr = py.io.saferepr(left, maxsize=int(width/2))
right_repr = py.io.saferepr(right, maxsize=width-len(left_repr))
summary = u('%s %s %s') % (left_repr, op, right_repr)
# the re-encoding is needed for python2 repr
# with non-ascii characters (see issue 877)
def ecu(s):
try:
return u(s, 'utf-8', 'replace')
except TypeError:
return s
summary = u('%s %s %s') % (ecu(left_repr), op, ecu(right_repr))
issequence = lambda x: (isinstance(x, (list, tuple, Sequence))
and not isinstance(x, basestring))

View File

@@ -69,10 +69,22 @@ class Cache(object):
like e. g. lists of dictionaries.
"""
path = self._getvaluepath(key)
path.dirpath().ensure_dir()
with path.open("w") as f:
self.trace("cache-write %s: %r" % (key, value,))
json.dump(value, f, indent=2, sort_keys=True)
try:
path.dirpath().ensure_dir()
except (py.error.EEXIST, py.error.EACCES):
self.config.warn(
code='I9', message='could not create cache path %s' % (path,)
)
return
try:
f = path.open('w')
except py.error.ENOTDIR:
self.config.warn(
code='I9', message='cache could not write path %s' % (path,))
else:
with f:
self.trace("cache-write %s: %r" % (key, value,))
json.dump(value, f, indent=2, sort_keys=True)
class LFPlugin:
@@ -174,8 +186,20 @@ def pytest_configure(config):
@pytest.fixture
def cache(request):
"""
Return a cache object that can persist state between testing sessions.
cache.get(key, default)
cache.set(key, value)
Keys must be a ``/`` separated value, where the first part is usually the
name of your plugin or application to avoid clashes with other cache users.
Values can be any object handled by the json stdlib module.
"""
return request.config.cache
def pytest_report_header(config):
if config.option.verbose:
relpath = py.path.local().bestrelpath(config.cache._cachedir)

View File

@@ -147,8 +147,8 @@ class CaptureManager:
def suspendcapture_item(self, item, when):
out, err = self.suspendcapture()
item.add_report_section(when, "out", out)
item.add_report_section(when, "err", err)
item.add_report_section(when, "stdout", out)
item.add_report_section(when, "stderr", err)
error_capsysfderror = "cannot use capsys and capfd at the same time"

View File

@@ -120,12 +120,6 @@ def _prepareconfig(args=None, plugins=None):
raise
def exclude_pytest_names(name):
return not name.startswith(name) or name == "pytest_plugins" or \
name.startswith("pytest_funcarg__")
class PytestPluginManager(PluginManager):
"""
Overwrites :py:class:`pluggy.PluginManager` to add pytest-specific
@@ -165,14 +159,21 @@ class PytestPluginManager(PluginManager):
"""
warning = dict(code="I2",
fslocation=py.code.getfslineno(sys._getframe(1)),
nodeid=None,
message="use pluginmanager.add_hookspecs instead of "
"deprecated addhooks() method.")
self._warn(warning)
return self.add_hookspecs(module_or_class)
def parse_hookimpl_opts(self, plugin, name):
if exclude_pytest_names(name):
return None
# pytest hooks are always prefixed with pytest_
# so we avoid accessing possibly non-readable attributes
# (see issue #1073)
if not name.startswith("pytest_"):
return
# ignore some historic special names which can not be hooks anyway
if name == "pytest_plugins" or name.startswith("pytest_funcarg__"):
return
method = getattr(plugin, name)
opts = super(PytestPluginManager, self).parse_hookimpl_opts(plugin, name)

View File

@@ -5,6 +5,7 @@ import pytest, py
from _pytest.python import FixtureRequest
from py._code.code import TerminalRepr, ReprFileLocation
def pytest_addoption(parser):
parser.addini('doctest_optionflags', 'option flags for doctests',
type="args", default=["ELLIPSIS"])
@@ -22,6 +23,7 @@ def pytest_addoption(parser):
help="ignore doctest ImportErrors",
dest="doctest_ignore_import_errors")
def pytest_collect_file(path, parent):
config = parent.config
if path.ext == ".py":
@@ -31,20 +33,33 @@ def pytest_collect_file(path, parent):
path.check(fnmatch=config.getvalue("doctestglob")):
return DoctestTextfile(path, parent)
class ReprFailDoctest(TerminalRepr):
def __init__(self, reprlocation, lines):
self.reprlocation = reprlocation
self.lines = lines
def toterminal(self, tw):
for line in self.lines:
tw.line(line)
self.reprlocation.toterminal(tw)
class DoctestItem(pytest.Item):
def __init__(self, name, parent, runner=None, dtest=None):
super(DoctestItem, self).__init__(name, parent)
self.runner = runner
self.dtest = dtest
self.obj = None
self.fixture_request = None
def setup(self):
if self.dtest is not None:
self.fixture_request = _setup_fixtures(self)
globs = dict(getfixture=self.fixture_request.getfuncargvalue)
self.dtest.globs.update(globs)
def runtest(self):
_check_all_skipped(self.dtest)
@@ -94,6 +109,7 @@ class DoctestItem(pytest.Item):
def reportinfo(self):
return self.fspath, None, "[doctest] %s" % self.name
def _get_flag_lookup():
import doctest
return dict(DONT_ACCEPT_TRUE_FOR_1=doctest.DONT_ACCEPT_TRUE_FOR_1,
@@ -104,6 +120,7 @@ def _get_flag_lookup():
COMPARISON_FLAGS=doctest.COMPARISON_FLAGS,
ALLOW_UNICODE=_get_allow_unicode_flag())
def get_optionflags(parent):
optionflags_str = parent.config.getini("doctest_optionflags")
flag_lookup_table = _get_flag_lookup()
@@ -113,7 +130,7 @@ def get_optionflags(parent):
return flag_acc
class DoctestTextfile(DoctestItem, pytest.File):
class DoctestTextfile(DoctestItem, pytest.Module):
def runtest(self):
import doctest
@@ -148,7 +165,7 @@ def _check_all_skipped(test):
pytest.skip('all tests skipped by +SKIP option')
class DoctestModule(pytest.File):
class DoctestModule(pytest.Module):
def collect(self):
import doctest
if self.fspath.basename == "conftest.py":
@@ -161,23 +178,19 @@ class DoctestModule(pytest.File):
pytest.skip('unable to import module %r' % self.fspath)
else:
raise
# satisfy `FixtureRequest` constructor...
fixture_request = _setup_fixtures(self)
doctest_globals = dict(getfixture=fixture_request.getfuncargvalue)
# uses internal doctest module parsing mechanism
finder = doctest.DocTestFinder()
optionflags = get_optionflags(self)
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
checker=_get_unicode_checker())
for test in finder.find(module, module.__name__,
extraglobs=doctest_globals):
for test in finder.find(module, module.__name__):
if test.examples: # skip empty doctests
yield DoctestItem(test.name, self, runner, test)
def _setup_fixtures(doctest_item):
"""
Used by DoctestTextfile and DoctestModule to setup fixture information.
Used by DoctestTextfile and DoctestItem to setup fixture information.
"""
def func():
pass

View File

@@ -80,13 +80,23 @@ def showhelp(config):
line = " %-24s %s" %(spec, help)
tw.line(line[:tw.fullwidth])
tw.line() ; tw.line()
#tw.sep("=")
tw.line()
tw.line("environment variables:")
vars = [
("PYTEST_ADDOPTS", "extra command line options"),
("PYTEST_PLUGINS", "comma-separated plugins to load during startup"),
("PYTEST_DEBUG", "set to enable debug tracing of pytest's internals")
]
for name, help in vars:
tw.line(" %-24s %s" % (name, help))
tw.line()
tw.line()
tw.line("to see available markers type: py.test --markers")
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)")
tw.line(str(reporter.stats))
for warningreport in reporter.stats.get('warnings', []):
tw.line("warning : " + warningreport.message, red=True)
return

View File

@@ -30,8 +30,15 @@ def pytest_plugin_registered(plugin, manager):
def pytest_addoption(parser):
"""register argparse-style options and ini-style config values.
This function must be implemented in a :ref:`plugin <pluginorder>` and is
called once at the beginning of a test run.
.. warning::
This function must be implemented in a :ref:`plugin <pluginorder>`
and is called once at the beginning of a test run.
Implementing this hook from ``conftest.py`` files is **strongly**
discouraged because ``conftest.py`` files are lazily loaded and
may give strange *unknown option* errors depending on the directory
``py.test`` is invoked from.
:arg parser: To add command line options, call
:py:func:`parser.addoption(...) <_pytest.config.Parser.addoption>`.
@@ -284,4 +291,6 @@ def pytest_exception_interact(node, call, report):
"""
def pytest_enter_pdb():
""" called upon pdb.set_trace()"""
""" called upon pdb.set_trace(), can be used by plugins to take special
action just before the python debugger enters in interactive mode.
"""

View File

@@ -1,9 +1,13 @@
""" report test results in JUnit-XML format, for use with Hudson and build integration servers.
"""
report test results in JUnit-XML format,
for use with Jenkins and build integration servers.
Output conforms to https://github.com/jenkinsci/xunit-plugin/blob/master/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd
Based on initial code from Ross Lawley.
"""
# Output conforms to https://github.com/jenkinsci/xunit-plugin/blob/master/
# src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd
import py
import os
import re
@@ -19,10 +23,10 @@ else:
unicode = str
long = int
class Junit(py.xml.Namespace):
pass
# We need to get the subset of the invalid unicode ranges according to
# XML 1.0 which are valid in this python build. Hence we calculate
# this dynamically instead of hardcoding it. The spec range of valid
@@ -30,21 +34,19 @@ class Junit(py.xml.Namespace):
# | [#x10000-#x10FFFF]
_legal_chars = (0x09, 0x0A, 0x0d)
_legal_ranges = (
(0x20, 0x7E),
(0x80, 0xD7FF),
(0xE000, 0xFFFD),
(0x10000, 0x10FFFF),
(0x20, 0x7E), (0x80, 0xD7FF), (0xE000, 0xFFFD), (0x10000, 0x10FFFF),
)
_legal_xml_re = [unicode("%s-%s") % (unichr(low), unichr(high))
for (low, high) in _legal_ranges
if low < sys.maxunicode]
_legal_xml_re = [
unicode("%s-%s") % (unichr(low), unichr(high))
for (low, high) in _legal_ranges if low < sys.maxunicode
]
_legal_xml_re = [unichr(x) for x in _legal_chars] + _legal_xml_re
illegal_xml_re = re.compile(unicode('[^%s]') %
unicode('').join(_legal_xml_re))
illegal_xml_re = re.compile(unicode('[^%s]') % unicode('').join(_legal_xml_re))
del _legal_chars
del _legal_ranges
del _legal_xml_re
def bin_xml_escape(arg):
def repl(matchobj):
i = ord(matchobj.group())
@@ -52,112 +54,93 @@ def bin_xml_escape(arg):
return unicode('#x%02X') % i
else:
return unicode('#x%04X') % i
return py.xml.raw(illegal_xml_re.sub(repl, py.xml.escape(arg)))
@pytest.fixture
def record_xml_property(request):
"""Fixture that adds extra xml properties to the tag for the calling test.
The fixture is callable with (name, value), with value being automatically
xml-encoded.
"""
def inner(name, value):
if hasattr(request.config, "_xml"):
request.config._xml.add_custom_property(name, value)
msg = 'record_xml_property is an experimental feature'
request.config.warn(code='C3', message=msg,
fslocation=request.node.location[:2])
return inner
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting")
group.addoption('--junitxml', '--junit-xml', action="store",
dest="xmlpath", metavar="path", default=None,
help="create junit-xml style report file at given path.")
group.addoption('--junitprefix', '--junit-prefix', action="store",
metavar="str", default=None,
help="prepend prefix to classnames in junit-xml output")
class _NodeReporter(object):
def __init__(self, nodeid, xml):
def pytest_configure(config):
xmlpath = config.option.xmlpath
# prevent opening xmllog on slave nodes (xdist)
if xmlpath and not hasattr(config, 'slaveinput'):
config._xml = LogXML(xmlpath, config.option.junitprefix)
config.pluginmanager.register(config._xml)
self.id = nodeid
self.xml = xml
self.add_stats = self.xml.add_stats
self.duration = 0
self.properties = {}
self.property_insert_order = []
self.nodes = []
self.testcase = None
self.attrs = {}
def pytest_unconfigure(config):
xml = getattr(config, '_xml', None)
if xml:
del config._xml
config.pluginmanager.unregister(xml)
def mangle_testnames(names):
names = [x.replace(".py", "") for x in names if x != '()']
names[0] = names[0].replace("/", '.')
return names
def append(self, node):
self.xml.add_stats(type(node).__name__)
self.nodes.append(node)
class LogXML(object):
def __init__(self, logfile, prefix):
logfile = os.path.expanduser(os.path.expandvars(logfile))
self.logfile = os.path.normpath(os.path.abspath(logfile))
self.prefix = prefix
self.tests = []
self.passed = self.skipped = 0
self.failed = self.errors = 0
self.custom_properties = {}
def add_property(self, name, value):
name = str(name)
if name not in self.property_insert_order:
self.property_insert_order.append(name)
self.properties[name] = bin_xml_escape(value)
def add_custom_property(self, name, value):
self.custom_properties[str(name)] = bin_xml_escape(str(value))
def _opentestcase(self, report):
names = mangle_testnames(report.nodeid.split("::"))
def make_properties_node(self):
"""Return a Junit node containing custom properties, if any.
"""
if self.properties:
return Junit.properties([
Junit.property(name=name, value=self.properties[name])
for name in self.property_insert_order
])
return ''
def record_testreport(self, testreport):
assert not self.testcase
names = mangle_testnames(testreport.nodeid.split("::"))
classnames = names[:-1]
if self.prefix:
classnames.insert(0, self.prefix)
if self.xml.prefix:
classnames.insert(0, self.xml.prefix)
attrs = {
"classname": ".".join(classnames),
"name": bin_xml_escape(names[-1]),
"file": report.location[0],
"time": 0,
"file": testreport.location[0],
}
if report.location[1] is not None:
attrs["line"] = report.location[1]
self.tests.append(Junit.testcase(**attrs))
if testreport.location[1] is not None:
attrs["line"] = testreport.location[1]
self.attrs = attrs
def to_xml(self):
testcase = Junit.testcase(time=self.duration, **self.attrs)
testcase.append(self.make_properties_node())
for node in self.nodes:
testcase.append(node)
return testcase
def _add_simple(self, kind, message, data=None):
data = bin_xml_escape(data)
node = kind(data, message=message)
self.append(node)
def _write_captured_output(self, report):
for capname in ('out', 'err'):
allcontent = ""
for name, content in report.get_sections("Captured std%s" %
capname):
capname):
allcontent += content
if allcontent:
tag = getattr(Junit, 'system-'+capname)
tag = getattr(Junit, 'system-' + capname)
self.append(tag(bin_xml_escape(allcontent)))
def append(self, obj):
self.tests[-1].append(obj)
def append_custom_properties(self):
if self.custom_properties:
self.tests[-1].append(
Junit.properties(
[
Junit.property(name=name, value=value)
for name, value in self.custom_properties.items()
]
)
)
self.custom_properties.clear()
def append_pass(self, report):
self.passed += 1
self.add_stats('passed')
self._write_captured_output(report)
def append_failure(self, report):
#msg = str(report.longrepr.reprtraceback.extraline)
# msg = str(report.longrepr.reprtraceback.extraline)
if hasattr(report, "wasxfail"):
self.append(
Junit.skipped(message="xfail-marked test passes unexpectedly"))
self.skipped += 1
self._add_simple(
Junit.skipped,
"xfail-marked test passes unexpectedly")
else:
if hasattr(report.longrepr, "reprcrash"):
message = report.longrepr.reprcrash.message
@@ -169,30 +152,26 @@ class LogXML(object):
fail = Junit.failure(message=message)
fail.append(bin_xml_escape(report.longrepr))
self.append(fail)
self.failed += 1
self._write_captured_output(report)
def append_collect_error(self, report):
#msg = str(report.longrepr.reprtraceback.extraline)
# msg = str(report.longrepr.reprtraceback.extraline)
self.append(Junit.error(bin_xml_escape(report.longrepr),
message="collection failure"))
self.errors += 1
def append_collect_skipped(self, report):
#msg = str(report.longrepr.reprtraceback.extraline)
self.append(Junit.skipped(bin_xml_escape(report.longrepr),
message="collection skipped"))
self.skipped += 1
self._add_simple(
Junit.skipped, "collection skipped", report.longrepr)
def append_error(self, report):
self.append(Junit.error(bin_xml_escape(report.longrepr),
message="test setup failure"))
self.errors += 1
self._add_simple(
Junit.error, "test setup failure", report.longrepr)
def append_skipped(self, report):
if hasattr(report, "wasxfail"):
self.append(Junit.skipped(bin_xml_escape(report.wasxfail),
message="expected test failure"))
self._add_simple(
Junit.skipped, "expected test failure", report.wasxfail
)
else:
filename, lineno, skipreason = report.longrepr
if skipreason.startswith("Skipped: "):
@@ -200,43 +179,172 @@ class LogXML(object):
self.append(
Junit.skipped("%s:%s: %s" % (filename, lineno, skipreason),
type="pytest.skip",
message=skipreason
))
self.skipped += 1
message=skipreason))
self._write_captured_output(report)
def finalize(self):
data = self.to_xml().unicode(indent=0)
self.__dict__.clear()
self.to_xml = lambda: py.xml.raw(data)
@pytest.fixture
def record_xml_property(request):
"""Fixture that adds extra xml properties to the tag for the calling test.
The fixture is callable with (name, value), with value being automatically
xml-encoded.
"""
request.node.warn(
code='C3',
message='record_xml_property is an experimental feature',
)
xml = getattr(request.config, "_xml", None)
if xml is not None:
node_reporter = xml.node_reporter(request.node.nodeid)
return node_reporter.add_property
else:
def add_property_noop(name, value):
pass
return add_property_noop
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting")
group.addoption(
'--junitxml', '--junit-xml',
action="store",
dest="xmlpath",
metavar="path",
default=None,
help="create junit-xml style report file at given path.")
group.addoption(
'--junitprefix', '--junit-prefix',
action="store",
metavar="str",
default=None,
help="prepend prefix to classnames in junit-xml output")
def pytest_configure(config):
xmlpath = config.option.xmlpath
# prevent opening xmllog on slave nodes (xdist)
if xmlpath and not hasattr(config, 'slaveinput'):
config._xml = LogXML(xmlpath, config.option.junitprefix)
config.pluginmanager.register(config._xml)
def pytest_unconfigure(config):
xml = getattr(config, '_xml', None)
if xml:
del config._xml
config.pluginmanager.unregister(xml)
def mangle_testnames(names):
names = [x.replace(".py", "") for x in names if x != '()']
names[0] = names[0].replace("/", '.')
return names
class LogXML(object):
def __init__(self, logfile, prefix):
logfile = os.path.expanduser(os.path.expandvars(logfile))
self.logfile = os.path.normpath(os.path.abspath(logfile))
self.prefix = prefix
self.stats = dict.fromkeys([
'error',
'passed',
'failure',
'skipped',
], 0)
self.node_reporters = {} # nodeid -> _NodeReporter
self.node_reporters_ordered = []
def node_reporter(self, report):
nodeid = getattr(report, 'nodeid', report)
# local hack to handle xdist report order
slavenode = getattr(report, 'node', None)
key = nodeid, slavenode
if key in self.node_reporters:
#TODO: breasks for --dist=each
return self.node_reporters[key]
reporter = _NodeReporter(nodeid, self)
self.node_reporters[key] = reporter
self.node_reporters_ordered.append(reporter)
return reporter
def add_stats(self, key):
if key in self.stats:
self.stats[key] += 1
def _opentestcase(self, report):
reporter = self.node_reporter(report)
reporter.record_testreport(report)
return reporter
def pytest_runtest_logreport(self, report):
if report.when == "setup":
self._opentestcase(report)
self.tests[-1].attr.time += getattr(report, 'duration', 0)
self.append_custom_properties()
"""handle a setup/call/teardown report, generating the appropriate
xml tags as necessary.
note: due to plugins like xdist, this hook may be called in interlaced
order with reports from other nodes. for example:
usual call order:
-> setup node1
-> call node1
-> teardown node1
-> setup node2
-> call node2
-> teardown node2
possible call order in xdist:
-> setup node1
-> call node1
-> setup node2
-> call node2
-> teardown node2
-> teardown node1
"""
if report.passed:
if report.when == "call": # ignore setup/teardown
self.append_pass(report)
if report.when == "call": # ignore setup/teardown
reporter = self._opentestcase(report)
reporter.append_pass(report)
elif report.failed:
if report.when != "call":
self.append_error(report)
reporter = self._opentestcase(report)
if report.when == "call":
reporter.append_failure(report)
else:
self.append_failure(report)
reporter.append_error(report)
elif report.skipped:
self.append_skipped(report)
reporter = self._opentestcase(report)
reporter.append_skipped(report)
self.update_testcase_duration(report)
if report.when == "teardown":
self.node_reporter(report).finalize()
def update_testcase_duration(self, report):
"""accumulates total duration for nodeid from given report and updates
the Junit.testcase with the new total if already created.
"""
reporter = self.node_reporter(report)
reporter.duration += getattr(report, 'duration', 0.0)
def pytest_collectreport(self, report):
if not report.passed:
self._opentestcase(report)
reporter = self._opentestcase(report)
if report.failed:
self.append_collect_error(report)
reporter.append_collect_error(report)
else:
self.append_collect_skipped(report)
reporter.append_collect_skipped(report)
def pytest_internalerror(self, excrepr):
self.errors += 1
data = bin_xml_escape(excrepr)
self.tests.append(
Junit.testcase(
Junit.error(data, message="internal error"),
classname="pytest",
name="internal"))
reporter = self.node_reporter('internal')
reporter.attrs.update(classname="pytest", name='internal')
reporter._add_simple(Junit.error, 'internal error', excrepr)
def pytest_sessionstart(self):
self.suite_start_time = time.time()
@@ -248,19 +356,20 @@ class LogXML(object):
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
numtests = self.stats['passed'] + self.stats['failure']
logfile.write('<?xml version="1.0" encoding="utf-8"?>')
logfile.write(Junit.testsuite(
self.tests,
[x.to_xml() for x in self.node_reporters_ordered],
name="pytest",
errors=self.errors,
failures=self.failed,
skips=self.skipped,
errors=self.stats['error'],
failures=self.stats['failure'],
skips=self.stats['skipped'],
tests=numtests,
time="%.3f" % suite_time_delta,
).unicode(indent=0))
time="%.3f" % suite_time_delta, ).unicode(indent=0))
logfile.close()
def pytest_terminal_summary(self, terminalreporter):
terminalreporter.write_sep("-", "generated xml file: %s" % (self.logfile))
terminalreporter.write_sep("-",
"generated xml file: %s" % (self.logfile))

View File

@@ -240,17 +240,11 @@ class Node(object):
# used for storing artificial fixturedefs for direct parametrization
self._name2pseudofixturedef = {}
#self.extrainit()
@property
def ihook(self):
""" fspath sensitive hook proxy used to call pytest hooks"""
return self.session.gethookproxy(self.fspath)
#def extrainit(self):
# """"extra initialization after Node is initialized. Implemented
# by some subclasses. """
Module = compatproperty("Module")
Class = compatproperty("Class")
Instance = compatproperty("Instance")

View File

@@ -13,17 +13,21 @@ def pytest_addoption(parser):
@pytest.hookimpl(trylast=True)
def pytest_configure(config):
import py
if config.option.pastebin == "all":
tr = config.pluginmanager.getplugin('terminalreporter')
# if no terminal reporter plugin is present, nothing we can do here;
# this can happen when this function executes in a slave node
# when using pytest-xdist, for example
if tr is not None:
config._pastebinfile = tempfile.TemporaryFile('w+')
# pastebin file will be utf-8 encoded binary file
config._pastebinfile = tempfile.TemporaryFile('w+b')
oldwrite = tr._tw.write
def tee_write(s, **kwargs):
oldwrite(s, **kwargs)
config._pastebinfile.write(str(s))
if py.builtin._istext(s):
s = s.encode('utf-8')
config._pastebinfile.write(s)
tr._tw.write = tee_write
def pytest_unconfigure(config):
@@ -45,7 +49,7 @@ def create_new_paste(contents):
"""
Creates a new paste using bpaste.net service.
:contents: paste contents
:contents: paste contents as utf-8 encoded bytes
:returns: url to the pasted contents
"""
import re
@@ -61,8 +65,8 @@ def create_new_paste(contents):
'expiry': '1week',
}
url = 'https://bpaste.net'
response = urlopen(url, data=urlencode(params)).read()
m = re.search(r'href="/raw/(\w+)"', response)
response = urlopen(url, data=urlencode(params).encode('ascii')).read()
m = re.search(r'href="/raw/(\w+)"', response.decode('utf-8'))
if m:
return '%s/show/%s' % (url, m.group(1))
else:

View File

@@ -534,6 +534,20 @@ class Testdir:
if path is None:
path = self.tmpdir
sys.path.insert(0, str(path))
# a call to syspathinsert() usually means that the caller
# wants to import some dynamically created files.
# with python3 we thus invalidate import caches.
self._possibly_invalidate_import_caches()
def _possibly_invalidate_import_caches(self):
# invalidate caches if we can (py33 and above)
try:
import importlib
except ImportError:
pass
else:
if hasattr(importlib, "invalidate_caches"):
importlib.invalidate_caches()
def mkdir(self, name):
"""Create a new (sub)directory."""

View File

@@ -4,6 +4,7 @@ import fnmatch
import functools
import py
import inspect
import types
import sys
import pytest
from _pytest.mark import MarkDecorator, MarkerError
@@ -32,6 +33,9 @@ exc_clear = getattr(sys, 'exc_clear', lambda: None)
# The type of re.compile objects is not exposed in Python.
REGEX_TYPE = type(re.compile(''))
_PY3 = sys.version_info > (3, 0)
_PY2 = not _PY3
if hasattr(inspect, 'signature'):
def _format_args(func):
@@ -40,13 +44,31 @@ else:
def _format_args(func):
return inspect.formatargspec(*inspect.getargspec(func))
if sys.version_info[:2] == (2, 6):
def isclass(object):
""" Return true if the object is a class. Overrides inspect.isclass for
python 2.6 because it will return True for objects which always return
something on __getattr__ calls (see #1035).
Backport of https://hg.python.org/cpython/rev/35bf8f7a8edc
"""
return isinstance(object, (type, types.ClassType))
def _has_positional_arg(func):
return func.__code__.co_argcount
def filter_traceback(entry):
return entry.path != cutdir1 and not entry.path.relto(cutdir2)
# entry.path might sometimes return a str object when the entry
# points to dynamically generated code
# see https://bitbucket.org/pytest-dev/py/issues/71
raw_filename = entry.frame.code.raw.co_filename
is_generated = '<' in raw_filename and '>' in raw_filename
if is_generated:
return False
# entry.path might point to an inexisting file, in which case it will
# alsso return a str object. see #1133
p = py.path.local(entry.path)
return p != cutdir1 and not p.relto(cutdir2)
def get_real_func(obj):
@@ -293,11 +315,14 @@ def pytest_pycollect_makeitem(collector, name, obj):
elif collector.istestfunction(obj, name):
# mock seems to store unbound methods (issue473), normalize it
obj = getattr(obj, "__func__", obj)
if not isfunction(obj):
# We need to try and unwrap the function if it's a functools.partial
# or a funtools.wrapped.
# We musn't if it's been wrapped with mock.patch (python 2 only)
if not (isfunction(obj) or isfunction(get_real_func(obj))):
collector.warn(code="C2", message=
"cannot collect %r because it is not a function."
% name, )
if getattr(obj, "__test__", True):
elif getattr(obj, "__test__", True):
if is_generator(obj):
res = Generator(name, parent=collector)
else:
@@ -359,12 +384,13 @@ class PyobjMixin(PyobjContext):
def reportinfo(self):
# XXX caching?
obj = self.obj
if hasattr(obj, 'compat_co_firstlineno'):
compat_co_firstlineno = getattr(obj, 'compat_co_firstlineno', None)
if isinstance(compat_co_firstlineno, int):
# nose compatibility
fspath = sys.modules[obj.__module__].__file__
if fspath.endswith(".pyc"):
fspath = fspath[:-1]
lineno = obj.compat_co_firstlineno
lineno = compat_co_firstlineno
else:
fspath, lineno = getfslineno(obj)
modpath = self.getmodpath()
@@ -380,7 +406,10 @@ class PyCollector(PyobjMixin, pytest.Collector):
""" Look for the __test__ attribute, which is applied by the
@nose.tools.istest decorator
"""
return safe_getattr(obj, '__test__', False)
# We explicitly check for "is True" here to not mistakenly treat
# classes with a custom __getattr__ returning something truthy (like a
# function) as test classes.
return safe_getattr(obj, '__test__', False) is True
def classnamefilter(self, name):
return self._matches_prefix_or_glob_option('python_classes', name)
@@ -422,7 +451,7 @@ class PyCollector(PyobjMixin, pytest.Collector):
seen = {}
l = []
for dic in dicts:
for name, obj in dic.items():
for name, obj in list(dic.items()):
if name in seen:
continue
seen[name] = True
@@ -912,7 +941,7 @@ class Metafunc(FuncargnamesCompatAttr):
:arg argvalues: The list of argvalues determines how often a
test is invoked with different argument values. If only one
argname was specified argvalues is a list of simple values. If N
argname was specified argvalues is a list of values. If N
argnames were specified, argvalues must be a list of N-tuples,
where each tuple-element specifies a value for its respective
argname.
@@ -1037,6 +1066,40 @@ class Metafunc(FuncargnamesCompatAttr):
self._calls.append(cs)
if _PY3:
import codecs
def _escape_bytes(val):
"""
If val is pure ascii, returns it as a str(), otherwise escapes
into a sequence of escaped bytes:
b'\xc3\xb4\xc5\xd6' -> u'\\xc3\\xb4\\xc5\\xd6'
note:
the obvious "v.decode('unicode-escape')" will return
valid utf-8 unicode if it finds them in the string, but we
want to return escaped bytes for any byte, even if they match
a utf-8 string.
"""
if val:
# source: http://goo.gl/bGsnwC
encoded_bytes, _ = codecs.escape_encode(val)
return encoded_bytes.decode('ascii')
else:
# empty bytes crashes codecs.escape_encode (#1087)
return ''
else:
def _escape_bytes(val):
"""
In py2 bytes and str are the same type, so return it unchanged if it
is a full ascii string, otherwise escape it into its binary form.
"""
try:
return val.decode('ascii')
except UnicodeDecodeError:
return val.encode('string-escape')
def _idval(val, argname, idx, idfn):
if idfn:
try:
@@ -1046,7 +1109,9 @@ def _idval(val, argname, idx, idfn):
except Exception:
pass
if isinstance(val, (float, int, str, bool, NoneType)):
if isinstance(val, bytes):
return _escape_bytes(val)
elif isinstance(val, (float, int, str, bool, NoneType)):
return str(val)
elif isinstance(val, REGEX_TYPE):
return val.pattern
@@ -1054,6 +1119,14 @@ def _idval(val, argname, idx, idfn):
return str(val)
elif isclass(val) and hasattr(val, '__name__'):
return val.__name__
elif _PY2 and isinstance(val, unicode):
# special case for python 2: if a unicode string is
# convertible to ascii, return it as an str() object instead
try:
return str(val)
except UnicodeError:
# fallthrough
pass
return str(argname)+str(idx)
def _idvalset(idx, valset, argnames, idfn):
@@ -1140,6 +1213,28 @@ def raises(expected_exception, *args, **kwargs):
>>> with raises(ZeroDivisionError):
... 1/0
.. note::
When using ``pytest.raises`` as a context manager, it's worthwhile to
note that normal context manager rules apply and that the exception
raised *must* be the final line in the scope of the context manager.
Lines of code after that, within the scope of the context manager will
not be executed. For example::
>>> with raises(OSError) as err:
assert 1 == 1 # this will execute as expected
raise OSError(errno.EEXISTS, 'directory exists')
assert err.errno == errno.EEXISTS # this will not execute
Instead, the following approach must be taken (note the difference in
scope)::
>>> with raises(OSError) as err:
assert 1 == 1 # this will execute as expected
raise OSError(errno.EEXISTS, 'directory exists')
assert err.errno == errno.EEXISTS # this will now execute
Or you can specify a callable by passing a to-be-called lambda::
>>> raises(ZeroDivisionError, lambda: 1/0)
@@ -1876,14 +1971,14 @@ class FixtureManager:
autousenames = []
for name in dir(holderobj):
obj = getattr(holderobj, name, None)
if not callable(obj):
continue
# fixture functions have a pytest_funcarg__ prefix (pre-2.3 style)
# or are "@pytest.fixture" marked
marker = getfixturemarker(obj)
if marker is None:
if not name.startswith(self._argprefix):
continue
if not callable(obj):
continue
marker = defaultfuncargprefixmarker
name = name[len(self._argprefix):]
elif not isinstance(marker, FixtureFunctionMarker):
@@ -2061,7 +2156,7 @@ def num_mock_patch_args(function):
def getfuncargnames(function, startindex=None):
# XXX merge with main.py's varnames
#assert not inspect.isclass(function)
#assert not isclass(function)
realfunction = function
while hasattr(realfunction, "__wrapped__"):
realfunction = realfunction.__wrapped__

View File

@@ -29,17 +29,39 @@ def pytest_namespace():
def deprecated_call(func, *args, **kwargs):
"""Assert that ``func(*args, **kwargs)`` triggers a DeprecationWarning.
"""
wrec = WarningsRecorder()
with wrec:
warnings.simplefilter('always') # ensure all warnings are triggered
ret = func(*args, **kwargs)
""" assert that calling ``func(*args, **kwargs)`` triggers a
``DeprecationWarning`` or ``PendingDeprecationWarning``.
if not any(r.category is DeprecationWarning for r in wrec):
Note: we cannot use WarningsRecorder here because it is still subject
to the mechanism that prevents warnings of the same type from being
triggered twice for the same module. See #1190.
"""
categories = []
def warn_explicit(message, category, *args, **kwargs):
categories.append(category)
old_warn_explicit(message, category, *args, **kwargs)
def warn(message, category=None, *args, **kwargs):
if isinstance(message, Warning):
categories.append(message.__class__)
else:
categories.append(category)
old_warn(message, category, *args, **kwargs)
old_warn = warnings.warn
old_warn_explicit = warnings.warn_explicit
warnings.warn_explicit = warn_explicit
warnings.warn = warn
try:
ret = func(*args, **kwargs)
finally:
warnings.warn_explicit = old_warn_explicit
warnings.warn = old_warn
deprecation_categories = (DeprecationWarning, PendingDeprecationWarning)
if not any(issubclass(c, deprecation_categories) for c in categories):
__tracebackhide__ = True
raise AssertionError("%r did not produce DeprecationWarning" % (func,))
return ret

View File

@@ -226,7 +226,7 @@ def pytest_runtest_makereport(item, call):
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))
sections.append(("Captured %s %s" %(key, rwhen), content))
return TestReport(item.nodeid, item.location,
keywords, outcome, longrepr, when,
sections, duration)
@@ -469,7 +469,7 @@ def skip(msg=""):
skip.Exception = Skipped
def fail(msg="", pytrace=True):
""" explicitely fail an currently-executing test with the given Message.
""" explicitly fail an currently-executing test with the given Message.
:arg pytrace: if false the msg represents the full failure information
and no python traceback will be reported.

View File

@@ -22,7 +22,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 (w)warnings (a)all.")
"(E)error, (s)skipped, (x)failed, (X)passed (w)pytest-warnings (a)all.")
group._addoption('-l', '--showlocals',
action="store_true", dest="showlocals", default=False,
help="show locals in tracebacks (disabled by default).")
@@ -458,7 +458,8 @@ class TerminalReporter:
self.write_line(line)
else:
msg = self._getfailureheadline(rep)
self.write_sep("_", msg)
markup = {'red': True, 'bold': True}
self.write_sep("_", msg, **markup)
self._outrep_summary(rep)
def summary_errors(self):
@@ -543,7 +544,11 @@ def build_summary_stats_line(stats):
if val:
key_name = key_translation.get(key, key)
parts.append("%d %s" % (len(val), key_name))
line = ", ".join(parts)
if parts:
line = ", ".join(parts)
else:
line = "no tests ran"
if 'failed' in stats or 'error' in stats:
color = 'red'

View File

@@ -78,7 +78,7 @@ def get_user():
import getpass
try:
return getpass.getuser()
except ImportError:
except (ImportError, KeyError):
return None
# backward compatibility

View File

@@ -69,12 +69,26 @@ class TestCaseFunction(pytest.Function):
def setup(self):
self._testcase = self.parent.obj(self.name)
self._fix_unittest_skip_decorator()
self._obj = getattr(self._testcase, self.name)
if hasattr(self._testcase, 'setup_method'):
self._testcase.setup_method(self._obj)
if hasattr(self, "_request"):
self._request._fillfixtures()
def _fix_unittest_skip_decorator(self):
"""
The @unittest.skip decorator calls functools.wraps(self._testcase)
The call to functools.wraps() fails unless self._testcase
has a __name__ attribute. This is usually automatically supplied
if the test is a function or method, but we need to add manually
here.
See issue #1169
"""
if sys.version_info[0] == 2:
setattr(self._testcase, "__name__", self.name)
def teardown(self):
if hasattr(self._testcase, 'teardown_method'):
self._testcase.teardown_method(self._obj)

View File

@@ -1,7 +0,0 @@
pluggy.py,sha256=Y_aZC2eNi0zEaaGPDF5d7S_w-2KbvsvvmcykfWB-NQ0,29671
pluggy-0.3.0.dist-info/top_level.txt,sha256=xKSCRhai-v9MckvMuWqNz16c1tbsmOggoMSwTgcpYHE,7
pluggy-0.3.0.dist-info/RECORD,,
pluggy-0.3.0.dist-info/metadata.json,sha256=y8dkBTPYLTWwqPj12oWV0MriJ21FhCY0e185EhiAkeg,988
pluggy-0.3.0.dist-info/METADATA,sha256=i1WR19wl6r2qWC7YGnfiHzTlhmYmKuidTT5FobM0ctU,1286
pluggy-0.3.0.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110
pluggy-0.3.0.dist-info/DESCRIPTION.rst,sha256=P5Akh1EdIBR6CeqtV2P8ZwpGSpZiTKPw0NyS7jEiD-g,306

View File

@@ -1 +0,0 @@
{"license": "MIT license", "name": "pluggy", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "plugin and hook calling mechanisms for python", "platform": "unix", "version": "0.3.0", "extensions": {"python.details": {"document_names": {"description": "DESCRIPTION.rst"}, "contacts": [{"role": "author", "email": "holger at merlinux.eu", "name": "Holger Krekel"}]}}, "classifiers": ["Development Status :: 3 - Alpha ", "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 :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4"]}

View File

@@ -1,6 +1,6 @@
Metadata-Version: 2.0
Name: pluggy
Version: 0.3.0
Version: 0.3.1
Summary: plugin and hook calling mechanisms for python
Home-page: UNKNOWN
Author: Holger Krekel
@@ -10,7 +10,7 @@ Platform: unix
Platform: linux
Platform: osx
Platform: win32
Classifier: Development Status :: 3 - Alpha
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: POSIX
@@ -25,6 +25,7 @@ Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Plugin registration and hook calling for Python
===============================================

View File

@@ -0,0 +1,8 @@
pluggy.py,sha256=v_RfWzyW6DPU1cJu_EFoL_OHq3t13qloVdR6UaMCXQA,29862
pluggy-0.3.1.dist-info/top_level.txt,sha256=xKSCRhai-v9MckvMuWqNz16c1tbsmOggoMSwTgcpYHE,7
pluggy-0.3.1.dist-info/pbr.json,sha256=xX3s6__wOcAyF-AZJX1sdZyW6PUXT-FkfBlM69EEUCg,47
pluggy-0.3.1.dist-info/RECORD,,
pluggy-0.3.1.dist-info/metadata.json,sha256=nLKltOT78dMV-00uXD6Aeemp4xNsz2q59j6ORSDeLjw,1027
pluggy-0.3.1.dist-info/METADATA,sha256=1b85Ho2u4iK30M099k7axMzcDDhLcIMb-A82JUJZnSo,1334
pluggy-0.3.1.dist-info/WHEEL,sha256=AvR0WeTpDaxT645bl5FQxUK6NPsTls2ttpcGJg3j1Xg,110
pluggy-0.3.1.dist-info/DESCRIPTION.rst,sha256=P5Akh1EdIBR6CeqtV2P8ZwpGSpZiTKPw0NyS7jEiD-g,306

View File

@@ -0,0 +1 @@
{"license": "MIT license", "name": "pluggy", "metadata_version": "2.0", "generator": "bdist_wheel (0.24.0)", "summary": "plugin and hook calling mechanisms for python", "platform": "unix", "version": "0.3.1", "extensions": {"python.details": {"document_names": {"description": "DESCRIPTION.rst"}, "contacts": [{"role": "author", "email": "holger at merlinux.eu", "name": "Holger Krekel"}]}}, "classifiers": ["Development Status :: 4 - Beta", "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 :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5"]}

View File

@@ -0,0 +1 @@
{"is_release": false, "git_version": "7d4c9cd"}

View File

@@ -573,7 +573,7 @@ class _MultiCall:
# XXX note that the __multicall__ argument is supported only
# for pytest compatibility reasons. It was never officially
# supported there and is explicitely deprecated since 2.8
# supported there and is explicitly deprecated since 2.8
# so we can remove it soon, allowing to avoid the below recursion
# in execute() and simplify/speed up the execute loop.

View File

@@ -1,76 +1,19 @@
environment:
matrix:
# Pre-installed Python versions, which Appveyor may upgrade to
# a later point release.
- PYTHON: "C:\\Python27"
PYTHON_VERSION: "2.7.x" # currently 2.7.9
PYTHON_ARCH: "32"
TESTENV: "py27"
- PYTHON: "C:\\Python27-x64"
PYTHON_VERSION: "2.7.x" # currently 2.7.9
PYTHON_ARCH: "64"
TESTENV: "py27"
- PYTHON: "C:\\Python33"
PYTHON_VERSION: "3.3.x" # currently 3.3.5
PYTHON_ARCH: "32"
TESTENV: "py33"
- PYTHON: "C:\\Python33-x64"
PYTHON_VERSION: "3.3.x" # currently 3.3.5
PYTHON_ARCH: "64"
TESTENV: "py33"
- PYTHON: "C:\\Python34"
PYTHON_VERSION: "3.4.x" # currently 3.4.3
PYTHON_ARCH: "32"
TESTENV: "py34"
- PYTHON: "C:\\Python34-x64"
PYTHON_VERSION: "3.4.x" # currently 3.4.3
PYTHON_ARCH: "64"
TESTENV: "py34"
# Also test a Python version not pre-installed
# See: https://github.com/ogrisel/python-appveyor-demo/issues/10
- PYTHON: "C:\\Python266"
PYTHON_VERSION: "2.6.6"
PYTHON_ARCH: "32"
TESTENV: "py26"
install:
- ECHO "Filesystem root:"
- ps: "ls \"C:/\""
- echo Installed Pythons
- dir c:\Python*
- ECHO "Installed SDKs:"
- ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
# Install Python (from the official .msi of http://python.org) and pip when
# not already installed.
- ps: if (-not(Test-Path($env:PYTHON))) { & appveyor\install.ps1 }
# Prepend newly installed Python to the PATH of this build (this cannot be
# done from inside the powershell script as it would require to restart
# the parent CMD process).
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
# Check that we have the expected version and architecture for Python
- "python --version"
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
# Install the build dependencies of the project. If some dependencies contain
# compiled extensions and are not provided as pre-built wheel packages,
# pip will build them from source using the MSVC compiler matching the
# target Python version and architecture
- C:\Python27\python -m pip install tox
- C:\Python35\python -m pip install tox
build: false # Not a C# project, build stuff at the test step instead.
test_script:
# Build the compiled extension and run the project tests
- C:\Python27\python -m tox -e %TESTENV%
- 'set TESTENVS=
flakes,
py26,
py27,
py33,
py34,
py27-xdist,
py35-xdist
'
- C:\Python35\python -m tox -e "%TESTENVS%"

View File

@@ -1,180 +0,0 @@
# Sample script to install Python and pip under Windows
# Authors: Olivier Grisel, Jonathan Helmus and Kyle Kastner
# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
$MINICONDA_URL = "http://repo.continuum.io/miniconda/"
$BASE_URL = "https://www.python.org/ftp/python/"
$GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py"
$GET_PIP_PATH = "C:\get-pip.py"
function DownloadPython ($python_version, $platform_suffix) {
$webclient = New-Object System.Net.WebClient
$filename = "python-" + $python_version + $platform_suffix + ".msi"
$url = $BASE_URL + $python_version + "/" + $filename
$basedir = $pwd.Path + "\"
$filepath = $basedir + $filename
if (Test-Path $filename) {
Write-Host "Reusing" $filepath
return $filepath
}
# Download and retry up to 3 times in case of network transient errors.
Write-Host "Downloading" $filename "from" $url
$retry_attempts = 2
for($i=0; $i -lt $retry_attempts; $i++){
try {
$webclient.DownloadFile($url, $filepath)
break
}
Catch [Exception]{
Start-Sleep 1
}
}
if (Test-Path $filepath) {
Write-Host "File saved at" $filepath
} else {
# Retry once to get the error message if any at the last try
$webclient.DownloadFile($url, $filepath)
}
return $filepath
}
function InstallPython ($python_version, $architecture, $python_home) {
Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
if (Test-Path $python_home) {
Write-Host $python_home "already exists, skipping."
return $false
}
if ($architecture -eq "32") {
$platform_suffix = ""
} else {
$platform_suffix = ".amd64"
}
$msipath = DownloadPython $python_version $platform_suffix
Write-Host "Installing" $msipath "to" $python_home
$install_log = $python_home + ".log"
$install_args = "/qn /log $install_log /i $msipath TARGETDIR=$python_home"
$uninstall_args = "/qn /x $msipath"
RunCommand "msiexec.exe" $install_args
if (-not(Test-Path $python_home)) {
Write-Host "Python seems to be installed else-where, reinstalling."
RunCommand "msiexec.exe" $uninstall_args
RunCommand "msiexec.exe" $install_args
}
if (Test-Path $python_home) {
Write-Host "Python $python_version ($architecture) installation complete"
} else {
Write-Host "Failed to install Python in $python_home"
Get-Content -Path $install_log
Exit 1
}
}
function RunCommand ($command, $command_args) {
Write-Host $command $command_args
Start-Process -FilePath $command -ArgumentList $command_args -Wait -Passthru
}
function InstallPip ($python_home) {
$pip_path = $python_home + "\Scripts\pip.exe"
$python_path = $python_home + "\python.exe"
if (-not(Test-Path $pip_path)) {
Write-Host "Installing pip..."
$webclient = New-Object System.Net.WebClient
$webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH)
Write-Host "Executing:" $python_path $GET_PIP_PATH
Start-Process -FilePath "$python_path" -ArgumentList "$GET_PIP_PATH" -Wait -Passthru
} else {
Write-Host "pip already installed."
}
}
function DownloadMiniconda ($python_version, $platform_suffix) {
$webclient = New-Object System.Net.WebClient
if ($python_version -eq "3.4") {
$filename = "Miniconda3-3.5.5-Windows-" + $platform_suffix + ".exe"
} else {
$filename = "Miniconda-3.5.5-Windows-" + $platform_suffix + ".exe"
}
$url = $MINICONDA_URL + $filename
$basedir = $pwd.Path + "\"
$filepath = $basedir + $filename
if (Test-Path $filename) {
Write-Host "Reusing" $filepath
return $filepath
}
# Download and retry up to 3 times in case of network transient errors.
Write-Host "Downloading" $filename "from" $url
$retry_attempts = 2
for($i=0; $i -lt $retry_attempts; $i++){
try {
$webclient.DownloadFile($url, $filepath)
break
}
Catch [Exception]{
Start-Sleep 1
}
}
if (Test-Path $filepath) {
Write-Host "File saved at" $filepath
} else {
# Retry once to get the error message if any at the last try
$webclient.DownloadFile($url, $filepath)
}
return $filepath
}
function InstallMiniconda ($python_version, $architecture, $python_home) {
Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
if (Test-Path $python_home) {
Write-Host $python_home "already exists, skipping."
return $false
}
if ($architecture -eq "32") {
$platform_suffix = "x86"
} else {
$platform_suffix = "x86_64"
}
$filepath = DownloadMiniconda $python_version $platform_suffix
Write-Host "Installing" $filepath "to" $python_home
$install_log = $python_home + ".log"
$args = "/S /D=$python_home"
Write-Host $filepath $args
Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru
if (Test-Path $python_home) {
Write-Host "Python $python_version ($architecture) installation complete"
} else {
Write-Host "Failed to install Python in $python_home"
Get-Content -Path $install_log
Exit 1
}
}
function InstallMinicondaPip ($python_home) {
$pip_path = $python_home + "\Scripts\pip.exe"
$conda_path = $python_home + "\Scripts\conda.exe"
if (-not(Test-Path $pip_path)) {
Write-Host "Installing pip..."
$args = "install --yes pip"
Write-Host $conda_path $args
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
} else {
Write-Host "pip already installed."
}
}
function main () {
InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON
InstallPip $env:PYTHON
}
main

View File

@@ -12,6 +12,13 @@ PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
REGENDOC_ARGS := \
--normalize "/={8,} (.*) ={8,}/======= \1 ========/" \
--normalize "/_{8,} (.*) _{8,}/_______ \1 ________/" \
--normalize "/in \d+.\d+ seconds/in 0.12 seconds/" \
--normalize "@/tmp/pytest-of-.*/pytest-\d+@PYTEST_TMPDIR@" \
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
@@ -46,7 +53,7 @@ installall: clean install installpdf
@echo "done"
regen:
PYTHONDONTWRITEBYTECODE=1 COLUMNS=76 regendoc --update *.rst */*.rst
PYTHONDONTWRITEBYTECODE=1 COLUMNS=76 regendoc --update *.rst */*.rst ${REGENDOC_ARGS}
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html

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://github.com/pytest-dev/pytest/">pytest @ GitHub</a></li>
<li><a href="http://pytest.org/latest/plugins_index/index.html">3rd party plugins</a></li>
<li><a href="http://plugincompat.herokuapp.com/">3rd party plugins</a></li>
<li><a href="https://github.com/pytest-dev/pytest/issues">Issue Tracker</a></li>
<li><a href="http://pytest.org/latest/pytest.pdf">PDF Documentation</a>
</ul>

View File

@@ -5,6 +5,11 @@ Release announcements
.. toctree::
:maxdepth: 2
release-2.8.5
release-2.8.4
release-2.8.3
release-2.8.2
release-2.7.2
release-2.7.1
release-2.7.0

View File

@@ -0,0 +1,44 @@
pytest-2.8.2: bug fixes
=======================
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 supposed to be drop-in compatible to 2.8.1.
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 to this release, among them:
Bruno Oliveira
Demian Brecht
Florian Bruhin
Ionel Cristian Mărieș
Raphael Pierzina
Ronny Pfannschmidt
holger krekel
Happy testing,
The py.test Development Team
2.8.2 (compared to 2.7.2)
-----------------------------
- fix #1085: proper handling of encoding errors when passing encoded byte
strings to pytest.parametrize in Python 2.
Thanks Themanwithoutaplan for the report and Bruno Oliveira for the PR.
- fix #1087: handling SystemError when passing empty byte strings to
pytest.parametrize in Python 3.
Thanks Paul Kehrer for the report and Bruno Oliveira for the PR.
- fix #995: fixed internal error when filtering tracebacks where one entry
was generated by an exec() statement.
Thanks Daniel Hahler, Ashley C Straw, Philippe Gauthier and Pavel Savchenko
for contributing and Bruno Oliveira for the PR.

View File

@@ -0,0 +1,59 @@
pytest-2.8.3: bug fixes
=======================
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 supposed to be drop-in compatible to 2.8.2.
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 to this release, among them:
Bruno Oliveira
Florian Bruhin
Gabe Hollombe
Gabriel Reis
Hartmut Goebel
John Vandenberg
Lee Kamentsky
Michael Birtwell
Raphael Pierzina
Ronny Pfannschmidt
William Martin Stewart
Happy testing,
The py.test Development Team
2.8.3 (compared to 2.8.2)
-----------------------------
- fix #1169: add __name__ attribute to testcases in TestCaseFunction to
support the @unittest.skip decorator on functions and methods.
Thanks Lee Kamentsky for the PR.
- fix #1035: collecting tests if test module level obj has __getattr__().
Thanks Suor for the report and Bruno Oliveira / Tom Viner for the PR.
- fix #331: don't collect tests if their failure cannot be reported correctly
e.g. they are a callable instance of a class.
- fix #1133: fixed internal error when filtering tracebacks where one entry
belongs to a file which is no longer available.
Thanks Bruno Oliveira for the PR.
- enhancement made to highlight in red the name of the failing tests so
they stand out in the output.
Thanks Gabriel Reis for the PR.
- add more talks to the documentation
- extend documentation on the --ignore cli option
- use pytest-runner for setuptools integration
- minor fixes for interaction with OS X El Capitan system integrity protection (thanks Florian)

View File

@@ -0,0 +1,52 @@
pytest-2.8.4
============
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 supposed to be drop-in compatible to 2.8.2.
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 to this release, among them:
Bruno Oliveira
Florian Bruhin
Jeff Widman
Mehdy Khoshnoody
Nicholas Chammas
Ronny Pfannschmidt
Tim Chan
Happy testing,
The py.test Development Team
2.8.4 (compared to 2.8.3)
-----------------------------
- fix #1190: ``deprecated_call()`` now works when the deprecated
function has been already called by another test in the same
module. Thanks Mikhail Chernykh for the report and Bruno Oliveira for the
PR.
- fix #1198: ``--pastebin`` option now works on Python 3. Thanks
Mehdy Khoshnoody for the PR.
- fix #1219: ``--pastebin`` now works correctly when captured output contains
non-ascii characters. Thanks Bruno Oliveira for the PR.
- fix #1204: another error when collecting with a nasty __getattr__().
Thanks Florian Bruhin for the PR.
- fix the summary printed when no tests did run.
Thanks Florian Bruhin for the PR.
- a number of documentation modernizations wrt good practices.
Thanks Bruno Oliveira for the PR.

View File

@@ -0,0 +1,39 @@
pytest-2.8.5
============
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 supposed to be drop-in compatible to 2.8.4.
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 to this release, among them:
Alex Gaynor
aselus-hub
Bruno Oliveira
Ronny Pfannschmidt
Happy testing,
The py.test Development Team
2.8.5 (compared to 2.8.4)
-------------------------
- fix #1243: fixed issue where class attributes injected during collection could break pytest.
PR by Alexei Kozlenok, thanks Ronny Pfannschmidt and Bruno Oliveira for the review and help.
- fix #1074: precompute junitxml chunks instead of storing the whole tree in objects
Thanks Bruno Oliveira for the report and Ronny Pfannschmidt for the PR
- fix #1238: fix ``pytest.deprecated_call()`` receiving multiple arguments
(Regression introduced in 2.8.4). Thanks Alex Gaynor for the report and
Bruno Oliveira for the PR.

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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -146,7 +146,7 @@ if you run this module::
$ py.test test_assert2.py
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -192,15 +192,18 @@ provides an alternative explanation for ``Foo`` objects::
from test_foocompare import Foo
def pytest_assertrepr_compare(op, left, right):
if isinstance(left, Foo) and isinstance(right, Foo) and op == "==":
return ['Comparing Foo instances:',
' vals: %s != %s' % (left.val, right.val)]
return ['Comparing Foo instances:',
' vals: %s != %s' % (left.val, right.val)]
now, given this test module::
# content of test_foocompare.py
class Foo:
def __init__(self, val):
self.val = val
self.val = val
def __eq__(self, other):
return self.val == other.val
def test_compare():
f1 = Foo(1)
@@ -222,7 +225,7 @@ the conftest file::
E assert Comparing Foo instances:
E vals: 1 != 2
test_foocompare.py:8: AssertionError
test_foocompare.py:11: AssertionError
1 failed in 0.12 seconds
.. _assert-details:

View File

@@ -73,6 +73,16 @@ You can ask for available builtin or project-custom
:ref:`fixtures <fixtures>` by typing::
$ py.test -q --fixtures
cache
Return a cache object that can persist state between testing sessions.
cache.get(key, default)
cache.set(key, value)
Keys must be a ``/`` separated value, where the first part is usually the
name of your plugin or application to avoid clashes with other cache users.
Values can be any object handled by the json stdlib module.
capsys
enables capturing of writes to sys.stdout/sys.stderr and makes
captured output available via ``capsys.readouterr()`` method calls
@@ -81,6 +91,10 @@ You can ask for available builtin or project-custom
enables capturing of writes to file descriptors 1 and 2 and makes
captured output available via ``capfd.readouterr()`` method calls
which return a ``(out, err)`` tuple.
record_xml_property
Fixture that adds extra xml properties to the tag for the calling test.
The fixture is callable with (name, value), with value being automatically
xml-encoded.
monkeypatch
The returned ``monkeypatch`` funcarg provides these
helper methods to modify objects, dictionaries or os.environ::
@@ -108,6 +122,8 @@ You can ask for available builtin or project-custom
See http://docs.python.org/library/warnings.html for information
on warning categories.
tmpdir_factory
Return a TempdirFactory instance for the test session.
tmpdir
return a temporary directory path object
which is unique to each test function invocation,
@@ -115,4 +131,4 @@ You can ask for available builtin or project-custom
directory. The returned object is a `py.path.local`_
path object.
in 0.12 seconds
no tests ran in 0.12 seconds

View File

@@ -1,15 +1,16 @@
cache: working with cross-testrun state
Cache: working with cross-testrun state
=======================================
.. versionadded:: 2.8
.. warning::
The functionality of this core plugin was previosuly distributed
The functionality of this core plugin was previously distributed
as a third party plugin named ``pytest-cache``. The core plugin
is compatible regarding command line options and API usage except that you
can only store/receive data between test runs that is json-serializable.
Usage
---------
@@ -26,6 +27,12 @@ all cross-session cache contents ahead of a test run.
Other plugins may access the `config.cache`_ object to set/get
**json encodable** values between ``py.test`` invocations.
.. note::
This plugin is enabled by default, but can be disabled if needed: see
:ref:`cmdunregister` (the internal name for this plugin is
``cacheprovider``).
Rerunning only failures or failures first
-----------------------------------------------
@@ -44,8 +51,8 @@ If you run this for the first time you will see two failures::
$ py.test -q
.................F.......F........................
================================= FAILURES =================================
_______________________________ test_num[17] _______________________________
======= FAILURES ========
_______ test_num[17] ________
i = 17
@@ -56,7 +63,7 @@ If you run this for the first time you will see two failures::
E Failed: bad luck
test_50.py:6: Failed
_______________________________ test_num[25] _______________________________
_______ test_num[25] ________
i = 25
@@ -67,21 +74,21 @@ If you run this for the first time you will see two failures::
E Failed: bad luck
test_50.py:6: Failed
2 failed, 48 passed in 0.04 seconds
2 failed, 48 passed in 0.12 seconds
If you then run it with ``--lf``::
$ py.test --lf
=========================== test session starts ============================
platform linux2 -- Python 2.7.6, pytest-2.7.3.dev428+ng79d22bf.d20150916, py-1.4.30, pluggy-0.3.0
======= test session starts ========
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
run-last-failure: rerun last 2 failures
rootdir: /tmp/doc-exec-94, inifile:
rootdir: $REGENDOC_TMPDIR, inifile:
collected 50 items
test_50.py FF
================================= FAILURES =================================
_______________________________ test_num[17] _______________________________
======= FAILURES ========
_______ test_num[17] ________
i = 17
@@ -92,7 +99,7 @@ If you then run it with ``--lf``::
E Failed: bad luck
test_50.py:6: Failed
_______________________________ test_num[25] _______________________________
_______ test_num[25] ________
i = 25
@@ -103,7 +110,7 @@ If you then run it with ``--lf``::
E Failed: bad luck
test_50.py:6: Failed
================= 2 failed, 48 deselected in 0.01 seconds ==================
======= 2 failed, 48 deselected in 0.12 seconds ========
You have run only the two failing test from the last run, while 48 tests have
not been run ("deselected").
@@ -113,16 +120,16 @@ previous failures will be executed first (as can be seen from the series
of ``FF`` and dots)::
$ py.test --ff
=========================== test session starts ============================
platform linux2 -- Python 2.7.6, pytest-2.7.3.dev428+ng79d22bf.d20150916, py-1.4.30, pluggy-0.3.0
======= test session starts ========
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
run-last-failure: rerun last 2 failures first
rootdir: /tmp/doc-exec-94, inifile:
rootdir: $REGENDOC_TMPDIR, inifile:
collected 50 items
test_50.py FF................................................
================================= FAILURES =================================
_______________________________ test_num[17] _______________________________
======= FAILURES ========
_______ test_num[17] ________
i = 17
@@ -133,7 +140,7 @@ of ``FF`` and dots)::
E Failed: bad luck
test_50.py:6: Failed
_______________________________ test_num[25] _______________________________
_______ test_num[25] ________
i = 25
@@ -144,7 +151,7 @@ of ``FF`` and dots)::
E Failed: bad luck
test_50.py:6: Failed
=================== 2 failed, 48 passed in 0.03 seconds ====================
======= 2 failed, 48 passed in 0.12 seconds ========
.. _`config.cache`:
@@ -179,8 +186,8 @@ of the sleep::
$ py.test -q
F
================================= FAILURES =================================
______________________________ test_function _______________________________
======= FAILURES ========
_______ test_function ________
mydata = 42
@@ -189,15 +196,15 @@ of the sleep::
E assert 42 == 23
test_caching.py:14: AssertionError
1 failed in 5.41 seconds
1 failed in 0.12 seconds
If you run it a second time the value will be retrieved from
the cache and this will be quick::
$ py.test -q
F
================================= FAILURES =================================
______________________________ test_function _______________________________
======= FAILURES ========
_______ test_function ________
mydata = 42
@@ -206,7 +213,7 @@ the cache and this will be quick::
E assert 42 == 23
test_caching.py:14: AssertionError
1 failed in 0.01 seconds
1 failed in 0.12 seconds
See the `cache-api`_ for more details.
@@ -218,15 +225,15 @@ You can always peek at the content of the cache using the
``--cache-clear`` command line option::
$ py.test --cache-clear
=========================== test session starts ============================
platform linux2 -- Python 2.7.6, pytest-2.7.3.dev428+ng79d22bf.d20150916, py-1.4.30, pluggy-0.3.0
rootdir: /tmp/doc-exec-94, inifile:
======= test session starts ========
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
test_caching.py F
================================= FAILURES =================================
______________________________ test_function _______________________________
======= FAILURES ========
_______ test_function ________
mydata = 42
@@ -235,7 +242,7 @@ You can always peek at the content of the cache using the
E assert 42 == 23
test_caching.py:14: AssertionError
========================= 1 failed in 5.41 seconds =========================
======= 1 failed in 0.12 seconds ========
Clearing Cache content
-------------------------------
@@ -253,7 +260,7 @@ than speed.
.. _`cache-api`:
config.cache API
========================================
------------------
The `config.cache`` object allows other plugins,
including ``conftest.py`` files,

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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items
@@ -78,7 +78,7 @@ of the failing function and hide the other one::
E assert False
test_module.py:9: AssertionError
---------------------------- Captured stdout setup -----------------------------
-------------------------- Captured stdout setup ---------------------------
setting up <function test_func2 at 0xdeadbeef>
======= 1 failed, 1 passed in 0.12 seconds ========

View File

@@ -12,17 +12,23 @@ Full pytest documentation
overview
apiref
cache
plugins
plugins_index/index
example/index
talks
plugins
cache
contributing
funcarg_compare
announce/index
talks
.. toctree::
:hidden:
.. only:: html
changelog
.. toctree::
funcarg_compare
announce/index
.. only:: html
.. toctree::
:hidden:
changelog

View File

@@ -162,7 +162,7 @@ Builtin configuration file options
.. versionadded:: 2.8
Sets list of directories that should be searched for tests when
no specific directories or files are given in the command line when
no specific directories, files or test ids are given in the command line when
executing pytest from the :ref:`rootdir <rootdir>` directory.
Useful when all project tests are in a known location to speed up
test collection and to avoid picking up undesired tests by accident.

View File

@@ -46,7 +46,7 @@ then you can just invoke ``py.test`` without command line options::
$ py.test
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
collected 1 items

View File

@@ -31,7 +31,8 @@ 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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0 -- $PWD/.env/bin/python2.7
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items
@@ -44,7 +45,8 @@ Or the inverse, running all tests except the webtest ones::
$ py.test -v -m "not webtest"
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0 -- $PWD/.env/bin/python2.7
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items
@@ -64,7 +66,8 @@ tests based on their module, class, method, or function name::
$ py.test -v test_server.py::TestClass::test_method
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0 -- $PWD/.env/bin/python2.7
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 5 items
@@ -76,7 +79,8 @@ You can also select on the class::
$ py.test -v test_server.py::TestClass
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0 -- $PWD/.env/bin/python2.7
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items
@@ -88,7 +92,8 @@ Or select multiple nodes::
$ py.test -v test_server.py::TestClass test_server.py::test_send_http
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0 -- $PWD/.env/bin/python2.7
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 8 items
@@ -125,7 +130,8 @@ 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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0 -- $PWD/.env/bin/python2.7
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items
@@ -138,7 +144,8 @@ 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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0 -- $PWD/.env/bin/python2.7
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items
@@ -153,7 +160,8 @@ Or to select "http" and "quick" tests::
$ py.test -k "http or quick" -v
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0 -- $PWD/.env/bin/python2.7
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items
@@ -211,7 +219,7 @@ For an example on how to add and work with markers from a plugin, see
.. note::
It is recommended to explicitely register markers so that:
It is recommended to explicitly register markers so that:
* there is one place in your test suite defining your markers
@@ -342,7 +350,7 @@ the test needs::
$ py.test -E stage2
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -354,7 +362,7 @@ and here is one that specifies exactly the environment needed::
$ py.test -E stage1
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -473,28 +481,28 @@ 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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
test_plat.py s.s.
test_plat.py sss.
======= short test summary info ========
SKIP [2] $REGENDOC_TMPDIR/conftest.py:12: cannot run on platform linux2
SKIP [3] $REGENDOC_TMPDIR/conftest.py:12: cannot run on platform linux
======= 2 passed, 2 skipped in 0.12 seconds ========
======= 1 passed, 3 skipped in 0.12 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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
test_plat.py .
test_plat.py s
======= 3 tests deselected by "-m 'linux2'" ========
======= 1 passed, 3 deselected in 0.12 seconds ========
======= 1 skipped, 3 deselected in 0.12 seconds ========
then the unmarked-tests will not be run. It is thus a way to restrict the run to the specific tests.
@@ -539,7 +547,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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
@@ -561,7 +569,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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items

View File

@@ -27,11 +27,11 @@ now execute the test specification::
nonpython $ py.test test_simple.yml
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
rootdir: $PWD/doc/en, inifile: pytest.ini
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR/nonpython, inifile:
collected 2 items
test_simple.yml .F
test_simple.yml F.
======= FAILURES ========
_______ usecase: hello ________
@@ -40,6 +40,8 @@ now execute the test specification::
no further details known at this point.
======= 1 failed, 1 passed in 0.12 seconds ========
.. regendoc:wipe
You get one dot for the passing ``sub1: sub1`` check and one failure.
Obviously in the above ``conftest.py`` you'll want to implement a more
interesting interpretation of the yaml-values. You can easily write
@@ -57,12 +59,13 @@ consulted when reporting in ``verbose`` mode::
nonpython $ py.test -v
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0 -- $PWD/.env/bin/python2.7
rootdir: $PWD/doc/en, inifile: pytest.ini
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4
cachedir: .cache
rootdir: $REGENDOC_TMPDIR/nonpython, inifile:
collecting ... collected 2 items
test_simple.yml::ok PASSED
test_simple.yml::hello FAILED
test_simple.yml::ok PASSED
======= FAILURES ========
_______ usecase: hello ________
@@ -71,16 +74,18 @@ consulted when reporting in ``verbose`` mode::
no further details known at this point.
======= 1 failed, 1 passed in 0.12 seconds ========
.. regendoc:wipe
While developing your custom test collection and execution it's also
interesting to just look at the collection tree::
nonpython $ py.test --collect-only
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
rootdir: $PWD/doc/en, inifile: pytest.ini
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR/nonpython, inifile:
collected 2 items
<YamlFile 'example/nonpython/test_simple.yml'>
<YamlItem 'ok'>
<YamlFile 'test_simple.yml'>
<YamlItem 'hello'>
<YamlItem 'ok'>
======= in 0.12 seconds ========
======= no tests ran in 0.12 seconds ========

View File

@@ -83,35 +83,38 @@ the argument name::
# content of test_time.py
import pytest
from datetime import datetime, timedelta
testdata = [(datetime(2001, 12, 12), datetime(2001, 12, 11), timedelta(1)),
(datetime(2001, 12, 11), datetime(2001, 12, 12), timedelta(-1)),
]
testdata = [
(datetime(2001, 12, 12), datetime(2001, 12, 11), timedelta(1)),
(datetime(2001, 12, 11), datetime(2001, 12, 12), timedelta(-1)),
]
@pytest.mark.parametrize("a,b,expected", testdata)
def test_timedistance_v0(a, b, expected):
diff = a - b
assert diff == expected
diff = a - b
assert diff == expected
@pytest.mark.parametrize("a,b,expected", testdata, ids=["forward", "backward"])
def test_timedistance_v1(a, b, expected):
diff = a - b
assert diff == expected
diff = a - b
assert diff == expected
def idfn(val):
if isinstance(val, (datetime,)):
# note this wouldn't show any hours/minutes/seconds
return val.strftime('%Y%m%d')
if isinstance(val, (datetime,)):
# note this wouldn't show any hours/minutes/seconds
return val.strftime('%Y%m%d')
@pytest.mark.parametrize("a,b,expected", testdata, ids=idfn)
def test_timedistance_v2(a, b, expected):
diff = a - b
assert diff == expected
diff = a - b
assert diff == expected
In ``test_timedistance_v0``, we let pytest generate the test IDs.
@@ -127,11 +130,18 @@ objects, they are still using the default pytest representation::
$ py.test test_time.py --collect-only
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 6 items
<Module 'test_time.py'>
<Function 'test_timedistance_v0[a0-b0-expected0]'>
<Function 'test_timedistance_v0[a1-b1-expected1]'>
<Function 'test_timedistance_v1[forward]'>
<Function 'test_timedistance_v1[backward]'>
<Function 'test_timedistance_v2[20011212-20011211-expected0]'>
<Function 'test_timedistance_v2[20011211-20011212-expected1]'>
======= in 0.12 seconds ========
ERROR: file not found: test_time.py
======= no tests ran in 0.12 seconds ========
A quick port of "testscenarios"
------------------------------------
@@ -171,7 +181,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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
@@ -184,7 +194,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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
<Module 'test_scenarios.py'>
@@ -195,7 +205,7 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia
<Function 'test_demo1[advanced]'>
<Function 'test_demo2[advanced]'>
======= in 0.12 seconds ========
======= no tests ran in 0.12 seconds ========
Note that we told ``metafunc.parametrize()`` that your scenario values
should be considered class-scoped. With pytest-2.3 this leads to a
@@ -249,14 +259,14 @@ 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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items
<Module 'test_backends.py'>
<Function 'test_db_initialized[d1]'>
<Function 'test_db_initialized[d2]'>
======= in 0.12 seconds ========
======= no tests ran in 0.12 seconds ========
And then when we run the test::
@@ -265,7 +275,7 @@ And then when we run the test::
======= FAILURES ========
_______ test_db_initialized[d2] ________
db = <conftest.DB2 instance at 0xdeadbeef>
db = <conftest.DB2 object at 0xdeadbeef>
def test_db_initialized(db):
# a dummy test
@@ -288,7 +298,7 @@ parameter on particular arguments. It can be done by passing list or tuple of
arguments' names to ``indirect``. In the example below there is a function ``test_indirect`` which uses
two fixtures: ``x`` and ``y``. Here we give to indirect the list, which contains the name of the
fixture ``x``. The indirect parameter will be applied to this argument only, and the value ``a``
will be passed to respective fixture function.
will be passed to respective fixture function::
# content of test_indirect_list.py
@@ -306,29 +316,29 @@ will be passed to respective fixture function.
assert x == 'aaa'
assert y == 'b'
The result of this test will be successful:
The result of this test will be successful::
$ py.test test_indirect_list.py --collect-only
============================= test session starts ==============================
platform linux2 -- Python 2.7.3, pytest-2.8.0.dev4, py-1.4.30, pluggy-0.3.0
rootdir: /home/elizabeth/work/pytest, inifile: tox.ini
======= test session starts ========
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
<Module 'testing/test_argnames.py'>
<Function 'test_simple[a-b]'>
=============================== in 0.02 seconds ===============================
<Module 'test_indirect_list.py'>
<Function 'test_indirect[a-b]'>
======= no tests ran in 0.12 seconds ========
.. regendoc:wipe
Parametrizing test methods through per-class configuration
--------------------------------------------------------------
.. _`unittest parameterizer`: http://code.google.com/p/unittest-ext/source/browse/trunk/params.py
.. _`unittest parametrizer`: http://code.google.com/p/unittest-ext/source/browse/trunk/params.py
Here is an example ``pytest_generate_function`` function implementing a
parametrization scheme similar to Michael Foord's `unittest
parameterizer`_ but in a lot less code::
parametrizer`_ but in a lot less code::
# content of ./test_parametrize.py
import pytest
@@ -359,9 +369,9 @@ argument sets to use for each test function. Let's run it::
$ py.test -q
F..
======= FAILURES ========
_______ TestClass.test_equals[1-2] ________
_______ TestClass.test_equals[2-1] ________
self = <test_parametrize.TestClass instance at 0xdeadbeef>, a = 1, b = 2
self = <test_parametrize.TestClass object at 0xdeadbeef>, a = 1, b = 2
def test_equals(self, a, b):
> assert a == b
@@ -389,8 +399,8 @@ Running it results in some skips if we don't have all the python interpreters in
. $ py.test -rs -q multipython.py
ssssssssssss...ssssssssssss
======= short test summary info ========
SKIP [12] $PWD/doc/en/example/multipython.py:22: 'python3.3' not found
SKIP [12] $PWD/doc/en/example/multipython.py:22: 'python2.6' not found
SKIP [12] $REGENDOC_TMPDIR/CWD/multipython.py:22: 'python2.6' not found
SKIP [12] $REGENDOC_TMPDIR/CWD/multipython.py:22: 'python3.3' not found
3 passed, 24 skipped in 0.12 seconds
Indirect parametrization of optional implementations/imports
@@ -438,7 +448,7 @@ If you run this with reporting for skips enabled::
$ py.test -rs test_module.py
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items

View File

@@ -1,6 +1,45 @@
Changing standard (Python) test discovery
===============================================
Ignore paths during test collection
-----------------------------------
You can easily ignore certain test directories and modules during collection
by passing the ``--ignore=path`` option on the cli. ``pytest`` allows multiple
``--ignore`` options. Example::
tests/
├── example
│   ├── test_example_01.py
│   ├── test_example_02.py
│   └── test_example_03.py
├── foobar
│   ├── test_foobar_01.py
│   ├── test_foobar_02.py
│   └── test_foobar_03.py
└── hello
└── world
├── test_world_01.py
├── test_world_02.py
└── test_world_03.py
Now if you invoke ``pytest`` with ``--ignore=tests/foobar/test_foobar_03.py --ignore=tests/hello/``,
you will see that ``pytest`` only collects test-modules, which do not match the patterns specified::
========= test session starts ==========
platform darwin -- Python 2.7.10, pytest-2.8.2, py-1.4.30, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 5 items
tests/example/test_example_01.py .
tests/example/test_example_02.py .
tests/example/test_example_03.py .
tests/foobar/test_foobar_01.py .
tests/foobar/test_foobar_02.py .
======= 5 passed in 0.02 seconds =======
Changing directory recursion
-----------------------------------------------------
@@ -43,7 +82,7 @@ then the test collection looks like this::
$ py.test --collect-only
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: setup.cfg
collected 2 items
<Module 'check_myapp.py'>
@@ -52,7 +91,7 @@ then the test collection looks like this::
<Function 'simple_check'>
<Function 'complex_check'>
======= in 0.12 seconds ========
======= no tests ran in 0.12 seconds ========
.. note::
@@ -89,17 +128,17 @@ 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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
rootdir: $PWD/doc/en, inifile: pytest.ini
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
collected 3 items
<Module 'example/pythoncollection.py'>
<Module 'CWD/pythoncollection.py'>
<Function 'test_function'>
<Class 'TestClass'>
<Instance '()'>
<Function 'test_method'>
<Function 'test_anothermethod'>
======= in 0.12 seconds ========
======= no tests ran in 0.12 seconds ========
customizing test collection to find all .py files
---------------------------------------------------------
@@ -136,20 +175,18 @@ And then if you have a module file like this::
and a setup.py dummy file like this::
# content of setup.py
0/0 # will raise exeption if imported
0/0 # will raise exception if imported
then a pytest run on python2 will find the one test when run with a python2
interpreters and will leave out the setup.py file::
$ py.test --collect-only
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
collected 1 items
<Module 'pkg/module_py2.py'>
<Function 'test_only_on_python2'>
collected 0 items
======= in 0.12 seconds ========
======= no tests ran in 0.12 seconds ========
If you run with a Python3 interpreter the moduled added through the conftest.py file will not be considered for test collection.

View File

@@ -13,8 +13,8 @@ get on the terminal - we are working on that):
assertion $ py.test failure_demo.py
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
rootdir: $PWD/doc/en, inifile: pytest.ini
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR/assertion, inifile:
collected 42 items
failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
@@ -41,8 +41,8 @@ get on the terminal - we are working on that):
> assert f() == g()
E assert 42 == 43
E + where 42 = <function f at 0xdeadbeef>()
E + and 43 = <function g at 0xdeadbeef>()
E + where 42 = <function TestFailing.test_simple.<locals>.f at 0xdeadbeef>()
E + and 43 = <function TestFailing.test_simple.<locals>.g at 0xdeadbeef>()
failure_demo.py:28: AssertionError
_______ TestFailing.test_simple_multiline ________
@@ -55,7 +55,7 @@ get on the terminal - we are working on that):
> 6*9)
failure_demo.py:33:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
a = 42, b = 54
@@ -74,7 +74,7 @@ get on the terminal - we are working on that):
return 42
> assert not f()
E assert not 42
E + where 42 = <function f at 0xdeadbeef>()
E + where 42 = <function TestFailing.test_not.<locals>.f at 0xdeadbeef>()
failure_demo.py:38: AssertionError
_______ TestSpecialisedExplanations.test_eq_text ________
@@ -277,7 +277,7 @@ get on the terminal - we are working on that):
E ? +++
failure_demo.py:90: AssertionError
_______ TestSpecialisedExplanations.test_not_in_text_single_long_term ________
______ TestSpecialisedExplanations.test_not_in_text_single_long_term _______
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -298,7 +298,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 0xdeadbeef>.b
E + where 1 = <failure_demo.test_attribute.<locals>.Foo object at 0xdeadbeef>.b
failure_demo.py:101: AssertionError
_______ test_attribute_instance ________
@@ -308,8 +308,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 0xdeadbeef>.b
E + where <failure_demo.Foo object at 0xdeadbeef> = <class 'failure_demo.Foo'>()
E + where 1 = <failure_demo.test_attribute_instance.<locals>.Foo object at 0xdeadbeef>.b
E + where <failure_demo.test_attribute_instance.<locals>.Foo object at 0xdeadbeef> = <class 'failure_demo.test_attribute_instance.<locals>.Foo'>()
failure_demo.py:107: AssertionError
_______ test_attribute_failure ________
@@ -323,9 +323,9 @@ get on the terminal - we are working on that):
> assert i.b == 2
failure_demo.py:116:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <failure_demo.Foo object at 0xdeadbeef>
self = <failure_demo.test_attribute_failure.<locals>.Foo object at 0xdeadbeef>
def _get_b(self):
> raise Exception('Failed to get attrib')
@@ -341,30 +341,30 @@ 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 0xdeadbeef>.b
E + where <failure_demo.Foo object at 0xdeadbeef> = <class 'failure_demo.Foo'>()
E + and 2 = <failure_demo.Bar object at 0xdeadbeef>.b
E + where <failure_demo.Bar object at 0xdeadbeef> = <class 'failure_demo.Bar'>()
E + where 1 = <failure_demo.test_attribute_multiple.<locals>.Foo object at 0xdeadbeef>.b
E + where <failure_demo.test_attribute_multiple.<locals>.Foo object at 0xdeadbeef> = <class 'failure_demo.test_attribute_multiple.<locals>.Foo'>()
E + and 2 = <failure_demo.test_attribute_multiple.<locals>.Bar object at 0xdeadbeef>.b
E + where <failure_demo.test_attribute_multiple.<locals>.Bar object at 0xdeadbeef> = <class 'failure_demo.test_attribute_multiple.<locals>.Bar'>()
failure_demo.py:124: AssertionError
_______ TestRaises.test_raises ________
self = <failure_demo.TestRaises instance at 0xdeadbeef>
self = <failure_demo.TestRaises object at 0xdeadbeef>
def test_raises(self):
s = 'qwe'
> raises(TypeError, "int(s)")
failure_demo.py:133:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> int(s)
E ValueError: invalid literal for int() with base 10: 'qwe'
<0-codegen $PWD/_pytest/python.py:1091>:1: ValueError
<0-codegen $PYTHON_PREFIX/lib/python3.4/site-packages/_pytest/python.py:1300>:1: ValueError
_______ TestRaises.test_raises_doesnt ________
self = <failure_demo.TestRaises instance at 0xdeadbeef>
self = <failure_demo.TestRaises object at 0xdeadbeef>
def test_raises_doesnt(self):
> raises(IOError, "int('3')")
@@ -373,7 +373,7 @@ get on the terminal - we are working on that):
failure_demo.py:136: Failed
_______ TestRaises.test_raise ________
self = <failure_demo.TestRaises instance at 0xdeadbeef>
self = <failure_demo.TestRaises object at 0xdeadbeef>
def test_raise(self):
> raise ValueError("demo error")
@@ -382,16 +382,16 @@ get on the terminal - we are working on that):
failure_demo.py:139: ValueError
_______ TestRaises.test_tupleerror ________
self = <failure_demo.TestRaises instance at 0xdeadbeef>
self = <failure_demo.TestRaises object at 0xdeadbeef>
def test_tupleerror(self):
> a,b = [1]
E ValueError: need more than 1 value to unpack
failure_demo.py:142: ValueError
_______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ________
______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______
self = <failure_demo.TestRaises instance at 0xdeadbeef>
self = <failure_demo.TestRaises object at 0xdeadbeef>
def test_reinterpret_fails_with_print_for_the_fun_of_it(self):
l = [1,2,3]
@@ -400,15 +400,15 @@ get on the terminal - we are working on that):
E TypeError: 'int' object is not iterable
failure_demo.py:147: TypeError
----------------------------- Captured stdout call -----------------------------
--------------------------- Captured stdout call ---------------------------
l is [1, 2, 3]
_______ TestRaises.test_some_error ________
self = <failure_demo.TestRaises instance at 0xdeadbeef>
self = <failure_demo.TestRaises object at 0xdeadbeef>
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 ________
@@ -423,16 +423,16 @@ get on the terminal - we are working on that):
> module.foo()
failure_demo.py:165:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def foo():
> assert 1 == 0
E assert 1 == 0
<2-codegen 'abc-123' $PWD/doc/en/example/assertion/failure_demo.py:162>:2: AssertionError
<2-codegen 'abc-123' $REGENDOC_TMPDIR/assertion/failure_demo.py:162>:2: AssertionError
_______ TestMoreErrors.test_complex_error ________
self = <failure_demo.TestMoreErrors instance at 0xdeadbeef>
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
def test_complex_error(self):
def f():
@@ -442,10 +442,10 @@ get on the terminal - we are working on that):
> somefunc(f(), g())
failure_demo.py:175:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
failure_demo.py:8: in somefunc
otherfunc(x,y)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
a = 44, b = 43
@@ -456,7 +456,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 0xdeadbeef>
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
def test_z1_unpack_error(self):
l = []
@@ -466,7 +466,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 0xdeadbeef>
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
def test_z2_type_error(self):
l = 3
@@ -476,7 +476,7 @@ get on the terminal - we are working on that):
failure_demo.py:183: TypeError
_______ TestMoreErrors.test_startswith ________
self = <failure_demo.TestMoreErrors instance at 0xdeadbeef>
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
def test_startswith(self):
s = "123"
@@ -488,7 +488,7 @@ get on the terminal - we are working on that):
failure_demo.py:188: AssertionError
_______ TestMoreErrors.test_startswith_nested ________
self = <failure_demo.TestMoreErrors instance at 0xdeadbeef>
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
def test_startswith_nested(self):
def f():
@@ -498,13 +498,13 @@ get on the terminal - we are working on that):
> assert f().startswith(g())
E assert <built-in method startswith of str object at 0xdeadbeef>('456')
E + where <built-in method startswith of str object at 0xdeadbeef> = '123'.startswith
E + where '123' = <function f at 0xdeadbeef>()
E + and '456' = <function g at 0xdeadbeef>()
E + where '123' = <function TestMoreErrors.test_startswith_nested.<locals>.f at 0xdeadbeef>()
E + and '456' = <function TestMoreErrors.test_startswith_nested.<locals>.g at 0xdeadbeef>()
failure_demo.py:195: AssertionError
_______ TestMoreErrors.test_global_func ________
self = <failure_demo.TestMoreErrors instance at 0xdeadbeef>
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
def test_global_func(self):
> assert isinstance(globf(42), float)
@@ -514,18 +514,18 @@ get on the terminal - we are working on that):
failure_demo.py:198: AssertionError
_______ TestMoreErrors.test_instance ________
self = <failure_demo.TestMoreErrors instance at 0xdeadbeef>
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
def test_instance(self):
self.x = 6*7
> assert self.x != 42
E assert 42 != 42
E + where 42 = <failure_demo.TestMoreErrors instance at 0xdeadbeef>.x
E + where 42 = <failure_demo.TestMoreErrors object at 0xdeadbeef>.x
failure_demo.py:202: AssertionError
_______ TestMoreErrors.test_compare ________
self = <failure_demo.TestMoreErrors instance at 0xdeadbeef>
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
def test_compare(self):
> assert globf(10) < 5
@@ -535,7 +535,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 0xdeadbeef>
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
def test_try_finally(self):
x = 1
@@ -546,7 +546,7 @@ get on the terminal - we are working on that):
failure_demo.py:210: AssertionError
_______ TestCustomAssertMsg.test_single_line ________
self = <failure_demo.TestCustomAssertMsg instance at 0xdeadbeef>
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
def test_single_line(self):
class A:
@@ -555,12 +555,12 @@ get on the terminal - we are working on that):
> 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.A at 0xdeadbeef>.a
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 instance at 0xdeadbeef>
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
def test_multiline(self):
class A:
@@ -572,12 +572,12 @@ get on the terminal - we are working on that):
E or does not appear to be b
E one of those
E assert 1 == 2
E + where 1 = <class failure_demo.A at 0xdeadbeef>.a
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 instance at 0xdeadbeef>
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
def test_custom_repr(self):
class JSON:

View File

@@ -53,7 +53,7 @@ Let's run this without supplying our new option::
E assert 0
test_sample.py:6: AssertionError
----------------------------- Captured stdout call -----------------------------
--------------------------- Captured stdout call ---------------------------
first
1 failed in 0.12 seconds
@@ -75,7 +75,7 @@ And now with supplying a command line option::
E assert 0
test_sample.py:6: AssertionError
----------------------------- Captured stdout call -----------------------------
--------------------------- Captured stdout call ---------------------------
second
1 failed in 0.12 seconds
@@ -108,11 +108,11 @@ directory with the above conftest.py::
$ py.test
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 0 items
======= in 0.12 seconds ========
======= no tests ran in 0.12 seconds ========
.. _`excontrolskip`:
@@ -131,20 +131,23 @@ line option to control skipping of ``slow`` marked tests::
parser.addoption("--runslow", action="store_true",
help="run slow tests")
def pytest_runtest_setup(item):
if 'slow' in item.keywords and not item.config.getoption("--runslow"):
pytest.skip("need --runslow option to run")
We can now write a test module like this::
# content of test_module.py
import pytest
slow = pytest.mark.slow
slow = pytest.mark.skipif(
not pytest.config.getoption("--runslow"),
reason="need --runslow option to run"
)
def test_func_fast():
pass
@slow
def test_func_slow():
pass
@@ -153,13 +156,13 @@ 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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items
test_module.py .s
======= short test summary info ========
SKIP [1] $REGENDOC_TMPDIR/conftest.py:9: need --runslow option to run
SKIP [1] test_module.py:14: need --runslow option to run
======= 1 passed, 1 skipped in 0.12 seconds ========
@@ -167,7 +170,7 @@ Or run it including the ``slow`` marked test::
$ py.test --runslow
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items
@@ -259,12 +262,12 @@ which will add the string to the test header accordingly::
$ py.test
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
project deps: mylib-1.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 0 items
======= in 0.12 seconds ========
======= no tests ran in 0.12 seconds ========
.. regendoc:wipe
@@ -283,23 +286,24 @@ which will add info only when run with "--v"::
$ py.test -v
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0 -- $PWD/.env/bin/python2.7
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4
cachedir: .cache
info1: did you know that ...
did you?
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 0 items
======= in 0.12 seconds ========
======= no tests ran in 0.12 seconds ========
and nothing when run plainly::
$ py.test
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 0 items
======= in 0.12 seconds ========
======= no tests ran in 0.12 seconds ========
profiling test duration
--------------------------
@@ -309,7 +313,7 @@ profiling test duration
.. versionadded: 2.2
If you have a slow running large test suite you might want to find
out which tests are the slowest. Let's make an artifical test suite::
out which tests are the slowest. Let's make an artificial test suite::
# content of test_some_are_slow.py
@@ -328,7 +332,7 @@ Now we can profile which test functions execute the slowest::
$ py.test --durations=3
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 3 items
@@ -337,7 +341,7 @@ 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
0.00s setup test_some_are_slow.py::test_funcslow2
======= 3 passed in 0.12 seconds ========
incremental testing - test steps
@@ -390,7 +394,7 @@ If we run this::
$ py.test -rx
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
@@ -399,7 +403,7 @@ If we run this::
======= FAILURES ========
_______ TestUserHandling.test_modification ________
self = <test_step.TestUserHandling instance at 0xdeadbeef>
self = <test_step.TestUserHandling object at 0xdeadbeef>
def test_modification(self):
> assert 0
@@ -423,7 +427,7 @@ by placing fixture functions in a ``conftest.py`` file in that directory
You can use all types of fixtures including :ref:`autouse fixtures
<autouse fixtures>` which are the equivalent of xUnit's setup/teardown
concept. It's however recommended to have explicit fixture references in your
tests or test classes rather than relying on implicitely executing
tests or test classes rather than relying on implicitly executing
setup/teardown functions, especially if they are far away from the actual tests.
Here is a an example for making a ``db`` fixture available in a directory::
@@ -461,7 +465,7 @@ We can run this::
$ py.test
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 7 items
@@ -475,14 +479,14 @@ We can run this::
file $REGENDOC_TMPDIR/b/test_error.py, line 1
def test_root(db): # no db here, will error out
fixture 'db' not found
available fixtures: pytestconfig, recwarn, monkeypatch, capfd, capsys, tmpdir
available fixtures: capsys, capfd, pytestconfig, tmpdir_factory, monkeypatch, record_xml_property, cache, tmpdir, recwarn
use 'py.test --fixtures [testpath]' for help on them.
$REGENDOC_TMPDIR/b/test_error.py:1
======= FAILURES ========
_______ TestUserHandling.test_modification ________
self = <test_step.TestUserHandling instance at 0xdeadbeef>
self = <test_step.TestUserHandling object at 0xdeadbeef>
def test_modification(self):
> assert 0
@@ -491,21 +495,21 @@ We can run this::
test_step.py:9: AssertionError
_______ test_a1 ________
db = <conftest.DB instance at 0xdeadbeef>
db = <conftest.DB object at 0xdeadbeef>
def test_a1(db):
> assert 0, db # to show value
E AssertionError: <conftest.DB instance at 0xdeadbeef>
E AssertionError: <conftest.DB object at 0xdeadbeef>
E assert 0
a/test_db.py:2: AssertionError
_______ test_a2 ________
db = <conftest.DB instance at 0xdeadbeef>
db = <conftest.DB object at 0xdeadbeef>
def test_a2(db):
> assert 0, db # to show value
E AssertionError: <conftest.DB instance at 0xdeadbeef>
E AssertionError: <conftest.DB object at 0xdeadbeef>
E assert 0
a/test_db2.py:2: AssertionError
@@ -565,7 +569,7 @@ and run them::
$ py.test test_module.py
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items
@@ -574,7 +578,7 @@ and run them::
======= FAILURES ========
_______ test_fail1 ________
tmpdir = local('/tmp/pytest-NaN/test_fail10')
tmpdir = local('PYTEST_TMPDIR/test_fail10')
def test_fail1(tmpdir):
> assert 0
@@ -593,7 +597,8 @@ and run them::
you will have a "failures" file which contains the failing test ids::
$ cat failures
cat: failures: No such file or directory
test_module.py::test_fail1 (PYTEST_TMPDIR/test_fail10)
test_module.py::test_fail2
Making test result information available in fixtures
-----------------------------------------------------------
@@ -655,12 +660,12 @@ and run it::
$ py.test -s test_module.py
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 3 items
test_module.py E('setting up a test failed!', 'test_module.py::test_setup_fails')
F('executing test failed', 'test_module.py::test_call_fails')
test_module.py Esetting up a test failed! test_module.py::test_setup_fails
Fexecuting test failed test_module.py::test_call_fails
F
======= ERRORS ========
@@ -689,7 +694,7 @@ and run it::
E assert 0
test_module.py:15: AssertionError
======= 2 failed, 1 warnings, 1 error in 0.12 seconds ========
======= 2 failed, 1 error in 0.12 seconds ========
You'll see that the fixture finalizers could use the precise reporting
information.

View File

@@ -60,7 +60,7 @@ and customizable testing framework for Python. Note, however, that
thus likely not something for Python beginners.
A second "magic" issue was the assert statement debugging feature.
Nowadays, ``pytest`` explicitely rewrites assert statements in test modules
Nowadays, ``pytest`` explicitly rewrites assert statements in test modules
in order to provide more useful :ref:`assert feedback <assertfeedback>`.
This completely avoids previous issues of confusing assertion-reporting.
It also means, that you can use Python's ``-O`` optimization without losing
@@ -76,7 +76,7 @@ be the same, confusing the reinterpreter and obfuscating the initial
error (this is also explained at the command line if it happens).
You can also turn off all assertion interaction using the
``--assertmode=off`` option.
``--assert=plain`` option.
.. _`py namespaces`: index.html
.. _`py/__init__.py`: http://bitbucket.org/hpk42/py-trunk/src/trunk/py/__init__.py
@@ -141,10 +141,10 @@ However, with pytest-2.3 you can use the :ref:`@pytest.fixture` decorator
and specify ``params`` so that all tests depending on the factory-created
resource will run multiple times with different parameters.
You can also use the `pytest_generate_tests`_ hook to
implement the `parametrization scheme of your choice`_.
You can also use the ``pytest_generate_tests`` hook to
implement the `parametrization scheme of your choice`_. See also
:ref:`paramexamples` for more examples.
.. _`pytest_generate_tests`: test/funcargs.html#parametrizing-tests
.. _`parametrization scheme of your choice`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/
pytest interaction with other packages

View File

@@ -75,7 +75,7 @@ marked ``smtp`` fixture function. Running the test looks like this::
$ py.test test_smtpsimple.py
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -84,7 +84,7 @@ marked ``smtp`` fixture function. Running the test looks like this::
======= FAILURES ========
_______ test_ehlo ________
smtp = <smtplib.SMTP instance at 0xdeadbeef>
smtp = <smtplib.SMTP object at 0xdeadbeef>
def test_ehlo(smtp):
response, msg = smtp.ehlo()
@@ -180,8 +180,8 @@ function (in or below the directory where ``conftest.py`` is located)::
def test_ehlo(smtp):
response, msg = smtp.ehlo()
assert response == 250
assert "smtp.gmail.com" in str(msg, 'ascii')
assert 0 # for demo purposes
assert b"smtp.gmail.com" in msg
assert 0 # for demo purposes
def test_noop(smtp):
response, msg = smtp.noop()
@@ -193,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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items
@@ -202,23 +202,23 @@ inspect what is going on and can now run the tests::
======= FAILURES ========
_______ test_ehlo ________
smtp = <smtplib.SMTP instance at 0xdeadbeef>
smtp = <smtplib.SMTP object at 0xdeadbeef>
def test_ehlo(smtp):
response = smtp.ehlo()
assert response[0] == 250
assert "merlinux" in response[1]
response, msg = smtp.ehlo()
assert response == 250
assert b"smtp.gmail.com" in msg
> assert 0 # for demo purposes
E assert 0
test_module.py:6: AssertionError
_______ test_noop ________
smtp = <smtplib.SMTP instance at 0xdeadbeef>
smtp = <smtplib.SMTP object at 0xdeadbeef>
def test_noop(smtp):
response = smtp.noop()
assert response[0] == 250
response, msg = smtp.noop()
assert response == 250
> assert 0 # for demo purposes
E assert 0
@@ -243,7 +243,7 @@ instance, you can simply declare it:
.. _`finalization`:
fixture finalization / executing teardown code
Fixture finalization / executing teardown code
-------------------------------------------------------------
pytest supports execution of fixture specific finalization code
@@ -313,7 +313,7 @@ We use the ``request.module`` attribute to optionally obtain an
again, nothing much has changed::
$ py.test -s -q --tb=no
FFteardown smtp
FFfinalizing <smtplib.SMTP object at 0xdeadbeef> (smtp.gmail.com)
2 failed in 0.12 seconds
@@ -335,7 +335,7 @@ Running it::
_______ test_showhelo ________
test_anothersmtp.py:5: in test_showhelo
assert 0, smtp.helo()
E AssertionError: (250, 'hq.merlinux.eu')
E AssertionError: (250, b'mail.python.org')
E assert 0
voila! The ``smtp`` fixture function picked up our mail server name
@@ -381,49 +381,49 @@ So let's just do another run::
$ py.test -q test_module.py
FFFF
======= FAILURES ========
_______ test_ehlo[merlinux.eu] ________
_______ test_ehlo[smtp.gmail.com] ________
smtp = <smtplib.SMTP instance at 0xdeadbeef>
smtp = <smtplib.SMTP object at 0xdeadbeef>
def test_ehlo(smtp):
response = smtp.ehlo()
assert response[0] == 250
assert "merlinux" in response[1]
response, msg = smtp.ehlo()
assert response == 250
assert b"smtp.gmail.com" in msg
> assert 0 # for demo purposes
E assert 0
test_module.py:6: AssertionError
_______ test_noop[merlinux.eu] ________
_______ test_noop[smtp.gmail.com] ________
smtp = <smtplib.SMTP instance at 0xdeadbeef>
smtp = <smtplib.SMTP object at 0xdeadbeef>
def test_noop(smtp):
response = smtp.noop()
assert response[0] == 250
response, msg = smtp.noop()
assert response == 250
> assert 0 # for demo purposes
E assert 0
test_module.py:11: AssertionError
_______ test_ehlo[mail.python.org] ________
smtp = <smtplib.SMTP instance at 0xdeadbeef>
smtp = <smtplib.SMTP object at 0xdeadbeef>
def test_ehlo(smtp):
response = smtp.ehlo()
assert response[0] == 250
> assert "merlinux" in response[1]
E assert 'merlinux' in 'mail.python.org\nSIZE 51200000\nETRN\nSTARTTLS\nENHANCEDSTATUSCODES\n8BITMIME\nDSN\nSMTPUTF8'
response, msg = smtp.ehlo()
assert response == 250
> assert b"smtp.gmail.com" in msg
E assert b'smtp.gmail.com' in b'mail.python.org\nSIZE 51200000\nETRN\nSTARTTLS\nENHANCEDSTATUSCODES\n8BITMIME\nDSN\nSMTPUTF8'
test_module.py:5: AssertionError
---------------------------- Captured stdout setup -----------------------------
finalizing <smtplib.SMTP instance at 0xdeadbeef>
-------------------------- Captured stdout setup ---------------------------
finalizing <smtplib.SMTP object at 0xdeadbeef>
_______ test_noop[mail.python.org] ________
smtp = <smtplib.SMTP instance at 0xdeadbeef>
smtp = <smtplib.SMTP object at 0xdeadbeef>
def test_noop(smtp):
response = smtp.noop()
assert response[0] == 250
response, msg = smtp.noop()
assert response == 250
> assert 0 # for demo purposes
E assert 0
@@ -480,19 +480,24 @@ Running the above tests results in the following test IDs being used::
$ py.test --collect-only
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 6 items
collected 10 items
<Module 'test_anothersmtp.py'>
<Function 'test_showhelo[merlinux.eu]'>
<Function 'test_showhelo[smtp.gmail.com]'>
<Function 'test_showhelo[mail.python.org]'>
<Module 'test_ids.py'>
<Function 'test_a[spam]'>
<Function 'test_a[ham]'>
<Function 'test_b[eggs]'>
<Function 'test_b[1]'>
<Module 'test_module.py'>
<Function 'test_ehlo[merlinux.eu]'>
<Function 'test_noop[merlinux.eu]'>
<Function 'test_ehlo[smtp.gmail.com]'>
<Function 'test_noop[smtp.gmail.com]'>
<Function 'test_ehlo[mail.python.org]'>
<Function 'test_noop[mail.python.org]'>
======= in 0.12 seconds ========
======= no tests ran in 0.12 seconds ========
.. _`interdependent fixtures`:
@@ -526,11 +531,12 @@ 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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0 -- $PWD/.env/bin/python2.7
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 2 items
test_appsetup.py::test_smtp_exists[merlinux.eu] PASSED
test_appsetup.py::test_smtp_exists[smtp.gmail.com] PASSED
test_appsetup.py::test_smtp_exists[mail.python.org] PASSED
======= 2 passed in 0.12 seconds ========
@@ -591,27 +597,28 @@ 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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0 -- $PWD/.env/bin/python2.7
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.4
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 8 items
test_module.py::test_0[1] (' test0', 1)
test_module.py::test_0[1] test0 1
PASSED
test_module.py::test_0[2] (' test0', 2)
test_module.py::test_0[2] test0 2
PASSED
test_module.py::test_1[mod1] ('create', 'mod1')
(' test1', 'mod1')
test_module.py::test_1[mod1] create mod1
test1 mod1
PASSED
test_module.py::test_2[1-mod1] (' test2', 1, 'mod1')
test_module.py::test_2[1-mod1] test2 1 mod1
PASSED
test_module.py::test_2[2-mod1] (' test2', 2, 'mod1')
test_module.py::test_2[2-mod1] test2 2 mod1
PASSED
test_module.py::test_1[mod2] ('create', 'mod2')
(' test1', 'mod2')
test_module.py::test_1[mod2] create mod2
test1 mod2
PASSED
test_module.py::test_2[1-mod2] (' test2', 1, 'mod2')
test_module.py::test_2[1-mod2] test2 1 mod2
PASSED
test_module.py::test_2[2-mod2] (' test2', 2, 'mod2')
test_module.py::test_2[2-mod2] test2 2 mod2
PASSED
======= 8 passed in 0.12 seconds ========
@@ -623,7 +630,7 @@ before the ``mod2`` resource was setup.
.. _`usefixtures`:
using fixtures from classes, modules or projects
Using fixtures from classes, modules or projects
----------------------------------------------------------------------
.. regendoc:wipe
@@ -685,6 +692,9 @@ a generic feature of the mark mechanism:
pytestmark = pytest.mark.usefixtures("cleandir")
Note that the assigned variable *must* be called ``pytestmark``, assigning e.g.
``foomark`` will not activate the fixtures.
Lastly you can put fixtures required by all tests in your project
into an ini-file:
@@ -698,7 +708,7 @@ into an ini-file:
.. _`autouse`:
.. _`autouse fixtures`:
autouse fixtures (xUnit setup on steroids)
Autouse fixtures (xUnit setup on steroids)
----------------------------------------------------------------------
.. regendoc:wipe

View File

@@ -209,7 +209,7 @@ fixtures:
and let pytest figure things out for you.
* if you used parametrization and funcarg factories which made use of
``request.cached_setup()`` it is recommeneded to invest a few minutes
``request.cached_setup()`` it is recommended to invest a few minutes
and simplify your fixture function code to use the :ref:`@pytest.fixture`
decorator instead. This will also allow to take advantage of
the automatic per-resource grouping of tests.

View File

@@ -27,7 +27,7 @@ Installation options::
To check your installation has installed the correct version::
$ py.test --version
This is pytest version 2.8.0.dev4, imported from $PWD/pytest.pyc
This is pytest version 2.8.5, imported from $PYTHON_PREFIX/lib/python3.4/site-packages/pytest.py
If you get an error checkout :ref:`installation issues`.
@@ -49,7 +49,7 @@ That's it. You can execute the test function now::
$ py.test
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -66,7 +66,7 @@ That's it. You can execute the test function now::
test_sample.py:5: AssertionError
======= 1 failed in 0.12 seconds ========
``pytest`` found the ``test_answer`` function by following :ref:`standard test discovery rules <test discovery>`, basically detecting the ``test_`` prefixes. We got a failure report because our little ``func(3)`` call did not return ``5``.
We got a failure report because our little ``func(3)`` call did not return ``5``.
.. note::
@@ -79,6 +79,12 @@ That's it. You can execute the test function now::
.. _`assert statement`: http://docs.python.org/reference/simple_stmts.html#the-assert-statement
Running multiple tests
----------------------------------------------------------
``pytest`` will run all files in the current directory and its subdirectories of the form test_*.py or \*_test.py. More generally, it follows :ref:`standard test discovery rules <test discovery>`.
Asserting that a certain exception is raised
--------------------------------------------------------------
@@ -100,8 +106,6 @@ Running it with, this time in "quiet" reporting mode::
.
1 passed in 0.12 seconds
.. todo:: For further ways to assert exceptions see the `raises`
Grouping multiple tests in a class
--------------------------------------------------------------
@@ -128,7 +132,7 @@ run the module by passing its filename::
======= FAILURES ========
_______ TestClass.test_two ________
self = <test_class.TestClass instance at 0xdeadbeef>
self = <test_class.TestClass object at 0xdeadbeef>
def test_two(self):
x = "hello"
@@ -164,7 +168,7 @@ before performing the test function call. Let's just run it::
======= FAILURES ========
_______ test_needsfiles ________
tmpdir = local('/tmp/pytest-NaN/test_needsfiles0')
tmpdir = local('PYTEST_TMPDIR/test_needsfiles0')
def test_needsfiles(tmpdir):
print (tmpdir)
@@ -172,8 +176,8 @@ before performing the test function call. Let's just run it::
E assert 0
test_tmpdir.py:3: AssertionError
----------------------------- Captured stdout call -----------------------------
/tmp/pytest-NaN/test_needsfiles0
--------------------------- Captured stdout call ---------------------------
PYTEST_TMPDIR/test_needsfiles0
1 failed in 0.12 seconds
Before the test runs, a unique-per-test-invocation temporary directory

View File

@@ -4,29 +4,28 @@
Good Integration Practices
=================================================
Work with virtual environments
-----------------------------------------------------------
We recommend to use virtualenv_ environments and use pip_
(or easy_install_) for installing your application and any dependencies
as well as the ``pytest`` package itself. This way you will get an isolated
and reproducible environment. Given you have installed virtualenv_
and execute it from the command line, here is an example session for unix
or windows::
.. _`test discovery`:
.. _`Python test discovery`:
virtualenv . # create a virtualenv directory in the current directory
Conventions for Python test discovery
-------------------------------------------------
source bin/activate # on unix
``pytest`` implements the following standard test discovery:
scripts/activate # on Windows
* If no arguments are specified then collection starts from :confval:`testpaths`
(if configured) or the current directory. Alternatively, command line arguments
can be used in any combination of directories, file names or node ids.
* recurse into directories, unless they match :confval:`norecursedirs`
* ``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
We can now install pytest::
For examples of how to customize your test discovery :doc:`example/pythoncollection`.
pip install pytest
Within Python modules, ``pytest`` also discovers tests using the standard
:ref:`unittest.TestCase <unittest.TestCase>` subclassing technique.
Due to the ``activate`` step above the ``pip`` will come from
the virtualenv directory and install any package into the isolated
virtual environment.
Choosing a test layout / import rules
------------------------------------------
@@ -38,7 +37,7 @@ Choosing a test layout / import rules
want to keep tests separate from actual application code (often a good
idea)::
setup.py # your distutils/setuptools Python package metadata
setup.py # your setuptools Python package metadata
mypkg/
__init__.py
appmodule.py
@@ -51,7 +50,7 @@ Choosing a test layout / import rules
have direct relation between (unit-)test and application modules and
want to distribute your tests along with your application::
setup.py # your distutils/setuptools Python package metadata
setup.py # your setuptools Python package metadata
mypkg/
__init__.py
appmodule.py
@@ -135,8 +134,13 @@ required configurations.
.. _`use tox`:
Use tox and Continuous Integration servers
-------------------------------------------------
Tox
------
For development, we recommend to use virtualenv_ environments and pip_
for installing your application and any dependencies
as well as the ``pytest`` package itself. This ensures your code and
dependencies are isolated from the system Python installation.
If you frequently release code and want to make sure that your actual
package passes all tests you may want to look into `tox`_, the
@@ -148,89 +152,56 @@ options. It will run tests against the installed package and not
against your source code checkout, helping to detect packaging
glitches.
If you want to use Jenkins_ you can use the ``--junitxml=PATH`` option
to create a JUnitXML file that Jenkins_ can pick up and generate reports.
.. _standalone:
.. _`genscript method`:
(deprecated) Create a pytest standalone script
-----------------------------------------------
If you are a maintainer or application developer and want people
who don't deal with python much to easily run tests you may generate
a standalone ``pytest`` script::
py.test --genscript=runtests.py
This generates a ``runtests.py`` script which is a fully functional basic
``pytest`` script, running unchanged under Python2 and Python3.
You can tell people to download the script and then e.g. run it like this::
python runtests.py
.. note::
You must have pytest and its dependencies installed as an sdist, not
as wheels because genscript need the source code for generating a
standalone script.
Continuous integration services such as Jenkins_ can make use of the
``--junitxml=PATH`` option to create a JUnitXML file and generate reports.
Integrating with setuptools / ``python setup.py test`` / ``pytest-runner``
--------------------------------------------------------------------------
You can integrate test runs into your setuptools based project
with the `pytest-runner <https://pypi.python.org/pypi/pytest-runner>`_ plugin.
Integrating with distutils / ``python setup.py test``
--------------------------------------------------------
Add this to ``setup.py`` file:
You can integrate test runs into your distutils or
setuptools based project. Use the `genscript method`_
to generate a standalone ``pytest`` script::
py.test --genscript=runtests.py
and make this script part of your distribution and then add
this to your ``setup.py`` file::
from distutils.core import setup, Command
# you can also import from setuptools
class PyTest(Command):
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
import subprocess
import sys
errno = subprocess.call([sys.executable, 'runtests.py'])
raise SystemExit(errno)
.. code-block:: python
from setuptools import setup
setup(
#...,
cmdclass = {'test': PyTest},
setup_requires=['pytest-runner', ...],
tests_require=['pytest', ...],
#...,
)
And create an alias into ``setup.cfg`` file:
.. code-block:: ini
[aliases]
test=pytest
If you now type::
python setup.py test
this will execute your tests using ``runtests.py``. As this is a
this will execute your tests using ``pytest-runner``. As this is a
standalone version of ``pytest`` no prior installation whatsoever is
required for calling the test command. You can also pass additional
arguments to the subprocess-calls such as your test directory or other
options.
arguments to py.test such as your test directory or other
options using ``--addopts``.
Integration with setuptools test commands
----------------------------------------------------
Manual Integration
^^^^^^^^^^^^^^^^^^
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::
If for some reason you don't want/can't use ``pytest-runner``, you can write
your own setuptools Test command for invoking pytest.
.. code-block:: python
import sys
@@ -244,11 +215,6 @@ get started with setuptools integration::
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
@@ -274,32 +240,39 @@ using the ``--pytest-args`` or ``-a`` command-line option. For example::
is equivalent to running ``py.test --durations=5``.
.. seealso::
For a more powerful solution, take a look at the
`pytest-runner <https://pypi.python.org/pypi/pytest-runner>`_ plugin.
.. _standalone:
.. _`genscript method`:
.. _`test discovery`:
.. _`Python test discovery`:
(deprecated) Create a pytest standalone script
-----------------------------------------------
Conventions for Python test discovery
-------------------------------------------------
.. deprecated:: 2.8
``pytest`` implements the following standard test discovery:
.. note::
* collection starts from paths specified in :confval:`testpaths` if configured,
otherwise from initial command line arguments which may be directories,
filenames or test ids. If :confval:`testpaths` is not configured and no
directories or files were given in the command line, start collection from
the current directory.
* recurse into directories, unless they match :confval:`norecursedirs`
* ``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
``genscript`` has been deprecated because:
For examples of how to customize your test discovery :doc:`example/pythoncollection`.
* It cannot support plugins, rendering its usefulness extremely limited;
* Tooling has become much better since ``genscript`` was introduced;
* It is possible to build a zipped ``pytest`` application without the
shortcomings above.
There's no planned version in which this command will be removed
at the moment of this writing, but its use is discouraged for new
applications.
If you are a maintainer or application developer and want people
who don't deal with python much to easily run tests you may generate
a standalone ``pytest`` script::
py.test --genscript=runtests.py
This generates a ``runtests.py`` script which is a fully functional basic
``pytest`` script, running unchanged under Python2 and Python3.
You can tell people to download the script and then e.g. run it like this::
python runtests.py
Within Python modules, ``pytest`` also discovers tests using the standard
:ref:`unittest.TestCase <unittest.TestCase>` subclassing technique.
.. include:: links.inc

View File

@@ -55,7 +55,7 @@ them in turn::
$ py.test
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 3 items
@@ -103,7 +103,7 @@ Let's run this::
$ py.test
======= test session starts ========
platform linux2 -- Python 2.7.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 3 items
@@ -196,12 +196,12 @@ As expected our test function fails.
If you don't specify a stringinput it will be skipped because
``metafunc.parametrize()`` will be called with an empty parameter
listlist::
list::
$ py.test -q -rs test_strings.py
s
======= short test summary info ========
SKIP [1] $PWD/_pytest/python.py:1201: got empty parameter set, function test_valid_string at $REGENDOC_TMPDIR/test_strings.py:1
SKIP [1] $PYTHON_PREFIX/lib/python3.4/site-packages/_pytest/python.py:1417: got empty parameter set, function test_valid_string at $REGENDOC_TMPDIR/test_strings.py:1
1 skipped in 0.12 seconds
For further examples, you might want to look at :ref:`more

View File

@@ -14,10 +14,9 @@ Installing a third party plugin can be easily done with ``pip``::
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:`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:
there is no need to activate it.
Here is a little annotated list for some popular plugins:
.. _`django`: https://www.djangoproject.com/
@@ -28,7 +27,7 @@ for some popular plugins:
for `twisted <http://twistedmatrix.com>`_ apps, starting a reactor and
processing deferreds from test functions.
* `pytest-capturelog <http://pypi.python.org/pypi/pytest-capturelog>`_:
* `pytest-catchlog <http://pypi.python.org/pypi/pytest-catchlog>`_:
to capture and assert about messages from the logging module
* `pytest-cov <http://pypi.python.org/pypi/pytest-cov>`_:
@@ -50,15 +49,14 @@ for some popular plugins:
* `pytest-timeout <http://pypi.python.org/pypi/pytest-timeout>`_:
to timeout tests based on function marks or global definitions.
* `pytest-cache <http://pypi.python.org/pypi/pytest-cache>`_:
to interactively re-run failing tests and help other plugins to
store test run information across invocations.
* `pytest-pep8 <http://pypi.python.org/pypi/pytest-pep8>`_:
a ``--pep8`` option to enable PEP8 compliance checking.
* `pytest-flakes <https://pypi.python.org/pypi/pytest-flakes>`_:
check source code with pyflakes.
* `oejskit <http://pypi.python.org/pypi/oejskit>`_:
a plugin to run javascript unittests in life browsers
a plugin to run javascript unittests in life browsers.
To see a complete list of all plugins with their latest testing
status against different py.test and Python versions, please visit
@@ -108,13 +106,26 @@ You can prevent plugins from loading or unregister them::
py.test -p no:NAME
This means that any subsequent try to activate/load the named
plugin will it already existing. See :ref:`findpluginname` for
how to obtain the name of a plugin.
plugin will not work.
If you want to unconditionally disable a plugin for a project, you can add
this option to your ``pytest.ini`` file:
.. code-block:: ini
[pytest]
addopts = -p no:NAME
Alternatively to disable it only in certain environments (for example in a
CI server), you can set ``PYTEST_ADDOPTS`` environment variable to
``-p no:name``.
See :ref:`findpluginname` for how to obtain the name of a plugin.
.. _`builtin plugins`:
pytest default plugin reference
===============================
Pytest default plugin reference
-------------------------------
You can find the source code for the following plugins
@@ -123,6 +134,7 @@ in the `pytest repository <https://github.com/pytest-dev/pytest>`_.
.. autosummary::
_pytest.assertion
_pytest.cacheprovider
_pytest.capture
_pytest.config
_pytest.doctest

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 734 B

View File

@@ -1,290 +0,0 @@
.. _plugins_index:
List of Third-Party Plugins
===========================
The table below contains a listing of plugins found in PyPI and
their status when tested when using latest py.test and python versions.
A complete listing can also be found at
`plugincompat <http://plugincompat.herokuapp.com/>`_, which contains tests
status against other py.test releases.
============================================================================================ ===================================================================================================================== ===================================================================================================================== =========================================================================== =============================================================================================================================================
Name Py27 Py34 Home Summary
============================================================================================ ===================================================================================================================== ===================================================================================================================== =========================================================================== =============================================================================================================================================
`pytest-allure-adaptor <http://pypi.python.org/pypi/pytest-allure-adaptor>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-allure-adaptor-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-allure-adaptor-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Plugin for py.test to generate allure xml reports
:target: http://plugincompat.herokuapp.com/output/pytest-allure-adaptor-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-allure-adaptor-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/allure-framework/allure-python
`pytest-ansible <http://pypi.python.org/pypi/pytest-ansible>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-ansible-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-ansible-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Plugin for py.test to allow running ansible
:target: http://plugincompat.herokuapp.com/output/pytest-ansible-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-ansible-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/jlaska/pytest-ansible
`pytest-asyncio <http://pypi.python.org/pypi/pytest-asyncio>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-asyncio-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-asyncio-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Pytest support for asyncio.
:target: http://plugincompat.herokuapp.com/output/pytest-asyncio-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-asyncio-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/pytest-dev/pytest-asyncio
`pytest-autochecklog <http://pypi.python.org/pypi/pytest-autochecklog>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-autochecklog-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-autochecklog-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png automatically check condition and log all the checks
:target: http://plugincompat.herokuapp.com/output/pytest-autochecklog-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-autochecklog-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/steven004/python-autochecklog
`pytest-bdd <http://pypi.python.org/pypi/pytest-bdd>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-bdd-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-bdd-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png BDD for pytest
:target: http://plugincompat.herokuapp.com/output/pytest-bdd-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-bdd-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/pytest-dev/pytest-bdd
`pytest-beakerlib <http://pypi.python.org/pypi/pytest-beakerlib>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-beakerlib-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-beakerlib-latest?py=py34&pytest=2.8.0.dev4 `link <https://fedorahosted.org/python-pytest-beakerlib/>`_ A pytest plugin that reports test results to the BeakerLib framework
:target: http://plugincompat.herokuapp.com/output/pytest-beakerlib-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-beakerlib-latest?py=py34&pytest=2.8.0.dev4
`pytest-beds <http://pypi.python.org/pypi/pytest-beds>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-beds-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-beds-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Fixtures for testing Google Appengine (GAE) apps
:target: http://plugincompat.herokuapp.com/output/pytest-beds-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-beds-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/kaste/pytest-beds
`pytest-bench <http://pypi.python.org/pypi/pytest-bench>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-bench-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-bench-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Benchmark utility that plugs into pytest.
:target: http://plugincompat.herokuapp.com/output/pytest-bench-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-bench-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/concordusapps/pytest-bench
`pytest-benchmark <http://pypi.python.org/pypi/pytest-benchmark>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-benchmark-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-benchmark-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test fixture for benchmarking code
:target: http://plugincompat.herokuapp.com/output/pytest-benchmark-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-benchmark-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/ionelmc/pytest-benchmark
`pytest-blockage <http://pypi.python.org/pypi/pytest-blockage>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-blockage-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-blockage-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Disable network requests during a test run.
:target: http://plugincompat.herokuapp.com/output/pytest-blockage-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-blockage-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/rob-b/pytest-blockage
`pytest-bpdb <http://pypi.python.org/pypi/pytest-bpdb>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-bpdb-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-bpdb-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png A py.test plug-in to enable drop to bpdb debugger on test failure.
:target: http://plugincompat.herokuapp.com/output/pytest-bpdb-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-bpdb-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/slafs/pytest-bpdb
`pytest-browsermob-proxy <http://pypi.python.org/pypi/pytest-browsermob-proxy>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-browsermob-proxy-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-browsermob-proxy-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png BrowserMob proxy plugin for py.test.
:target: http://plugincompat.herokuapp.com/output/pytest-browsermob-proxy-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-browsermob-proxy-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/davehunt/pytest-browsermob-proxy
`pytest-bugzilla <http://pypi.python.org/pypi/pytest-bugzilla>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-bugzilla-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-bugzilla-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test bugzilla integration plugin
:target: http://plugincompat.herokuapp.com/output/pytest-bugzilla-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-bugzilla-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/nibrahim/pytest_bugzilla
`pytest-marker-bugzilla <http://pypi.python.org/pypi/pytest-marker-bugzilla>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-marker-bugzilla-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-marker-bugzilla-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test bugzilla integration plugin, using markers
:target: http://plugincompat.herokuapp.com/output/pytest-marker-bugzilla-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-marker-bugzilla-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/eanxgeek/pytest_marker_bugzilla
`pytest-remove-stale-bytecode <http://pypi.python.org/pypi/pytest-remove-stale-bytecode>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-remove-stale-bytecode-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-remove-stale-bytecode-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png py.test plugin to remove stale byte code files.
:target: http://plugincompat.herokuapp.com/output/pytest-remove-stale-bytecode-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-remove-stale-bytecode-latest?py=py34&pytest=2.8.0.dev4 :target: https://bitbucket.org/gocept/pytest-remove-stale-bytecode/
`pytest-cache <http://pypi.python.org/pypi/pytest-cache>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-cache-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-cache-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png pytest plugin with mechanisms for caching across test runs
:target: http://plugincompat.herokuapp.com/output/pytest-cache-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-cache-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/hpk42/pytest-cache/
`pytest-cagoule <http://pypi.python.org/pypi/pytest-cagoule>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-cagoule-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-cagoule-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Pytest plugin to only run tests affected by changes
:target: http://plugincompat.herokuapp.com/output/pytest-cagoule-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-cagoule-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/davidszotten/pytest-cagoule
`pytest-capturelog <http://pypi.python.org/pypi/pytest-capturelog>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-capturelog-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-capturelog-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png py.test plugin to capture log messages
:target: http://plugincompat.herokuapp.com/output/pytest-capturelog-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-capturelog-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/memedough/pytest-capturelog/overview
`pytest-django-casperjs <http://pypi.python.org/pypi/pytest-django-casperjs>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-django-casperjs-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-django-casperjs-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Integrate CasperJS with your django tests as a pytest fixture.
:target: http://plugincompat.herokuapp.com/output/pytest-django-casperjs-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-django-casperjs-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/EnTeQuAk/pytest-django-casperjs/
`pytest-catchlog <http://pypi.python.org/pypi/pytest-catchlog>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-catchlog-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-catchlog-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin to catch log messages. This is a fork of pytest-capturelog.
:target: http://plugincompat.herokuapp.com/output/pytest-catchlog-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-catchlog-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/eisensheng/pytest-catchlog
`pytest-circleci <http://pypi.python.org/pypi/pytest-circleci>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-circleci-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-circleci-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin for CircleCI
:target: http://plugincompat.herokuapp.com/output/pytest-circleci-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-circleci-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/micktwomey/pytest-circleci
`pytest-cloud <http://pypi.python.org/pypi/pytest-cloud>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-cloud-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-cloud-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Distributed tests planner plugin for pytest testing framework.
:target: http://plugincompat.herokuapp.com/output/pytest-cloud-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-cloud-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/pytest-dev/pytest-cloud
`pytest-codecheckers <http://pypi.python.org/pypi/pytest-codecheckers>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-codecheckers-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-codecheckers-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png pytest plugin to add source code sanity checks (pep8 and friends)
:target: http://plugincompat.herokuapp.com/output/pytest-codecheckers-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-codecheckers-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/RonnyPfannschmidt/pytest-codecheckers/
`pytest-colordots <http://pypi.python.org/pypi/pytest-colordots>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-colordots-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-colordots-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Colorizes the progress indicators
:target: http://plugincompat.herokuapp.com/output/pytest-colordots-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-colordots-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/svenstaro/pytest-colordots
`pytest-paste-config <http://pypi.python.org/pypi/pytest-paste-config>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-paste-config-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-paste-config-latest?py=py34&pytest=2.8.0.dev4 ? Allow setting the path to a paste config file
:target: http://plugincompat.herokuapp.com/output/pytest-paste-config-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-paste-config-latest?py=py34&pytest=2.8.0.dev4
`pytest-config <http://pypi.python.org/pypi/pytest-config>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-config-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-config-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Base configurations and utilities for developing your Python project test suite with pytest.
:target: http://plugincompat.herokuapp.com/output/pytest-config-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-config-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/buzzfeed/pytest_config
`pytest-contextfixture <http://pypi.python.org/pypi/pytest-contextfixture>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-contextfixture-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-contextfixture-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Define pytest fixtures as context managers.
:target: http://plugincompat.herokuapp.com/output/pytest-contextfixture-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-contextfixture-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/pelme/pytest-contextfixture/
`pytest-couchdbkit <http://pypi.python.org/pypi/pytest-couchdbkit>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-couchdbkit-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-couchdbkit-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png py.test extension for per-test couchdb databases using couchdbkit
:target: http://plugincompat.herokuapp.com/output/pytest-couchdbkit-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-couchdbkit-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/RonnyPfannschmidt/pytest-couchdbkit
`pytest-cov <http://pypi.python.org/pypi/pytest-cov>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-cov-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-cov-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin for coverage reporting with support for both centralised and distributed testing, including subprocesses and multiprocessing
:target: http://plugincompat.herokuapp.com/output/pytest-cov-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-cov-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/schlamar/pytest-cov
`pytest-cover <http://pypi.python.org/pypi/pytest-cover>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-cover-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-cover-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Pytest plugin for measuring coverage. Forked from `pytest-cov`.
:target: http://plugincompat.herokuapp.com/output/pytest-cover-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-cover-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/ionelmc/pytest-cover
`pytest-coverage <http://pypi.python.org/pypi/pytest-coverage>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-coverage-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-coverage-latest?py=py34&pytest=2.8.0.dev4 `link <https://pypi.python.org/pypi/pytest-cover/>`_ Pytest plugin for measuring coverage. Forked from `pytest-cov`.
:target: http://plugincompat.herokuapp.com/output/pytest-coverage-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-coverage-latest?py=py34&pytest=2.8.0.dev4
`pytest-cpp <http://pypi.python.org/pypi/pytest-cpp>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-cpp-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-cpp-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Use pytest's runner to discover and execute C++ tests
:target: http://plugincompat.herokuapp.com/output/pytest-cpp-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-cpp-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/pytest-dev/pytest-cpp
`pytest-curl-report <http://pypi.python.org/pypi/pytest-curl-report>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-curl-report-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-curl-report-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png pytest plugin to generate curl command line report
:target: http://plugincompat.herokuapp.com/output/pytest-curl-report-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-curl-report-latest?py=py34&pytest=2.8.0.dev4 :target: https://bitbucket.org/pytest-dev/pytest-curl-report
`pytest-dbfixtures <http://pypi.python.org/pypi/pytest-dbfixtures>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-dbfixtures-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-dbfixtures-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Databases fixtures plugin for py.test.
:target: http://plugincompat.herokuapp.com/output/pytest-dbfixtures-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-dbfixtures-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/ClearcodeHQ/pytest-dbfixtures
`pytest-dbus-notification <http://pypi.python.org/pypi/pytest-dbus-notification>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-dbus-notification-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-dbus-notification-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png D-BUS notifications for pytest results.
:target: http://plugincompat.herokuapp.com/output/pytest-dbus-notification-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-dbus-notification-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/bmathieu33/pytest-dbus-notification
`pytest-describe <http://pypi.python.org/pypi/pytest-describe>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-describe-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-describe-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Describe-style plugin for pytest
:target: http://plugincompat.herokuapp.com/output/pytest-describe-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-describe-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/ropez/pytest-describe
`pytest-diffeo <http://pypi.python.org/pypi/pytest-diffeo>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-diffeo-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-diffeo-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Common py.test support for Diffeo packages
:target: http://plugincompat.herokuapp.com/output/pytest-diffeo-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-diffeo-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/diffeo/pytest-diffeo
`pytest-django-sqlcounts <http://pypi.python.org/pypi/pytest-django-sqlcounts>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-django-sqlcounts-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-django-sqlcounts-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin for reporting the number of SQLs executed per django testcase.
:target: http://plugincompat.herokuapp.com/output/pytest-django-sqlcounts-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-django-sqlcounts-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/stj/pytest-django-sqlcount
`pytest-django-sqlcount <http://pypi.python.org/pypi/pytest-django-sqlcount>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-django-sqlcount-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-django-sqlcount-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin for reporting the number of SQLs executed per django testcase.
:target: http://plugincompat.herokuapp.com/output/pytest-django-sqlcount-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-django-sqlcount-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/stj/pytest-django-sqlcount
`pytest-django-haystack <http://pypi.python.org/pypi/pytest-django-haystack>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-django-haystack-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-django-haystack-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Cleanup your Haystack indexes between tests
:target: http://plugincompat.herokuapp.com/output/pytest-django-haystack-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-django-haystack-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/rouge8/pytest-django-haystack
`pytest-django-lite <http://pypi.python.org/pypi/pytest-django-lite>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-django-lite-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-django-lite-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png The bare minimum to integrate py.test with Django.
:target: http://plugincompat.herokuapp.com/output/pytest-django-lite-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-django-lite-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/dcramer/pytest-django-lite
`pytest-django <http://pypi.python.org/pypi/pytest-django>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-django-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-django-latest?py=py34&pytest=2.8.0.dev4 `link <http://pytest-django.readthedocs.org/>`_ A Django plugin for py.test.
:target: http://plugincompat.herokuapp.com/output/pytest-django-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-django-latest?py=py34&pytest=2.8.0.dev4
`pytest-doc <http://pypi.python.org/pypi/pytest-doc>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-doc-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-doc-latest?py=py34&pytest=2.8.0.dev4 `link <http://pytest-doc.readthedocs.org/>`_ A documentation plugin for py.test.
:target: http://plugincompat.herokuapp.com/output/pytest-doc-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-doc-latest?py=py34&pytest=2.8.0.dev4
`pytest-dump2json <http://pypi.python.org/pypi/pytest-dump2json>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-dump2json-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-dump2json-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png A pytest plugin for dumping test results to json.
:target: http://plugincompat.herokuapp.com/output/pytest-dump2json-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-dump2json-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/d6e/pytest-dump2json
`pytest-echo <http://pypi.python.org/pypi/pytest-echo>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-echo-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-echo-latest?py=py34&pytest=2.8.0.dev4 `link <http://pypi.python.org/pypi/pytest-echo/>`_ pytest plugin with mechanisms for echoing environment variables, package version and generic attributes
:target: http://plugincompat.herokuapp.com/output/pytest-echo-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-echo-latest?py=py34&pytest=2.8.0.dev4
`pytest-env <http://pypi.python.org/pypi/pytest-env>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-env-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-env-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin that allows you to add environment variables.
:target: http://plugincompat.herokuapp.com/output/pytest-env-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-env-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/MobileDynasty/pytest-env
`pytest-eradicate <http://pypi.python.org/pypi/pytest-eradicate>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-eradicate-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-eradicate-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin to check for commented out code
:target: http://plugincompat.herokuapp.com/output/pytest-eradicate-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-eradicate-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/spil-johan/pytest-eradicate
`pytest-factoryboy <http://pypi.python.org/pypi/pytest-factoryboy>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-factoryboy-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-factoryboy-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Factory Boy support for pytest.
:target: http://plugincompat.herokuapp.com/output/pytest-factoryboy-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-factoryboy-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/pytest-dev/pytest-factoryboy
`pytest-poo-fail <http://pypi.python.org/pypi/pytest-poo-fail>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-poo-fail-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-poo-fail-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Visualize your failed tests with poo
:target: http://plugincompat.herokuapp.com/output/pytest-poo-fail-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-poo-fail-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/alyssa.barela/pytest-poo-fail
`pytest-faker <http://pypi.python.org/pypi/pytest-faker>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-faker-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-faker-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Faker integration for pytest framework.
:target: http://plugincompat.herokuapp.com/output/pytest-faker-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-faker-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/pytest-dev/pytest-faker
`pytest-faulthandler <http://pypi.python.org/pypi/pytest-faulthandler>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-faulthandler-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-faulthandler-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin that activates the fault handler module for tests
:target: http://plugincompat.herokuapp.com/output/pytest-faulthandler-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-faulthandler-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/pytest-dev/pytest-faulthandler
`pytest-fauxfactory <http://pypi.python.org/pypi/pytest-fauxfactory>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-fauxfactory-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-fauxfactory-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Integration of fauxfactory into pytest.
:target: http://plugincompat.herokuapp.com/output/pytest-fauxfactory-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-fauxfactory-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/mfalesni/pytest-fauxfactory
`pytest-figleaf <http://pypi.python.org/pypi/pytest-figleaf>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-figleaf-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-figleaf-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png py.test figleaf coverage plugin
:target: http://plugincompat.herokuapp.com/output/pytest-figleaf-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-figleaf-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/hpk42/pytest-figleaf
`pytest-fixture-tools <http://pypi.python.org/pypi/pytest-fixture-tools>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-fixture-tools-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-fixture-tools-latest?py=py34&pytest=2.8.0.dev4 ? Plugin for pytest which provides tools for fixtures
:target: http://plugincompat.herokuapp.com/output/pytest-fixture-tools-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-fixture-tools-latest?py=py34&pytest=2.8.0.dev4
`pytest-flake8 <http://pypi.python.org/pypi/pytest-flake8>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-flake8-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-flake8-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin to check FLAKE8 requirements
:target: http://plugincompat.herokuapp.com/output/pytest-flake8-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-flake8-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/tholo/pytest-flake8
`pytest-flakes <http://pypi.python.org/pypi/pytest-flakes>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-flakes-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-flakes-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin to check source code with pyflakes
:target: http://plugincompat.herokuapp.com/output/pytest-flakes-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-flakes-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/fschulze/pytest-flakes
`pytest-flask <http://pypi.python.org/pypi/pytest-flask>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-flask-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-flask-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png A set of py.test fixtures to test Flask applications.
:target: http://plugincompat.herokuapp.com/output/pytest-flask-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-flask-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/vitalk/pytest-flask
`pytest-gitignore <http://pypi.python.org/pypi/pytest-gitignore>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-gitignore-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-gitignore-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin to ignore the same files as git
:target: http://plugincompat.herokuapp.com/output/pytest-gitignore-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-gitignore-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/tgs/pytest-gitignore
`pytest-greendots <http://pypi.python.org/pypi/pytest-greendots>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-greendots-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-greendots-latest?py=py34&pytest=2.8.0.dev4 ? Green progress dots
:target: http://plugincompat.herokuapp.com/output/pytest-greendots-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-greendots-latest?py=py34&pytest=2.8.0.dev4
`pytest-growl <http://pypi.python.org/pypi/pytest-growl>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-growl-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-growl-latest?py=py34&pytest=2.8.0.dev4 ? Growl notifications for pytest results.
:target: http://plugincompat.herokuapp.com/output/pytest-growl-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-growl-latest?py=py34&pytest=2.8.0.dev4
`pytest-html <http://pypi.python.org/pypi/pytest-html>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-html-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-html-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin for generating HTML reports
:target: http://plugincompat.herokuapp.com/output/pytest-html-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-html-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/davehunt/pytest-html
`pytest-httpbin <http://pypi.python.org/pypi/pytest-httpbin>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-httpbin-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-httpbin-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Easily test your HTTP library against a local copy of httpbin
:target: http://plugincompat.herokuapp.com/output/pytest-httpbin-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-httpbin-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/kevin1024/pytest-httpbin
`pytest-httpretty <http://pypi.python.org/pypi/pytest-httpretty>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-httpretty-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-httpretty-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png A thin wrapper of HTTPretty for pytest
:target: http://plugincompat.herokuapp.com/output/pytest-httpretty-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-httpretty-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/papaeye/pytest-httpretty
`pytest-incremental <http://pypi.python.org/pypi/pytest-incremental>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-incremental-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-incremental-latest?py=py34&pytest=2.8.0.dev4 `link <http://pytest-incremental.readthedocs.org>`_ an incremental test runner (pytest plugin)
:target: http://plugincompat.herokuapp.com/output/pytest-incremental-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-incremental-latest?py=py34&pytest=2.8.0.dev4
`pytest-instafail <http://pypi.python.org/pypi/pytest-instafail>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-instafail-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-instafail-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin to show failures instantly
:target: http://plugincompat.herokuapp.com/output/pytest-instafail-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-instafail-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/jpvanhal/pytest-instafail
`pytest-ipdb <http://pypi.python.org/pypi/pytest-ipdb>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-ipdb-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-ipdb-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png A py.test plug-in to enable drop to ipdb debugger on test failure.
:target: http://plugincompat.herokuapp.com/output/pytest-ipdb-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-ipdb-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/mverteuil/pytest-ipdb
`pytest-ipynb <http://pypi.python.org/pypi/pytest-ipynb>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-ipynb-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-ipynb-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Use pytest's runner to discover and execute tests as cells of IPython notebooks
:target: http://plugincompat.herokuapp.com/output/pytest-ipynb-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-ipynb-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/zonca/pytest-ipynb
`pytest-isort <http://pypi.python.org/pypi/pytest-isort>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-isort-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-isort-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin to perform isort checks (import ordering)
:target: http://plugincompat.herokuapp.com/output/pytest-isort-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-isort-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/moccu/pytest-isort/
`pytest-jira <http://pypi.python.org/pypi/pytest-jira>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-jira-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-jira-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test JIRA integration plugin, using markers
:target: http://plugincompat.herokuapp.com/output/pytest-jira-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-jira-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/jlaska/pytest_jira
`pytest-knows <http://pypi.python.org/pypi/pytest-knows>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-knows-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-knows-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png A pytest plugin that can automaticly skip test case based on dependence info calculated by trace
:target: http://plugincompat.herokuapp.com/output/pytest-knows-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-knows-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/mapix/ptknows
`pytest-konira <http://pypi.python.org/pypi/pytest-konira>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-konira-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-konira-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Run Konira DSL tests with py.test
:target: http://plugincompat.herokuapp.com/output/pytest-konira-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-konira-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/alfredodeza/pytest-konira
`pytest-localserver <http://pypi.python.org/pypi/pytest-localserver>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-localserver-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-localserver-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png py.test plugin to test server connections locally.
:target: http://plugincompat.herokuapp.com/output/pytest-localserver-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-localserver-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/basti/pytest-localserver/
`pytest-markfiltration <http://pypi.python.org/pypi/pytest-markfiltration>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-markfiltration-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-markfiltration-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png UNKNOWN
:target: http://plugincompat.herokuapp.com/output/pytest-markfiltration-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-markfiltration-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/adamgoucher/pytest-markfiltration
`pytest-marks <http://pypi.python.org/pypi/pytest-marks>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-marks-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-marks-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png UNKNOWN
:target: http://plugincompat.herokuapp.com/output/pytest-marks-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-marks-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/adamgoucher/pytest-marks
`pytest-mccabe <http://pypi.python.org/pypi/pytest-mccabe>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-mccabe-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-mccabe-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin to run the mccabe code complexity checker.
:target: http://plugincompat.herokuapp.com/output/pytest-mccabe-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-mccabe-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/The-Compiler/pytest-mccabe
`pytest-mock <http://pypi.python.org/pypi/pytest-mock>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-mock-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-mock-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Thin-wrapper around the mock package for easier use with py.test
:target: http://plugincompat.herokuapp.com/output/pytest-mock-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-mock-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/pytest-dev/pytest-mock/
`pytest-monkeyplus <http://pypi.python.org/pypi/pytest-monkeyplus>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-monkeyplus-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-monkeyplus-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png pytest's monkeypatch subclass with extra functionalities
:target: http://plugincompat.herokuapp.com/output/pytest-monkeyplus-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-monkeyplus-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/hsoft/pytest-monkeyplus/
`pytest-mozwebqa <http://pypi.python.org/pypi/pytest-mozwebqa>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-mozwebqa-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-mozwebqa-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Mozilla WebQA plugin for py.test.
:target: http://plugincompat.herokuapp.com/output/pytest-mozwebqa-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-mozwebqa-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/mozilla/pytest-mozwebqa
`pytest-mpl <http://pypi.python.org/pypi/pytest-mpl>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-mpl-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-mpl-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin to help with testing figures output from Matplotlib
:target: http://plugincompat.herokuapp.com/output/pytest-mpl-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-mpl-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/astrofrog/pytest-mpl
`pytest-multihost <http://pypi.python.org/pypi/pytest-multihost>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-multihost-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-multihost-latest?py=py34&pytest=2.8.0.dev4 `link <https://fedorahosted.org/python-pytest-multihost/>`_ Utility for writing multi-host tests for pytest
:target: http://plugincompat.herokuapp.com/output/pytest-multihost-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-multihost-latest?py=py34&pytest=2.8.0.dev4
`pytest-oerp <http://pypi.python.org/pypi/pytest-oerp>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-oerp-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-oerp-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin to test OpenERP modules
:target: http://plugincompat.herokuapp.com/output/pytest-oerp-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-oerp-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/santagada/pytest-oerp/
`pytest-oot <http://pypi.python.org/pypi/pytest-oot>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-oot-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-oot-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Run object-oriented tests in a simple format
:target: http://plugincompat.herokuapp.com/output/pytest-oot-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-oot-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/steven004/pytest_oot
`pytest-optional <http://pypi.python.org/pypi/pytest-optional>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-optional-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-optional-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png include/exclude values of fixtures in pytest
:target: http://plugincompat.herokuapp.com/output/pytest-optional-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-optional-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/maho/pytest-optional
`pytest-ordering <http://pypi.python.org/pypi/pytest-ordering>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-ordering-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-ordering-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin to run your tests in a specific order
:target: http://plugincompat.herokuapp.com/output/pytest-ordering-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-ordering-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/ftobia/pytest-ordering
`pytest-osxnotify <http://pypi.python.org/pypi/pytest-osxnotify>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-osxnotify-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-osxnotify-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png OS X notifications for py.test results.
:target: http://plugincompat.herokuapp.com/output/pytest-osxnotify-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-osxnotify-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/dbader/pytest-osxnotify
`pytest-pep257 <http://pypi.python.org/pypi/pytest-pep257>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-pep257-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-pep257-latest?py=py34&pytest=2.8.0.dev4 ? py.test plugin for pep257
:target: http://plugincompat.herokuapp.com/output/pytest-pep257-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-pep257-latest?py=py34&pytest=2.8.0.dev4
`pytest-pep8 <http://pypi.python.org/pypi/pytest-pep8>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-pep8-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-pep8-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png pytest plugin to check PEP8 requirements
:target: http://plugincompat.herokuapp.com/output/pytest-pep8-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-pep8-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/hpk42/pytest-pep8/
`pytest-pipeline <http://pypi.python.org/pypi/pytest-pipeline>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-pipeline-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-pipeline-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Pytest plugin for functional testing of data analysis pipelines
:target: http://plugincompat.herokuapp.com/output/pytest-pipeline-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-pipeline-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/bow/pytest-pipeline
`pytest-poo <http://pypi.python.org/pypi/pytest-poo>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-poo-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-poo-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Visualize your crappy tests
:target: http://plugincompat.herokuapp.com/output/pytest-poo-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-poo-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/pelme/pytest-poo
`pytest-proper-wheel <http://pypi.python.org/pypi/pytest-proper-wheel>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-proper-wheel-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-proper-wheel-latest?py=py34&pytest=2.8.0.dev4 `link <http://pytest.org>`_ pytest: simple powerful testing with Python
:target: http://plugincompat.herokuapp.com/output/pytest-proper-wheel-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-proper-wheel-latest?py=py34&pytest=2.8.0.dev4
`pytest-purkinje <http://pypi.python.org/pypi/pytest-purkinje>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-purkinje-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-purkinje-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin for purkinje test runner
:target: http://plugincompat.herokuapp.com/output/pytest-purkinje-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-purkinje-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/bbiskup
`pytest-pycharm <http://pypi.python.org/pypi/pytest-pycharm>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-pycharm-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-pycharm-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Plugin for py.test to enter PyCharm debugger on uncaught exceptions
:target: http://plugincompat.herokuapp.com/output/pytest-pycharm-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-pycharm-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/jlubcke/pytest-pycharm
`pytest-pydev <http://pypi.python.org/pypi/pytest-pydev>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-pydev-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-pydev-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png py.test plugin to connect to a remote debug server with PyDev or PyCharm.
:target: http://plugincompat.herokuapp.com/output/pytest-pydev-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-pydev-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/basti/pytest-pydev/
`pytest-pylint <http://pypi.python.org/pypi/pytest-pylint>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-pylint-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-pylint-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin to check source code with pylint
:target: http://plugincompat.herokuapp.com/output/pytest-pylint-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-pylint-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/carsongee/pytest-pylint
`pytest-pyq <http://pypi.python.org/pypi/pytest-pyq>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-pyq-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-pyq-latest?py=py34&pytest=2.8.0.dev4 `link <http://pyq.enlnt.com>`_ Pytest fixture "q" for pyq
:target: http://plugincompat.herokuapp.com/output/pytest-pyq-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-pyq-latest?py=py34&pytest=2.8.0.dev4
`pytest-sftpserver <http://pypi.python.org/pypi/pytest-sftpserver>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-sftpserver-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-sftpserver-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin to locally test sftp server connections.
:target: http://plugincompat.herokuapp.com/output/pytest-sftpserver-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-sftpserver-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/ulope/pytest-sftpserver/
`pytest-rage <http://pypi.python.org/pypi/pytest-rage>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-rage-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-rage-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin to implement PEP712
:target: http://plugincompat.herokuapp.com/output/pytest-rage-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-rage-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/santagada/pytest-rage/
`pytest-smartcov <http://pypi.python.org/pypi/pytest-smartcov>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-smartcov-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-smartcov-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Smart coverage plugin for pytest.
:target: http://plugincompat.herokuapp.com/output/pytest-smartcov-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-smartcov-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/carljm/pytest-smartcov/
`pytest-variables <http://pypi.python.org/pypi/pytest-variables>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-variables-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-variables-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin for providing variables to tests/fixtures
:target: http://plugincompat.herokuapp.com/output/pytest-variables-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-variables-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/davehunt/pytest-variables
`pytest-selenium <http://pypi.python.org/pypi/pytest-selenium>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-selenium-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-selenium-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png A selenium plugin for pytest
:target: http://plugincompat.herokuapp.com/output/pytest-selenium-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-selenium-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/codingjoe/pytest-selenium
`pytest-readme <http://pypi.python.org/pypi/pytest-readme>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-readme-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-readme-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Test your README.md file
:target: http://plugincompat.herokuapp.com/output/pytest-readme-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-readme-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/boxed/pytest-readme
`pytest-translations <http://pypi.python.org/pypi/pytest-translations>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-translations-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-translations-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Test your translation files
:target: http://plugincompat.herokuapp.com/output/pytest-translations-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-translations-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/thermondo/pytest-translations
`pytest-xprocess <http://pypi.python.org/pypi/pytest-xprocess>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-xprocess-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-xprocess-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png pytest plugin to manage external processes across test runs
:target: http://plugincompat.herokuapp.com/output/pytest-xprocess-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-xprocess-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/hpk42/pytest-xprocess/
`pytest-random <http://pypi.python.org/pypi/pytest-random>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-random-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-random-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin to randomize tests
:target: http://plugincompat.herokuapp.com/output/pytest-random-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-random-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/klrmn/pytest-random
`pytest-sourceorder <http://pypi.python.org/pypi/pytest-sourceorder>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-sourceorder-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-sourceorder-latest?py=py34&pytest=2.8.0.dev4 `link <https://fedorahosted.org/python-pytest-sourceorder/>`_ Test-ordering plugin for pytest
:target: http://plugincompat.herokuapp.com/output/pytest-sourceorder-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-sourceorder-latest?py=py34&pytest=2.8.0.dev4
`pytest-zap <http://pypi.python.org/pypi/pytest-zap>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-zap-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-zap-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png OWASP ZAP plugin for py.test.
:target: http://plugincompat.herokuapp.com/output/pytest-zap-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-zap-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/davehunt/pytest-zap
`pytest-raisesregexp <http://pypi.python.org/pypi/pytest-raisesregexp>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-raisesregexp-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-raisesregexp-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Simple pytest plugin to look for regex in Exceptions
:target: http://plugincompat.herokuapp.com/output/pytest-raisesregexp-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-raisesregexp-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/Walkman/pytest_raisesregexp
`pytest-trialtemp <http://pypi.python.org/pypi/pytest-trialtemp>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-trialtemp-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-trialtemp-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin for using the same _trial_temp working directory as trial
:target: http://plugincompat.herokuapp.com/output/pytest-trialtemp-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-trialtemp-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/jerith/pytest-trialtemp
`pytest-sftpserver <http://pypi.python.org/pypi/pytest-sftpserver>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-sftpserver-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-sftpserver-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin to locally test sftp server connections.
:target: http://plugincompat.herokuapp.com/output/pytest-sftpserver-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-sftpserver-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/ulope/pytest-sftpserver/
`pytest-rerunfailures <http://pypi.python.org/pypi/pytest-rerunfailures>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-rerunfailures-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-rerunfailures-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin to re-run tests to eliminate flakey failures
:target: http://plugincompat.herokuapp.com/output/pytest-rerunfailures-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-rerunfailures-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/klrmn/pytest-rerunfailures
`pytest-spec <http://pypi.python.org/pypi/pytest-spec>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-spec-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-spec-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin to display test execution output like a SPECIFICATION
:target: http://plugincompat.herokuapp.com/output/pytest-spec-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-spec-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/pchomik/pytest-spec
`pytest-testmon <http://pypi.python.org/pypi/pytest-testmon>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-testmon-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-testmon-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png take TDD to a new level with py.test and testmon
:target: http://plugincompat.herokuapp.com/output/pytest-testmon-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-testmon-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/tarpas/pytest-testmon/
`pytest-sftpserver <http://pypi.python.org/pypi/pytest-sftpserver>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-sftpserver-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-sftpserver-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin to locally test sftp server connections.
:target: http://plugincompat.herokuapp.com/output/pytest-sftpserver-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-sftpserver-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/ulope/pytest-sftpserver/
`pytest-stepwise <http://pypi.python.org/pypi/pytest-stepwise>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-stepwise-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-stepwise-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Run a test suite one failing test at a time.
:target: http://plugincompat.herokuapp.com/output/pytest-stepwise-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-stepwise-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/nip3o/pytest-stepwise
`pytest-runfailed <http://pypi.python.org/pypi/pytest-runfailed>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-runfailed-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-runfailed-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png implement a --failed option for pytest
:target: http://plugincompat.herokuapp.com/output/pytest-runfailed-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-runfailed-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/dmerejkowsky/pytest-runfailed
`pytest-tornado <http://pypi.python.org/pypi/pytest-tornado>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-tornado-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-tornado-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png A py.test plugin providing fixtures and markers to simplify testing of asynchronous tornado applications.
:target: http://plugincompat.herokuapp.com/output/pytest-tornado-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-tornado-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/eugeniy/pytest-tornado
`pytest-sftpserver <http://pypi.python.org/pypi/pytest-sftpserver>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-sftpserver-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-sftpserver-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin to locally test sftp server connections.
:target: http://plugincompat.herokuapp.com/output/pytest-sftpserver-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-sftpserver-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/ulope/pytest-sftpserver/
`pytest-timeout <http://pypi.python.org/pypi/pytest-timeout>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-timeout-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-timeout-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png py.test plugin to abort hanging tests
:target: http://plugincompat.herokuapp.com/output/pytest-timeout-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-timeout-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/flub/pytest-timeout/
`pytest-sftpserver <http://pypi.python.org/pypi/pytest-sftpserver>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-sftpserver-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-sftpserver-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin to locally test sftp server connections.
:target: http://plugincompat.herokuapp.com/output/pytest-sftpserver-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-sftpserver-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/ulope/pytest-sftpserver/
`pytest-ubersmith <http://pypi.python.org/pypi/pytest-ubersmith>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-ubersmith-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-ubersmith-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Easily mock calls to ubersmith at the `requests` level.
:target: http://plugincompat.herokuapp.com/output/pytest-ubersmith-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-ubersmith-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/hivelocity/pytest-ubersmith
`pytest-services <http://pypi.python.org/pypi/pytest-services>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-services-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-services-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Services plugin for pytest testing framework
:target: http://plugincompat.herokuapp.com/output/pytest-services-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-services-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/pytest-dev/pytest-services
`pytest-pythonpath <http://pypi.python.org/pypi/pytest-pythonpath>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-pythonpath-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-pythonpath-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest plugin for adding to the PYTHONPATH from command line or configs.
:target: http://plugincompat.herokuapp.com/output/pytest-pythonpath-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-pythonpath-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/bigsassy/pytest-pythonpath
`pytest-yamlwsgi <http://pypi.python.org/pypi/pytest-yamlwsgi>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-yamlwsgi-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-yamlwsgi-latest?py=py34&pytest=2.8.0.dev4 ? Run tests against wsgi apps defined in yaml
:target: http://plugincompat.herokuapp.com/output/pytest-yamlwsgi-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-yamlwsgi-latest?py=py34&pytest=2.8.0.dev4
`pytest-trello <http://pypi.python.org/pypi/pytest-trello>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-trello-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-trello-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Plugin for py.test that integrates trello using markers
:target: http://plugincompat.herokuapp.com/output/pytest-trello-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-trello-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/jlaska/pytest-trello
`pytest-quickcheck <http://pypi.python.org/pypi/pytest-quickcheck>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-quickcheck-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-quickcheck-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png pytest plugin to generate random data inspired by QuickCheck
:target: http://plugincompat.herokuapp.com/output/pytest-quickcheck-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-quickcheck-latest?py=py34&pytest=2.8.0.dev4 :target: https://bitbucket.org/pytest-dev/pytest-quickcheck
`pytest-twisted <http://pypi.python.org/pypi/pytest-twisted>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-twisted-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-twisted-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png A twisted plugin for py.test.
:target: http://plugincompat.herokuapp.com/output/pytest-twisted-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-twisted-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/schmir/pytest-twisted
`pytest-sftpserver <http://pypi.python.org/pypi/pytest-sftpserver>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-sftpserver-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-sftpserver-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png py.test plugin to locally test sftp server connections.
:target: http://plugincompat.herokuapp.com/output/pytest-sftpserver-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-sftpserver-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/ulope/pytest-sftpserver/
`pytest-watch <http://pypi.python.org/pypi/pytest-watch>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-watch-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-watch-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Local continuous test runner with pytest and watchdog.
:target: http://plugincompat.herokuapp.com/output/pytest-watch-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-watch-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/joeyespo/pytest-watch
`pytest-unmarked <http://pypi.python.org/pypi/pytest-unmarked>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-unmarked-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-unmarked-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Run only unmarked tests
:target: http://plugincompat.herokuapp.com/output/pytest-unmarked-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-unmarked-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/alyssa.barela/pytest-unmarked
`pytest-regtest <http://pypi.python.org/pypi/pytest-regtest>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-regtest-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-regtest-latest?py=py34&pytest=2.8.0.dev4 `link <https://sissource.ethz.ch/uweschmitt/pytest-regtest/tree/master>`_ py.test plugin for regression tests
:target: http://plugincompat.herokuapp.com/output/pytest-regtest-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-regtest-latest?py=py34&pytest=2.8.0.dev4
`pytest-xdist <http://pypi.python.org/pypi/pytest-xdist>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-xdist-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-xdist-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png py.test xdist plugin for distributed testing and loop-on-failing modes
:target: http://plugincompat.herokuapp.com/output/pytest-xdist-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-xdist-latest?py=py34&pytest=2.8.0.dev4 :target: http://bitbucket.org/hpk42/pytest-xdist
`pytest-sugar <http://pypi.python.org/pypi/pytest-sugar>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-sugar-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-sugar-latest?py=py34&pytest=2.8.0.dev4 .. 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://plugincompat.herokuapp.com/output/pytest-sugar-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-sugar-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/Frozenball/pytest-sugar
`pytest-qt <http://pypi.python.org/pypi/pytest-qt>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-qt-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-qt-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png pytest support for PyQt and PySide applications
:target: http://plugincompat.herokuapp.com/output/pytest-qt-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-qt-latest?py=py34&pytest=2.8.0.dev4 :target: http://github.com/pytest-dev/pytest-qt
`pytest-runner <http://pypi.python.org/pypi/pytest-runner>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-runner-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-runner-latest?py=py34&pytest=2.8.0.dev4 .. image:: bitbucket.png Invoke py.test as distutils command with dependency resolution.
:target: http://plugincompat.herokuapp.com/output/pytest-runner-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-runner-latest?py=py34&pytest=2.8.0.dev4 :target: https://bitbucket.org/pytest-dev/pytest-runner
`pytest-splinter <http://pypi.python.org/pypi/pytest-splinter>`_ .. image:: http://plugincompat.herokuapp.com/status/pytest-splinter-latest?py=py27&pytest=2.8.0.dev4 .. image:: http://plugincompat.herokuapp.com/status/pytest-splinter-latest?py=py34&pytest=2.8.0.dev4 .. image:: github.png Splinter plugin for pytest testing framework
:target: http://plugincompat.herokuapp.com/output/pytest-splinter-latest?py=py27&pytest=2.8.0.dev4 :target: http://plugincompat.herokuapp.com/output/pytest-splinter-latest?py=py34&pytest=2.8.0.dev4 :target: https://github.com/pytest-dev/pytest-splinter
============================================================================================ ===================================================================================================================== ===================================================================================================================== =========================================================================== =============================================================================================================================================
*(Updated on 2015-06-30)*

View File

@@ -1,307 +0,0 @@
"""
Script to generate the file `index.txt` with information about
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://plugincompat.herokuapp.com.
"""
from __future__ import print_function
from collections import namedtuple
import datetime
from distutils.version import LooseVersion
import itertools
from optparse import OptionParser
import os
import sys
import pytest
def get_proxy(url):
"""
wrapper function to obtain a xmlrpc proxy, taking in account import
differences between python 2.X and 3.X
:param url: url to bind the proxy to
:return: a ServerProxy instance
"""
if sys.version_info < (3, 0):
from xmlrpclib import ServerProxy
else:
from xmlrpc.client import ServerProxy
return ServerProxy(url)
def iter_plugins(client):
"""
Returns an iterator of (name, version) from PyPI.
:param client: ServerProxy
:param search: package names to search for
"""
for plug_data in client.search({'name': 'pytest'}):
if plug_data['name'].startswith('pytest-'):
yield plug_data['name'], plug_data['version']
def get_latest_versions(plugins):
"""
Returns an iterator of (name, version) from the given list of (name,
version), but returning only the latest version of the package. Uses
distutils.LooseVersion to ensure compatibility with PEP386.
"""
plugins = [(name, LooseVersion(version)) for (name, version) in plugins]
for name, grouped_plugins in itertools.groupby(plugins, key=lambda x: x[0]):
name, loose_version = list(grouped_plugins)[-1]
yield name, str(loose_version)
def obtain_plugins_table(plugins, client, verbose, pytest_ver):
"""
Returns information to populate a table of plugins, their versions,
authors, etc.
The returned information is a list of columns of `ColumnData`
namedtuples(text, link). Link can be None if the text for that column
should not be linked to anything.
:param plugins: list of (name, version)
:param client: ServerProxy
:param verbose: print plugin name and version as they are fetch
:param pytest_ver: pytest version to use.
"""
if pytest_ver is None:
pytest_ver = pytest.__version__
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 ('`link <%s>`_' % 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', 'Py34', 'Home', 'Summary']
repositories = obtain_override_repositories()
print('Generating plugins_index page (pytest-{0})'.format(pytest_ver))
plugins = list(plugins)
for index, (package_name, version) in enumerate(plugins):
if verbose:
print(package_name, version, '...', end='')
release_data = client.release_data(package_name, version)
common_params = dict(
site='http://plugincompat.herokuapp.com',
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}-latest'
image_url = url.format(**common_params)
image_url += '?py={py}&pytest={pytest}'
row = (
ColumnData(package_name, release_data['package_url']),
ColumnData(image_url.format(py='py27', pytest=pytest_ver),
None),
ColumnData(image_url.format(py='py34', pytest=pytest_ver),
None),
ColumnData(
repo_markup_1,
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}-latest'
output_url = url.format(**common_params)
output_url += '?py={py}&pytest={pytest}'
row = (
ColumnData('', None),
ColumnData(output_url.format(py='py27', pytest=pytest_ver),
None),
ColumnData(output_url.format(py='py34', pytest=pytest_ver),
None),
ColumnData(repo_markup_2, None),
ColumnData('', None),
)
assert len(row) == len(headers)
rows.append(row)
if verbose:
print('OK (%d%%)' % ((index + 1) * 100 / len(plugins)))
print('Done: %d plugins' % len(plugins))
return headers, rows
def obtain_override_repositories():
"""
Used to override the "home_page" obtained from pypi to known
package repositories. Used when the author didn't fill the "home_page"
field in setup.py.
:return: dict of {package_name: repository_url}
"""
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',
}
def generate_plugins_index_from_table(filename, headers, rows, pytest_ver):
"""
Generates a RST file with the table data given.
:param filename: output filename
:param headers: see `obtain_plugins_table`
:param rows: see `obtain_plugins_table`
:param pytest_ver: see `obtain_plugins_table`
"""
# creates a list of rows, each being a str containing appropriate column
# text and link
table_texts = []
for row in rows:
column_texts = []
for i, col_data in enumerate(row):
text = '`%s <%s>`_' % (
col_data.text,
col_data.link) if col_data.link else col_data.text
column_texts.append(text)
table_texts.append(column_texts)
# compute max length of each column so we can build the rst table
column_lengths = [len(x) for x in headers]
for column_texts in table_texts:
for i, row_text in enumerate(column_texts):
column_lengths[i] = max(column_lengths[i], len(row_text) + 2)
def get_row_limiter(char):
return ' '.join(char * length for length in column_lengths)
with open(filename, 'w') as f:
# header
print(HEADER, file=f)
print(file=f)
# table
print(get_row_limiter('='), file=f)
formatted_headers = [
'{0:^{fill}}'.format(header, fill=column_lengths[i])
for i, header in enumerate(headers)]
print(*formatted_headers, file=f)
print(get_row_limiter('='), file=f)
for column_texts in table_texts:
formatted_rows = [
'{0:^{fill}}'.format(row_text, fill=column_lengths[i])
for i, row_text in enumerate(column_texts)
]
print(*formatted_rows, file=f)
print(file=f)
print(get_row_limiter('='), file=f)
print(file=f)
today = datetime.date.today().strftime('%Y-%m-%d')
print('*(Updated on %s)*' % today, file=f)
def generate_plugins_index(client, filename, verbose, pytest_ver):
"""
Generates an RST file with a table of the latest pytest plugins found in
PyPI.
:param client: ServerProxy
:param filename: output filename
:param verbose: print name and version of each plugin as they are fetch
:param pytest_ver: pytest version to use; if not given, use current pytest
version.
"""
plugins = get_latest_versions(iter_plugins(client))
headers, rows = obtain_plugins_table(plugins, client, verbose, pytest_ver)
generate_plugins_index_from_table(filename, headers, rows, pytest_ver)
def main(argv):
"""
Script entry point. Configures an option parser and calls the appropriate
internal function.
"""
filename = os.path.join(os.path.dirname(__file__), 'index.txt')
url = 'http://pypi.python.org/pypi'
parser = OptionParser(
description='Generates a restructured document of pytest plugins from PyPI')
parser.add_option('-f', '--filename', default=filename,
help='output filename [default: %default]')
parser.add_option('-u', '--url', default=url,
help='url of PyPI server to obtain data from [default: %default]')
parser.add_option('-v', '--verbose', default=False, action='store_true',
help='verbose output')
parser.add_option('--pytest-ver', default=None, action='store',
help='generate index for this pytest version (default current version)')
(options, _) = parser.parse_args(argv[1:])
client = get_proxy(options.url)
generate_plugins_index(client, options.filename, options.verbose, options.pytest_ver)
print()
print('%s updated.' % options.filename)
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 when using latest py.test and python versions.
A complete listing can also be found at
`plugincompat <http://plugincompat.herokuapp.com/>`_, which contains tests
status against other py.test releases.
'''
if __name__ == '__main__':
sys.exit(main(sys.argv))

View File

@@ -41,6 +41,10 @@ additional information::
Alternatively, you can examine raised warnings in detail using the
:ref:`recwarn <recwarn>` fixture (see below).
.. note::
``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated
differently; see :ref:`ensuring_function_triggers`.
.. _recwarn:
Recording warnings
@@ -87,6 +91,9 @@ Each recorded warning has the attributes ``message``, ``category``,
class of the warning. The ``message`` is the warning itself; calling
``str(message)`` will return the actual message of the warning.
.. note::
``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated
differently; see :ref:`ensuring_function_triggers`.
.. _ensuring_function_triggers:
@@ -94,16 +101,17 @@ Ensuring a function triggers a deprecation warning
-------------------------------------------------------
You can also call a global helper for checking
that a certain function call triggers a ``DeprecationWarning``::
that a certain function call triggers a ``DeprecationWarning`` or
``PendingDeprecationWarning``::
import pytest
def test_global():
pytest.deprecated_call(myfunction, 17)
By default, deprecation warnings will not be caught when using ``pytest.warns``
or ``recwarn``, since the default Python warnings filters hide
DeprecationWarnings. If you wish to record them in your own code, use the
By default, ``DeprecationWarning`` and ``PendingDeprecationWarning`` will not be
caught when using ``pytest.warns`` or ``recwarn`` because default Python warnings filters hide
them. If you wish to record them in your own code, use the
command ``warnings.simplefilter('always')``::
import warnings

View File

@@ -83,8 +83,8 @@ As with all function :ref:`marking <mark>` you can skip test functions at the
`whole class- or module level`_. If your code targets python2.6 or above you
use the skipif decorator (and any other marker) on classes::
@pytest.mark.skipif(sys.platform != 'win32',
reason="requires windows")
@pytest.mark.skipif(sys.platform == 'win32',
reason="does not run on windows")
class TestPosixCalls:
def test_function(self):
@@ -97,8 +97,8 @@ If your code targets python2.5 where class-decorators are not available,
you can set the ``pytestmark`` attribute of a class::
class TestPosixCalls:
pytestmark = pytest.mark.skipif(sys.platform != 'win32',
reason="requires Windows")
pytestmark = pytest.mark.skipif(sys.platform == 'win32',
reason="does not run on windows")
def test_function(self):
"will not be setup or run under 'win32' platform"
@@ -165,8 +165,8 @@ 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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
rootdir: $PWD/doc/en, inifile: pytest.ini
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR/example, inifile:
collected 7 items
xfail_demo.py xxxxxxx

View File

@@ -14,6 +14,9 @@ Talks and blog postings
.. _`tutorial1 repository`: http://bitbucket.org/pytest-dev/pytest-tutorial1/
.. _`pycon 2010 tutorial PDF`: http://bitbucket.org/pytest-dev/pytest-tutorial1/raw/tip/pytest-basic.pdf
- `Improve your testing with Pytest and Mock, Gabe Hollombe, PyCon SG 2015
<https://www.youtube.com/watch?v=RcN26hznmk4>`_.
- `Introduction to pytest, Andreas Pelme, EuroPython 2014
<https://www.youtube.com/watch?v=LdVJj65ikRY>`_.

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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -38,7 +38,7 @@ Running this would result in a passed test except for the last
======= FAILURES ========
_______ test_create_file ________
tmpdir = local('/tmp/pytest-NaN/test_create_file0')
tmpdir = local('PYTEST_TMPDIR/test_create_file0')
def test_create_file(tmpdir):
p = tmpdir.mkdir("sub").join("hello.txt")
@@ -51,7 +51,6 @@ Running this would result in a passed test except for the last
test_tmpdir.py:7: AssertionError
======= 1 failed in 0.12 seconds ========
The 'tmpdir_factory' fixture
----------------------------

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.9, pytest-2.8.0.dev4, py-1.4.28, pluggy-0.3.0
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items
@@ -102,7 +102,7 @@ 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 0xdeadbeef>
E AssertionError: <conftest.db_class.<locals>.DummyDB object at 0xdeadbeef>
E assert 0
test_unittest_db.py:9: AssertionError
@@ -112,7 +112,7 @@ 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 0xdeadbeef>
E AssertionError: <conftest.db_class.<locals>.DummyDB object at 0xdeadbeef>
E assert 0
test_unittest_db.py:12: AssertionError
@@ -126,7 +126,7 @@ when writing the class-scoped fixture function above.
autouse fixtures and accessing other fixtures
-------------------------------------------------------------------
Although it's usually better to explicitely declare use of fixtures you need
Although it's usually better to explicitly declare use of fixtures you need
for a given test, you may sometimes want to have fixtures that are
automatically used in a given context. After all, the traditional
style of unittest-setup mandates the use of this implicit fixture writing
@@ -180,3 +180,11 @@ was executed ahead of the ``test_method``.
to selectively leave away the ``unittest.TestCase`` subclassing, use
plain asserts and get the unlimited pytest feature set.
Converting from unittest to pytest
---------------------------------------
If you want to convert your unittest testcases to pytest, there are
some helpers like `unittest2pytest
<https://pypi.python.org/pypi/unittest2pytest/>`__, which uses lib2to3
and introspection for the transformation.

View File

@@ -46,7 +46,7 @@ Several test run options::
py.test test_mod.py # run tests in module
py.test somepath # run all tests below somepath
py.test -k stringexpr # only run tests with names that match the
# the "string expression", e.g. "MyClass and not method"
# "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",
@@ -123,7 +123,7 @@ automatically disables its output capture when you enter PDB_ tracing:
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
for test output occurring after you exit the interactive PDB_ tracing session
and continue with the regular test run.
.. versionadded: 2.4.0
@@ -186,6 +186,8 @@ This will add an extra property ``example_key="1"`` to the generated
by something more powerful and general in future versions. The
functionality per-se will be kept, however.
Currently it does not work when used with the ``pytest-xdist`` plugin.
Also please note that using this feature will break any schema verification.
This might be a problem when used with some CI servers.
@@ -266,6 +268,6 @@ hook was invoked::
$ python myinvoke.py
*** test run reporting finishing
.. include:: links.inc

View File

@@ -16,7 +16,7 @@ reporting by calling `well specified hooks`_ of the following plugins:
* :ref:`builtin plugins`: loaded from pytest's internal ``_pytest`` directory.
* :ref:`external plugins <plugins_index>`: modules discovered through
* :ref:`external plugins <extplugins>`: modules discovered through
`setuptools entry points`_
* `conftest.py plugins`_: modules auto-discovered in test directories
@@ -110,7 +110,7 @@ you can copy from:
* a custom collection example plugin: :ref:`yaml plugin`
* around 20 doc:`builtin plugins` which provide pytest's own functionality
* many :ref:`external plugins <plugins_index>` providing additional features
* many `external plugins <http://plugincompat.herokuapp.com>`_ providing additional features
All of these plugins implement the documented `well specified hooks`_
to extend and add functionality.
@@ -203,13 +203,13 @@ pytest comes with some facilities that you can enable for testing your
plugin. Given that you have an installed plugin you can enable the
:py:class:`testdir <_pytest.pytester.Testdir>` fixture via specifying a
command line option to include the pytester plugin (``-p pytester``) or
by putting ``pytest_plugins = pytester`` into your test or
``conftest.py`` file. You then will have a ``testdir`` fixure which you
by putting ``pytest_plugins = "pytester"`` into your test or
``conftest.py`` file. You then will have a ``testdir`` fixture which you
can use like this::
# content of test_myplugin.py
pytest_plugins = pytester # to get testdir fixture
pytest_plugins = "pytester" # to get testdir fixture
def test_myplugin(testdir):
testdir.makepyfile("""
@@ -332,17 +332,17 @@ after others, i.e. the position in the ``N``-sized list of functions:
.. code-block:: python
# Plugin 1
@pytest.hookimpl_spec(tryfirst=True)
@pytest.hookimpl(tryfirst=True)
def pytest_collection_modifyitems(items):
# will execute as early as possible
# Plugin 2
@pytest.hookimpl_spec(trylast=True)
@pytest.hookimpl(trylast=True)
def pytest_collection_modifyitems(items):
# will execute as late as possible
# Plugin 3
@pytest.hookimpl_spec(hookwrapper=True)
@pytest.hookimpl(hookwrapper=True)
def pytest_collection_modifyitems(items):
# will execute even before the tryfirst one above!
outcome = yield
@@ -386,7 +386,7 @@ are expected.
For an example, see `newhooks.py`_ from :ref:`xdist`.
.. _`newhooks.py`: https://bitbucket.org/pytest-dev/pytest-xdist/src/52082f70e7dd04b00361091b8af906c60fd6700f/xdist/newhooks.py?at=default
.. _`newhooks.py`: https://github.com/pytest-dev/pytest-xdist/blob/974bd566c599dc6a9ea291838c6f226197208b46/xdist/newhooks.py
Optionally using hooks from 3rd party plugins
@@ -501,7 +501,7 @@ reporting or interaction with exceptions:
.. autofunction:: pytest_internalerror
.. autofunction:: pytest_keyboard_interrupt
.. autofunction:: pytest_exception_interact
.. autofunction:: pytest_enter_pdb
Reference of objects involved in hooks

View File

@@ -95,6 +95,16 @@ class TestClass:
"*1 passed*",
])
def test_issue1035_obj_has_getattr(self, testdir):
modcol = testdir.getmodulecol("""
class Chameleon(object):
def __getattr__(self, name):
return True
chameleon = Chameleon()
""")
colitems = modcol.collect()
assert len(colitems) == 0
class TestGenerator:
def test_generative_functions(self, testdir):
@@ -733,6 +743,78 @@ class TestTracebackCutting:
"E*NameError*",
])
def test_traceback_filter_error_during_fixture_collection(self, testdir):
"""integration test for issue #995.
"""
testdir.makepyfile("""
import pytest
def fail_me(func):
ns = {}
exec('def w(): raise ValueError("fail me")', ns)
return ns['w']
@pytest.fixture(scope='class')
@fail_me
def fail_fixture():
pass
def test_failing_fixture(fail_fixture):
pass
""")
result = testdir.runpytest()
assert result.ret != 0
out = result.stdout.str()
assert "INTERNALERROR>" not in out
result.stdout.fnmatch_lines([
"*ValueError: fail me*",
"* 1 error in *",
])
def test_filter_traceback_generated_code(self):
"""test that filter_traceback() works with the fact that
py.code.Code.path attribute might return an str object.
In this case, one of the entries on the traceback was produced by
dynamically generated code.
See: https://bitbucket.org/pytest-dev/py/issues/71
This fixes #995.
"""
from _pytest.python import filter_traceback
try:
ns = {}
exec('def foo(): raise ValueError', ns)
ns['foo']()
except ValueError:
_, _, tb = sys.exc_info()
tb = py.code.Traceback(tb)
assert isinstance(tb[-1].path, str)
assert not filter_traceback(tb[-1])
def test_filter_traceback_path_no_longer_valid(self, testdir):
"""test that filter_traceback() works with the fact that
py.code.Code.path attribute might return an str object.
In this case, one of the files in the traceback no longer exists.
This fixes #1133.
"""
from _pytest.python import filter_traceback
testdir.syspathinsert()
testdir.makepyfile(filter_traceback_entry_as_str='''
def foo():
raise ValueError
''')
try:
import filter_traceback_entry_as_str
filter_traceback_entry_as_str.foo()
except ValueError:
_, _, tb = sys.exc_info()
testdir.tmpdir.join('filter_traceback_entry_as_str.py').remove()
tb = py.code.Traceback(tb)
assert isinstance(tb[-1].path, str)
assert filter_traceback(tb[-1])
class TestReportInfo:
def test_itemreport_reportinfo(self, testdir, linecomp):
testdir.makeconftest("""
@@ -798,6 +880,21 @@ class TestReportInfo:
pass
"""
def test_reportinfo_with_nasty_getattr(self, testdir):
# https://github.com/pytest-dev/pytest/issues/1204
modcol = testdir.getmodulecol("""
# lineno 0
class TestClass:
def __getattr__(self, name):
return "this is not an int"
def test_foo(self):
pass
""")
classcol = testdir.collect_by_name(modcol, "TestClass")
instance = classcol.collect()[0]
fspath, lineno, msg = instance.reportinfo()
def test_customized_python_discovery(testdir):
testdir.makeini("""
@@ -955,3 +1052,50 @@ def test_collect_functools_partial(testdir):
""")
result = testdir.inline_run()
result.assertoutcome(passed=6, failed=2)
def test_dont_collect_non_function_callable(testdir):
"""Test for issue https://github.com/pytest-dev/pytest/issues/331
In this case an INTERNALERROR occurred trying to report the failure of
a test like this one because py test failed to get the source lines.
"""
testdir.makepyfile("""
class Oh(object):
def __call__(self):
pass
test_a = Oh()
def test_real():
pass
""")
result = testdir.runpytest('-rw')
result.stdout.fnmatch_lines([
'*collected 1 item*',
'WC2 *',
'*1 passed, 1 pytest-warnings in *',
])
def test_class_injection_does_not_break_collection(testdir):
"""Tests whether injection during collection time will terminate testing.
In this case the error should not occur if the TestClass itself
is modified during collection time, and the original method list
is still used for collection.
"""
testdir.makeconftest("""
from test_inject import TestClass
def pytest_generate_tests(metafunc):
TestClass.changed_var = {}
""")
testdir.makepyfile(test_inject='''
class TestClass(object):
def test_injection(self):
"""Test being parametrized."""
pass
''')
result = testdir.runpytest()
assert "RuntimeError: dictionary changed size during iteration" not in result.stdout.str()
result.stdout.fnmatch_lines(['*1 passed*'])

View File

@@ -283,6 +283,35 @@ class TestNoselikeTestAttribute:
assert len(call.items) == 1
assert call.items[0].cls.__name__ == "TC"
def test_class_with_nasty_getattr(self, testdir):
"""Make sure we handle classes with a custom nasty __getattr__ right.
With a custom __getattr__ which e.g. returns a function (like with a
RPC wrapper), we shouldn't assume this meant "__test__ = True".
"""
# https://github.com/pytest-dev/pytest/issues/1204
testdir.makepyfile("""
class MetaModel(type):
def __getattr__(cls, key):
return lambda: None
BaseModel = MetaModel('Model', (), {})
class Model(BaseModel):
__metaclass__ = MetaModel
def test_blah(self):
pass
""")
reprec = testdir.inline_run()
assert not reprec.getfailedcollections()
call = reprec.getcalls("pytest_collection_modifyitems")[0]
assert not call.items
@pytest.mark.issue351
class TestParameterize:

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
import re
import pytest, py
@@ -118,6 +119,41 @@ class TestMetafunc:
assert metafunc._calls[2].id == "x1-a"
assert metafunc._calls[3].id == "x1-b"
@pytest.mark.skipif('sys.version_info[0] >= 3')
def test_unicode_idval_python2(self):
"""unittest for the expected behavior to obtain ids for parametrized
unicode values in Python 2: if convertible to ascii, they should appear
as ascii values, otherwise fallback to hide the value behind the name
of the parametrized variable name. #1086
"""
from _pytest.python import _idval
values = [
(u'', ''),
(u'ascii', 'ascii'),
(u'ação', 'a6'),
(u'josé@blah.com', 'a6'),
(u'δοκ.ιμή@παράδειγμα.δοκιμή', 'a6'),
]
for val, expected in values:
assert _idval(val, 'a', 6, None) == expected
def test_bytes_idval(self):
"""unittest for the expected behavior to obtain ids for parametrized
bytes values:
- python2: non-ascii strings are considered bytes and formatted using
"binary escape", where any byte < 127 is escaped into its hex form.
- python3: bytes objects are always escaped using "binary escape".
"""
from _pytest.python import _idval
values = [
(b'', ''),
(b'\xc3\xb4\xff\xe4', '\\xc3\\xb4\\xff\\xe4'),
(b'ascii', 'ascii'),
(u'αρά'.encode('utf-8'), '\\xce\\xb1\\xcf\\x81\\xce\\xac'),
]
for val, expected in values:
assert _idval(val, 'a', 6, None) == expected
@pytest.mark.issue250
def test_idmaker_autoname(self):
from _pytest.python import idmaker
@@ -129,11 +165,12 @@ class TestMetafunc:
(object(), object())])
assert result == ["a0-1.0", "a1-b1"]
# unicode mixing, issue250
result = idmaker((py.builtin._totext("a"), "b"), [({}, '\xc3\xb4')])
assert result == ['a0-\xc3\xb4']
result = idmaker((py.builtin._totext("a"), "b"), [({}, b'\xc3\xb4')])
assert result == ['a0-\\xc3\\xb4']
def test_idmaker_native_strings(self):
from _pytest.python import idmaker
totext = py.builtin._totext
result = idmaker(("a", "b"), [(1.0, -1.1),
(2, -202),
("three", "three hundred"),
@@ -143,7 +180,9 @@ class TestMetafunc:
(str, int),
(list("six"), [66, 66]),
(set([7]), set("seven")),
(tuple("eight"), (8, -8, 8))
(tuple("eight"), (8, -8, 8)),
(b'\xc3\xb4', b"name"),
(b'\xc3\xb4', totext("other")),
])
assert result == ["1.0--1.1",
"2--202",
@@ -154,7 +193,10 @@ class TestMetafunc:
"str-int",
"a7-b7",
"a8-b8",
"a9-b9"]
"a9-b9",
"\\xc3\\xb4-name",
"\\xc3\\xb4-other",
]
def test_idmaker_enum(self):
from _pytest.python import idmaker
@@ -312,7 +354,6 @@ class TestMetafunc:
"*uses no fixture 'y'*",
])
@pytest.mark.xfail
@pytest.mark.issue714
def test_parametrize_uses_no_fixture_error_indirect_true(self, testdir):
testdir.makepyfile("""
@@ -333,7 +374,6 @@ class TestMetafunc:
"*uses no fixture 'y'*",
])
@pytest.mark.xfail
@pytest.mark.issue714
def test_parametrize_indirect_uses_no_fixture_error_indirect_list(self, testdir):
testdir.makepyfile("""

View File

@@ -231,6 +231,17 @@ class TestAssert_reprcompare:
assert expl[1] == py.builtin._totext('- £€', 'utf-8')
assert expl[2] == py.builtin._totext('+ £', 'utf-8')
def test_nonascii_text(self):
"""
:issue: 877
non ascii python2 str caused a UnicodeDecodeError
"""
class A(str):
def __repr__(self):
return '\xff'
expl = callequal(A(), '1')
assert expl
def test_mojibake(self):
# issue 429
left = 'e'

View File

@@ -1,3 +1,4 @@
import sys
import pytest
import os
import shutil
@@ -25,6 +26,36 @@ class TestNewAPI:
val = config.cache.get("key/name", -2)
assert val == -2
def test_cache_writefail_cachfile_silent(self, testdir):
testdir.makeini("[pytest]")
testdir.tmpdir.join('.cache').write('gone wrong')
config = testdir.parseconfigure()
cache = config.cache
cache.set('test/broken', [])
@pytest.mark.skipif(sys.platform.startswith('win'), reason='no chmod on windows')
def test_cache_writefail_permissions(self, testdir):
testdir.makeini("[pytest]")
testdir.tmpdir.ensure_dir('.cache').chmod(0)
config = testdir.parseconfigure()
cache = config.cache
cache.set('test/broken', [])
@pytest.mark.skipif(sys.platform.startswith('win'), reason='no chmod on windows')
def test_cache_failure_warns(self, testdir):
testdir.tmpdir.ensure_dir('.cache').chmod(0)
testdir.makepyfile("""
def test_pass():
pass
""")
result = testdir.runpytest('-rw')
assert result.ret == 0
result.stdout.fnmatch_lines([
"*could not create cache path*",
"*1 pytest-warnings*",
])
def test_config_cache(self, testdir):
testdir.makeconftest("""
def pytest_configure(config):
@@ -238,6 +269,22 @@ class TestLastFailed:
lastfailed = config.cache.get("cache/lastfailed", -1)
assert not lastfailed
def test_non_serializable_parametrize(self, testdir):
"""Test that failed parametrized tests with unmarshable parameters
don't break pytest-cache.
"""
testdir.makepyfile(r"""
import pytest
@pytest.mark.parametrize('val', [
b'\xac\x10\x02G',
])
def test_fail(val):
assert False
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines('*1 failed in*')
def test_lastfailed_collectfailure(self, testdir, monkeypatch):
testdir.makepyfile(test_maybe="""

View File

@@ -388,3 +388,19 @@ def test_search_conftest_up_to_inifile(testdir, confcutdir, passed, error):
if error:
match += '*%d error*' % error
result.stdout.fnmatch_lines(match)
def test_issue1073_conftest_special_objects(testdir):
testdir.makeconftest("""
class DontTouchMe:
def __getattr__(self, x):
raise Exception('cant touch me')
x = DontTouchMe()
""")
testdir.makepyfile("""
def test_some():
pass
""")
res = testdir.runpytest()
assert res.ret == 0

View File

@@ -371,38 +371,6 @@ class TestDoctests:
"--junit-xml=junit.xml")
reprec.assertoutcome(failed=1)
def test_doctest_module_session_fixture(self, testdir):
"""Test that session fixtures are initialized for doctest modules (#768)
"""
# session fixture which changes some global data, which will
# be accessed by doctests in a module
testdir.makeconftest("""
import pytest
import sys
@pytest.yield_fixture(autouse=True, scope='session')
def myfixture():
assert not hasattr(sys, 'pytest_session_data')
sys.pytest_session_data = 1
yield
del sys.pytest_session_data
""")
testdir.makepyfile(foo="""
import sys
def foo():
'''
>>> assert sys.pytest_session_data == 1
'''
def bar():
'''
>>> assert sys.pytest_session_data == 1
'''
""")
result = testdir.runpytest("--doctest-modules")
result.stdout.fnmatch_lines('*2 passed*')
@pytest.mark.parametrize('config_mode', ['ini', 'comment'])
def test_allow_unicode(self, testdir, config_mode):
"""Test that doctests which output unicode work in all python versions
@@ -446,7 +414,7 @@ class TestDoctests:
reprec.assertoutcome(passed=passed, failed=int(not passed))
class TestDocTestSkips:
class TestDoctestSkips:
"""
If all examples in a doctest are skipped due to the SKIP option, then
the tests should be SKIPPED rather than PASSED. (#957)
@@ -493,3 +461,122 @@ class TestDocTestSkips:
""")
reprec = testdir.inline_run("--doctest-modules")
reprec.assertoutcome(skipped=1)
class TestDoctestAutoUseFixtures:
SCOPES = ['module', 'session', 'class', 'function']
def test_doctest_module_session_fixture(self, testdir):
"""Test that session fixtures are initialized for doctest modules (#768)
"""
# session fixture which changes some global data, which will
# be accessed by doctests in a module
testdir.makeconftest("""
import pytest
import sys
@pytest.yield_fixture(autouse=True, scope='session')
def myfixture():
assert not hasattr(sys, 'pytest_session_data')
sys.pytest_session_data = 1
yield
del sys.pytest_session_data
""")
testdir.makepyfile(foo="""
import sys
def foo():
'''
>>> assert sys.pytest_session_data == 1
'''
def bar():
'''
>>> assert sys.pytest_session_data == 1
'''
""")
result = testdir.runpytest("--doctest-modules")
result.stdout.fnmatch_lines('*2 passed*')
@pytest.mark.parametrize('scope', SCOPES)
@pytest.mark.parametrize('enable_doctest', [True, False])
def test_fixture_scopes(self, testdir, scope, enable_doctest):
"""Test that auto-use fixtures work properly with doctest modules.
See #1057 and #1100.
"""
testdir.makeconftest('''
import pytest
@pytest.fixture(autouse=True, scope="{scope}")
def auto(request):
return 99
'''.format(scope=scope))
testdir.makepyfile(test_1='''
def test_foo():
"""
>>> getfixture('auto') + 1
100
"""
def test_bar():
assert 1
''')
params = ('--doctest-modules',) if enable_doctest else ()
passes = 3 if enable_doctest else 2
result = testdir.runpytest(*params)
result.stdout.fnmatch_lines(['*=== %d passed in *' % passes])
@pytest.mark.parametrize('scope', SCOPES)
@pytest.mark.parametrize('autouse', [True, False])
@pytest.mark.parametrize('use_fixture_in_doctest', [True, False])
def test_fixture_module_doctest_scopes(self, testdir, scope, autouse,
use_fixture_in_doctest):
"""Test that auto-use fixtures work properly with doctest files.
See #1057 and #1100.
"""
testdir.makeconftest('''
import pytest
@pytest.fixture(autouse={autouse}, scope="{scope}")
def auto(request):
return 99
'''.format(scope=scope, autouse=autouse))
if use_fixture_in_doctest:
testdir.maketxtfile(test_doc="""
>>> getfixture('auto')
99
""")
else:
testdir.maketxtfile(test_doc="""
>>> 1 + 1
2
""")
result = testdir.runpytest('--doctest-modules')
assert 'FAILURES' not in str(result.stdout.str())
result.stdout.fnmatch_lines(['*=== 1 passed in *'])
@pytest.mark.parametrize('scope', SCOPES)
def test_auto_use_request_attributes(self, testdir, scope):
"""Check that all attributes of a request in an autouse fixture
behave as expected when requested for a doctest item.
"""
testdir.makeconftest('''
import pytest
@pytest.fixture(autouse=True, scope="{scope}")
def auto(request):
if "{scope}" == 'module':
assert request.module is None
if "{scope}" == 'class':
assert request.cls is None
if "{scope}" == 'function':
assert request.function is None
return 99
'''.format(scope=scope))
testdir.maketxtfile(test_doc="""
>>> 1 + 1
2
""")
result = testdir.runpytest('--doctest-modules')
assert 'FAILURES' not in str(result.stdout.str())
result.stdout.fnmatch_lines(['*=== 1 passed in *'])

View File

@@ -2,23 +2,82 @@
from xml.dom import minidom
from _pytest.main import EXIT_NOTESTSCOLLECTED
import py, sys, os
import py
import sys
import os
from _pytest.junitxml import LogXML
import pytest
def runandparse(testdir, *args):
resultpath = testdir.tmpdir.join("junit.xml")
result = testdir.runpytest("--junitxml=%s" % resultpath, *args)
xmldoc = minidom.parse(str(resultpath))
return result, xmldoc
return result, DomNode(xmldoc)
def assert_attr(node, **kwargs):
__tracebackhide__ = True
for name, expected in kwargs.items():
def nodeval(node, name):
anode = node.getAttributeNode(name)
assert anode, "node %r has no attribute %r" %(node, name)
val = anode.value
if val != str(expected):
py.test.fail("%r != %r" %(str(val), str(expected)))
if anode is not None:
return anode.value
expected = dict((name, str(value)) for name, value in kwargs.items())
on_node = dict((name, nodeval(node, name)) for name in expected)
assert on_node == expected
class DomNode(object):
def __init__(self, dom):
self.__node = dom
def __repr__(self):
return self.__node.toxml()
def find_first_by_tag(self, tag):
return self.find_nth_by_tag(tag, 0)
def _by_tag(self, tag):
return self.__node.getElementsByTagName(tag)
def find_nth_by_tag(self, tag, n):
items = self._by_tag(tag)
try:
nth = items[n]
except IndexError:
pass
else:
return type(self)(nth)
def find_by_tag(self, tag):
t = type(self)
return [t(x) for x in self.__node.getElementsByTagName(tag)]
def __getitem__(self, key):
node = self.__node.getAttributeNode(key)
if node is not None:
return node.value
def assert_attr(self, **kwargs):
__tracebackhide__ = True
return assert_attr(self.__node, **kwargs)
def toxml(self):
return self.__node.toxml()
@property
def text(self):
return self.__node.childNodes[0].wholeText
@property
def tag(self):
return self.__node.tagName
@property
def next_siebling(self):
return type(self)(self.__node.nextSibling)
class TestPython:
def test_summing_simple(self, testdir):
@@ -39,8 +98,8 @@ class TestPython:
""")
result, dom = runandparse(testdir)
assert result.ret
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, name="pytest", errors=0, failures=1, skips=3, tests=2)
node = dom.find_first_by_tag("testsuite")
node.assert_attr(name="pytest", errors=0, failures=1, skips=3, tests=2)
def test_timing_function(self, testdir):
testdir.makepyfile("""
@@ -53,9 +112,9 @@ class TestPython:
time.sleep(0.01)
""")
result, dom = runandparse(testdir)
node = dom.getElementsByTagName("testsuite")[0]
tnode = node.getElementsByTagName("testcase")[0]
val = tnode.getAttributeNode("time").value
node = dom.find_first_by_tag("testsuite")
tnode = node.find_first_by_tag("testcase")
val = tnode["time"]
assert round(float(val), 2) >= 0.03
def test_setup_error(self, testdir):
@@ -67,16 +126,16 @@ class TestPython:
""")
result, dom = runandparse(testdir)
assert result.ret
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, errors=1, tests=0)
tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode,
node = dom.find_first_by_tag("testsuite")
node.assert_attr(errors=1, tests=0)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(
file="test_setup_error.py",
line="2",
classname="test_setup_error",
name="test_function")
fnode = tnode.getElementsByTagName("error")[0]
assert_attr(fnode, message="test setup failure")
fnode = tnode.find_first_by_tag("error")
fnode.assert_attr(message="test setup failure")
assert "ValueError" in fnode.toxml()
def test_skip_contains_name_reason(self, testdir):
@@ -87,19 +146,16 @@ class TestPython:
""")
result, dom = runandparse(testdir)
assert result.ret == 0
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, skips=1)
tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode,
node = dom.find_first_by_tag("testsuite")
node.assert_attr(skips=1)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(
file="test_skip_contains_name_reason.py",
line="1",
classname="test_skip_contains_name_reason",
name="test_skip")
snode = tnode.getElementsByTagName("skipped")[0]
assert_attr(snode,
type="pytest.skip",
message="hello23",
)
snode = tnode.find_first_by_tag("skipped")
snode.assert_attr(type="pytest.skip", message="hello23", )
def test_classname_instance(self, testdir):
testdir.makepyfile("""
@@ -109,10 +165,10 @@ class TestPython:
""")
result, dom = runandparse(testdir)
assert result.ret
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, failures=1)
tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode,
node = dom.find_first_by_tag("testsuite")
node.assert_attr(failures=1)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(
file="test_classname_instance.py",
line="1",
classname="test_classname_instance.TestClass",
@@ -123,10 +179,10 @@ class TestPython:
p.write("def test_func(): 0/0")
result, dom = runandparse(testdir)
assert result.ret
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, failures=1)
tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode,
node = dom.find_first_by_tag("testsuite")
node.assert_attr(failures=1)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(
file=os.path.join("sub", "test_hello.py"),
line="0",
classname="sub.test_hello",
@@ -137,12 +193,12 @@ class TestPython:
testdir.makepyfile("def test_function(): pass")
result, dom = runandparse(testdir)
assert result.ret
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, errors=1, tests=0)
tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode, classname="pytest", name="internal")
fnode = tnode.getElementsByTagName("error")[0]
assert_attr(fnode, message="internal error")
node = dom.find_first_by_tag("testsuite")
node.assert_attr(errors=1, tests=0)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(classname="pytest", name="internal")
fnode = tnode.find_first_by_tag("error")
fnode.assert_attr(message="internal error")
assert "Division" in fnode.toxml()
def test_failure_function(self, testdir):
@@ -156,22 +212,22 @@ class TestPython:
result, dom = runandparse(testdir)
assert result.ret
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, failures=1, tests=1)
tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode,
node = dom.find_first_by_tag("testsuite")
node.assert_attr(failures=1, tests=1)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(
file="test_failure_function.py",
line="1",
classname="test_failure_function",
name="test_fail")
fnode = tnode.getElementsByTagName("failure")[0]
assert_attr(fnode, message="ValueError: 42")
fnode = tnode.find_first_by_tag("failure")
fnode.assert_attr(message="ValueError: 42")
assert "ValueError" in fnode.toxml()
systemout = fnode.nextSibling
assert systemout.tagName == "system-out"
systemout = fnode.next_siebling
assert systemout.tag == "system-out"
assert "hello-stdout" in systemout.toxml()
systemerr = systemout.nextSibling
assert systemerr.tagName == "system-err"
systemerr = systemout.next_siebling
assert systemerr.tag == "system-err"
assert "hello-stderr" in systemerr.toxml()
def test_failure_verbose_message(self, testdir):
@@ -182,10 +238,10 @@ class TestPython:
""")
result, dom = runandparse(testdir)
node = dom.getElementsByTagName("testsuite")[0]
tnode = node.getElementsByTagName("testcase")[0]
fnode = tnode.getElementsByTagName("failure")[0]
assert_attr(fnode, message="AssertionError: An error assert 0")
node = dom.find_first_by_tag("testsuite")
tnode = node.find_first_by_tag("testcase")
fnode = tnode.find_first_by_tag("failure")
fnode.assert_attr(message="AssertionError: An error assert 0")
def test_failure_escape(self, testdir):
testdir.makepyfile("""
@@ -197,22 +253,21 @@ class TestPython:
""")
result, dom = runandparse(testdir)
assert result.ret
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, failures=3, tests=3)
node = dom.find_first_by_tag("testsuite")
node.assert_attr(failures=3, tests=3)
for index, char in enumerate("<&'"):
tnode = node.getElementsByTagName("testcase")[index]
assert_attr(tnode,
tnode = node.find_nth_by_tag("testcase", index)
tnode.assert_attr(
file="test_failure_escape.py",
line="1",
classname="test_failure_escape",
name="test_func[%s]" % char)
sysout = tnode.getElementsByTagName('system-out')[0]
text = sysout.childNodes[0].wholeText
sysout = tnode.find_first_by_tag('system-out')
text = sysout.text
assert text == '%s\n' % char
def test_junit_prefixing(self, testdir):
testdir.makepyfile("""
def test_func():
@@ -223,20 +278,20 @@ class TestPython:
""")
result, dom = runandparse(testdir, "--junitprefix=xyz")
assert result.ret
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, failures=1, tests=2)
tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode,
node = dom.find_first_by_tag("testsuite")
node.assert_attr(failures=1, tests=2)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(
file="test_junit_prefixing.py",
line="0",
classname="xyz.test_junit_prefixing",
name="test_func")
tnode = node.getElementsByTagName("testcase")[1]
assert_attr(tnode,
tnode = node.find_nth_by_tag("testcase", 1)
tnode.assert_attr(
file="test_junit_prefixing.py",
line="3",
classname="xyz.test_junit_prefixing."
"TestHello",
"TestHello",
name="test_hello")
def test_xfailure_function(self, testdir):
@@ -247,17 +302,17 @@ class TestPython:
""")
result, dom = runandparse(testdir)
assert not result.ret
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, skips=1, tests=0)
tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode,
node = dom.find_first_by_tag("testsuite")
node.assert_attr(skips=1, tests=0)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(
file="test_xfailure_function.py",
line="1",
classname="test_xfailure_function",
name="test_xfail")
fnode = tnode.getElementsByTagName("skipped")[0]
assert_attr(fnode, message="expected test failure")
#assert "ValueError" in fnode.toxml()
fnode = tnode.find_first_by_tag("skipped")
fnode.assert_attr(message="expected test failure")
# assert "ValueError" in fnode.toxml()
def test_xfailure_xpass(self, testdir):
testdir.makepyfile("""
@@ -267,49 +322,50 @@ class TestPython:
pass
""")
result, dom = runandparse(testdir)
#assert result.ret
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, skips=1, tests=0)
tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode,
# assert result.ret
node = dom.find_first_by_tag("testsuite")
node.assert_attr(skips=1, tests=0)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(
file="test_xfailure_xpass.py",
line="1",
classname="test_xfailure_xpass",
name="test_xpass")
fnode = tnode.getElementsByTagName("skipped")[0]
assert_attr(fnode, message="xfail-marked test passes unexpectedly")
#assert "ValueError" in fnode.toxml()
fnode = tnode.find_first_by_tag("skipped")
fnode.assert_attr(message="xfail-marked test passes unexpectedly")
# assert "ValueError" in fnode.toxml()
def test_collect_error(self, testdir):
testdir.makepyfile("syntax error")
result, dom = runandparse(testdir)
assert result.ret
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, errors=1, tests=0)
tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode,
node = dom.find_first_by_tag("testsuite")
node.assert_attr(errors=1, tests=0)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(
file="test_collect_error.py",
#classname="test_collect_error",
name="test_collect_error")
assert tnode.getAttributeNode("line") is None
fnode = tnode.getElementsByTagName("error")[0]
assert_attr(fnode, message="collection failure")
assert tnode["line"] is None
fnode = tnode.find_first_by_tag("error")
fnode.assert_attr(message="collection failure")
assert "SyntaxError" in fnode.toxml()
def test_collect_skipped(self, testdir):
testdir.makepyfile("import pytest; pytest.skip('xyz')")
result, dom = runandparse(testdir)
assert result.ret == EXIT_NOTESTSCOLLECTED
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, skips=1, tests=0)
tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode,
node = dom.find_first_by_tag("testsuite")
node.assert_attr(skips=1, tests=0)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(
file="test_collect_skipped.py",
#classname="test_collect_error",
name="test_collect_skipped")
assert tnode.getAttributeNode("line") is None # py.test doesn't give us a line here.
fnode = tnode.getElementsByTagName("skipped")[0]
assert_attr(fnode, message="collection skipped")
# py.test doesn't give us a line here.
assert tnode["line"] is None
fnode = tnode.find_first_by_tag("skipped")
fnode.assert_attr(message="collection skipped")
def test_unicode(self, testdir):
value = 'hx\xc4\x85\xc4\x87\n'
@@ -321,8 +377,8 @@ class TestPython:
""" % value)
result, dom = runandparse(testdir)
assert result.ret == 1
tnode = dom.getElementsByTagName("testcase")[0]
fnode = tnode.getElementsByTagName("failure")[0]
tnode = dom.find_first_by_tag("testcase")
fnode = tnode.find_first_by_tag("failure")
if not sys.platform.startswith("java"):
assert "hx" in fnode.toxml()
@@ -345,9 +401,9 @@ class TestPython:
print('hello-stdout')
""")
result, dom = runandparse(testdir)
node = dom.getElementsByTagName("testsuite")[0]
pnode = node.getElementsByTagName("testcase")[0]
systemout = pnode.getElementsByTagName("system-out")[0]
node = dom.find_first_by_tag("testsuite")
pnode = node.find_first_by_tag("testcase")
systemout = pnode.find_first_by_tag("system-out")
assert "hello-stdout" in systemout.toxml()
def test_pass_captures_stderr(self, testdir):
@@ -357,27 +413,32 @@ class TestPython:
sys.stderr.write('hello-stderr')
""")
result, dom = runandparse(testdir)
node = dom.getElementsByTagName("testsuite")[0]
pnode = node.getElementsByTagName("testcase")[0]
systemout = pnode.getElementsByTagName("system-err")[0]
node = dom.find_first_by_tag("testsuite")
pnode = node.find_first_by_tag("testcase")
systemout = pnode.find_first_by_tag("system-err")
assert "hello-stderr" in systemout.toxml()
def test_mangle_testnames():
from _pytest.junitxml import mangle_testnames
names = ["a/pything.py", "Class", "()", "method"]
newnames = mangle_testnames(names)
assert newnames == ["a.pything", "Class", "method"]
def test_dont_configure_on_slaves(tmpdir):
gotten = []
class FakeConfig:
def __init__(self):
self.pluginmanager = self
self.option = self
junitprefix = None
#XXX: shouldnt need tmpdir ?
# XXX: shouldnt need tmpdir ?
xmlpath = str(tmpdir.join('junix.xml'))
register = gotten.append
fake_config = FakeConfig()
from _pytest import junitxml
junitxml.pytest_configure(fake_config)
@@ -406,14 +467,12 @@ class TestNonPython:
testdir.tmpdir.join("myfile.xyz").write("hello")
result, dom = runandparse(testdir)
assert result.ret
node = dom.getElementsByTagName("testsuite")[0]
assert_attr(node, errors=0, failures=1, skips=0, tests=1)
tnode = node.getElementsByTagName("testcase")[0]
assert_attr(tnode,
#classname="test_collect_error",
name="myfile.xyz")
fnode = tnode.getElementsByTagName("failure")[0]
assert_attr(fnode, message="custom item runtest failed")
node = dom.find_first_by_tag("testsuite")
node.assert_attr(errors=0, failures=1, skips=0, tests=1)
tnode = node.find_first_by_tag("testcase")
tnode.assert_attr(name="myfile.xyz")
fnode = tnode.find_first_by_tag("failure")
fnode.assert_attr(message="custom item runtest failed")
assert "custom item runtest failed" in fnode.toxml()
@@ -447,6 +506,7 @@ def test_nullbyte_replace(testdir):
text = xmlf.read()
assert '#x0' in text
def test_invalid_xml_escape():
# Test some more invalid xml chars, the full range should be
# tested really but let's just thest the edges of the ranges
@@ -461,14 +521,13 @@ def test_invalid_xml_escape():
unichr(65)
except NameError:
unichr = chr
invalid = (0x00, 0x1, 0xB, 0xC, 0xE, 0x19,
27, # issue #126
0xD800, 0xDFFF, 0xFFFE, 0x0FFFF) #, 0x110000)
valid = (0x9, 0xA, 0x20,) # 0xD, 0xD7FF, 0xE000, 0xFFFD, 0x10000, 0x10FFFF)
invalid = (0x00, 0x1, 0xB, 0xC, 0xE, 0x19, 27, # issue #126
0xD800, 0xDFFF, 0xFFFE, 0x0FFFF) # , 0x110000)
valid = (0x9, 0xA, 0x20, )
# 0xD, 0xD7FF, 0xE000, 0xFFFD, 0x10000, 0x10FFFF)
from _pytest.junitxml import bin_xml_escape
for i in invalid:
got = bin_xml_escape(unichr(i)).uniobj
if i <= 0xFF:
@@ -479,6 +538,7 @@ def test_invalid_xml_escape():
for i in valid:
assert chr(i) == bin_xml_escape(unichr(i)).uniobj
def test_logxml_path_expansion(tmpdir, monkeypatch):
home_tilde = py.path.local(os.path.expanduser('~')).join('test.xml')
@@ -492,6 +552,7 @@ def test_logxml_path_expansion(tmpdir, monkeypatch):
xml_var = LogXML('$HOME%stest.xml' % tmpdir.sep, None)
assert xml_var.logfile == home_var
def test_logxml_changingdir(testdir):
testdir.makepyfile("""
def test_func():
@@ -503,6 +564,7 @@ def test_logxml_changingdir(testdir):
assert result.ret == 0
assert testdir.tmpdir.join("a/x.xml").check()
def test_logxml_makedir(testdir):
"""--junitxml should automatically create directories for the xml file"""
testdir.makepyfile("""
@@ -513,6 +575,7 @@ def test_logxml_makedir(testdir):
assert result.ret == 0
assert testdir.tmpdir.join("path/to/results.xml").check()
def test_escaped_parametrized_names_xml(testdir):
testdir.makepyfile("""
import pytest
@@ -522,46 +585,100 @@ def test_escaped_parametrized_names_xml(testdir):
""")
result, dom = runandparse(testdir)
assert result.ret == 0
node = dom.getElementsByTagName("testcase")[0]
assert_attr(node,
name="test_func[#x00]")
node = dom.find_first_by_tag("testcase")
node.assert_attr(name="test_func[#x00]")
def test_unicode_issue368(testdir):
path = testdir.tmpdir.join("test.xml")
log = LogXML(str(path), None)
ustr = py.builtin._totext("ВНИ!", "utf-8")
from _pytest.runner import BaseReport
class Report(BaseReport):
longrepr = ustr
sections = []
nodeid = "something"
location = 'tests/filename.py', 42, 'TestClass.method'
report = Report()
test_report = Report()
# hopefully this is not too brittle ...
log.pytest_sessionstart()
log._opentestcase(report)
log.append_failure(report)
log.append_collect_error(report)
log.append_collect_skipped(report)
log.append_error(report)
report.longrepr = "filename", 1, ustr
log.append_skipped(report)
report.longrepr = "filename", 1, "Skipped: 卡嘣嘣"
log.append_skipped(report)
report.wasxfail = ustr
log.append_skipped(report)
node_reporter = log._opentestcase(test_report)
node_reporter.append_failure(test_report)
node_reporter.append_collect_error(test_report)
node_reporter.append_collect_skipped(test_report)
node_reporter.append_error(test_report)
test_report.longrepr = "filename", 1, ustr
node_reporter.append_skipped(test_report)
test_report.longrepr = "filename", 1, "Skipped: 卡嘣嘣"
node_reporter.append_skipped(test_report)
test_report.wasxfail = ustr
node_reporter.append_skipped(test_report)
log.pytest_sessionfinish()
def test_record_property(testdir):
testdir.makepyfile("""
def test_record(record_xml_property):
import pytest
@pytest.fixture
def other(record_xml_property):
record_xml_property("bar", 1)
def test_record(record_xml_property, other):
record_xml_property("foo", "<1");
""")
result, dom = runandparse(testdir, '-rw')
node = dom.getElementsByTagName("testsuite")[0]
tnode = node.getElementsByTagName("testcase")[0]
psnode = tnode.getElementsByTagName('properties')[0]
pnode = psnode.getElementsByTagName('property')[0]
assert_attr(pnode, name="foo", value="<1")
node = dom.find_first_by_tag("testsuite")
tnode = node.find_first_by_tag("testcase")
psnode = tnode.find_first_by_tag('properties')
pnodes = psnode.find_by_tag('property')
pnodes[0].assert_attr(name="bar", value="1")
pnodes[1].assert_attr(name="foo", value="<1")
result.stdout.fnmatch_lines('*C3*test_record_property.py*experimental*')
def test_random_report_log_xdist(testdir):
"""xdist calls pytest_runtest_logreport as they are executed by the slaves,
with nodes from several nodes overlapping, so junitxml must cope with that
to produce correct reports. #1064
"""
pytest.importorskip('xdist')
testdir.makepyfile("""
import pytest, time
@pytest.mark.parametrize('i', list(range(30)))
def test_x(i):
assert i != 22
""")
_, dom = runandparse(testdir, '-n2')
suite_node = dom.find_first_by_tag("testsuite")
failed = []
for case_node in suite_node.find_by_tag("testcase"):
if case_node.find_first_by_tag('failure'):
failed.append(case_node['name'])
assert failed == ['test_x[22]']
def test_runs_twice(testdir):
f = testdir.makepyfile('''
def test_pass():
pass
''')
result = testdir.runpytest(f, f, '--junitxml', testdir.tmpdir.join("test.xml"))
assert 'INTERNALERROR' not in str(result.stdout)
def test_runs_twice_xdist(testdir):
pytest.importorskip('xdist')
f = testdir.makepyfile('''
def test_pass():
pass
''')
result = testdir.runpytest(f,
'--dist', 'each', '--tx', '2*popen',
'--junitxml', testdir.tmpdir.join("test.xml"))
assert 'INTERNALERROR' not in str(result.stdout)

View File

@@ -1,7 +1,8 @@
# encoding: utf-8
import sys
import pytest
class TestPasting:
class TestPasteCapture:
@pytest.fixture
def pastebinlist(self, monkeypatch, request):
@@ -27,6 +28,7 @@ class TestPasting:
assert reprec.countoutcomes() == [1,1,1]
def test_all(self, testdir, pastebinlist):
from _pytest.pytester import LineMatcher
testpath = testdir.makepyfile("""
import pytest
def test_pass():
@@ -39,9 +41,34 @@ class TestPasting:
reprec = testdir.inline_run(testpath, "--pastebin=all", '-v')
assert reprec.countoutcomes() == [1,1,1]
assert len(pastebinlist) == 1
s = pastebinlist[0]
for x in 'test_fail test_skip test_pass'.split():
assert x in s
contents = pastebinlist[0].decode('utf-8')
matcher = LineMatcher(contents.splitlines())
matcher.fnmatch_lines([
'*test_pass PASSED*',
'*test_fail FAILED*',
'*test_skip SKIPPED*',
'*== 1 failed, 1 passed, 1 skipped in *'
])
def test_non_ascii_paste_text(self, testdir):
"""Make sure that text which contains non-ascii characters is pasted
correctly. See #1219.
"""
testdir.makepyfile(test_unicode="""
# encoding: utf-8
def test():
assert '' == 1
""")
result = testdir.runpytest('--pastebin=all')
if sys.version_info[0] == 3:
expected_msg = "*assert '' == 1*"
else:
expected_msg = "*assert '\\xe2\\x98\\xba' == 1*"
result.stdout.fnmatch_lines([
expected_msg,
"*== 1 failed in *",
'*Sending information to Paste Service*',
])
class TestPaste:
@@ -62,7 +89,7 @@ class TestPaste:
class DummyFile:
def read(self):
# part of html of a normal response
return 'View <a href="/raw/3c0c6750bd">raw</a>.'
return b'View <a href="/raw/3c0c6750bd">raw</a>.'
return DummyFile()
if sys.version_info < (3, 0):
@@ -74,14 +101,15 @@ class TestPaste:
return calls
def test_create_new_paste(self, pastebin, mocked_urlopen):
result = pastebin.create_new_paste('full-paste-contents')
result = pastebin.create_new_paste(b'full-paste-contents')
assert result == 'https://bpaste.net/show/3c0c6750bd'
assert len(mocked_urlopen) == 1
url, data = mocked_urlopen[0]
assert type(data) is bytes
lexer = 'python3' if sys.version_info[0] == 3 else 'python'
assert url == 'https://bpaste.net'
assert 'lexer=%s' % lexer in data
assert 'code=full-paste-contents' in data
assert 'expiry=1week' in data
assert 'lexer=%s' % lexer in data.decode()
assert 'code=full-paste-contents' in data.decode()
assert 'expiry=1week' in data.decode()

View File

@@ -145,6 +145,23 @@ class TestPytestPluginInteractions:
assert len(warnings) == len(before) + 1
assert "deprecated" in warnings[-1]
def test_warn_on_deprecated_addhooks(self, pytestpm):
warnings = []
class get_warnings:
def pytest_logwarning(self, code, fslocation, message, nodeid):
warnings.append(message)
class Plugin:
def pytest_testhook():
pass
pytestpm.register(get_warnings())
before = list(warnings)
pytestpm.addhooks(Plugin())
assert len(warnings) == len(before) + 1
assert "deprecated" in warnings[-1]
def test_namespace_has_default_and_env_plugins(testdir):
p = testdir.makepyfile("""

View File

@@ -63,32 +63,31 @@ class TestWarningsRecorderChecker(object):
with rec:
pass # can't enter twice
#
# ============ test pytest.deprecated_call() ==============
#
def dep(i):
if i == 0:
py.std.warnings.warn("is deprecated", DeprecationWarning)
return 42
reg = {}
def dep_explicit(i):
if i == 0:
py.std.warnings.warn_explicit("dep_explicit", category=DeprecationWarning,
filename="hello", lineno=3)
class TestDeprecatedCall(object):
"""test pytest.deprecated_call()"""
def dep(self, i, j=None):
if i == 0:
py.std.warnings.warn("is deprecated", DeprecationWarning,
stacklevel=1)
return 42
def dep_explicit(self, i):
if i == 0:
py.std.warnings.warn_explicit("dep_explicit", category=DeprecationWarning,
filename="hello", lineno=3)
def test_deprecated_call_raises(self):
excinfo = pytest.raises(AssertionError,
"pytest.deprecated_call(dep, 3)")
with pytest.raises(AssertionError) as excinfo:
pytest.deprecated_call(self.dep, 3, 5)
assert str(excinfo).find("did not produce") != -1
def test_deprecated_call(self):
pytest.deprecated_call(dep, 0)
pytest.deprecated_call(self.dep, 0, 5)
def test_deprecated_call_ret(self):
ret = pytest.deprecated_call(dep, 0)
ret = pytest.deprecated_call(self.dep, 0)
assert ret == 42
def test_deprecated_call_preserves(self):
@@ -104,12 +103,47 @@ class TestDeprecatedCall(object):
assert warn_explicit is py.std.warnings.warn_explicit
def test_deprecated_explicit_call_raises(self):
pytest.raises(AssertionError,
"pytest.deprecated_call(dep_explicit, 3)")
with pytest.raises(AssertionError):
pytest.deprecated_call(self.dep_explicit, 3)
def test_deprecated_explicit_call(self):
pytest.deprecated_call(dep_explicit, 0)
pytest.deprecated_call(dep_explicit, 0)
pytest.deprecated_call(self.dep_explicit, 0)
pytest.deprecated_call(self.dep_explicit, 0)
def test_deprecated_call_pending(self):
def f():
py.std.warnings.warn(PendingDeprecationWarning("hi"))
pytest.deprecated_call(f)
def test_deprecated_call_specificity(self):
other_warnings = [Warning, UserWarning, SyntaxWarning, RuntimeWarning,
FutureWarning, ImportWarning, UnicodeWarning]
for warning in other_warnings:
def f():
py.std.warnings.warn(warning("hi"))
with pytest.raises(AssertionError):
pytest.deprecated_call(f)
def test_deprecated_function_already_called(self, testdir):
"""deprecated_call should be able to catch a call to a deprecated
function even if that function has already been called in the same
module. See #1190.
"""
testdir.makepyfile("""
import warnings
import pytest
def deprecated_function():
warnings.warn("deprecated", DeprecationWarning)
def test_one():
deprecated_function()
def test_two():
pytest.deprecated_call(deprecated_function)
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines('*=== 2 passed in *===')
class TestWarns(object):
@@ -181,4 +215,3 @@ class TestWarns(object):
''')
result = testdir.runpytest()
result.stdout.fnmatch_lines(['*2 passed in*'])

View File

@@ -779,10 +779,10 @@ def test_terminal_summary(testdir):
("green", "1 passed, 1 xpassed", {"xpassed": (1,), "passed": (1,)}),
# Likewise if no tests were found at all
("yellow", "", {}),
("yellow", "no tests ran", {}),
# Test the empty-key special case
("yellow", "", {"": (1,)}),
("yellow", "no tests ran", {"": (1,)}),
("green", "1 passed", {"": (1,), "passed": (1,)}),

View File

@@ -136,6 +136,41 @@ def test_tmpdir_fallback_tox_env(testdir, monkeypatch):
reprec.assertoutcome(passed=1)
@pytest.fixture
def break_getuser(monkeypatch):
monkeypatch.setattr('os.getuid', lambda: -1)
# taken from python 2.7/3.4
for envvar in ('LOGNAME', 'USER', 'LNAME', 'USERNAME'):
monkeypatch.delenv(envvar, raising=False)
@pytest.mark.usefixtures("break_getuser")
@pytest.mark.skipif(sys.platform.startswith('win'), reason='no os.getuid on windows')
def test_tmpdir_fallback_uid_not_found(testdir):
"""Test that tmpdir works even if the current process's user id does not
correspond to a valid user.
"""
testdir.makepyfile("""
import pytest
def test_some(tmpdir):
assert tmpdir.isdir()
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
@pytest.mark.usefixtures("break_getuser")
@pytest.mark.skipif(sys.platform.startswith('win'), reason='no os.getuid on windows')
def test_get_user_uid_not_found():
"""Test that get_user() function works even if the current process's
user id does not correspond to a valid user (e.g. running pytest in a
Docker container with 'docker run -u'.
"""
from _pytest.tmpdir import get_user
assert get_user() is None
@pytest.mark.skipif(not sys.platform.startswith('win'), reason='win only')
def test_get_user(monkeypatch):
"""Test that get_user() function works even if environment variables

View File

@@ -718,3 +718,19 @@ def test_unittest_raise_skip_issue748(testdir):
*SKIP*[1]*test_foo.py*skipping due to reasons*
*1 skipped*
""")
@pytest.mark.skipif("sys.version_info < (2,7)")
def test_unittest_skip_issue1169(testdir):
testdir.makepyfile(test_foo="""
import unittest
class MyTestCase(unittest.TestCase):
@unittest.skip("skipping due to reasons")
def test_skip(self):
self.fail()
""")
result = testdir.runpytest("-v", '-rs')
result.stdout.fnmatch_lines("""
*SKIP*[1]*skipping due to reasons*
*1 skipped*
""")

16
tox.ini
View File

@@ -3,7 +3,7 @@ minversion=2.0
distshare={homedir}/.tox/distshare
envlist=
flakes,py26,py27,py33,py34,py35,pypy,
{py27,py34}-{pexpect,xdist,trial},
{py27,py35}-{pexpect,xdist,trial},
py27-nobyte,doctesting,py27-cxfreeze
[testenv]
@@ -43,7 +43,7 @@ deps=pytest-xdist>=1.13
commands=
py.test -n1 -rfsxX {posargs:testing}
[testenv:py34-xdist]
[testenv:py35-xdist]
deps={[testenv:py27-xdist]deps}
commands=
py.test -n3 -rfsxX {posargs:testing}
@@ -55,7 +55,7 @@ deps=pexpect
commands=
py.test -rfsxX test_pdb.py test_terminal.py test_unittest.py
[testenv:py34-pexpect]
[testenv:py35-pexpect]
changedir=testing
platform=linux|darwin
deps={[testenv:py27-pexpect]deps}
@@ -75,8 +75,7 @@ deps=twisted
commands=
py.test -rsxf {posargs:testing/test_unittest.py}
[testenv:py34-trial]
# py34-trial does not work
[testenv:py35-trial]
platform=linux|darwin
deps={[testenv:py27-trial]deps}
commands=
@@ -105,12 +104,15 @@ commands= py.test -rfsxX {posargs}
[testenv:regen]
changedir=doc/en
basepython = python3.4
deps=sphinx
PyYAML
whitelist_externals=rm
regendoc>=0.6.1
whitelist_externals=
rm
make
commands=
rm -rf /tmp/doc-exec*
#pip install pytest==2.3.4
make regen
[testenv:jython]