Compare commits

...

581 Commits
2.9.2 ... 3.0.2

Author SHA1 Message Date
Bruno Oliveira
4e58c9a7d0 Fix use of deprecated getfuncargvalue method in the internal doctest plugin
Fix #1898
2016-09-01 07:19:11 -04:00
Bruno Oliveira
a9f3053f72 Fix version typo in announce for 3.0.2 2016-09-01 06:59:31 -04:00
Bruno Oliveira
d512e7f26b Run regendoc for 3.0.2 release 2016-08-31 20:32:05 -04:00
Bruno Oliveira
f985f47a02 Fix reportingdemo call to pytest 2016-08-31 20:30:06 -04:00
Bruno Oliveira
4c45b93007 Changes for 3.0.2 release 2016-08-31 20:28:38 -04:00
Bruno Oliveira
a094fb3aa6 Merge pull request #1890 from mbyt/disable_tearDown_and_cleanups_for_post_mortem_debugging
unittest runner: avoid tearDown and cleanup to ease post mortem debugging
2016-08-31 21:09:45 -03:00
mbyt
e43d1174f7 spelling 2016-08-31 22:46:40 +02:00
mbyt
696a9112be integrating review commets of @nicoddemus
plus small scale refactoring
2016-08-31 22:33:47 +02:00
mbyt
be08223d5a Merge branch 'master' into disable_tearDown_and_cleanups_for_post_mortem_debugging
Conflicts:
	CHANGELOG.rst
2016-08-31 20:35:31 +02:00
mbyt
10b3274924 adding corresponding test, authors and changelog 2016-08-31 20:22:54 +02:00
Florian Bruhin
67ba8aaaa2 Merge pull request #1891 from nicoddemus/find-spec-rewrite-hook
Fix issue pytest_plugins as string was marking wrong modules for rewrite
2016-08-31 05:23:33 +02:00
Bruno Oliveira
edf8283bd8 Add CHANGELOG entry for #1888 2016-08-30 23:13:27 -03:00
Bruno Oliveira
c8a366e551 Fix issue where pytest_plugins as string was marking wrong modules for rewrite
Fix #1888
2016-08-30 22:53:50 -03:00
mbyt
4eeb475138 avoid tearDown and cleanup for unittest debugging 2016-08-30 21:55:49 +02:00
Bruno Oliveira
82218e4ee1 Merge pull request #1887 from mbyt/pdbcls_example_with_tab_completion
pdbcls ipython example with tab completion
2016-08-29 17:11:51 -03:00
mbyt
8593bb12ee pdbcls ipython example with tab completion 2016-08-29 21:15:12 +02:00
Raphael Pierzina
e75078eae2 Merge pull request #1848 from pytest-dev/doc-warnings
docs warnings as errors and initial page similar to README
2016-08-26 23:02:28 +01:00
Bruno Oliveira
519f02b014 docs warnings as errors and initial page similar to README
* Changed "index" to be more similar to the README (#1708).
* Fixes numerous issues like missing documents, syntax errors, etc (#1829, #432).
* Mention all docs in "contents.rst" so it's easier for users to locate (#1112).
* Add doc generation and checking to Travis and AppVeyor, to avoid re-introducing errors.

Fixes #432, Fixes #1112, Fixes #1708, Fixes #1829
2016-08-26 17:47:18 -03:00
Florian Bruhin
cb7c472e34 Merge pull request #1876 from nicoddemus/remove-monkeypatch-invocation-example
Remove example of "monkeypatch" used in session scope
2016-08-26 06:15:07 +02:00
Bruno Oliveira
a947e83be9 Merge pull request #1870 from AiOO/bugfix/assertion-with-unicode
Fix UnicodeEncodeError when string comparison with unicode has failed.
2016-08-25 22:29:32 -03:00
Bruno Oliveira
e92d373460 Remove example of "monkeypatch" used in session scope
This is a leftover when invocation-scoped fixtures
were pulled back.

Fix #1872
2016-08-25 21:50:57 -03:00
Ahn Ki-Wook
86b8801470 Update AUTHORS and CHANGELOG 2016-08-26 09:42:17 +09:00
Ahn Ki-Wook
856ad719d3 Fix UnicodeEncodeError when string comparison with unicode has failed. 2016-08-26 09:41:40 +09:00
Ronny Pfannschmidt
9c45d6cd83 Merge pull request #1866 from joguSD/bugfix-stdin-stub-buffer
Add buffer attribute to DontReadFromInput
2016-08-25 07:07:44 +02:00
Jordan Guymon
a152ea2dbb Add buffer attribute to stdin stub 2016-08-24 16:26:34 -07:00
Florian Bruhin
3345ac9216 Merge pull request #1861 from nicoddemus/ids-invalid-type-msg
Improve error message when passing non-string ids to pytest.mark.parametrize
2016-08-24 06:43:57 +02:00
Bruno Oliveira
972a5fb5d5 Improve error message when passing non-string ids to pytest.mark.parametrize
Fix #1857
2016-08-23 23:31:45 -03:00
Bruno Oliveira
ea0febad28 Updates for new patch version 3.0.2 2016-08-23 21:33:57 -03:00
Bruno Oliveira
ecb20b96fc Merge pull request #1856 from nicoddemus/release-3.0.1
Changes for 3.0.1 release
2016-08-23 21:21:24 -03:00
Bruno Oliveira
49fc4e5e4c Changes for 3.0.1 release 2016-08-23 18:15:43 -04:00
Florian Bruhin
3c866e7080 Merge pull request #1855 from nicoddemus/fix-empty-parametrize-ids
Fix internal error when parametrizing using and empty list of ids()
2016-08-23 23:38:27 +02:00
Bruno Oliveira
df200297e2 Fix internal error when parametrizing using and empty list of ids()
Fix #1849
2016-08-23 18:18:46 -03:00
Ronny Pfannschmidt
7538680c98 Merge pull request #1847 from nicoddemus/parametrize-session-scopes
Fix code which guesses parametrized scope based on arguments
2016-08-23 18:03:52 +02:00
Bruno Oliveira
847067fb02 Merge pull request #1851 from adamchainz/deprecated_setup.cfg
Delete unreferenced setup.cfg from docs
2016-08-23 12:35:48 -03:00
Adam Chainz
1673667232 Delete unreferenced setup.cfg from docs
Noticed it's not using the new `[tool:pytest]` header as changed in #567, can't find any reference to it or `testfilepatterns`. It was added in b1e4301457 6 years ago, there don't seem to have ever been references to it.
2016-08-23 16:08:24 +01:00
Bruno Oliveira
53a0e2b118 Fix code which guesses parametrized scope based on arguments
Fix #1832
2016-08-22 21:05:41 -03:00
Bruno Oliveira
d99ceb1218 Merge pull request #1844 from nicoddemus/importer-error
Importer loader error
2016-08-22 20:47:25 -03:00
Bruno Oliveira
b54ea74d4d Update AUTHORS and CHANGELOG for #1837 2016-08-22 17:59:42 -03:00
Bruno Oliveira
6a8160b318 Add acceptance test for module loader
Related to #1837
2016-08-22 17:57:25 -03:00
Bruno Oliveira
c3148d1d6b Merge pull request #1842 from Stranger6667/doc-fix
Fix documentation
2016-08-22 14:11:36 -03:00
Bruno Oliveira
b0ede044ac Merge pull request #1835 from RonnyPfannschmidt/mark-extract-param
mark plugin: move the unclean marked parameter extraction
2016-08-22 14:11:11 -03:00
Dmitry Dygalo
3fbf2e7a80 Fix documentation 2016-08-22 18:38:02 +02:00
Florian Bruhin
af0ec120fe Merge pull request #1836 from asvetlov/patch-1
Remove duplicated name
2016-08-21 22:09:58 +02:00
Marcin Bachry
678750c8f8 Fix importer call 2016-08-21 22:07:18 +02:00
Andrew Svetlov
4e9c1fbe96 Remove duplicated name 2016-08-21 22:20:29 +03:00
Ronny Pfannschmidt
406777d104 mark plugin: move the unclean marked parameter extraction 2016-08-21 20:44:37 +02:00
Florian Bruhin
abe8f5e23f Merge pull request #1824 from nicoddemus/update-howtorelease
Update HOWTORELEASE based on the 3.0.0 release
2016-08-20 23:03:59 +02:00
Bruno Oliveira
6a0e849067 Update HOWTORELEASE based on the 3.0.0 release 2016-08-20 15:47:34 -03:00
Florian Bruhin
a20c3f9c44 Merge pull request #1827 from blueyed/Fix-spelling-s-outside-a-outside-of-a-
Fix spelling: s/outside a/outside of a/
2016-08-20 20:04:58 +02:00
Florian Bruhin
783aff17dd Merge pull request #1828 from blueyed/minor-s-no-pkg_resources-pkg_resources-
minor: s/no pkg_resources/pkg_resources/
2016-08-20 20:04:48 +02:00
Daniel Hahler
86ec3f37af minor: s/no pkg_resources/pkg_resources/ 2016-08-20 18:47:42 +02:00
Daniel Hahler
e306a53999 Fix spelling: s/outside a/outside of a/ 2016-08-20 18:43:39 +02:00
Florian Bruhin
90fb8cb08b Merge pull request #1823 from nicoddemus/importorskip-regression
Fix regression when using importorskip at module level
2016-08-20 18:37:14 +02:00
Bruno Oliveira
5129c2f867 Merge pull request #1826 from blueyed/Remove-duplicate-entry-for-#717-in-CHANGELOG
Remove duplicate entry for #717 in CHANGELOG
2016-08-20 11:21:53 -03:00
Daniel Hahler
87d2d1d838 Remove duplicate entry for #717 in CHANGELOG 2016-08-20 15:12:08 +02:00
Bruno Oliveira
9aec8d9a47 py.test team -> Pytest team :) 2016-08-19 18:59:13 -03:00
Bruno Oliveira
c8f53d6690 Fix typo in 3.0.0 release announcement 2016-08-19 18:58:14 -03:00
Bruno Oliveira
875bcd4224 Add 3.0.0 release announcement to index.rst 2016-08-19 18:30:11 -03:00
Bruno Oliveira
63dc71c57e Fix regression when using importorskip at module level
Fix #1822
2016-08-19 18:21:25 -03:00
Bruno Oliveira
3a200b75c9 Bump version to 3.0.1.dev 2016-08-19 17:41:45 -03:00
Bruno Oliveira
745c8c17f1 Merge remote-tracking branch 'upstream/master' 2016-08-19 17:38:21 -03:00
Bruno Oliveira
5ecf3d78f1 Merge pull request #1819 from matthiasha/patch-1
Documentation update for rootdir discovery
2016-08-19 17:36:44 -03:00
Bruno Oliveira
b85a3b0d71 Merge pull request #1820 from The-Compiler/changelog-duplicates
Remove duplicate CHANGELOG messages
2016-08-19 17:35:23 -03:00
Bruno Oliveira
8777f61e7b Merge pull request #1818 from nicoddemus/release-3.0
Release 3.0
2016-08-19 17:33:15 -03:00
Florian Bruhin
31ede2432c Remove duplicate CHANGELOG messages
Those are both already mentioned in the breaking changes at the top.
2016-08-19 17:05:02 +02:00
matthiasha
c8fbf3ae34 remove dot in pytest 2016-08-19 14:02:25 +02:00
matthiasha
3455dfc804 add missing @matthiasha link 2016-08-19 14:01:07 +02:00
matthiasha
cd39cc1eec Mention doc update in CHANGELOG 2016-08-19 09:08:11 +02:00
matthiasha
ccfa8d15bf Update AUTHORS 2016-08-19 09:04:19 +02:00
matthiasha
799dab9dba Documentation update for rootdir discovery
This covers issue https://github.com/pytest-dev/pytest/issues/1435.
2016-08-19 09:01:12 +02:00
Bruno Oliveira
c74ce371ab Add release announcement 2016-08-18 12:02:01 -04:00
Bruno Oliveira
7f18367582 Finalize CHANGELOG 2016-08-18 11:43:21 -04:00
Bruno Oliveira
a3e6c14da3 Bump version to 3.0.0 2016-08-18 11:41:10 -04:00
Florian Bruhin
be9356aeba Merge pull request #1817 from nicoddemus/regendoc-run
Run regendoc for 3.0 release
2016-08-18 15:31:03 +02:00
Bruno Oliveira
9ce30e0085 Run regendoc for 3.0 release 2016-08-18 08:27:16 -04:00
Bruno Oliveira
3748112a94 Merge pull request #1816 from nicoddemus/merge-master-into-features
Merge master into features
2016-08-18 08:48:01 -03:00
Bruno Oliveira
0334e75c30 Use "pytest" instead of "py.test" on trial environments 2016-08-18 08:37:55 -03:00
Bruno Oliveira
56df9fcc72 Tweak CHANGELOG: move "change" entry to the proper place 2016-08-17 23:08:13 -03:00
Bruno Oliveira
66673c0dd3 Remove obsolete docstring 2016-08-17 22:59:18 -03:00
Bruno Oliveira
030c42203d Fix conflicts in CHANGELOG 2016-08-17 22:58:12 -03:00
Bruno Oliveira
3ba475c0f2 Move internal _is_unittest_unexpected_success_a_failure to "compat" module
Fix #1815
2016-08-17 22:50:10 -03:00
Bruno Oliveira
463e6572c5 Merge branch 'master' into merge-master-into-features
Preparing for 3.0
2016-08-17 22:39:23 -03:00
Bruno Oliveira
3e685d6a8d Merge pull request #1795 from hackebrot/fix-report-outcome-for-xpass
WIP Change outcome to 'passed' for xfail unless it's strict
2016-08-17 22:18:06 -03:00
Bruno Oliveira
68ebf552a1 Merge remote-tracking branch 'upstream/master' into fix-report-outcome-for-xpass 2016-08-17 21:55:10 -03:00
Bruno Oliveira
a01cbce662 Merge pull request #1814 from nicoddemus/py35-trial-windows
Enable py35-trial testenv on Windows
2016-08-17 21:54:47 -03:00
Bruno Oliveira
0fb34cd2a1 Update CHANGELOG entries 2016-08-17 21:32:07 -03:00
Bruno Oliveira
224ef67374 Quick fix for tests in config depended on the current directory
When running those tests from pytest's root folder, they would
fail because they would end up picking pytest's own pytest.ini
2016-08-17 21:32:05 -03:00
Bruno Oliveira
4ed412eb59 unittest's unexpectedSuccess should work as non-strict xpass
Make sure tests for that behavior obtain the same return code
using either pytest or unittest to run the same file
2016-08-17 21:32:04 -03:00
Bruno Oliveira
92498109e4 Enable py35-trial testenv on Windows 2016-08-17 21:20:12 -03:00
Raphael Pierzina
dfc659f781 Fix sys.version_info expression in xfail marker 2016-08-17 23:32:56 +01:00
Raphael Pierzina
0173952961 Fix py3 xfail expression evaluation and parametrize strict 2016-08-17 23:15:14 +01:00
Raphael Pierzina
767c28d422 Fix broken test in test_junitxml 2016-08-17 22:32:27 +01:00
Raphael Pierzina
d1f2f779ee Use a better xfail reason 2016-08-17 22:31:56 +01:00
Raphael Pierzina
bb3d6d87b6 Merge branch 'master' into fix-report-outcome-for-xpass 2016-08-17 22:15:29 +01:00
Raphael Pierzina
018197d72a Fix broken test in test_skipping and add one for strict xfail 2016-08-17 22:14:51 +01:00
Raphael Pierzina
ea379e0e4f Fix test in test_junitxml and add one for strict 2016-08-17 22:02:54 +01:00
Florian Bruhin
789e4670e7 Merge pull request #1813 from nicoddemus/pytest-setup.cfg
Support [tool:pytest] in setup.cfg files
2016-08-17 20:33:57 +02:00
Florian Bruhin
c8ab79402c Merge pull request #1811 from nicoddemus/revert-invocation-fixtures
Revert invocation-fixtures code
2016-08-17 20:32:54 +02:00
Bruno Oliveira
ab86dea529 Support [tool:pytest] in setup.cfg files
Also deprecate [pytest] usage in setup.cfg files

Fix #567
2016-08-17 08:19:38 -03:00
Bruno Oliveira
707b6b5e3f Revert all invocation-fixtures code
Due to a serious regression found in #1794, it was decided to pull off
invocation features from 3.0 so it can be (hopefully) re-introduced
in 3.1
2016-08-17 08:12:55 -03:00
Florian Bruhin
09e647c7d9 Merge pull request #1812 from nicoddemus/deprecate-resultlog
Deprecate --resultlog cmdline option
2016-08-17 09:17:13 +02:00
Bruno Oliveira
f25771a101 Deprecate --resultlog cmdline option
Fix #830
2016-08-16 21:40:34 -03:00
Raphael Pierzina
55ec1d7f56 Update test_junitxml.py to interpret XPASS as passed 2016-08-15 23:58:16 +01:00
Bruno Oliveira
497152505e Add CHANGELOG entry for #1809 2016-08-15 19:31:00 -03:00
Bruno Oliveira
ca5957932b Merge pull request #1806 from blueyed/fix-off-by-one-error-with-warnings
Fix off-by-one error with lines from request.node.warn
2016-08-15 19:04:00 -03:00
Bruno Oliveira
d58a8e36d7 Merge pull request #1807 from blueyed/improve-multiline-error-format
Improve display of continuation lines with multiline errors
2016-08-15 19:03:35 -03:00
Bruno Oliveira
d3b855104c Merge pull request #1809 from blueyed/exitstatus-with-pytest_terminal_summary
Pass exitstatus to pytest_terminal_summary hook
2016-08-15 19:02:30 -03:00
Daniel Hahler
c163cc7937 Improve display of continuation lines with multiline errors
Fixes https://github.com/pytest-dev/pytest/issues/717.
Follow-up to https://github.com/pytest-dev/pytest/pull/1762.
2016-08-14 22:34:31 +02:00
Daniel Hahler
16cb5d01b1 Fix off-by-one error with lines from request.node.warn
The line numbers in `node.location` seem to be zero-based?!
2016-08-14 22:10:01 +02:00
Daniel Hahler
5b95ee3c19 Pass exitstatus to pytest_terminal_summary hook
This is useful to know if a testrun has been interrupted
(EXIT_INTERRUPTED).
2016-08-14 22:06:35 +02:00
Raphael Pierzina
225341cf2c Set wasxfail only for xpass w/o strict and else set longrepr 2016-08-13 00:00:51 +01:00
Raphael Pierzina
14a4dd0697 Extend test to verify longrepr in stdout 2016-08-12 23:31:38 +01:00
Raphael Pierzina
296f42a2c9 Treat unittest.expectedFailure pass as a failure 2016-08-12 23:18:36 +01:00
Raphael Pierzina
10a6ed1707 Update unittest test to expect failure for an unexpected success 2016-08-12 23:18:02 +01:00
Bruno Oliveira
34925a31a9 Merge pull request #1799 from cryporchild/junitxml-tests-tally-fix
Fix #1798 to include errors in total tests in junit xml output.
2016-08-08 10:43:38 -03:00
Christian Boelsen
c4d9c7ea55 Add thanks as requested. 2016-08-08 13:45:10 +01:00
Christian Boelsen
e4028b4505 Fix #1798 to include errors in total tests in junit xml output. 2016-08-08 13:35:49 +01:00
Floris Bruynooghe
99a4a1a784 Merge pull request #1791 from nicoddemus/ide-integration-1790
Internal adjustments for easier integration with IDEs
2016-08-07 23:50:50 +01:00
Bruno Oliveira
4ab2e57ebd Merge pull request #1797 from nicoddemus/merge-master-into-features
Merge master into features
2016-08-06 18:48:40 -03:00
Bruno Oliveira
802755ceed Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2016-08-06 17:58:17 -03:00
Bruno Oliveira
ac5c39e534 Merge pull request #1796 from nicoddemus/fix-rootdir-common-ancestor
Fix rootdir common ancestor
2016-08-06 17:38:42 -03:00
Bruno Oliveira
21230aa017 Add CHANGELOG entry 2016-08-06 17:14:13 -03:00
Dave Hunt
eb08135280 Update documentation to describe expected rootdir behaviour 2016-08-06 19:35:40 +02:00
Daniel Hahler
a2891420de Fix determining rootdir from common_ancestor 2016-08-06 19:35:40 +02:00
Raphael Pierzina
4fc20d09fe Change outcome to 'passed' for xfail unless it's strict 2016-08-05 19:25:55 +01:00
Bruno Oliveira
1a79137d04 Add originalname attribute to Function
Related to #1790
2016-08-03 22:56:12 -03:00
Bruno Oliveira
530b0050b4 Improve TestReport.sections docs a bit
Related to #1790
2016-08-03 21:57:58 -03:00
Bruno Oliveira
ff296fd541 Add capstdout and capstderr attrs to TestReport
Related to #1790
2016-08-03 21:49:43 -03:00
Bruno Oliveira
08002ab75a Add longreprtext property to TestReport objects
Related to #1790
2016-08-03 21:49:28 -03:00
Bruno Oliveira
6759b042b5 Merge pull request #1789 from nicoddemus/regendoc-take-2
Regendoc take 2
2016-08-03 18:21:36 -03:00
Bruno Oliveira
8b8c698f1a Add more interpreter versions to multipython example 2016-08-03 16:48:49 -04:00
Bruno Oliveira
d28801d794 Make parametrize example deterministic 2016-08-03 16:48:11 -04:00
Bruno Oliveira
72df32f1fd Fix missing print() 2016-08-03 17:34:55 -03:00
Bruno Oliveira
701d5fc727 Regendoc after more fixes on features branch 2016-08-03 16:31:44 -04:00
Bruno Oliveira
6e3105dc8f Merge pull request #1787 from nicoddemus/fix-rewrite-conftest
Rewrite asserts in test-modules loaded very early in the startup
2016-08-03 16:10:55 -03:00
Bruno Oliveira
6711b1d6ab Rewrite asserts in test-modules loaded very early in the startup
Also now match modules which start with any of the names registered
using register_assert_rewrite as discussed in #1787

Fix #1784
2016-08-03 12:49:48 -03:00
Florian Bruhin
d5be6cba13 Merge pull request #1788 from nicoddemus/available-fixtures-sorted
Sort fixture names when a fixture lookup error occurs
2016-08-03 07:31:28 +02:00
Bruno Oliveira
277b6d3974 Sort fixture names when a fixture lookup error occurs 2016-08-02 19:45:31 -03:00
Bruno Oliveira
ea6191a0cd Merge pull request #1779 from RonnyPfannschmidt/deselect-no-reason
terminal: dont pretend to know the deselection reason
2016-08-02 08:38:17 -03:00
Floris Bruynooghe
9540106fe7 Merge pull request #1780 from nicoddemus/regen-pytest30
Run regen-docs for pytest 3.0
2016-08-02 12:07:16 +01:00
Ronny Pfannschmidt
1c8fe962f3 add changelog entry 2016-08-02 10:51:10 +02:00
Ronny Pfannschmidt
48f4e18280 fix deselect tests to match reason removal 2016-08-02 10:43:25 +02:00
Bruno Oliveira
21a90c8c50 Run regendoc again 2016-08-01 20:12:00 -04:00
Bruno Oliveira
eed21e06db Sort yml items to get same results for regendoc runs 2016-08-01 20:09:35 -04:00
Bruno Oliveira
a6b2732507 Pass list of params to pytest.main() in docs 2016-08-01 20:09:35 -04:00
Bruno Oliveira
946466abf4 Run regen-docs for pytest 3.0 2016-08-01 20:09:35 -04:00
Raphael Pierzina
3cd2e37c55 Merge pull request #1783 from nicoddemus/inv-scoped-fixture-msg
Strip invocation-scope suffix when displaying fixture lookup error
2016-08-02 01:08:25 +01:00
Bruno Oliveira
553dc2600f Strip invocation-scope suffix when displaying fixture lookup error 2016-08-01 20:34:56 -03:00
Raphael Pierzina
226f2795ba Merge pull request #1782 from nicoddemus/invocation-fixtures-help
invocation-scoped fixtures show up once with --fixtures
2016-08-01 23:21:28 +01:00
Bruno Oliveira
b380eb5b34 Merge pull request #1781 from nicoddemus/highlight-file-loc
Highlight the path of file location in error report
2016-08-01 19:18:52 -03:00
Bruno Oliveira
44ecf2ab2f invocation-scoped fixtures show up once with --fixtures 2016-08-01 18:48:29 -03:00
Bruno Oliveira
31c5194562 Fix broken test in py3k 2016-08-01 18:35:42 -03:00
satoru
3c8222f1db Highlight the path of file location in error report
So that it's more obvious when we need to copy the file path.
2016-08-01 17:42:20 -03:00
Ronny Pfannschmidt
ac215e9cff terminal: dont pretend to know the deselection reason
this addresses #1372 - we pretend we know the deselection reason from internal plugins and ignore 3rd party/local reasons
2016-08-01 13:50:59 +02:00
Bruno Oliveira
aa145fa83e Add 'invocation' scope option to fixture docstring 2016-07-29 12:47:30 -03:00
Bruno Oliveira
76fbc6379f Fix deprecated directive in docstring 2016-07-29 12:39:48 -03:00
Bruno Oliveira
80508203b0 Merge pull request #1776 from nicoddemus/pytest-30-version
Set version to 3.0.0.dev1
2016-07-28 21:57:13 -03:00
Bruno Oliveira
eaf8d9ce19 Set version to 3.0.0.dev1
For a long time now we've considering the next version to be 3.0.0
2016-07-28 21:30:16 -03:00
Floris Bruynooghe
510a6083ba Merge pull request #1758 from nicoddemus/deprecated-module
Add deprecation module to centralize deprecation messages and bits of…
2016-07-28 22:36:55 +01:00
Florian Bruhin
ffb583ae91 Merge pull request #1773 from nicoddemus/fix-freeze
Use PyInstaller for freeze test env
2016-07-27 15:06:54 +02:00
Bruno Oliveira
ae9d3bf886 Freeze docs: PyInstaller hook and wording
As discussed during the review, suggest in general
to use PyInstaller and just mention pytest.freeze_includes()
in less detail on how to actually use it, because it varies
from tool to tool.
2016-07-27 09:15:40 -03:00
Florian Bruhin
7b1520687e Merge pull request #1771 from nicoddemus/sort-links-changelog
Sort link refs in CHANGELOG
2016-07-27 06:26:45 +02:00
Florian Bruhin
fd765f854c Merge pull request #1772 from nicoddemus/pdf-link
Fix pdf links in docs and point to docs.pytest.org in README
2016-07-27 06:25:41 +02:00
Bruno Oliveira
ed36d627e4 Use PyInstaller for freeze test env
cx_freeze doesn't seem to be very well supported in Python 3.5.

Using pyinstaller instead and rename environment to "freeze" which
is a more generic term for freezing python code into standalone
executables.

Fix #1769
2016-07-26 22:02:37 -03:00
Bruno Oliveira
9a68681719 Point doc links in README to docs.pytest.org 2016-07-26 20:25:55 -03:00
Bruno Oliveira
0b8a91b858 Fix pdf links in the documentation
Fix #1436
2016-07-26 20:20:22 -03:00
Bruno Oliveira
5565c1f4ae Sort link refs in CHANGELOG 2016-07-26 20:11:49 -03:00
Florian Bruhin
c40dcb3c18 Merge pull request #1768 from ioggstream/1609-fix-description
fix keep-duplicates help line.
2016-07-26 11:34:06 +02:00
Roberto Polli
05728d1317 fix keep-duplicates help line. 2016-07-26 09:53:12 +02:00
Florian Bruhin
b4ad4cc46e Merge pull request #1767 from nicoddemus/merge-master
Merge master into features
2016-07-26 08:44:11 +02:00
Bruno Oliveira
c2864aba3d Merge branch 'master' into merge-master
# Conflicts:
#	AUTHORS
#	CHANGELOG.rst
#	_pytest/monkeypatch.py
#	_pytest/python.py
2016-07-25 19:06:29 -03:00
Bruno Oliveira
9cf09cda7b Remove some comments and improved changelog 2016-07-25 18:41:03 -03:00
Bruno Oliveira
eb5b163698 Merge branch '1609-features' of https://github.com/ioggstream/pytest into features 2016-07-25 18:37:55 -03:00
Bruno Oliveira
d911bfcb8a Merge branch 'issue634-scopes' of https://github.com/Stranger6667/pytest
# Conflicts:
#	CHANGELOG.rst
2016-07-25 18:26:50 -03:00
Bruno Oliveira
8f29ce26e9 Merge branch 'mark_missing_fixture_error' of https://github.com/eolo999/pytest 2016-07-25 18:20:17 -03:00
Bruno Oliveira
6c8b0a28e1 Add deprecation module to centralize deprecation messages and bits of code 2016-07-25 18:14:39 -03:00
Dmitry Dygalo
d72afe7e08 Fixed scope override inside metafunc.parametrize. Fixes #634 2016-07-25 12:42:50 +02:00
Roberto Polli
ab6aef1d1f feature: default behavior now is to ignore duplicate paths specified from the command line. Use --keep-duplicates to retain duplicate paths. 2016-07-25 12:41:58 +02:00
Florian Bruhin
a2b04d02c2 Merge pull request #1759 from Stranger6667/issue1579-invalid-class
Fixed collection of classes with custom ``__new__`` method. Fixes #1579.
2016-07-25 12:27:51 +02:00
Dmitry Dygalo
f7ad173fee Fixed collection of classes with custom `__new__` method 2016-07-25 11:33:37 +02:00
Ronny Pfannschmidt
d37af20527 Merge pull request #1765 from The-Compiler/1763-cleanup
Cleanups for #1763
2016-07-25 10:31:06 +02:00
Florian Bruhin
a309a571d9 Cleanups for #1763 2016-07-25 10:17:46 +02:00
Edoardo Batini
e9d729bd46 drop parenthesis around GH issue number 2016-07-25 10:11:37 +02:00
Bruno Oliveira
c9a2e611ce Merge pull request #1763 from tomviner/issue1210-exit-msg
Fix #1210 display msg for early calls to exit
2016-07-24 13:05:44 -03:00
Bruno Oliveira
a24146dd3c Merge pull request #1757 from tramwaj29/improved-message-when-not-using-parametrized-variable
Improved message when not using parametrized variable
2016-07-24 13:02:03 -03:00
Bruno Oliveira
7862517c28 Merge pull request #1760 from blueyed/followup-pr1718-remove-newline
Followup to #1718: style/formatting
2016-07-24 13:00:14 -03:00
Tom Viner
42adaf5a61 Fix #1210 display msg for early calls to exit 2016-07-24 14:16:34 +02:00
JJ
4aede6faa6 fixed conflicts 2016-07-24 12:10:32 +02:00
JJ
d000f2536a added a test for when the indirect is just a string 2016-07-24 10:47:06 +02:00
Edoardo Batini
0ae77be9f0 Add new target links in CHANGELOG 2016-07-24 00:46:06 +02:00
Daniel Hahler
5c5d7e05f7 Followup to #1718: style/formatting 2016-07-24 00:21:42 +02:00
Edoardo Batini
f450e0a1db Thanks to Tom Viner for his guidance during EuroPython2016 sprint 2016-07-24 00:06:16 +02:00
Edoardo Batini
fabe8cda2f Thanking myself in CHANGELOG 2016-07-23 23:59:34 +02:00
Edoardo Batini
3c4158ac35 Add changelog entry for this bugfix branch 2016-07-23 23:51:11 +02:00
Edoardo Batini
e00199212c Add myself to the AUTHORS 2016-07-23 23:49:44 +02:00
Edoardo Batini
e9a67e6702 Adjust test involving FixtureLookupErrorRepr
I added a starting 'E' to the expected error messages.

The tests were still passing after the previous patch but I think it's
better to have stricter tests.
2016-07-23 23:45:07 +02:00
Edoardo Batini
6799a47c78 Start FixtureLookupErrorRepr with an 'E' 2016-07-23 23:43:34 +02:00
Bruno Oliveira
655df7f839 Merge pull request #1755 from diegorusso/master
Testcase for overriding autouse fixture with a parametrized fixture.
2016-07-23 12:53:24 -03:00
Bruno Oliveira
9891593413 Merge pull request #1754 from hartym/1749_doctest_report_format
Doctest report format option (#1749)
2016-07-23 12:52:54 -03:00
JJ
bbc7f3a631 updated changelog, resolve #1539 2016-07-23 16:57:49 +02:00
Diego Russo
1704b7d265 Test case for overriding autouse fixtures
Test case for overriding autouse fixture with a parametrized fixture.
The test covers the problem explained in the issue 1601
Adding Diego Russo to AUTHORS
2016-07-23 16:53:39 +02:00
JJ
3631719050 added myself to authors 2016-07-23 16:51:55 +02:00
JJ
f26fa5a441 changed error message for unused parametrize name 2016-07-23 16:49:20 +02:00
Romain Dorgueil
94731fc2a1 Changes variable name so it better describes what it does now. 2016-07-23 16:26:33 +02:00
Romain Dorgueil
51fa244650 Cleaner implementation of #1749. 2016-07-23 16:18:12 +02:00
Romain Dorgueil
d5a70acd48 Simplify test in test_doctest_report_none_or_only_first_failure. 2016-07-23 15:58:13 +02:00
Bruno Oliveira
018acc6bae Explain why thanks yourself in the CHANGELOG 2016-07-23 10:44:38 -03:00
Romain Dorgueil
f8f690de64 adds the versionadded flag in docs (#1749) 2016-07-23 15:30:06 +02:00
Romain Dorgueil
e229a27e8b using @pytest.mark.parametrize instead of calling one test many times from another as suggested by @nicoddemus in pr #1754 2016-07-23 15:21:59 +02:00
Romain Dorgueil
ec7695e15d adds a bit of doctest hint on why the key and value getters are separate functions. 2016-07-23 15:19:18 +02:00
Romain Dorgueil
1a33025a76 Refactors test to be in its own class, as discussed with @nicoddemus. 2016-07-23 15:16:23 +02:00
Romain Dorgueil
922a295729 fixes changelog, I think I got it 2016-07-23 15:15:17 +02:00
Romain Dorgueil
014ebc9202 Removed bug reference in changelog because it makes the linting fail. 2016-07-23 15:04:19 +02:00
Romain Dorgueil
87ca4b95fb Separate the option keys and value to avoid importing "doctest" (and tested things like "logging") for argument parsing (fixes #1749) 2016-07-23 14:50:24 +02:00
Romain Dorgueil
fd8e019cc1 Choose the doctest output format in case of failure, still work in progress as a few checks fail (related to #1749) 2016-07-23 14:40:46 +02:00
Romain Dorgueil
625b603f1f Implements an option to choose the doctest output format in case of failure. (fixes #1749) 2016-07-23 13:06:05 +02:00
Bruno Oliveira
38e0e08074 Merge pull request #1751 from javiromero/docstrings
Uppercase first word in docstrings. Change to an imperative form.
2016-07-22 10:33:58 -03:00
Javi Romero
1aab6e3bc2 Add changes to changelog. 2016-07-22 12:54:42 +02:00
Javi Romero
7e37497d5a Uppercase first word in docstrings. Change to an imperative form. Add name to authors. 2016-07-22 12:39:06 +02:00
Bruno Oliveira
ae0798522f Merge pull request #1711 from nicoddemus/invocation-scoped-fixtures
Invocation scoped fixtures
2016-07-21 19:48:52 -03:00
Florian Bruhin
832ada1b44 Merge pull request #1747 from nicoddemus/line-match-stringio
Log LineMatcher output in a stream instead of stderr
2016-07-21 09:38:11 +02:00
Bruno Oliveira
4c112401c5 Log LineMatcher output in a stream instead of stderr
This makes the match/nomatch output appear as part
of the fnmatch_lines() error on pytest's output instead
of globbered together with general stdout/stderr capture
2016-07-20 22:35:43 -03:00
Bruno Oliveira
05f3422d7c Make monkeypatch invocation-scoped 2016-07-20 22:05:49 -03:00
Bruno Oliveira
4f2bf965cb Merge remote-tracking branch 'upstream/features' into invocation-scoped-fixtures 2016-07-20 21:16:27 -03:00
Bruno Oliveira
eaa4ee3fdf Merge pull request #1746 from pytest-dev/conftest-exception-printing
Conftest exception printing
2016-07-20 21:03:39 -03:00
Bruno Oliveira
6aea164b6d Add more tests for invocation scoped fixtures 2016-07-20 21:02:36 -03:00
Bruno Oliveira
20f97c3041 Small documentation improvements 2016-07-20 20:22:28 -03:00
Bruno Oliveira
e0f08a73ab Merge branch 'features' into conftest-exception-printing 2016-07-20 19:33:36 -03:00
Bruno Oliveira
93aae987a2 Merge pull request #1744 from RonnyPfannschmidt/existfirst-override
allow --exitfirst/-x to be overridden by a following --maxfail
2016-07-20 18:16:07 -03:00
Bruno Oliveira
1204cbade4 Merge pull request #1745 from RonnyPfannschmidt/skip-compat
skipping plugin: remove python2.5 compat code
2016-07-20 18:14:20 -03:00
Ronny Pfannschmidt
9dadaa8a41 skipping plugin: remove python2.5 compat code 2016-07-20 17:45:20 +02:00
Ronny Pfannschmidt
0403266bf0 record --exitfirst change in changelog 2016-07-20 17:23:07 +02:00
Ronny Pfannschmidt
3fd8257c17 add test for --maxfail=NUM overiding -x 2016-07-20 17:20:10 +02:00
Ronny Pfannschmidt
2a05c311e9 implement exitfirst as store_const option
this makes it possible to override with a later maxfail
2016-07-20 17:15:29 +02:00
Bruno Oliveira
bcc58ec916 Merge pull request #1740 from RonnyPfannschmidt/float-argument
optparse compatibility - add float and complex
2016-07-19 19:17:35 -03:00
Ronny Pfannschmidt
9af872a230 update changelog 2016-07-19 20:11:47 +02:00
Ronny Pfannschmidt
61cc5c4d4e argument parsing: always warn for string types
fix #1741
2016-07-19 10:33:25 +02:00
Ronny Pfannschmidt
317b3f257d optparse compatibility - add float and complex
also documents the implementation quality
fixes #457
2016-07-19 10:20:41 +02:00
Floris Bruynooghe
2b9973846e Merge pull request #1736 from Avira/features
Add backwards compatibility docs
2016-07-18 11:17:48 +02:00
Oliver Bestwalter
58a8150bc5 add backwards compatibility policy 2016-07-17 21:14:16 +02:00
Bruno Oliveira
0ac3eaa1db Merge pull request #1735 from flub/reinterpret-docs
Document the re-writing of plugins
2016-07-17 12:48:33 -03:00
Floris Bruynooghe
0a53797fa3 Document the re-writing of plugins 2016-07-17 12:30:21 +01:00
Ronny Pfannschmidt
8a73a2ad60 Merge pull request #1734 from nicoddemus/issue-1728-inconsistent-setup-teardown
setup_* and teardown_* functions argument now optional
2016-07-15 14:59:22 +02:00
Floris Bruynooghe
fb21493856 Merge pull request #1733 from flub/remove-reinterpret
Remove assertion reinterpretation
2016-07-15 12:46:25 +01:00
Bruno Oliveira
ff8fb4950e setup_* and teardown_* functions argument now optional
setup_module, setup_function and setup_method
extra argument are now optional and may be omitted.

Fix #1728
2016-07-14 23:41:40 -03:00
Floris Bruynooghe
d1852a48b7 Remove assertion reinterpretation
The assertion reinterpretation is an old backwards compatibility
mode which was no longer being maintained on feature-parity with
the assertion rewriting mode.  It was also responsible for some
dubious patching of builtins and test with side-effects would
suddenly start passing.  Since re-writing has been the default for
a long time and plugins are now also re-written it is time to
retire reinterpretation.
2016-07-15 00:33:39 +01:00
Bruno Oliveira
ee374e3b80 Merge pull request #1731 from nicoddemus/improve-test-args-deprecated
Make assert in test_str_args_deprecated more resilient
2016-07-14 19:18:13 -03:00
Bruno Oliveira
3328cd2620 Make assert in test_str_args_deprecated more resilient
This attempts to fix CI which broke because of this test.

Other warnings introduced in the future could break
this test.
2016-07-14 18:37:59 -03:00
Bruno Oliveira
350ebc9167 Merge pull request #1730 from RedBeardCode/pytest-1536
Added confcutdir in testing/test_conftest.py::test_conftest_import_or…
2016-07-14 17:02:58 -03:00
Floris Bruynooghe
24fbbbef1f Merge pull request #1641 from flub/rewrite-plugins
Rewrite plugins
2016-07-14 19:39:15 +01:00
RedBeardCode
22bb43413f Added confcutdir in testing/test_conftest.py::test_conftest_import_order and
testing/python/fixture.py::TestAutouseManagement::()::
  test_class_function_parametrization_finalization to avoid problems with
  abandoned conftest.py files in /tmp dir.
  Fixes #1536
2016-07-14 18:15:38 +02:00
Florian Bruhin
691dc8bc68 Merge pull request #1727 from nicoddemus/deprecate-str-pytest-main
Deprecate support for passing command-line as string to pytest.main()
2016-07-14 14:42:14 +02:00
Florian Bruhin
14af12cb7b Merge pull request #1717 from nicoddemus/nose-yield-tests-docs
Document limitations for yield-tests in nose
2016-07-14 14:40:27 +02:00
Floris Bruynooghe
51ee7f8734 Fixup things after rebase
Some changes to make things work on top of current features branch.
2016-07-14 12:42:29 +01:00
Bruno Oliveira
9007e16cdf Document limitations for yield-tests in nose
Also add nose doc to the root toctree

Closes #1716
2016-07-14 08:20:01 -03:00
Bruno Oliveira
02dd7d612a Remove duplicated changelog entry and formatting fix 2016-07-14 08:16:27 -03:00
Bruno Oliveira
ab0b6faa5f Deprecate support for passing command-line as string to pytest.main()
Fixes #1723
2016-07-14 08:11:43 -03:00
Bruno Oliveira
1fb09d9dd5 Merge pull request #1726 from nicoddemus/warnings-displayed-by-default
Warnings displayed by default
2016-07-13 19:33:49 -03:00
Bruno Oliveira
1266ebec83 Merge remote-tracking branch 'upstream/features' into warnings-displayed-by-default
# Conflicts:
#	CHANGELOG.rst
#	testing/test_terminal.py
2016-07-13 18:45:15 -03:00
Bruno Oliveira
6e9ee2b766 Merge pull request #1724 from blueyed/followup-pr1718-remove-newline
funcarg_prefix_warning: remove newline
2016-07-13 15:46:16 -03:00
Daniel Hahler
3cfebdd7c5 funcarg_prefix_warning: remove newline
Followup to https://github.com/pytest-dev/pytest/pull/1718.
2016-07-13 18:33:24 +02:00
Floris Bruynooghe
743f59afb2 Introduce pytest.register_assert_rewrite()
Plugins can now explicitly mark modules to be re-written.  By default
only the modules containing the plugin entrypoint are re-written.
2016-07-13 17:31:09 +01:00
Floris Bruynooghe
944da5b98a Avoid rewrite warning for inline runs
When running pytest inline/inprocess we plugins have already been
imported and re-writen, so avoid the warning.
2016-07-13 17:29:19 +01:00
Floris Bruynooghe
a98e3cefc5 Enable re-writing of setuptools-installed plugins
Hook up the PEP 302 import hook very early in pytest startup so
that it gets installed before setuptools-installed plugins are
imported.  Also iterate over all installed plugins and mark them
for rewriting.  If an installed plugin is already imported then
a warning is issued, we can not break since that might break
existing plugins and the fallback will still be gracefull to
plain asserts.

Some existing tests are failing in this commit because of the new
warning triggered by inline pytest runs due to the hypothesis
plugin already being imported.  The tests will be fixed in the next
commit.
2016-07-13 17:29:19 +01:00
Bruno Oliveira
dd5ce96cd7 Merge pull request #1718 from blueyed/fix-funcarg_prefix_warning
Add punctuation to funcarg_prefix_warning
2016-07-13 12:53:54 -03:00
Florian Bruhin
aeccd6b4a2 Merge pull request #1720 from nicoddemus/changelog-formatting
Improve overall CHANGELOG formatting and consistency for 3.0
2016-07-13 15:58:38 +02:00
Bruno Oliveira
44c3055e79 Merge pull request #1721 from bronsen/patch-1
Docs: De-404 links in changelog
2016-07-13 10:05:14 -03:00
Bruno Oliveira
4a763accc5 Improve overall CHANGELOG formatting and consistency for 3.0 2016-07-13 08:52:36 -03:00
Kalle Bronsen
dfe1209d2c De-404 links in changelog 2016-07-13 11:41:27 +02:00
Florian Bruhin
54ea27c283 Merge pull request #1719 from nicoddemus/fix-2.10-versions-in-docs
Fix 2.10 -> 3.0 versions in docs
2016-07-13 08:10:13 +02:00
Bruno Oliveira
f827810fa8 Fix 2.10 -> 3.0 versions in docs 2016-07-12 21:02:40 -03:00
Daniel Hahler
15e97a7c78 Add punctuation to funcarg_prefix_warning 2016-07-12 23:49:09 +02:00
Ronny Pfannschmidt
c4f20a1834 Merge pull request #1712 from anntzer/custom-debugger
Allow passing a custom Pdb subclass via --pdbcls.
2016-07-12 16:45:07 +02:00
Ronny Pfannschmidt
4c56c95eb8 Merge pull request #1714 from nicoddemus/deprecate-yield-tests-funcarg-prefix
Deprecate yield tests funcarg prefix
2016-07-12 11:43:59 +02:00
Antony Lee
7ee3dd1cb5 Add tests for custom pdb class.
(and edit CHANGELOG)
2016-07-11 20:07:29 -07:00
Bruno Oliveira
458ecae1df Replace all usages of "pytest_funcarg__" for @pytest.fixture 2016-07-11 22:21:52 -03:00
Bruno Oliveira
ad4125dc0d Deprecate "pytest_funcarg__" prefix to declare fixtures
Fixes #1684
2016-07-11 22:21:50 -03:00
Bruno Oliveira
5506dc700c Deprecate yield tests
Closes #16
Closes #1324
2016-07-11 22:21:49 -03:00
Bruno Oliveira
0dd1c8bf14 Add test to ensure capsys and capfd error out when using "getfixturevalue" inside a test 2016-07-11 20:48:38 -03:00
Bruno Oliveira
0ca06962e9 Improve docs 2016-07-11 20:33:16 -03:00
Bruno Oliveira
2ffe354f21 Add CHANGELOG for invocation-scoped fixtures 2016-07-11 20:32:59 -03:00
Bruno Oliveira
fb4da00a32 Merge remote-tracking branch 'upstream/features' into invocation-scoped-fixtures 2016-07-11 20:09:13 -03:00
Bruno Oliveira
6f68dfcc47 Merge pull request #1710 from RonnyPfannschmidt/fixture-split
Fixture split 2nd attempt
2016-07-10 12:10:07 -03:00
Antony Lee
6383b53ad9 Allow passing a custom Pdb subclass via --pdbcls.
This obviates the need for plugins such as `pytest-ipdb`; instead one
can simply call `py.test --pdb=IPython.core.debugger:Pdb`
2016-07-09 21:10:52 -07:00
Bruno Oliveira
8ed055efd8 Add acceptance test for invocation-scoped fixtures 2016-07-09 22:52:07 -03:00
Bruno Oliveira
775100881a Implement invocation-scoped fixtures 2016-07-09 22:52:05 -03:00
Bruno Oliveira
29289b472f Add documentation for "invocation" scoped fixture 2016-07-09 16:51:25 -03:00
Ronny Pfannschmidt
8c49561470 split most fixture related code into own plugin 2016-07-09 20:36:00 +02:00
Florian Bruhin
7a2058e3db Merge pull request #1709 from The-Compiler/changelog
Clean up changelog
2016-07-08 18:52:28 +02:00
Florian Bruhin
668ebb102c Clean up changelog
- Merged 3.0 and 2.10 as much stuff from the sprint went to the 2.10
  section.
- Cleaned up mixture of link/text blocks
- Moved some entries to "Bug Fixes" and "Incompatible changes"
- Stop doing "Fixes (#123) ..." because it looks weird
- Add some new empty points for all sections
2016-07-08 18:51:26 +02:00
Bruno Oliveira
293351cfd0 Merge pull request #1705 from RonnyPfannschmidt/merge-master
Merge from master to features
2016-07-08 08:15:54 -03:00
Ronny Pfannschmidt
dad6aa8a16 fix duplicate target in changelog 2016-07-06 13:51:13 +02:00
Ronny Pfannschmidt
b9a91dc112 merge from master to features 2016-07-06 11:51:48 +02:00
Bruno Oliveira
f31c31a73c Merge pull request #1695 from sallner/feature-setup-show
Feature setup show
2016-07-05 21:29:01 -03:00
aostr
94e4a2dd67 * implemented changes recommended by nicoddemus 2016-07-05 15:22:27 +02:00
Javier Domingo Cansino
0171cfa30f Fixing link to issue and creating testcase that shows that it finds the line in the stderr lines 2016-07-05 10:39:12 +01:00
Javier Domingo Cansino
61e605f60b Making conftest import failures easier to debug 2016-07-05 10:04:42 +01:00
Ronny Pfannschmidt
cc0920ceb1 Merge pull request #1699 from nicoddemus/404-links-on-talks-docs
Fix links and removed 404 links from talks.rst
2016-07-05 08:44:23 +02:00
Florian Bruhin
067e044f97 Merge pull request #1700 from nicoddemus/split-appveyor
Split AppVeyor test runs in multiple jobs to avoid timeout issues
2016-07-05 06:43:39 +02:00
Bruno Oliveira
10c5e6fd9c Split AppVeyor test runs in multiple jobs to avoid timeout issues
Some of our builds have been timing out (over 1 hour),
on AppVeyor
2016-07-04 21:54:21 -03:00
Bruno Oliveira
8d39ce17da Fix links and removed 404 links from talks.rst
Fix #1696
2016-07-04 21:32:57 -03:00
Steffen Allner
6438895a23 Fix PEP-8. 2016-07-03 22:33:21 +02:00
Steffen Allner
b650c3c118 Implement --setup-show cli flag
to also be able to see fixture setup with normal test execution.
2016-07-03 22:30:51 +02:00
Steffen Allner
f7b5bb2f97 Merged branch features into features 2016-07-03 21:07:02 +02:00
Bruno Oliveira
f74dd8550f Merge pull request #1692 from pytest-dev/changelog
Add changelog to requirements for pytest-dev plugins
2016-06-30 17:39:14 -03:00
Florian Bruhin
e3c43a1462 Add changelog to requirements for pytest-dev plugins
Closes #1691
2016-06-30 22:25:09 +02:00
Florian Bruhin
7927dff8a1 Merge pull request #1678 from RonnyPfannschmidt/drop-python30-32
drop python 3.0-3.2 support code from setup.py
2016-06-30 11:15:49 +02:00
Ronny Pfannschmidt
1451a1ab00 remove unsupported python versions from code/source xfail 2016-06-30 10:03:40 +02:00
Bruno Oliveira
75ecd94294 Merge pull request #1689 from quodlibetor/autouse-docs
Document the interaction of autouse scopes
2016-06-29 18:08:06 -03:00
Brandon W Maister
771c4539fa Document the interaction of autouse scopes
I wouldn't have even attempted what I did to cause #1688 if this had
been there.
2016-06-29 16:52:13 -04:00
Ronny Pfannschmidt
2a43237527 docs: no longer include python 3.0-3.2 in the index page 2016-06-27 18:20:56 +02:00
Ronny Pfannschmidt
7dc8d1ab60 fix typo and remove python3.2 from readme 2016-06-27 18:19:00 +02:00
Florian Bruhin
1e60294188 Merge pull request #1679 from eli-b/patch-1
catched -> caught
2016-06-27 18:02:16 +02:00
Ronny Pfannschmidt
e877e25587 drop python 3.0-3.2 support code from setup.py
addresses #1627
2016-06-27 17:55:37 +02:00
Eli Boyarski
21d27784eb catched -> caught
Even though catch is a Python keyword, 'catched' just looks terrible in text.
If the text was supposed to reference the keyword, then 'catched' should be changed to "'catch'ed".
2016-06-27 15:41:40 +03:00
Bruno Oliveira
ccd395ffe0 Merge pull request #1659 from RonnyPfannschmidt/failtest-586
xfailing test for #568
2016-06-27 07:38:14 -03:00
Ronny Pfannschmidt
76756c0c0b mark tests: use better name of the test for #568 2016-06-27 11:57:21 +02:00
Bruno Oliveira
44695ae46c Fix CHANGELOG: obestwalter appearing twice due to mergig separate PRs 2016-06-26 23:44:07 +02:00
Bruno Oliveira
7e78965c79 Merge branch 'logic_brackets' 2016-06-26 21:34:37 +02:00
Bruno Oliveira
58e558141d Remove commented out code 2016-06-26 21:19:07 +02:00
Bruno Oliveira
22c2d87633 Fix bad merge in CHANGELOG 2016-06-26 21:18:01 +02:00
Bruno Oliveira
5891061ac1 Merge pull request #1675 from kvas-it/issue-1562
Add warning for assertions on tuples #1562
2016-06-26 16:09:15 -03:00
Bruno Oliveira
48ac1a0986 Merge branch 'remove-old-entry-points' into features 2016-06-26 20:38:59 +02:00
Bruno Oliveira
db9b3e9522 Merge pull request #1677 from nicoddemus/remove_cmd_options
Remove cmd options
2016-06-26 15:37:59 -03:00
Bruno Oliveira
b9536608c5 Add issue and obestwalter to CHANGELOG
Fix #1632
2016-06-26 20:36:04 +02:00
Bruno Oliveira
f7a2048e96 Merge branch 'features' of https://github.com/Avira/pytest into remove-old-entry-points 2016-06-26 20:32:38 +02:00
Bruno Oliveira
7239f36466 Improve formatting in CHANGELOG 2016-06-26 19:41:01 +02:00
RedBeardCode
1b0dbd8c40 Move the freezing function from genscript.py to a new module freeze_support.py 2016-06-26 19:37:24 +02:00
RedBeardCode
0e2ebc96ff Remove deprecated cmd options
Fixes #1657
2016-06-26 19:26:04 +02:00
aostr
b4e0fabf93 * added missing link to the referenced issue 2016-06-26 06:52:50 +02:00
aostr
1ce4670062 * removed tailing whitespaces 2016-06-26 06:51:57 +02:00
Vasily Kuznetsov
6d4cee2159 Add a test for indirect use of tuple in the assert that should not cause a warning 2016-06-26 02:21:51 +02:00
Vasily Kuznetsov
0db4ae15a9 Update changelog 2016-06-25 19:34:55 +02:00
Vasily Kuznetsov
c17027e576 Warn about asserts on tuples (fixes #1562) 2016-06-25 19:21:48 +02:00
aostr
e04d9ff80b * now showing pytest warnings summary by default.
* added ``--disable-pytest-warnings` flag to let users disable the warnings summary.
* extended/changed unit tests for the changes in the pytest core.
2016-06-25 18:16:13 +02:00
RedBeardCode
e2f550156e Improve of the test output for logical expression with brackets.
Fixes #925
2016-06-25 18:10:36 +02:00
holger krekel
68bed00d5b Merge pull request #1667 from fengxx/feature/override_ini_option
Add --overwrite-ini ININAME=INIVALUE cli option
2016-06-25 18:10:10 +02:00
Ted Xiao
856e6cab75 add --override-ini option to overrides ini values
Signed-off-by: Ted Xiao <xiao.xj@gmail.com>
2016-06-25 23:45:32 +08:00
holger krekel
13a188fe37 Merge pull request #1647 from sallner/features
Add new options to report fixture setup and teardown
2016-06-25 16:38:37 +02:00
Oliver Bestwalter
3a9e9fdf82 rephrase changes in CHANGELOG.rst 2016-06-25 16:04:23 +02:00
Oliver Bestwalter
72450408ed add changes in CHANGELOG.rst 2016-06-25 16:00:49 +02:00
Ronny Pfannschmidt
95b83958f4 add xfailing test for issue #568 2016-06-25 15:49:23 +02:00
Ronny Pfannschmidt
2af3a7a9d7 Merge pull request #1519 from omarkohl/pytest_skip_decorator
Raise CollectError if pytest.skip() is called during collection
2016-06-25 15:20:34 +02:00
Florian Bruhin
35cd12e4de Merge pull request #1660 from hackebrot/parametrize-with-fixtures
Proposal: Parametrize with fixtures
2016-06-25 15:05:27 +02:00
Raphael Pierzina
1b6bc4d606 Add feature proposal to changelog 2016-06-25 14:58:18 +02:00
Bruno Oliveira
c519b9517a Merge pull request #1663 from aostr/master
Rename the default plugin "pdb" into "debugging"
2016-06-25 09:56:54 -03:00
Raphael Pierzina
eb98a8eefb Change version in issues section to pytest 3.0 only 2016-06-25 14:52:57 +02:00
Raphael Pierzina
acfdd85dff Move document to proposals subfolder 2016-06-25 14:42:19 +02:00
Bruno Oliveira
e0242146ec Merge pull request #1666 from pytest-dev/1564-changelog
Add changelog entry for #1564
2016-06-25 09:34:21 -03:00
Bruno Oliveira
df17f862fa Merge pull request #1648 from blueyed/simplify-Argument-__repr__
Simplify Argument.__repr__
2016-06-25 09:26:50 -03:00
Bruno Oliveira
7eb1318db2 Merge pull request #1656 from pytest-dev/rm-indiegogo-links
Update website wrt indiegogo campaign
2016-06-25 09:22:07 -03:00
Florian Bruhin
ce603dc0ea Add changelog entry for #1564 2016-06-25 14:18:41 +02:00
Ronny Pfannschmidt
70ea3ce7f7 Merge pull request #1564 from The-Compiler/issue1479
Don't ignore ImportError when importing setuptools plugins
2016-06-25 14:09:48 +02:00
aostr
9a5224e2f8 Renamed the pdb module and changed unit tests accordingly 2016-06-25 12:37:31 +02:00
Danielle Jenkins
32ca5cdb09 Update changelog for new fixture hooks. 2016-06-25 12:33:31 +02:00
Oliver Bestwalter
891e1677b6 Remove all py.test-X* entry points.
The versioned, suffixed entry points are not documented and a leftover from a pre-virtualenv world. They also are broken for wheels.
2016-06-25 12:27:05 +02:00
Danielle Jenkins
9877bf47e3 Improve commenting for setupplan unittest. 2016-06-25 12:21:31 +02:00
Danielle Jenkins
7a3daac85b Add docs for setuponly and setupplan options. 2016-06-25 12:21:12 +02:00
Danielle Jenkins
da5c579d82 Move setupplan and setuponly options to their respective modules.
Also, changed their group from "general" to "debugconfig".
2016-06-25 12:20:56 +02:00
Danielle Jenkins
032ce8baf6 Switch setuponly and setupplan options to a hook-based implementation. 2016-06-25 12:19:46 +02:00
aostr
05b5554cac Renamed pytest pdb to debugging which conflicts with python pdb.
Combining multiple imports the "import pdb" imports the pytest module
as opposed to the python debugger.
2016-06-25 12:09:05 +02:00
Raphael Pierzina
5860c609ae Remove note on scoping 2016-06-25 11:09:46 +02:00
Raphael Pierzina
526c564576 Fix rst bullet point lists 2016-06-25 11:06:17 +02:00
Raphael Pierzina
693859210a Add yielded values to function example 2016-06-25 11:00:54 +02:00
Raphael Pierzina
4f8b8c8d31 Add alternative approach that uses wrappers 2016-06-25 10:55:08 +02:00
Raphael Pierzina
c6a711c2fc Add proposed solution using a module function 2016-06-25 10:50:14 +02:00
Raphael Pierzina
84f0dcecf8 Add issues section to proposal doc 2016-06-25 10:10:57 +02:00
Florian Bruhin
757f37f445 Don't ignore ImportError with setuptools plugins
This was added in b2d66b9e7b but is a bad
idea. When a plugin can't be imported, commandline options (optionally
set in pytest.ini) could be undefined, which means pytest bails out
much earlier before showing the warning, which is hard to debug.

Fixes #1479, also see #1307 and #1497
2016-06-25 09:56:22 +02:00
Daniel Hahler
939407ef63 Simplify Argument.__repr__
I have came across this when noticing that universal-ctags fails to parse
this correctly (https://github.com/universal-ctags/ctags/issues/997).
2016-06-25 09:31:31 +02:00
Omar Kohl
b3615ac29d Update CHANGELOG with #607 and add version 3.0.0.dev1 2016-06-24 20:56:21 +02:00
Omar Kohl
d81f23009b Raise CollectError if pytest.skip() is called during collection
pytest.skip() must not be used at module level because it can easily be
misunderstood and used as a decorator instead of pytest.mark.skip, causing the
whole module to be skipped instead of just the test being decorated.

This is unexpected for users used to the @unittest.skip decorator and therefore
it is best to bail out with a clean error when it happens.

The pytest equivalent of @unittest.skip is @pytest.mark.skip .

Adapt existing tests that were actually relying on this behaviour and add a
test that explicitly test that collection fails.

fix #607
2016-06-24 20:56:21 +02:00
Bruno Oliveira
0c63762d9c Merge pull request #1654 from tomviner/issue1503/remove_collapse_false
Fixes #1503 no longer collapse false explanations
2016-06-24 12:53:49 -03:00
Brianna Laugher
7612b650a0 update sprint page to be past tense 2016-06-24 17:24:06 +02:00
Brianna Laugher
62255d8000 rm global header 2016-06-24 17:12:41 +02:00
Brianna Laugher
ea5bda0898 remove links to funding campaign 2016-06-24 17:11:29 +02:00
Tom Viner
77689eb486 Fixes #1503 no longer collapse false explanations 2016-06-24 15:35:24 +02:00
Bruno Oliveira
3d263c64c3 Merge pull request #1626 from tomviner/issue1625/rename-getfuncargvalue
issue1625, rename getfuncargvalue to getfixturevalue
2016-06-24 08:58:32 -03:00
Raphael Pierzina
dc55551213 Start proposal for parametrize with fixtures 2016-06-24 12:08:57 +02:00
Tom Viner
df9918eda3 issue1625, name getfuncargvalue to getfixturevalue 2016-06-24 10:08:19 +02:00
Vasily Kuznetsov
c6af737d4e Fix fixture parameter display when ids is a function 2016-06-23 10:54:22 +02:00
Vasily Kuznetsov
1a5e530b98 Fix capturing with --setup-only/--setup-plan 2016-06-23 10:23:04 +02:00
Ronny Pfannschmidt
f2bb3df310 Merge pull request #1645 from userzimmermann/sprint/addoption-check
added check for already existing option names to OptionGroup.addoption()
2016-06-23 07:52:46 +02:00
Florian Bruhin
6359e75ff8 Trivial spelling fix in runtest_setup.py 2016-06-22 20:18:00 +02:00
Stefan Zimmermann
69bab4ab04 added check for already existing option names to OptionGroup.addoption() 2016-06-22 18:01:35 +02:00
Steffen Allner
ecc97aa3b9 Use correct links in changelog. 2016-06-22 17:52:13 +02:00
Steffen Allner
dd97a2e7c8 Merge from upstream 2016-06-22 17:51:48 +02:00
Steffen Allner
0dbf77e08e Add to changelog and authors. 2016-06-22 17:37:58 +02:00
Vasily Kuznetsov
f7d50dfa91 Add a test for handling of dynamic requests for fixtures from other fixtures 2016-06-22 17:24:55 +02:00
Ronny Pfannschmidt
7d60fcc098 Merge pull request #1643 from RonnyPfannschmidt/merge-master
Merge master
2016-06-22 17:05:59 +02:00
Vasily Kuznetsov
c8c32fd9c0 Merge with upstream 2016-06-22 17:00:35 +02:00
Vasily Kuznetsov
61992b4e22 Implement --setup-plan option 2016-06-22 16:45:36 +02:00
Vasily Kuznetsov
f59d8f7720 Fix the tests (#3)
* Fix the tests

* Fix .format string failures on python 2.6
2016-06-22 16:23:58 +02:00
Ronny Pfannschmidt
18ef7de96b merge from master again 2016-06-22 16:03:52 +02:00
Ronny Pfannschmidt
e96cd51a2a Merge remote-tracking branch 'upstream/features' into merge-master 2016-06-22 16:03:00 +02:00
Ronny Pfannschmidt
f7585c7549 Merge pull request #1635 from Avira/master
Add test for change in pull request #1631
2016-06-22 15:49:09 +02:00
Ronny Pfannschmidt
9cb851716d Merge pull request #1644 from KangarooCreativeTeam/patch-1
cache.rst: Fix wrong command used
2016-06-22 15:46:09 +02:00
Ronny Pfannschmidt
a2420ce051 Merge pull request #1640 from Avira/features
Add tests for entry points (#1629 )
2016-06-22 15:41:19 +02:00
HEAD KANGAROO
be1dabd6a9 cache.rst: Fix wrong command used
The "Inspecting Cache content" section was showing --cache-clear command,
  but should actually be using --cache-show command.

  Also; update AUTHORS
2016-06-22 14:04:02 +01:00
Vasily Kuznetsov
5e0d78f4f1 Fix .format string failures on python 2.6 2016-06-22 14:53:37 +02:00
Ronny Pfannschmidt
083f64100d merge master into features 2016-06-22 14:39:33 +02:00
Oliver Bestwalter
db79ed5c4d Add tests to make sure expected entry points exist (#1629) 2016-06-22 14:28:53 +02:00
Bruno Oliveira
fb79fa711b Merge branch 'issue1553/diff-final-newline' of https://github.com/tomviner/pytest 2016-06-22 14:21:30 +02:00
Vasily Kuznetsov
1a75139f72 Fix the tests 2016-06-22 13:25:46 +02:00
Steffen Allner
ee311e1eae Merge pull request #2 from kvas-it/features
Add printing of fixture dependencies
2016-06-22 13:04:23 +02:00
Vasily Kuznetsov
2c5c4f3f78 Add printing of fixture dependencies 2016-06-22 12:54:36 +02:00
Steffen Allner
2c6cfa42fa Disable capturing for setuponly output 2016-06-22 12:14:35 +02:00
Steffen Allner
de9ed5e3f4 Merge pull request #1 from kvas-it/features
Factor setuponly code out of runtestprotocol().
2016-06-22 12:04:45 +02:00
Steffen Allner
92bcc36266 Refactor logging of fixtures 2016-06-22 12:01:51 +02:00
Steffen Allner
7d19f83982 Add test for setuponly option 2016-06-22 12:00:45 +02:00
Oliver Bestwalter
7d87a1b127 Add test for failing assertion
Should contain function name that caused the failure (see pull request #1631).
2016-06-22 11:23:50 +02:00
Vasily Kuznetsov
6874c3a3cc Factor setuponly code out of runtestprotocol(). 2016-06-22 11:09:54 +02:00
Ronny Pfannschmidt
24179dc99f Merge pull request #1639 from tomviner/fix-changelog-links
fix changelog links
2016-06-22 10:49:35 +02:00
Tom Viner
ec25d398a5 fix changelog links 2016-06-22 10:06:14 +02:00
Tom Viner
98adf204b2 issue 1553: Include terminal newlines in diffs 2016-06-22 09:50:15 +02:00
Steffen Allner
499c9551c8 Implement working version of --setuponly 2016-06-22 09:42:45 +02:00
Bruno Oliveira
144dc12e55 Merge pull request #1638 from blueyed/fix-CONTRIBUTING
CONTRIBUTING.rst: spelling fixes
2016-06-22 04:28:15 -03:00
Daniel Hahler
09389d2b20 CONTRIBUTING.rst: spelling fixes
[ci skip]
2016-06-22 09:14:07 +02:00
Bruno Oliveira
c3ee1c17bc Merge pull request #1620 from tomviner/issue460/parameterized-subrequest
Issue 460: Fail on getfuncargvalue(<fixture with params>)
2016-06-21 13:43:06 -03:00
Bruno Oliveira
4350f499b2 Merge branch 'issue1629' of https://github.com/davehunt/pytest into features 2016-06-21 18:37:14 +02:00
Bruno Oliveira
61ede096a3 Merge pull request #1631 from Avira/master
help the user in the rare case this assertion actually fails
2016-06-21 13:17:52 -03:00
Bruno Oliveira
2f9d5c2586 Merge pull request #1623 from blueyed/ignore-hidden-files-in-test_pytest_collect_file
Ignore hidden files (.testmondata) in test_pytest_collect_file
2016-06-21 13:17:20 -03:00
Bruno Oliveira
f05d65dc42 Merge pull request #1622 from nicoddemus/issue-1619-conftest-assert-rewrite
Issue 1619 conftest assert rewrite
2016-06-21 13:15:52 -03:00
Bruno Oliveira
573866bfad Merge remote-tracking branch 'upstream/features' into issue-1619-conftest-assert-rewrite 2016-06-21 18:10:19 +02:00
Bruno Oliveira
2305d3271d Merge pull request #1628 from omarkohl/exit_on_collection_error
Exit pytest on collection error (without executing tests)
2016-06-21 13:03:21 -03:00
Bruno Oliveira
406355fd10 Merge pull request #1624 from blueyed/getexecutable-skip-non-zero-returncode
tests: getexecutable: call `--version` on all Pythons
2016-06-21 12:51:48 -03:00
Dave Hunt
393167b94f Update CHANGELOG and add Oliver Bestwalter to AUTHORS 2016-06-21 16:59:14 +02:00
Dave Hunt
ef9dd14963 Introduce pytest command as recommended entry point
Fixes #1629
2016-06-21 16:16:57 +02:00
Oliver Bestwalter
2b5c2f3ed5 help the user in the rare case this assertion actually fails 2016-06-21 14:57:48 +02:00
Omar Kohl
ede7478dcc Exit pytest on collection error (without executing tests)
Add --continue-on-collection-errors option to restore the previous behaviour:
Execute tests (that were successfully collected) even when collection errors
happen.

Some tests had to be modified e.g. because the return code changed to 2
(EXIT_INTERRUPTED) instead of 1 (EXIT_TESTSFAILED) because an Interrupted
exception is raised on collection error.

Implemented via pair programming with:
    Oleg Pidsadnyi <oleg.pidsadnyi@gmail.com>

closes #1421
2016-06-21 13:32:34 +02:00
Bruno Oliveira
819942e964 Return explicit None from rewrite hook's find_module 2016-06-21 12:28:36 +02:00
Bruno Oliveira
8b0fb47c79 Remove print left by accident 2016-06-21 12:23:12 +02:00
Tom Viner
5854a71ece Issue 460: getfuncargvalue fixture w. params err 2016-06-21 11:29:21 +02:00
Bruno Oliveira
5d8d1db4df Update repository transfer instructions 2016-06-21 09:40:22 +02:00
Floris Bruynooghe
9118c0222f Merge .set_config() into constructor 2016-06-21 09:28:10 +02:00
Daniel Hahler
e53e45b55c tests: getexecutable: call --version on all Pythons
This should prevent errors from pyenv:

    pyenv: python2.6: command not found

    The `python2.6' command exists in these Python versions:
      2.6.9

While the pyenv wrapper explicitly returns 127, I think it is better to
just check for non-zero?!
2016-06-21 08:36:02 +02:00
Bruno Oliveira
e0cb046885 Update AUTHORS and CHANGELOG 2016-06-20 23:16:06 +02:00
Bruno Oliveira
3a81d2e012 conftest files now use assertion rewriting
Fix #1619
2016-06-20 23:13:29 +02:00
Daniel Hahler
e9d7989140 Ignore hidden files (.testmondata) in test_pytest_collect_file
`test_pytest_collect_file` fails if you run the tests using `--testmon`,
because pytest-testmon will put its DB there as `.testmondata`.
2016-06-20 22:30:36 +02:00
Florian Bruhin
54872e94b4 Fix test name typo 2016-06-20 18:44:34 +02:00
Florian Bruhin
4f2db6c08d Merge pull request #1616 from palaviv/pytest.raises-message
Pytest.raises custom error message
2016-06-20 18:43:12 +02:00
Ronny Pfannschmidt
f3aead8e49 Merge pull request #1600 from nicoddemus/issue-1599-disable-cap-fixtures
Add disabled() method to capsys and capfd
2016-06-20 15:55:54 +02:00
palaviv
f8d4cadc3d Added versionchanged directives 2016-06-19 23:56:43 +03:00
palaviv
c29130d400 Updated documentation 2016-06-19 23:34:42 +03:00
palaviv
ca093673fb pytest.raises accept cutom message only when used as context manager 2016-06-19 21:24:47 +03:00
Bruno Oliveira
d81ee9acfb Merge pull request #1597 from taschini/pyargs-fix
Ensure that a module within a namespace package can be found by --pyargs
2016-06-19 14:20:52 -03:00
Bruno Oliveira
72bf11cbe9 Add disabled() method to capsys and capfd
Fix #1599
2016-06-19 19:14:36 +02:00
palaviv
e6ff01ada3 CR fixes 2016-06-16 21:09:15 +03:00
palaviv
8ddbca36c9 Add CHANGLOG entry 2016-06-16 20:21:03 +03:00
palaviv
d21886c005 pytest.raises accpets custom message 2016-06-16 20:15:32 +03:00
Bruno Oliveira
7f8e315285 Merge pull request #1615 from gnprice/deadcode
Cut a dead test helper function
2016-06-16 00:42:01 -03:00
Bruno Oliveira
c5424643f0 Merge pull request #1614 from gnprice/loop
Simplify default pytest_runtestloop
2016-06-16 00:29:03 -03:00
Greg Price
ab8b2e75a3 Simplify default pytest_runtestloop
The inner function and the explanatory comment it makes necessary can
all be removed if we switch to an if/else rather than try/except for
this condition.

Perhaps this bit comes from my fondness for C, but I think I would
find this style clearer and easier to understand even if it weren't
for the Python 2 quirk that makes the other style require us to add an
unnecessary-looking function abstraction.  In any case, given that the
alternative does require that abstraction this is definitely simpler.
2016-06-15 18:27:08 -07:00
Greg Price
2a3cbdf4d1 Cut a dead test helper function
This appears to have been unused since commit
320835d "split out pytest-xdist related reporting to the plugin"
in July 2010.  It's the only caller outside of _pytest/runner.py
of the `call_and_report` helper function there, so cutting it out
makes that more of a pure helper function and makes it slightly
easier to understand the code in _pytest/runner.py .
2016-06-15 18:26:10 -07:00
Bruno Oliveira
308396ae3c Merge pull request #1606 from hackebrot/show-fixtures-per-test
Show fixtures per test
2016-06-14 09:54:18 -03:00
Ronny Pfannschmidt
feeee2803e Merge pull request #1586 from nicoddemus/issue-1461-merge-yield-fixture
Make normal fixtures work with "yield"
2016-06-14 10:31:09 +02:00
taschini
1218392413 Added taschini to AUTHORS and #1597 to CHANGELOG.rst. 2016-06-14 07:16:20 +02:00
taschini
4d9e293b4d Incorporated feedback (#1597).
Fixed problem caused in a test on Windows by file left open by PyPy and not immediately garbage collected.
2016-06-14 07:12:40 +02:00
taschini
e2e6e31711 Ensure that a module within a namespace package can be found by --pyargs. 2016-06-14 07:12:40 +02:00
Raphael Pierzina
adc50ac72f Change format for test function locations 2016-06-12 15:58:32 +01:00
Ronny Pfannschmidt
66e66f61e8 Merge pull request #1605 from guyzmo/issue/1604
Fixed issue shadowing error when missing argument on teardown_method
2016-06-12 12:05:37 +02:00
Guyzmo
accd962c9f Fixed issue shadowing error when missing argument on teardown_method
When the method argument is missing on teardown_method, the traceback is
100% internal to pytest, which with default options get pruned. Then
that traceback is empty, leading to a new exception as a traceback shall
not be empty.

This PR fixes that issue by pushing back the last stack on the
traceback, when the stacktrace is empty after pruning. Then the output
is still pruned, but gives meaningful information with the item where it
failed on the stack.

* fixes issue #1604

Signed-off-by: Guyzmo <guyzmo+github@m0g.net>
2016-06-12 03:45:24 +02:00
Raphael Pierzina
b99aace8a9 Fix py26 by using indices in str.format 2016-06-12 00:52:03 +01:00
Raphael Pierzina
bbc6c18448 Add changelog entry for new cli flag 2016-06-12 00:26:32 +01:00
Raphael Pierzina
7eea168106 Implement show_fixtures_per_test and add cli flag 2016-06-12 00:20:06 +01:00
Raphael Pierzina
b47f155d74 Implement tests for --fixtures-per-test 2016-06-12 00:17:50 +01:00
Ronny Pfannschmidt
577cce2554 Merge pull request #1593 from marscher/fix_cwd_explosion
Fix cwd explosion
2016-06-10 07:24:18 +02:00
Bruno Oliveira
bdc29968b8 Remove dead code and simplify code in call_fixture_func 2016-06-08 21:07:56 -03:00
Bruno Oliveira
ed69424917 Remove most content from yieldfixture as it is now deprecated 2016-06-08 21:07:55 -03:00
Bruno Oliveira
371fbe4388 Update CHANGELOG (yield statements in normal fixtures) 2016-06-08 21:07:53 -03:00
Bruno Oliveira
fe4f23c1bf Update docs in prol of using yield statements 2016-06-08 21:07:52 -03:00
Bruno Oliveira
98acda426f Remove yieldctx variable being passed around 2016-06-08 21:07:50 -03:00
Bruno Oliveira
d712428d33 Fix custom name for yield_fixtures 2016-06-08 21:07:49 -03:00
Bruno Oliveira
366879db27 Make normal fixtures work with "yield" 2016-06-08 21:07:47 -03:00
Bruno Oliveira
92323895c9 Use same python which invoked tox for "doctesting" env
This will work for Travis and AppVeyor because both start tox using Python 3
2016-06-08 21:06:19 -03:00
marscher
09d163aa3a [exception handling] Fix case the current working directory (CWD) gets deleted during testing.
Fixes #1235.
2016-06-08 15:18:23 +02:00
Ronny Pfannschmidt
70fdab4cfa Merge pull request #1584 from mgedmin/patch-1
Docs: config.option is deprecated
2016-06-02 09:27:32 +02:00
Marius Gedminas
3ad5b9de86 Docs: config.option is deprecated
https://pytest.org/latest/writing_plugins.html#_pytest.config.Config says config.option is deprecated and one should use config.getoption() instead.
2016-06-02 09:52:56 +03:00
Ronny Pfannschmidt
9b6dc93496 Merge pull request #1583 from nicoddemus/fix-tox-doctesting
Use same python which invoked tox for "doctesting" env
2016-06-02 08:10:33 +02:00
Bruno Oliveira
2c4b76b754 Use same python which invoked tox for "doctesting" env
This will work for Travis and AppVeyor because both start tox using Python 3
2016-06-01 20:30:26 -03:00
Bruno Oliveira
63ced4d486 List contributors alphabetically in AUTHORS 2016-06-01 20:21:51 -03:00
Bruno Oliveira
97c89e6dc3 Merge branch 'fix-all-skipped-but-none-exist' 2016-06-01 20:20:50 -03:00
Bruno Oliveira
dd9c81ca26 Mention #1580 in the CHANGELOG and add Thomas Grainger to AUTHORS 2016-06-01 19:56:45 -03:00
Thomas Grainger
74862b8f2f Don't mark empty doctest files as skipped, fixes #1578 2016-06-01 19:19:14 +01:00
Florian Bruhin
057007fb52 Merge pull request #1582 from graingert/patch-1
Fix rst-lint CHANGELOG error
2016-06-01 19:25:18 +02:00
Thomas Grainger
2898dffb9e Fix rst-lint CHANGELOG error 2016-06-01 17:43:41 +01:00
Ronny Pfannschmidt
7305adfdba fix another copy&paste error in the announcement list 2016-06-01 08:55:44 +02:00
Ronny Pfannschmidt
fad6266a47 finish up the version bump in __init__ i forgot 2016-06-01 08:18:10 +02:00
Ronny Pfannschmidt
b5bd4d959d merge master to features 2016-06-01 08:13:26 +02:00
Ronny Pfannschmidt
f423f08b45 prepare cangelog for the next bugfix release 2016-06-01 08:04:21 +02:00
Ronny Pfannschmidt
5c8b0fb523 fix minor typos 2016-06-01 08:03:22 +02:00
Bruno Oliveira
8c1be624a6 Merge pull request #1554 from RonnyPfannschmidt/merge-master
Merge master into features
2016-05-24 11:09:33 -03:00
Ronny Pfannschmidt
16794feaf6 Merge branch 'master' into merge-master 2016-05-24 08:15:10 +02:00
Bruno Oliveira
5ab5a11544 Merge pull request #1565 from tomviner/issue1544/ignore-build-dist-dirs
Issue 1544: norecursedirs build & dist dirs
2016-05-23 19:30:20 -03:00
Ronny Pfannschmidt
26b526967e merge from master again 2016-05-23 22:33:00 +02:00
TomV
d6dfb1a393 issue 1544: norecursedirs build & dist dirs 2016-05-23 21:02:29 +01:00
Ronny Pfannschmidt
85393d34b6 Merge pull request #1561 from AbdealiJK/ajk/1558_feature
unittest.UnitTestCase: Allow __test__ for methods
2016-05-19 10:17:28 +02:00
Ronny Pfannschmidt
be7a86270c Merge pull request #1541 from RonnyPfannschmidt/document-1540
Document #1540
2016-05-19 10:15:33 +02:00
AbdealiJK
d4c9fa9f1a unittest.UnitTestCase: Allow __test__ for methods
__test__ needs to be checked for methods of a class too. Earlier,
this was not done, and all methods in a class was assumed to be
a test. This commit adds the appropriate condition to ensure that
if the __test__ is set to False, it does not collect that method.

Fixes https://github.com/pytest-dev/pytest/issues/1558
2016-05-19 08:19:57 +05:30
Ronny Pfannschmidt
ec5e05834f fix typo 2016-05-18 21:35:31 +02:00
Ronny Pfannschmidt
eab762ea99 Merge branch 'master' into merge-master 2016-05-13 19:37:41 +02:00
Ronny Pfannschmidt
c49863aa63 merge next chunk from master and fix changelog linting issue 2016-05-13 19:36:47 +02:00
Ronny Pfannschmidt
01d2ff804b Merge commit '56156bb119194014129ac08c4a2c370f0b893104' into merge-master 2016-05-13 17:55:02 +02:00
Ronny Pfannschmidt
68f658b6cc Merge commit '890c2fa555314a67a8d97a1b8ea4881a14be69c4' into merge-master 2016-05-13 17:52:59 +02:00
Ronny Pfannschmidt
4bde70d060 Merge commit 'ec62a3c9e47c3b5b07aa1656815145ffa2882a09' into merge-master 2016-05-13 17:40:14 +02:00
Ronny Pfannschmidt
98dd2ce75c document reason for #1540 2016-04-28 16:22:31 +02:00
Ronny Pfannschmidt
308e76e19c add xfailing test for #1540 2016-04-28 16:11:30 +02:00
Ronny Pfannschmidt
6cc56b4a1b Merge pull request #1535 from palaviv/parametrize-test-ids-hook
introduce pytest_make_parametrize_id hook
2016-04-27 16:16:16 +02:00
palaviv
9733127951 pytest_make_parametrize_id receive config object 2016-04-26 10:23:57 +03:00
Bruno Oliveira
fdee88f086 Merge pull request #1520 from omarkohl/invalid_test_module_name
Raise CollectError if import test module fails
2016-04-25 21:42:41 -03:00
palaviv
53429ed8b8 Added hook to plugin docs and new CHANGELOG record 2016-04-25 18:03:34 +03:00
palaviv
b9faf78d51 Added test_pytest_make_parametrize_id 2016-04-25 17:48:28 +03:00
palaviv
79927428d1 Added pytest_make_parametrize_id hook 2016-04-25 17:11:47 +03:00
Omar Kohl
56855893ca Raise CollectError if import test module fails
One of the reasons for failing to import the test module is invalid Python
identifiers in the full package path of the test module.

fix #1426
2016-04-23 13:50:48 +02:00
Ronny Pfannschmidt
52babba33e Update sprint 2016 2016-04-23 08:56:28 +02:00
Bruno Oliveira
8552860a9b Merge pull request #1532 from RibeiroAna/features
Update sprint2016.rst :)
2016-04-23 01:05:25 -03:00
Ana Ribeiro
f02f72e651 Update sprint2016.rst 2016-04-23 00:11:44 -03:00
Ronny Pfannschmidt
b220c96bf8 Merge pull request #1526 from The-Compiler/tracebackhide
Filter selectively with __tracebackhide__
2016-04-20 13:07:02 +02:00
Florian Bruhin
aa87395c39 Use py.builtin.callable
This restores compatibility with Python 3.0/3.1
2016-04-20 11:18:47 +02:00
Florian Bruhin
75160547f2 Use a callable __tracebackhide__ for filtering
While this leads to slightly more complicated user code for the common
case (checking if the exception is of a given type) it's easier to
implement and more flexible.
2016-04-20 11:09:27 +02:00
Florian Bruhin
4c552d4ef7 Fix tests for python 2.6 2016-04-20 10:36:13 +02:00
Florian Bruhin
b607f6728f Filter selectively with __tracebackhide__
When __tracebackhide__ gets set to an exception type or list/tuple of
exception types, only those exceptions get filtered, while the full
traceback is shown if another exception (e.g. a bug in a assertion
helper) happens.
2016-04-20 10:25:33 +02:00
Ronny Pfannschmidt
0f7aeafe7c Merge pull request #1486 from roolebo/fix-issue-138
Fix issue #138 - support chained exceptions
2016-04-03 19:21:57 +02:00
Bruno Oliveira
e3bc6faa2b Merge pull request #1470 from ceridwen/features
Escape both bytes and unicode strings for "ids" in Metafunc.parametrize
2016-04-03 13:48:30 -03:00
Bruno Oliveira
909d72b474 Merge pull request #1502 from omarkohl/excinfo_match
Implement ExceptionInfo.match() method
2016-04-03 13:48:12 -03:00
Omar Kohl
0c38aacc33 Add self to AUTHORS 2016-04-03 11:23:30 +02:00
Omar Kohl
c578226d43 Implement ExceptionInfo.match() to match regexp on str(exception)
This implements similar functionality to
unittest.TestCase.assertRegexpMatches()

closes #372
2016-04-03 11:22:44 +02:00
Ceridwen
23a8e2b469 Add .hypothesis to .gitignore and try an older version of Hypothesis for 2.6 2016-04-02 11:47:37 -04:00
Ceridwen
08671fcf4a Fix the changelog and dependencies for tox 2016-04-02 10:52:28 -04:00
Ceridwen
491b30c5d9 Add Hypothesis test for _idval and fix bug it found 2016-04-01 22:45:44 -04:00
Ceridwen
b631fc0bc1 Fix test_escaped_parametrized_names_xml 2016-04-01 21:30:45 -04:00
Ceridwen
9b438d56e8 Fix a test_unicode_idval_python2 (now test_unicode_idval) and associated string handling on Python 3 2016-04-01 12:27:17 -04:00
Roman Bolshakov
89df701ae9 Comment a workaround for #1485. 2016-03-27 13:15:56 +03:00
Bruno Oliveira
fed89ef549 Merge pull request #1474 from palaviv/improve-idmaker-duplicate-names
Improve idmaker name selection in case of duplicate ids in parametrize
2016-03-23 20:38:29 -03:00
palaviv
3ffce6ae4a Added thanks and PR links in changlog 2016-03-23 18:53:50 +02:00
palaviv
c66aedfa65 checking first there are duplciates ids before changing to unique names 2016-03-23 18:47:27 +02:00
palaviv
412042d987 added entry to CHANGELOG 2016-03-23 00:21:24 +02:00
palaviv
b8c15a0215 improved idmaker name selection in case of duplicate ids 2016-03-23 00:20:58 +02:00
Ceridwen
1f46015de5 Merge remote-tracking branch 'upstream/features' into features 2016-03-22 16:22:00 -04:00
Ceridwen
4405dd0ffe Escape both bytes and unicode strings for "ids" in Metafunc.parametrize 2016-03-22 01:31:48 -04:00
Ronny Pfannschmidt
da1045151f Merge pull request #1468 from palaviv/allow-none-as-parametrized-test-id
None in paramtrized test id will use automatically generated id
2016-03-20 20:19:50 +01:00
palaviv
dd384f7f78 Added changlog entries 2016-03-20 19:01:47 +02:00
palaviv
7885e43b78 Merge remote-tracking branch 'upstream/features' into allow-none-as-parametrized-test-id 2016-03-20 18:57:17 +02:00
palaviv
32f44ce2fd updated parametrize documentation 2016-03-20 18:54:48 +02:00
Roman Bolshakov
52bc2f8616 Update authors & changelog 2016-03-20 01:06:53 +03:00
Roman Bolshakov
a736e26734 Merge remote-tracking branch 'pytest-dev/master' into fix-issue-138 2016-03-20 01:04:22 +03:00
Roman Bolshakov
fbc5ba08d9 Fix issue #138 2016-03-20 01:02:17 +03:00
palaviv
4b0237c8ee added test for unique names when recievieng identical ids in parametrize 2016-03-19 21:42:47 +02:00
palaviv
877ca5a0bf added test for None in paramtrized ids list 2016-03-19 21:38:24 +02:00
palaviv
a8cfd54871 added test for None in idmaker 2016-03-19 21:23:49 +02:00
palaviv
be1954afbc allow None to be passed in ids list for specific test and recieve idmaker name for test 2016-03-19 21:22:49 +02:00
Bruno Oliveira
2cfcf12d09 Merge pull request #1466 from nicoddemus/merge-master-into-features
Merge master into features after 2.9.1 release
2016-03-18 23:45:14 -03:00
Bruno Oliveira
5fcce8a7d6 Merge branch 'master' into merge-master-into-features 2016-03-18 18:26:56 -03:00
Bruno Oliveira
ceacc12b52 Merge pull request #1454 from tareqalayan/add-global-properties-node
junitxml: add properties node in testsuite level
2016-03-16 18:21:51 -03:00
Tareq Alayan
fa6acdcfd4 junitxml: add properties node in testsuite level
The commit allow users to add a properties node in testsuite level see
example below:

<testsuite errors="0" failures="0" name="pytest" skips="1" tests="1"
time="11.824">
  <properties>
    <property name="ARCH" value="PPC"/>
    <property name="OS" value="RHEL 7.2"/>
    <property name="TestPlanURL" value="https://url.."/>
    <property name="Automated" value="True"/>
  </properties>
  <testcase classname="git.....>
  </testcase>
</testsuite>

The current situation is that properties node can be added to every
testcase node. However, sometimes we need some global properties that
applies to all testcases and give better description for the testsuite
itself.
2016-03-16 13:24:33 +02:00
Ronny Pfannschmidt
5fd82078ad Merge pull request #1441 from kalekundert/features
Add a convenience function for floating-point comparisons
2016-03-15 07:45:07 +01:00
Kale Kundert
5ceee08590 Fix CHANGELOG merge conflicts. 2016-03-14 11:55:50 -07:00
Kale Kundert
0dcc862a56 Fix some typos in the documentation. 2016-03-14 11:38:00 -07:00
Kale Kundert
9e7206a1cf Fix a few stylistic issues. 2016-03-14 11:29:45 -07:00
Ronny Pfannschmidt
0cacdef6c5 Merge pull request #1444 from novas0x2a/fixture-custom-name
Allow custom fixture names for fixtures
2016-03-14 14:08:02 +01:00
Kale Kundert
861265411f Add "thanks" line to the CHANGELOG. 2016-03-12 22:15:19 -08:00
Kale Kundert
916c0a8b36 Fix Decimal() and __ne__() errors. 2016-03-11 16:29:18 -08:00
Kale Kundert
078448008c Discuss alternative float comparison algorithms. 2016-03-11 15:59:48 -08:00
Kale Kundert
42a7e0488d Properly handle inf, nan, and built-in numeric types.
This commit also:

- Dramatically increases the number of unit tests , mostly by borrowing
  from the standard  library's unit tests for math.isclose().

- Refactors approx() into two classes, one of which handles comparing
  individual numbers (ApproxNonIterable) and another which uses the
  first to compare individual numbers or sequences of numbers.
2016-03-11 08:49:26 -08:00
Mike Lundy
9577120592 Allow custom fixture names for fixtures
When defining a fixture in the same module as where it is used, the
function argument shadows the fixture name, which a) annoys pylint and
b) can lead to bugs where you forget to request a fixture into a test
method.

This allows one to define fixtures with a different name than the name
of the function, bypassing that problem.
2016-03-09 14:58:54 -08:00
Kale Kundert
7d155bd3cf Fix sys.version_info errors. 2016-03-08 10:12:31 -08:00
Kale Kundert
6a902924f8 Fix trailing whitespace errors. 2016-03-07 19:56:23 -08:00
Kale Kundert
c9c73b8d8e Fix zero-length field name error in python2.6 2016-03-07 19:54:43 -08:00
Kale Kundert
4d0f066db7 Add approx() to the CHANGELOG. 2016-03-07 18:29:22 -08:00
Kale Kundert
5dab0954a0 Add approx() to the Sphinx docs. 2016-03-07 18:14:49 -08:00
Kale Kundert
b8a8382c2c Reduce the default absolute error threshold to 1e-12. 2016-03-07 16:43:53 -08:00
Kale Kundert
bf97d5b817 Use the plus/minus unicode symbol in the repr string.
This was a challenge because it had to work in python2 and python3,
which have almost opposite unicode models, and I couldn't use the six
library.  I'm also not sure the solution I found would work in python3
before python3.3, because I use the u'' string prefix which I think was
initially not part of python3.
2016-03-07 16:40:41 -08:00
Kale Kundert
dd28e28b34 Make a few stylistic improvements. 2016-03-07 10:10:54 -08:00
Kale Kundert
6f5e1e386a Add a convenient and correct way to compare floats. 2016-03-07 10:10:54 -08:00
Bruno Oliveira
c2b9196a7c Merge remote-tracking branch 'upstream/master' into features 2016-03-02 23:41:56 -03:00
Bruno Oliveira
4a76b2e9b6 Merge branch 'doctest_namespace_inject' into features 2016-03-02 23:38:51 -03:00
Bruno Oliveira
28937a5cd9 Add versionadded directive to doctest_namespace section 2016-03-02 23:37:51 -03:00
Bruno Oliveira
2e02a1c370 Give proper credit for PR #1428 2016-03-02 23:30:42 -03:00
Matt Williams
6dd2ff5332 Correct indentation in documentation 2016-03-02 13:02:15 +00:00
Matt Williams
891e029518 Add a new doctest_namespace fixture
This fixture can be used to inject names into the namespace in which
your doctests run.
2016-03-02 12:43:57 +00:00
Bruno Oliveira
5a2500800d Add 2.10.0.dev1 to CHANGELOG 2016-03-01 18:54:08 -03:00
Bruno Oliveira
c8c5a416ef Bump version to 2.10.0.dev1 2016-03-01 18:48:13 -03:00
163 changed files with 8369 additions and 5026 deletions

View File

@@ -4,5 +4,5 @@ Here's a quick checklist in what to include:
- [ ] Include a detailed description of the bug or suggestion
- [ ] `pip list` of the virtual environment you are using
- [ ] py.test and operating system versions
- [ ] pytest and operating system versions
- [ ] Minimal example if possible

View File

@@ -2,7 +2,10 @@ Thanks for submitting a PR, your contribution is really appreciated!
Here's a quick checklist that should be present in PRs:
- [ ] Target: for bug or doc fixes, target `master`; for new features, target `features`
- [ ] Make sure to include one or more tests for your change
- [ ] Add yourself to `AUTHORS`
- [ ] Add a new entry to the `CHANGELOG` (choose any open position to avoid merge conflicts with other PRs)
- [ ] Target: for bug or doc fixes, target `master`; for new features, target `features`;
- [ ] Make sure to include one or more tests for your change;
- [ ] Add yourself to `AUTHORS`;
- [ ] Add a new entry to `CHANGELOG.rst`
* Choose any open position to avoid merge conflicts with other PRs.
* Add a link to the issue you are fixing (if any) using RST syntax.
* The pytest team likes to have people to acknowledged in the `CHANGELOG`, so please add a thank note to yourself ("Thanks @user for the PR") and a link to your GitHub profile. It may sound weird thanking yourself, but otherwise a maintainer would have to do it manually before or after merging instead of just using GitHub's merge button. This makes it easier on the maintainers to merge PRs.

1
.gitignore vendored
View File

@@ -33,3 +33,4 @@ env/
.coverage
.ropeproject
.idea
.hypothesis

View File

@@ -25,7 +25,8 @@ env:
- TESTENV=py35-trial
- TESTENV=py27-nobyte
- TESTENV=doctesting
- TESTENV=py27-cxfreeze
- TESTENV=freeze
- TESTENV=docs
script: tox --recreate -e $TESTENV

57
AUTHORS
View File

@@ -3,44 +3,61 @@ merlinux GmbH, Germany, office at merlinux eu
Contributors include::
Abdeali JK
Abhijeet Kasurde
Ahn Ki-Wook
Alexei Kozlenok
Anatoly Bubenkoff
Andreas Zeidler
Andrzej Ostrowski
Andy Freeland
Anthon van der Neut
Antony Lee
Armin Rigo
Aron Curzon
Aviv Palivoda
Ben Webb
Benjamin Peterson
Bernard Pratz
Bob Ippolito
Brian Dorsey
Brian Okken
Brianna Laugher
Bruno Oliveira
Cal Leeming
Carl Friedrich Bolz
Charles Cloud
Charnjit SiNGH (CCSJ)
Chris Lamb
Christian Boelsen
Christian Theunert
Christian Tismer
Christopher Gilling
Daniel Grana
Daniel Hahler
Daniel Nuri
Danielle Jenkins
Dave Hunt
David Díaz-Barquero
David Mohr
David Vierra
Diego Russo
Dmitry Dygalo
Edison Gustavo Muenz
Edoardo Batini
Eduardo Schettino
Endre Galaczi
Elizaveta Shashkova
Endre Galaczi
Eric Hunsberger
Eric Siegerman
Erik M. Bray
Feng Ma
Florian Bruhin
Floris Bruynooghe
Gabriel Reis
Georgy Dyuldin
Graham Horler
Greg Price
Grig Gheorghiu
Guido Wesdorp
Harald Armin Massa
@@ -49,9 +66,15 @@ Jaap Broekhuizen
Jan Balster
Janne Vanhala
Jason R. Coombs
Javier Domingo Cansino
Javier Romero
John Towler
Jon Sonesen
Jordan Guymon
Joshua Bronson
Jurko Gospodnetić
Justyna Janczyszyn
Kale Kundert
Katarzyna Jachim
Kevin Cox
Lee Kamentsky
@@ -59,33 +82,49 @@ Lukas Bednar
Maciek Fijalkowski
Maho
Marc Schlaich
Marcin Bachry
Mark Abramowitz
Markus Unterwaditzer
Martijn Faassen
Martin K. Scherer
Martin Prusse
Matt Bachmann
Matt Williams
Matthias Hafner
mbyt
Michael Aquilina
Michael Birtwell
Michael Droettboom
Mike Lundy
Nicolas Delaby
Oleg Pidsadnyi
Oliver Bestwalter
Omar Kohl
Pieter Mulder
Piotr Banaszkiewicz
Punyashloka Biswal
Quentin Pradet
Ralf Schmitt
Raphael Pierzina
Roberto Polli
Romain Dorgueil
Roman Bolshakov
Ronny Pfannschmidt
Ross Lawley
Russel Winder
Ryan Wooden
Samuele Pedroni
Simon Gomizelj
Stefan Farmbauer
Stefan Zimmermann
Stefano Taschini
Steffen Allner
Stephan Obermann
Tareq Alayan
Ted Xiao
Thomas Grainger
Tom Viner
Trevor Bekolay
Vasily Kuznetsov
Wouter van Ackooy
David Díaz-Barquero
Eric Hunsberger
Simon Gomizelj
Russel Winder
Ben Webb
Alexei Kozlenok
Cal Leeming
Feng Ma
Xuecong Liao

View File

@@ -1,3 +1,491 @@
3.0.2
=====
* Improve error message when passing non-string ids to ``pytest.mark.parametrize`` (`#1857`_).
Thanks `@okken`_ for the report and `@nicoddemus`_ for the PR.
* Add ``buffer`` attribute to stdin stub class ``pytest.capture.DontReadFromInput``
Thanks `@joguSD`_ for the PR.
* Fix ``UnicodeEncodeError`` when string comparison with unicode has failed. (`#1864`_)
Thanks `@AiOO`_ for the PR.
* ``pytest_plugins`` is now handled correctly if defined as a string (as opposed as
a sequence of strings) when modules are considered for assertion rewriting.
Due to this bug, much more modules were being rewritten than necessary
if a test suite uses ``pytest_plugins`` to load internal plugins (`#1888`_).
Thanks `@jaraco`_ for the report and `@nicoddemus`_ for the PR (`#1891`_).
* Do not call tearDown and cleanups when running tests from
``unittest.TestCase`` subclasses with ``--pdb``
enabled. This allows proper post mortem debugging for all applications
which have significant logic in their tearDown machinery (`#1890`_). Thanks
`@mbyt`_ for the PR.
* Fix use of deprecated ``getfuncargvalue`` method in the internal doctest plugin.
Thanks `@ViviCoder`_ for the report (`#1898`_).
.. _@joguSD: https://github.com/joguSD
.. _@AiOO: https://github.com/AiOO
.. _@mbyt: https://github.com/mbyt
.. _@ViviCoder: https://github.com/ViviCoder
.. _#1857: https://github.com/pytest-dev/pytest/issues/1857
.. _#1864: https://github.com/pytest-dev/pytest/issues/1864
.. _#1888: https://github.com/pytest-dev/pytest/issues/1888
.. _#1891: https://github.com/pytest-dev/pytest/pull/1891
.. _#1890: https://github.com/pytest-dev/pytest/issues/1890
.. _#1898: https://github.com/pytest-dev/pytest/issues/1898
3.0.1
=====
* Fix regression when ``importorskip`` is used at module level (`#1822`_).
Thanks `@jaraco`_ and `@The-Compiler`_ for the report and `@nicoddemus`_ for the PR.
* Fix parametrization scope when session fixtures are used in conjunction
with normal parameters in the same call (`#1832`_).
Thanks `@The-Compiler`_ for the report, `@Kingdread`_ and `@nicoddemus`_ for the PR.
* Fix internal error when parametrizing tests or fixtures using an empty ``ids`` argument (`#1849`_).
Thanks `@OPpuolitaival`_ for the report and `@nicoddemus`_ for the PR.
* Fix loader error when running ``pytest`` embedded in a zipfile.
Thanks `@mbachry`_ for the PR.
.. _@Kingdread: https://github.com/Kingdread
.. _@mbachry: https://github.com/mbachry
.. _@OPpuolitaival: https://github.com/OPpuolitaival
.. _#1822: https://github.com/pytest-dev/pytest/issues/1822
.. _#1832: https://github.com/pytest-dev/pytest/issues/1832
.. _#1849: https://github.com/pytest-dev/pytest/issues/1849
3.0.0
=====
**Incompatible changes**
A number of incompatible changes were made in this release, with the intent of removing features deprecated for a long
time or change existing behaviors in order to make them less surprising/more useful.
* Reinterpretation mode has now been removed. Only plain and rewrite
mode are available, consequently the ``--assert=reinterp`` option is
no longer available. Thanks `@flub`_ for the PR.
* The following deprecated commandline options were removed:
* ``--genscript``: no longer supported;
* ``--no-assert``: use ``--assert=plain`` instead;
* ``--nomagic``: use ``--assert=plain`` instead;
* ``--report``: use ``-r`` instead;
Thanks to `@RedBeardCode`_ for the PR (`#1664`_).
* ImportErrors in plugins now are a fatal error instead of issuing a
pytest warning (`#1479`_). Thanks to `@The-Compiler`_ for the PR.
* Removed support code for Python 3 versions < 3.3 (`#1627`_).
* Removed all ``py.test-X*`` entry points. The versioned, suffixed entry points
were never documented and a leftover from a pre-virtualenv era. These entry
points also created broken entry points in wheels, so removing them also
removes a source of confusion for users (`#1632`_).
Thanks `@obestwalter`_ for the PR.
* ``pytest.skip()`` now raises an error when used to decorate a test function,
as opposed to its original intent (to imperatively skip a test inside a test function). Previously
this usage would cause the entire module to be skipped (`#607`_).
Thanks `@omarkohl`_ for the complete PR (`#1519`_).
* Exit tests if a collection error occurs. A poll indicated most users will hit CTRL-C
anyway as soon as they see collection errors, so pytest might as well make that the default behavior (`#1421`_).
A ``--continue-on-collection-errors`` option has been added to restore the previous behaviour.
Thanks `@olegpidsadnyi`_ and `@omarkohl`_ for the complete PR (`#1628`_).
* Renamed the pytest ``pdb`` module (plugin) into ``debugging`` to avoid clashes with the builtin ``pdb`` module.
* Raise a helpful failure message when requesting a parametrized fixture at runtime,
e.g. with ``request.getfixturevalue``. Previously these parameters were simply
never defined, so a fixture decorated like ``@pytest.fixture(params=[0, 1, 2])``
only ran once (`#460`_).
Thanks to `@nikratio`_ for the bug report, `@RedBeardCode`_ and `@tomviner`_ for the PR.
* ``_pytest.monkeypatch.monkeypatch`` class has been renamed to ``_pytest.monkeypatch.MonkeyPatch``
so it doesn't conflict with the ``monkeypatch`` fixture.
* ``--exitfirst / -x`` can now be overridden by a following ``--maxfail=N``
and is just a synonym for ``--maxfail=1``.
**New Features**
* Support nose-style ``__test__`` attribute on methods of classes,
including unittest-style Classes. If set to ``False``, the test will not be
collected.
* New ``doctest_namespace`` fixture for injecting names into the
namespace in which doctests run.
Thanks `@milliams`_ for the complete PR (`#1428`_).
* New ``--doctest-report`` option available to change the output format of diffs
when running (failing) doctests (implements `#1749`_).
Thanks `@hartym`_ for the PR.
* New ``name`` argument to ``pytest.fixture`` decorator which allows a custom name
for a fixture (to solve the funcarg-shadowing-fixture problem).
Thanks `@novas0x2a`_ for the complete PR (`#1444`_).
* New ``approx()`` function for easily comparing floating-point numbers in
tests.
Thanks `@kalekundert`_ for the complete PR (`#1441`_).
* Ability to add global properties in the final xunit output file by accessing
the internal ``junitxml`` plugin (experimental).
Thanks `@tareqalayan`_ for the complete PR `#1454`_).
* New ``ExceptionInfo.match()`` method to match a regular expression on the
string representation of an exception (`#372`_).
Thanks `@omarkohl`_ for the complete PR (`#1502`_).
* ``__tracebackhide__`` can now also be set to a callable which then can decide
whether to filter the traceback based on the ``ExceptionInfo`` object passed
to it. Thanks `@The-Compiler`_ for the complete PR (`#1526`_).
* New ``pytest_make_parametrize_id(config, val)`` hook which can be used by plugins to provide
friendly strings for custom types.
Thanks `@palaviv`_ for the PR.
* ``capsys`` and ``capfd`` now have a ``disabled()`` context-manager method, which
can be used to temporarily disable capture within a test.
Thanks `@nicoddemus`_ for the PR.
* New cli flag ``--fixtures-per-test``: shows which fixtures are being used
for each selected test item. Features doc strings of fixtures by default.
Can also show where fixtures are defined if combined with ``-v``.
Thanks `@hackebrot`_ for the PR.
* Introduce ``pytest`` command as recommended entry point. Note that ``py.test``
still works and is not scheduled for removal. Closes proposal
`#1629`_. Thanks `@obestwalter`_ and `@davehunt`_ for the complete PR
(`#1633`_).
* New cli flags:
+ ``--setup-plan``: performs normal collection and reports
the potential setup and teardown and does not execute any fixtures and tests;
+ ``--setup-only``: performs normal collection, executes setup and teardown of
fixtures and reports them;
+ ``--setup-show``: performs normal test execution and additionally shows
setup and teardown of fixtures;
+ ``--keep-duplicates``: py.test now ignores duplicated paths given in the command
line. To retain the previous behavior where the same test could be run multiple
times by specifying it in the command-line multiple times, pass the ``--keep-duplicates``
argument (`#1609`_);
Thanks `@d6e`_, `@kvas-it`_, `@sallner`_, `@ioggstream`_ and `@omarkohl`_ for the PRs.
* New CLI flag ``--override-ini``/``-o``: overrides values from the ini file.
For example: ``"-o xfail_strict=True"``'.
Thanks `@blueyed`_ and `@fengxx`_ for the PR.
* New hooks:
+ ``pytest_fixture_setup(fixturedef, request)``: executes fixture setup;
+ ``pytest_fixture_post_finalizer(fixturedef)``: called after the fixture's
finalizer and has access to the fixture's result cache.
Thanks `@d6e`_, `@sallner`_.
* Issue warnings for asserts whose test is a tuple literal. Such asserts will
never fail because tuples are always truthy and are usually a mistake
(see `#1562`_). Thanks `@kvas-it`_, for the PR.
* Allow passing a custom debugger class (e.g. ``--pdbcls=IPython.core.debugger:Pdb``).
Thanks to `@anntzer`_ for the PR.
**Changes**
* Plugins now benefit from assertion rewriting. Thanks
`@sober7`_, `@nicoddemus`_ and `@flub`_ for the PR.
* Change ``report.outcome`` for ``xpassed`` tests to ``"passed"`` in non-strict
mode and ``"failed"`` in strict mode. Thanks to `@hackebrot`_ for the PR
(`#1795`_) and `@gprasad84`_ for report (`#1546`_).
* Tests marked with ``xfail(strict=False)`` (the default) now appear in
JUnitXML reports as passing tests instead of skipped.
Thanks to `@hackebrot`_ for the PR (`#1795`_).
* Highlight path of the file location in the error report to make it easier to copy/paste.
Thanks `@suzaku`_ for the PR (`#1778`_).
* Fixtures marked with ``@pytest.fixture`` can now use ``yield`` statements exactly like
those marked with the ``@pytest.yield_fixture`` decorator. This change renders
``@pytest.yield_fixture`` deprecated and makes ``@pytest.fixture`` with ``yield`` statements
the preferred way to write teardown code (`#1461`_).
Thanks `@csaftoiu`_ for bringing this to attention and `@nicoddemus`_ for the PR.
* Explicitly passed parametrize ids do not get escaped to ascii (`#1351`_).
Thanks `@ceridwen`_ for the PR.
* Fixtures are now sorted in the error message displayed when an unknown
fixture is declared in a test function.
Thanks `@nicoddemus`_ for the PR.
* ``pytest_terminal_summary`` hook now receives the ``exitstatus``
of the test session as argument. Thanks `@blueyed`_ for the PR (`#1809`_).
* Parametrize ids can accept ``None`` as specific test id, in which case the
automatically generated id for that argument will be used.
Thanks `@palaviv`_ for the complete PR (`#1468`_).
* The parameter to xunit-style setup/teardown methods (``setup_method``,
``setup_module``, etc.) is now optional and may be omitted.
Thanks `@okken`_ for bringing this to attention and `@nicoddemus`_ for the PR.
* Improved automatic id generation selection in case of duplicate ids in
parametrize.
Thanks `@palaviv`_ for the complete PR (`#1474`_).
* Now pytest warnings summary is shown up by default. Added a new flag
``--disable-pytest-warnings`` to explicitly disable the warnings summary (`#1668`_).
* Make ImportError during collection more explicit by reminding
the user to check the name of the test module/package(s) (`#1426`_).
Thanks `@omarkohl`_ for the complete PR (`#1520`_).
* Add ``build/`` and ``dist/`` to the default ``--norecursedirs`` list. Thanks
`@mikofski`_ for the report and `@tomviner`_ for the PR (`#1544`_).
* ``pytest.raises`` in the context manager form accepts a custom
``message`` to raise when no exception occurred.
Thanks `@palaviv`_ for the complete PR (`#1616`_).
* ``conftest.py`` files now benefit from assertion rewriting; previously it
was only available for test modules. Thanks `@flub`_, `@sober7`_ and
`@nicoddemus`_ for the PR (`#1619`_).
* Text documents without any doctests no longer appear as "skipped".
Thanks `@graingert`_ for reporting and providing a full PR (`#1580`_).
* Ensure that a module within a namespace package can be found when it
is specified on the command line together with the ``--pyargs``
option. Thanks to `@taschini`_ for the PR (`#1597`_).
* Always include full assertion explanation during assertion rewriting. The previous behaviour was hiding
sub-expressions that happened to be ``False``, assuming this was redundant information.
Thanks `@bagerard`_ for reporting (`#1503`_). Thanks to `@davehunt`_ and
`@tomviner`_ for the PR.
* ``OptionGroup.addoption()`` now checks if option names were already
added before, to make it easier to track down issues like `#1618`_.
Before, you only got exceptions later from ``argparse`` library,
giving no clue about the actual reason for double-added options.
* ``yield``-based tests are considered deprecated and will be removed in pytest-4.0.
Thanks `@nicoddemus`_ for the PR.
* ``[pytest]`` sections in ``setup.cfg`` files should now be named ``[tool:pytest]``
to avoid conflicts with other distutils commands (see `#567`_). ``[pytest]`` sections in
``pytest.ini`` or ``tox.ini`` files are supported and unchanged.
Thanks `@nicoddemus`_ for the PR.
* Using ``pytest_funcarg__`` prefix to declare fixtures is considered deprecated and will be
removed in pytest-4.0 (`#1684`_).
Thanks `@nicoddemus`_ for the PR.
* Passing a command-line string to ``pytest.main()`` is considered deprecated and scheduled
for removal in pytest-4.0. It is recommended to pass a list of arguments instead (`#1723`_).
* Rename ``getfuncargvalue`` to ``getfixturevalue``. ``getfuncargvalue`` is
still present but is now considered deprecated. Thanks to `@RedBeardCode`_ and `@tomviner`_
for the PR (`#1626`_).
* ``optparse`` type usage now triggers DeprecationWarnings (`#1740`_).
* ``optparse`` backward compatibility supports float/complex types (`#457`_).
* Refined logic for determining the ``rootdir``, considering only valid
paths which fixes a number of issues: `#1594`_, `#1435`_ and `#1471`_.
Updated the documentation according to current behavior. Thanks to
`@blueyed`_, `@davehunt`_ and `@matthiasha`_ for the PR.
* Always include full assertion explanation. The previous behaviour was hiding
sub-expressions that happened to be False, assuming this was redundant information.
Thanks `@bagerard`_ for reporting (`#1503`_). Thanks to `@davehunt`_ and
`@tomviner`_ for PR.
* Better message in case of not using parametrized variable (see `#1539`_).
Thanks to `@tramwaj29`_ for the PR.
* Updated docstrings with a more uniform style.
* Add stderr write for ``pytest.exit(msg)`` during startup. Previously the message was never shown.
Thanks `@BeyondEvil`_ for reporting `#1210`_. Thanks to `@JonathonSonesen`_ and
`@tomviner`_ for the PR.
* No longer display the incorrect test deselection reason (`#1372`_).
Thanks `@ronnypfannschmidt`_ for the PR.
* The ``--resultlog`` command line option has been deprecated: it is little used
and there are more modern and better alternatives (see `#830`_).
Thanks `@nicoddemus`_ for the PR.
* Improve error message with fixture lookup errors: add an 'E' to the first
line and '>' to the rest. Fixes `#717`_. Thanks `@blueyed`_ for reporting and
a PR, `@eolo999`_ for the initial PR and `@tomviner`_ for his guidance during
EuroPython2016 sprint.
**Bug Fixes**
* Parametrize now correctly handles duplicated test ids.
* Fix internal error issue when the ``method`` argument is missing for
``teardown_method()`` (`#1605`_).
* Fix exception visualization in case the current working directory (CWD) gets
deleted during testing (`#1235`_). Thanks `@bukzor`_ for reporting. PR by
`@marscher`_.
* Improve test output for logical expression with brackets (`#925`_).
Thanks `@DRMacIver`_ for reporting and `@RedBeardCode`_ for the PR.
* Create correct diff for strings ending with newlines (`#1553`_).
Thanks `@Vogtinator`_ for reporting and `@RedBeardCode`_ and
`@tomviner`_ for the PR.
* ``ConftestImportFailure`` now shows the traceback making it easier to
identify bugs in ``conftest.py`` files (`#1516`_). Thanks `@txomon`_ for
the PR.
* Text documents without any doctests no longer appear as "skipped".
Thanks `@graingert`_ for reporting and providing a full PR (`#1580`_).
* Fixed collection of classes with custom ``__new__`` method.
Fixes `#1579`_. Thanks to `@Stranger6667`_ for the PR.
* Fixed scope overriding inside metafunc.parametrize (`#634`_).
Thanks to `@Stranger6667`_ for the PR.
* Fixed the total tests tally in junit xml output (`#1798`_).
Thanks to `@cryporchild`_ for the PR.
* Fixed off-by-one error with lines from ``request.node.warn``.
Thanks to `@blueyed`_ for the PR.
.. _#1210: https://github.com/pytest-dev/pytest/issues/1210
.. _#1235: https://github.com/pytest-dev/pytest/issues/1235
.. _#1351: https://github.com/pytest-dev/pytest/issues/1351
.. _#1372: https://github.com/pytest-dev/pytest/issues/1372
.. _#1421: https://github.com/pytest-dev/pytest/issues/1421
.. _#1426: https://github.com/pytest-dev/pytest/issues/1426
.. _#1428: https://github.com/pytest-dev/pytest/pull/1428
.. _#1435: https://github.com/pytest-dev/pytest/issues/1435
.. _#1441: https://github.com/pytest-dev/pytest/pull/1441
.. _#1444: https://github.com/pytest-dev/pytest/pull/1444
.. _#1454: https://github.com/pytest-dev/pytest/pull/1454
.. _#1461: https://github.com/pytest-dev/pytest/pull/1461
.. _#1468: https://github.com/pytest-dev/pytest/pull/1468
.. _#1471: https://github.com/pytest-dev/pytest/issues/1471
.. _#1474: https://github.com/pytest-dev/pytest/pull/1474
.. _#1479: https://github.com/pytest-dev/pytest/issues/1479
.. _#1502: https://github.com/pytest-dev/pytest/pull/1502
.. _#1503: https://github.com/pytest-dev/pytest/issues/1503
.. _#1516: https://github.com/pytest-dev/pytest/pull/1516
.. _#1519: https://github.com/pytest-dev/pytest/pull/1519
.. _#1520: https://github.com/pytest-dev/pytest/pull/1520
.. _#1526: https://github.com/pytest-dev/pytest/pull/1526
.. _#1539: https://github.com/pytest-dev/pytest/issues/1539
.. _#1544: https://github.com/pytest-dev/pytest/issues/1544
.. _#1546: https://github.com/pytest-dev/pytest/issues/1546
.. _#1553: https://github.com/pytest-dev/pytest/issues/1553
.. _#1562: https://github.com/pytest-dev/pytest/issues/1562
.. _#1579: https://github.com/pytest-dev/pytest/issues/1579
.. _#1580: https://github.com/pytest-dev/pytest/pull/1580
.. _#1594: https://github.com/pytest-dev/pytest/issues/1594
.. _#1597: https://github.com/pytest-dev/pytest/pull/1597
.. _#1605: https://github.com/pytest-dev/pytest/issues/1605
.. _#1616: https://github.com/pytest-dev/pytest/pull/1616
.. _#1618: https://github.com/pytest-dev/pytest/issues/1618
.. _#1619: https://github.com/pytest-dev/pytest/issues/1619
.. _#1626: https://github.com/pytest-dev/pytest/pull/1626
.. _#1627: https://github.com/pytest-dev/pytest/pull/1627
.. _#1628: https://github.com/pytest-dev/pytest/pull/1628
.. _#1629: https://github.com/pytest-dev/pytest/issues/1629
.. _#1632: https://github.com/pytest-dev/pytest/issues/1632
.. _#1633: https://github.com/pytest-dev/pytest/pull/1633
.. _#1664: https://github.com/pytest-dev/pytest/pull/1664
.. _#1668: https://github.com/pytest-dev/pytest/issues/1668
.. _#1684: https://github.com/pytest-dev/pytest/pull/1684
.. _#1723: https://github.com/pytest-dev/pytest/pull/1723
.. _#1740: https://github.com/pytest-dev/pytest/issues/1740
.. _#1749: https://github.com/pytest-dev/pytest/issues/1749
.. _#1778: https://github.com/pytest-dev/pytest/pull/1778
.. _#1795: https://github.com/pytest-dev/pytest/pull/1795
.. _#1798: https://github.com/pytest-dev/pytest/pull/1798
.. _#1809: https://github.com/pytest-dev/pytest/pull/1809
.. _#372: https://github.com/pytest-dev/pytest/issues/372
.. _#457: https://github.com/pytest-dev/pytest/issues/457
.. _#460: https://github.com/pytest-dev/pytest/pull/460
.. _#567: https://github.com/pytest-dev/pytest/pull/567
.. _#607: https://github.com/pytest-dev/pytest/issues/607
.. _#634: https://github.com/pytest-dev/pytest/issues/634
.. _#717: https://github.com/pytest-dev/pytest/issues/717
.. _#830: https://github.com/pytest-dev/pytest/issues/830
.. _#925: https://github.com/pytest-dev/pytest/issues/925
.. _@anntzer: https://github.com/anntzer
.. _@bagerard: https://github.com/bagerard
.. _@BeyondEvil: https://github.com/BeyondEvil
.. _@blueyed: https://github.com/blueyed
.. _@ceridwen: https://github.com/ceridwen
.. _@cryporchild: https://github.com/cryporchild
.. _@csaftoiu: https://github.com/csaftoiu
.. _@d6e: https://github.com/d6e
.. _@davehunt: https://github.com/davehunt
.. _@DRMacIver: https://github.com/DRMacIver
.. _@eolo999: https://github.com/eolo999
.. _@fengxx: https://github.com/fengxx
.. _@flub: https://github.com/flub
.. _@gprasad84: https://github.com/gprasad84
.. _@graingert: https://github.com/graingert
.. _@hartym: https://github.com/hartym
.. _@JonathonSonesen: https://github.com/JonathonSonesen
.. _@kalekundert: https://github.com/kalekundert
.. _@kvas-it: https://github.com/kvas-it
.. _@marscher: https://github.com/marscher
.. _@mikofski: https://github.com/mikofski
.. _@milliams: https://github.com/milliams
.. _@nikratio: https://github.com/nikratio
.. _@novas0x2a: https://github.com/novas0x2a
.. _@obestwalter: https://github.com/obestwalter
.. _@okken: https://github.com/okken
.. _@olegpidsadnyi: https://github.com/olegpidsadnyi
.. _@omarkohl: https://github.com/omarkohl
.. _@palaviv: https://github.com/palaviv
.. _@RedBeardCode: https://github.com/RedBeardCode
.. _@sallner: https://github.com/sallner
.. _@sober7: https://github.com/sober7
.. _@Stranger6667: https://github.com/Stranger6667
.. _@suzaku: https://github.com/suzaku
.. _@tareqalayan: https://github.com/tareqalayan
.. _@taschini: https://github.com/taschini
.. _@tramwaj29: https://github.com/tramwaj29
.. _@txomon: https://github.com/txomon
.. _@Vogtinator: https://github.com/Vogtinator
.. _@matthiasha: https://github.com/matthiasha
2.9.2
=====
@@ -30,8 +518,8 @@
.. _#510: https://github.com/pytest-dev/pytest/issues/510
.. _#1506: https://github.com/pytest-dev/pytest/pull/1506
.. _#1496: https://github.com/pytest-dev/pytest/issue/1496
.. _#1524: https://github.com/pytest-dev/pytest/issue/1524
.. _#1496: https://github.com/pytest-dev/pytest/issues/1496
.. _#1524: https://github.com/pytest-dev/pytest/pull/1524
.. _@prusse-martin: https://github.com/prusse-martin
.. _@astraw38: https://github.com/astraw38
@@ -62,11 +550,13 @@
* Fix (`#649`_): parametrized test nodes cannot be specified to run on the command line.
* Fix (`#138`_): better reporting for python 3.3+ chained exceptions
.. _#1437: https://github.com/pytest-dev/pytest/issues/1437
.. _#469: https://github.com/pytest-dev/pytest/issues/469
.. _#1431: https://github.com/pytest-dev/pytest/pull/1431
.. _#649: https://github.com/pytest-dev/pytest/issues/649
.. _#138: https://github.com/pytest-dev/pytest/issues/138
.. _@asottile: https://github.com/asottile
@@ -156,7 +646,7 @@
Thanks `@biern`_ for the PR.
* Fix `traceback style docs`_ to describe all of the available options
(auto/long/short/line/native/no), with `auto` being the default since v2.6.
(auto/long/short/line/native/no), with ``auto`` being the default since v2.6.
Thanks `@hackebrot`_ for the PR.
* Fix (`#1422`_): junit record_xml_property doesn't allow multiple records
@@ -164,6 +654,7 @@
.. _`traceback style docs`: https://pytest.org/latest/usage.html#modifying-python-traceback-printing
.. _#1609: https://github.com/pytest-dev/pytest/issues/1609
.. _#1422: https://github.com/pytest-dev/pytest/issues/1422
.. _#1379: https://github.com/pytest-dev/pytest/issues/1379
.. _#1366: https://github.com/pytest-dev/pytest/issues/1366
@@ -188,8 +679,8 @@
.. _@RonnyPfannschmidt: https://github.com/RonnyPfannschmidt
.. _@rabbbit: https://github.com/rabbbit
.. _@hackebrot: https://github.com/hackebrot
.. _@omarkohl: https://github.com/omarkohl
.. _@pquentin: https://github.com/pquentin
.. _@ioggstream: https://github.com/ioggstream
2.8.7
=====
@@ -773,7 +1264,7 @@
dep). Thanks Charles Cloud for analysing the issue.
- fix conftest related fixture visibility issue: when running with a
CWD outside a test package pytest would get fixture discovery wrong.
CWD outside of a test package pytest would get fixture discovery wrong.
Thanks to Wolfgang Schnerring for figuring out a reproducable example.
- Introduce pytest_enter_pdb hook (needed e.g. by pytest_timeout to cancel the

View File

@@ -48,7 +48,7 @@ to fix the bug yet.
Fix bugs
--------
Look through the GitHub issues for bugs. Here is sample filter you can use:
Look through the GitHub issues for bugs. Here is a filter you can use:
https://github.com/pytest-dev/pytest/labels/bug
:ref:`Talk <contact>` to developers to find out how you can fix specific bugs.
@@ -60,8 +60,7 @@ Don't forget to check the issue trackers of your favourite plugins, too!
Implement features
------------------
Look through the GitHub issues for enhancements. Here is sample filter you
can use:
Look through the GitHub issues for enhancements. Here is a filter you can use:
https://github.com/pytest-dev/pytest/labels/enhancement
:ref:`Talk <contact>` to developers to find out how you can implement specific
@@ -70,16 +69,15 @@ features.
Write documentation
-------------------
pytest could always use more documentation. What exactly is needed?
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 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
without needing to make a fork and local copy. This can be convenient for
small fixes.
You can also edit documentation files directly in the GitHub web interface,
without using a local copy. This can be convenient for small fixes.
.. _submitplugin:
@@ -95,13 +93,14 @@ in repositories living under the ``pytest-dev`` organisations:
- `pytest-dev on Bitbucket <https://bitbucket.org/pytest-dev>`_
All pytest-dev Contributors team members have write access to all contained
repositories. pytest core and plugins are generally developed
repositories. Pytest core and plugins are generally developed
using `pull requests`_ to respective repositories.
The objectives of the ``pytest-dev`` organisation are:
* Having a central location for popular pytest plugins
* Sharing some of the maintenance responsibility (in case a maintainer no longer whishes to maintain a plugin)
* Sharing some of the maintenance responsibility (in case a maintainer no
longer wishes to maintain a plugin)
You can submit your plugin by subscribing to the `pytest-dev mail list
<https://mail.python.org/mailman/listinfo/pytest-dev>`_ and writing a
@@ -121,33 +120,26 @@ the following:
- an issue tracker for bug reports and enhancement requests.
- a `changelog <http://keepachangelog.com/>`_
If no contributor strongly objects and two agree, the repository can then be
transferred to the ``pytest-dev`` organisation.
Here's a rundown of how a repository transfer usually proceeds
(using a repository named ``joedoe/pytest-xyz`` as example):
* One of the ``pytest-dev`` administrators creates:
- ``pytest-xyz-admin`` team, with full administration rights to
``pytest-dev/pytest-xyz``.
- ``pytest-xyz-developers`` team, with write access to
``pytest-dev/pytest-xyz``.
* ``joedoe`` is invited to the ``pytest-xyz-admin`` team;
* After accepting the invitation, ``joedoe`` transfers the repository from its
original location to ``pytest-dev/pytest-xyz`` (A nice feature is that GitHub handles URL redirection from
the old to the new location automatically).
* ``joedoe`` is free to add any other collaborators to the
``pytest-xyz-admin`` or ``pytest-xyz-developers`` team as desired.
* ``joedoe`` transfers repository ownership to ``pytest-dev`` administrator ``calvin``.
* ``calvin`` creates ``pytest-xyz-admin`` and ``pytest-xyz-developers`` teams, inviting ``joedoe`` to both as **maintainer**.
* ``calvin`` transfers repository to ``pytest-dev`` and configures team access:
- ``pytest-xyz-admin`` **admin** access;
- ``pytest-xyz-developers`` **write** access;
The ``pytest-dev/Contributors`` team has write access to all projects, and
every project administrator is in it. We recommend that each plugin has at least three
people who have the right to release to PyPI.
Repository owners can be assured that no ``pytest-dev`` administrator will ever make
Repository owners can rest assured that no ``pytest-dev`` administrator will ever make
releases of your repository or take ownership in any way, except in rare cases
where someone becomes unresponsive after months of contact attempts.
As stated, the objective is to share maintenance and avoid "plugin-abandon".
@@ -159,15 +151,11 @@ As stated, the objective is to share maintenance and avoid "plugin-abandon".
Preparing Pull Requests on GitHub
---------------------------------
There's an excellent tutorial on how Pull Requests work in the
`GitHub Help Center <https://help.github.com/articles/using-pull-requests/>`_
.. note::
What is a "pull request"? It informs project's core developers about the
changes you want to review and merge. Pull requests are stored on
`GitHub servers <https://github.com/pytest-dev/pytest/pulls>`_.
Once you send pull request, we can discuss it's potential modifications and
Once you send a pull request, we can discuss its potential modifications and
even add more commits to it later on.
There's an excellent tutorial on how Pull Requests work in the
@@ -211,35 +199,35 @@ but here is a simple overview:
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 linting,py27,py35
$ python3 runtox.py -e linting,py27,py35
This command will run tests via the "tox" tool against Python 2.7 and 3.5
and also perform "lint" 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
index where newer (not yet released to PyPI) versions of dependencies
(especially ``py``) might be present.
#. 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::
To run tests on Python 2.7 and pass options to pytest (e.g. enter pdb on
failure) to pytest you can do::
$ python runtox.py -e py27 -- --pdb
$ python3 runtox.py -e py27 -- --pdb
or to only run tests in a particular test module on py35::
Or to only run tests in a particular test module on Python 3.5::
$ python runtox.py -e py35 -- testing/test_config.py
$ python3 runtox.py -e py35 -- testing/test_config.py
#. Commit and push once your tests pass and you are happy with your change(s)::
$ git commit -a -m "<commit message>"
$ git push -u
Make sure you add a CHANGELOG message, and add yourself to AUTHORS. If you
are unsure about either of these steps, submit your pull request and we'll
help you fix it up.
Make sure you add a message to ``CHANGELOG.rst`` and add yourself to
``AUTHORS``. If you 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 using this data::
@@ -248,6 +236,6 @@ but here is a simple overview:
base-fork: pytest-dev/pytest
base: master # if it's a bugfix
base: feature # if it's a feature
base: features # if it's a feature

View File

@@ -3,90 +3,83 @@ How to release pytest
Note: this assumes you have already registered on pypi.
0. create the branch release-VERSION
use features as base for minor/major releases
and master as base for bugfix releases
1. Bump version numbers in ``_pytest/__init__.py`` (``setup.py`` reads it).
1. Bump version numbers in _pytest/__init__.py (setup.py reads it)
2. Check and finalize ``CHANGELOG.rst``.
2. Check and finalize CHANGELOG
3. Write ``doc/en/announce/release-VERSION.txt`` and include
it in ``doc/en/announce/index.txt``. Run this command to list names of authors involved::
3. Write doc/en/announce/release-VERSION.txt and include
it in doc/en/announce/index.txt::
git log $(git describe --abbrev=0 --tags)..HEAD --format='%aN' | sort -u
git log 2.8.2..HEAD --format='%aN' | sort -u # lists the names of authors involved
4. Regenerate the docs examples using tox::
4. Use devpi for uploading a release tarball to a staging area::
tox -e regen
5. At this point, open a PR named ``release-X`` so others can help find regressions or provide suggestions.
6. Use devpi for uploading a release tarball to a staging area::
devpi use https://devpi.net/USER/dev
devpi upload --formats sdist,bdist_wheel
5. Run from multiple machines::
7. Run from multiple machines::
devpi use https://devpi.net/USER/dev
devpi test pytest==VERSION
6. Check that tests pass for relevant combinations with::
Alternatively, you can use `devpi-cloud-tester <https://github.com/nicoddemus/devpi-cloud-tester>`_ to test
the package on AppVeyor and Travis (follow instructions on the ``README``).
8. Check that tests pass for relevant combinations with::
devpi list pytest
or look at failures with "devpi list -f pytest".
7. Regenerate the docs examples using tox, and check for regressions::
9. Feeling confident? Publish to pypi::
tox -e regen
git diff
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>`_.
8. Build the docs, you need a virtualenv with py and sphinx
installed::
10. Tag the release::
cd doc/en
make html
git tag VERSION <hash>
git push origin VERSION
Commit any changes before tagging the release.
Make sure ``<hash>`` is **exactly** the git hash at the time the package was created.
9. Tag the release::
11. Send release announcement to mailing lists:
git tag VERSION
git push
10. Upload the docs using doc/en/Makefile::
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.
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
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>`_.
12. Send release announcement to mailing lists:
- pytest-dev
- testing-in-python
- pytest-dev@python.org
- testing-in-python@lists.idyll.org
- python-announce-list@python.org
And announce the release on Twitter, making sure to add the hashtag ``#pytest``.
12. **After the release**
a. **patch release (2.8.3)**:
1. Checkout ``master``.
2. Update version number in ``_pytest/__init__.py`` to ``"2.8.4.dev"``.
3. Create a new section in ``CHANGELOG.rst`` titled ``2.8.4.dev`` and add a few bullet points as placeholders for new entries.
4. Commit and push.
b. **minor release (2.9.0)**:
1. Merge ``features`` into ``master``.
2. Checkout ``master``.
3. Follow the same steps for a **patch release** above, using the next patch release: ``2.9.1.dev``.
4. Commit ``master``.
5. Checkout ``features`` and merge with ``master`` (should be a fast-forward at this point).
6. Update version number in ``_pytest/__init__.py`` to the next minor release: ``"2.10.0.dev"``.
7. Create a new section in ``CHANGELOG.rst`` titled ``2.10.0.dev``, above ``2.9.1.dev``, and add a few bullet points as placeholders for new entries.
8. Commit ``features``.
9. Push ``master`` and ``features``.
c. **major release (3.0.0)**: same steps as that of a **minor release**
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 master branch and do a pull request against it
15. merge from master to features

View File

@@ -1,365 +0,0 @@
recorder = monkeypatch.function(".......")
-------------------------------------------------------------
tags: nice feature
Like monkeypatch.replace but sets a mock-like call recorder:
recorder = monkeypatch.function("os.path.abspath")
recorder.set_return("/hello")
os.path.abspath("hello")
call, = recorder.calls
assert call.args.path == "hello"
assert call.returned == "/hello"
...
Unlike mock, "args.path" acts on the parsed auto-spec'ed ``os.path.abspath``
so it's independent from if the client side called "os.path.abspath(path=...)"
or "os.path.abspath('positional')".
refine parametrize API
-------------------------------------------------------------
tags: critical feature
extend metafunc.parametrize to directly support indirection, example:
def setupdb(request, config):
# setup "resource" based on test request and the values passed
# in to parametrize. setupfunc is called for each such value.
# you may use request.addfinalizer() or request.cached_setup ...
return dynamic_setup_database(val)
@pytest.mark.parametrize("db", ["pg", "mysql"], setupfunc=setupdb)
def test_heavy_functional_test(db):
...
There would be no need to write or explain funcarg factories and
their special __ syntax.
The examples and improvements should also show how to put the parametrize
decorator to a class, to a module or even to a directory. For the directory
part a conftest.py content like this::
pytestmark = [
@pytest.mark.parametrize_setup("db", ...),
]
probably makes sense in order to keep the declarative nature. This mirrors
the marker-mechanism with respect to a test module but puts it to a directory
scale.
When doing larger scoped parametrization it probably becomes necessary
to allow parametrization to be ignored if the according parameter is not
used (currently any parametrized argument that is not present in a function will cause a ValueError). Example:
@pytest.mark.parametrize("db", ..., mustmatch=False)
means to not raise an error but simply ignore the parametrization
if the signature of a decorated function does not match. XXX is it
not sufficient to always allow non-matches?
allow parametrized attributes on classes
--------------------------------------------------
tags: wish 2.4
example:
@pytest.mark.parametrize_attr("db", setupfunc, [1,2,3], scope="class")
@pytest.mark.parametrize_attr("tmp", setupfunc, scope="...")
class TestMe:
def test_hello(self):
access self.db ...
this would run the test_hello() function three times with three
different values for self.db. This could also work with unittest/nose
style tests, i.e. it leverages existing test suites without needing
to rewrite them. Together with the previously mentioned setup_test()
maybe the setupfunc could be omitted?
optimizations
---------------------------------------------------------------
tags: 2.4 core
- look at ihook optimization such that all lookups for
hooks relating to the same fspath are cached.
fix start/finish partial finailization problem
---------------------------------------------------------------
tags: bug core
if a configure/runtest_setup/sessionstart/... hook invocation partially
fails the sessionfinishes is not called. Each hook implementation
should better be repsonsible for registering a cleanup/finalizer
appropriately to avoid this issue. Moreover/Alternatively, we could
record which implementations of a hook succeeded and only call their
teardown.
relax requirement to have tests/testing contain an __init__
----------------------------------------------------------------
tags: feature
bb: http://bitbucket.org/hpk42/py-trunk/issue/64
A local test run of a "tests" directory may work
but a remote one fail because the tests directory
does not contain an "__init__.py". Either give
an error or make it work without the __init__.py
i.e. port the nose-logic of unloading a test module.
customize test function collection
-------------------------------------------------------
tags: feature
- introduce pytest.mark.nocollect for not considering a function for
test collection at all. maybe also introduce a pytest.mark.test to
explicitly mark a function to become a tested one. Lookup JUnit ways
of tagging tests.
introduce pytest.mark.importorskip
-------------------------------------------------------
tags: feature
in addition to the imperative pytest.importorskip also introduce
a pytest.mark.importorskip so that the test count is more correct.
introduce pytest.mark.platform
-------------------------------------------------------
tags: feature
Introduce nice-to-spell platform-skipping, examples:
@pytest.mark.platform("python3")
@pytest.mark.platform("not python3")
@pytest.mark.platform("win32 and not python3")
@pytest.mark.platform("darwin")
@pytest.mark.platform("not (jython and win32)")
@pytest.mark.platform("not (jython and win32)", xfail=True)
etc. Idea is to allow Python expressions which can operate
on common spellings for operating systems and python
interpreter versions.
pytest.mark.xfail signature change
-------------------------------------------------------
tags: feature
change to pytest.mark.xfail(reason, (optional)condition)
to better implement the word meaning. It also signals
better that we always have some kind of an implementation
reason that can be formualated.
Compatibility? how to introduce a new name/keep compat?
allow to non-intrusively apply skipfs/xfail/marks
---------------------------------------------------
tags: feature
use case: mark a module or directory structures
to be skipped on certain platforms (i.e. no import
attempt will be made).
consider introducing a hook/mechanism that allows to apply marks
from conftests or plugins. (See extended parametrization)
explicit referencing of conftest.py files
-----------------------------------------
tags: feature
allow to name conftest.py files (in sub directories) that should
be imported early, as to include command line options.
improve central pytest ini file
-------------------------------
tags: feature
introduce more declarative configuration options:
- (to-be-collected test directories)
- required plugins
- test func/class/file matching patterns
- skip/xfail (non-intrusive)
- pytest.ini and tox.ini and setup.cfg configuration in the same file
new documentation
----------------------------------
tags: feature
- logo pytest
- examples for unittest or functional testing
- resource management for functional testing
- patterns: page object
have imported module mismatch honour relative paths
--------------------------------------------------------
tags: bug
With 1.1.1 pytest fails at least on windows if an import
is relative and compared against an absolute conftest.py
path. Normalize.
consider globals: pytest.ensuretemp and config
--------------------------------------------------------------
tags: experimental-wish
consider deprecating pytest.ensuretemp and pytest.config
to further reduce pytest globality. Also consider
having pytest.config and ensuretemp coming from
a plugin rather than being there from the start.
consider pytest_addsyspath hook
-----------------------------------------
tags: wish
pytest could call a new pytest_addsyspath() in order to systematically
allow manipulation of sys.path and to inhibit it via --no-addsyspath
in order to more easily run against installed packages.
Alternatively it could also be done via the config object
and pytest_configure.
deprecate global pytest.config usage
----------------------------------------------------------------
tags: feature
pytest.ensuretemp and pytest.config are probably the last
objects containing global state. Often using them is not
necessary. This is about trying to get rid of them, i.e.
deprecating them and checking with PyPy's usages as well
as others.
remove deprecated bits in collect.py
-------------------------------------------------------------------
tags: feature
In an effort to further simplify code, review and remove deprecated bits
in collect.py. Probably good:
- inline consider_file/dir methods, no need to have them
subclass-overridable because of hooks
implement fslayout decorator
---------------------------------
tags: feature
Improve the way how tests can work with pre-made examples,
keeping the layout close to the test function:
@pytest.mark.fslayout("""
conftest.py:
# empty
tests/
test_%(NAME)s: # becomes test_run1.py
def test_function(self):
pass
""")
def test_run(pytester, fslayout):
p = fslayout.findone("test_*.py")
result = pytester.runpytest(p)
assert result.ret == 0
assert result.passed == 1
Another idea is to allow to define a full scenario including the run
in one content string::
runscenario("""
test_{TESTNAME}.py:
import pytest
@pytest.mark.xfail
def test_that_fails():
assert 0
@pytest.mark.skipif("True")
def test_hello():
pass
conftest.py:
import pytest
def pytest_runsetup_setup(item):
pytest.skip("abc")
runpytest -rsxX
*SKIP*{TESTNAME}*
*1 skipped*
""")
This could be run with at least three different ways to invoke pytest:
through the shell, through "python -m pytest" and inlined. As inlined
would be the fastest it could be run first (or "--fast" mode).
Create isolate plugin
---------------------
tags: feature
The idea is that you can e.g. import modules in a test and afterwards
sys.modules, sys.meta_path etc would be reverted. It can go further
then just importing however, e.g. current working directory, file
descriptors, ...
This would probably be done by marking::
@pytest.mark.isolate(importing=True, cwd=True, fds=False)
def test_foo():
...
With the possibility of doing this globally in an ini-file.
fnmatch for test names
----------------------
tags: feature-wish
various testsuites use suffixes instead of prefixes for test classes
also it lends itself to bdd style test names::
class UserBehaviour:
def anonymous_should_not_have_inbox(user):
...
def registred_should_have_inbox(user):
..
using the following in pytest.ini::
[pytest]
python_classes = Test *Behaviour *Test
python_functions = test *_should_*
mechanism for running named parts of tests with different reporting behaviour
------------------------------------------------------------------------------
tags: feature-wish-incomplete
a few use-cases come to mind:
* fail assertions and record that without stopping a complete test
* this is in particular hepfull if a small bit of a test is known to fail/xfail::
def test_fun():
with pytest.section('fdcheck, marks=pytest.mark.xfail_if(...)):
breaks_on_windows()
* divide functional/acceptance tests into sections
* provide a different mechanism for generators, maybe something like::
def pytest_runtest_call(item)
if not generator:
...
prepare_check = GeneratorCheckprepare()
gen = item.obj(**fixtures)
for check in gen
id, call = prepare_check(check)
# bubble should only prevent exception propagation after a failure
# the whole test should still fail
# there might be need for a lower level api and taking custom markers into account
with pytest.section(id, bubble=False):
call()

View File

@@ -4,6 +4,7 @@ include AUTHORS
include README.rst
include CONTRIBUTING.rst
include HOWTORELEASE.rst
include tox.ini
include setup.py
@@ -29,6 +30,3 @@ recursive-exclude * *.pyc *.pyo
exclude appveyor/install.ps1
exclude appveyor.yml
exclude appveyor
exclude ISSUES.txt
exclude HOWTORELEASE.rst

View File

@@ -1,5 +1,5 @@
.. image:: http://pytest.org/latest/_static/pytest1.png
:target: http://pytest.org
.. image:: http://docs.pytest.org/en/latest/_static/pytest1.png
:target: http://docs.pytest.org
:align: center
:alt: pytest
@@ -17,7 +17,7 @@
:target: https://ci.appveyor.com/project/pytestbot/pytest
The ``pytest`` framework makes it easy to write small tests, yet
scales to support complex functional testing for applications and libraries.
scales to support complex functional testing for applications and libraries.
An example of a simple test:
@@ -33,9 +33,8 @@ An example of a simple test:
To execute it::
$ py.test
$ pytest
======= test session starts ========
platform linux -- Python 3.4.3, pytest-2.8.5, py-1.4.31, pluggy-0.3.1
collected 1 items
test_sample.py F
@@ -51,33 +50,34 @@ To execute it::
test_sample.py:5: AssertionError
======= 1 failed in 0.12 seconds ========
Due to ``py.test``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started <http://pytest.org/latest/getting-started.html#our-first-test-run>`_ for more examples.
Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started <http://docs.pytest.org/en/latest/getting-started.html#our-first-test-run>`_ for more examples.
Features
--------
- Detailed info on failing `assert statements <http://pytest.org/latest/assert.html>`_ (no need to remember ``self.assert*`` names);
- Detailed info on failing `assert statements <http://docs.pytest.org/en/latest/assert.html>`_ (no need to remember ``self.assert*`` names);
- `Auto-discovery
<http://pytest.org/latest/goodpractices.html#python-test-discovery>`_
<http://docs.pytest.org/en/latest/goodpractices.html#python-test-discovery>`_
of test modules and functions;
- `Modular fixtures <http://pytest.org/latest/fixture.html>`_ for
- `Modular fixtures <http://docs.pytest.org/en/latest/fixture.html>`_ for
managing small or parametrized long-lived test resources;
- Can run `unittest <http://pytest.org/latest/unittest.html>`_ (or trial),
`nose <http://pytest.org/latest/nose.html>`_ test suites out of the box;
- Can run `unittest <http://docs.pytest.org/en/latest/unittest.html>`_ (or trial),
`nose <http://docs.pytest.org/en/latest/nose.html>`_ test suites out of the box;
- Python2.6+, Python3.2+, PyPy-2.3, Jython-2.5 (untested);
- Python2.6+, Python3.3+, PyPy-2.3, Jython-2.5 (untested);
- Rich plugin architecture, with over 150+ `external plugins <http://pytest.org/latest/plugins.html#installing-external-plugins-searching>`_ and thriving community;
- Rich plugin architecture, with over 150+ `external plugins <http://docs.pytest.org/en/latest/plugins.html#installing-external-plugins-searching>`_ and thriving community;
Documentation
-------------
For full documentation, including installation, tutorials and PDF documents, please see http://pytest.org.
For full documentation, including installation, tutorials and PDF documents, please see http://docs.pytest.org.
Bugs/Requests
@@ -89,7 +89,7 @@ Please use the `GitHub issue tracker <https://github.com/pytest-dev/pytest/issue
Changelog
---------
Consult the `Changelog <http://pytest.org/latest/changelog.html>`_ page for fixes and enhancements of each version.
Consult the `Changelog <http://docs.pytest.org/en/latest/changelog.html>`_ page for fixes and enhancements of each version.
License

View File

@@ -1,2 +1,2 @@
#
__version__ = '2.9.2'
__version__ = '3.0.2'

View File

@@ -4,9 +4,6 @@ from .code import ExceptionInfo # noqa
from .code import Frame # noqa
from .code import Traceback # noqa
from .code import getrawcode # noqa
from .code import patch_builtins # noqa
from .code import unpatch_builtins # noqa
from .source import Source # noqa
from .source import compile_ as compile # noqa
from .source import getfslineno # noqa

View File

@@ -1,8 +1,8 @@
import sys
from inspect import CO_VARARGS, CO_VARKEYWORDS
import re
import py
builtin_repr = repr
reprlib = py.builtin._tryimport('repr', 'reprlib')
@@ -35,12 +35,16 @@ class Code(object):
def path(self):
""" return a path object pointing to source code (note that it
might not point to an actually existing file). """
p = py.path.local(self.raw.co_filename)
# maybe don't try this checking
if not p.check():
try:
p = py.path.local(self.raw.co_filename)
# maybe don't try this checking
if not p.check():
raise OSError("py.path check failed.")
except OSError:
# XXX maybe try harder like the weird logic
# in the standard lib [linecache.updatecache] does?
p = self.raw.co_filename
return p
@property
@@ -139,7 +143,8 @@ class TracebackEntry(object):
_repr_style = None
exprinfo = None
def __init__(self, rawentry):
def __init__(self, rawentry, excinfo=None):
self._excinfo = excinfo
self._rawentry = rawentry
self.lineno = rawentry.tb_lineno - 1
@@ -174,18 +179,6 @@ class TracebackEntry(object):
return self.frame.f_locals
locals = property(getlocals, None, None, "locals of underlaying frame")
def reinterpret(self):
"""Reinterpret the failing statement and returns a detailed information
about what operations are performed."""
from _pytest.assertion.reinterpret import reinterpret
if self.exprinfo is None:
source = py.builtin._totext(self.statement).strip()
x = reinterpret(source, self.frame, should_fail=True)
if not py.builtin._istext(x):
raise TypeError("interpret returned non-string %r" % (x,))
self.exprinfo = x
return self.exprinfo
def getfirstlinesource(self):
# on Jython this firstlineno can be -1 apparently
return max(self.frame.code.firstlineno, 0)
@@ -220,16 +213,24 @@ class TracebackEntry(object):
""" return True if the current frame has a var __tracebackhide__
resolving to True
If __tracebackhide__ is a callable, it gets called with the
ExceptionInfo instance and can decide whether to hide the traceback.
mostly for internal use
"""
try:
return self.frame.f_locals['__tracebackhide__']
tbh = self.frame.f_locals['__tracebackhide__']
except KeyError:
try:
return self.frame.f_globals['__tracebackhide__']
tbh = self.frame.f_globals['__tracebackhide__']
except KeyError:
return False
if py.builtin.callable(tbh):
return tbh(self._excinfo)
else:
return tbh
def __str__(self):
try:
fn = str(self.path)
@@ -253,12 +254,13 @@ class Traceback(list):
access to Traceback entries.
"""
Entry = TracebackEntry
def __init__(self, tb):
""" initialize from given python traceback object. """
def __init__(self, tb, excinfo=None):
""" initialize from given python traceback object and ExceptionInfo """
self._excinfo = excinfo
if hasattr(tb, 'tb_next'):
def f(cur):
while cur is not None:
yield self.Entry(cur)
yield self.Entry(cur, excinfo=excinfo)
cur = cur.tb_next
list.__init__(self, f(tb))
else:
@@ -282,7 +284,7 @@ class Traceback(list):
not codepath.relto(excludepath)) and
(lineno is None or x.lineno == lineno) and
(firstlineno is None or x.frame.code.firstlineno == firstlineno)):
return Traceback(x._rawentry)
return Traceback(x._rawentry, self._excinfo)
return self
def __getitem__(self, key):
@@ -301,7 +303,7 @@ class Traceback(list):
by default this removes all the TracebackEntries which are hidden
(see ishidden() above)
"""
return Traceback(filter(fn, self))
return Traceback(filter(fn, self), self._excinfo)
def getcrashentry(self):
""" return last non-hidden traceback entry that lead
@@ -352,7 +354,7 @@ class ExceptionInfo(object):
if exprinfo is None and isinstance(tup[1], AssertionError):
exprinfo = getattr(tup[1], 'msg', None)
if exprinfo is None:
exprinfo = str(tup[1])
exprinfo = py._builtin._totext(tup[1])
if exprinfo and exprinfo.startswith('assert '):
self._striptext = 'AssertionError: '
self._excinfo = tup
@@ -365,7 +367,7 @@ class ExceptionInfo(object):
#: the exception type name
self.typename = self.type.__name__
#: the exception traceback (_pytest._code.Traceback instance)
self.traceback = _pytest._code.Traceback(self.tb)
self.traceback = _pytest._code.Traceback(self.tb, excinfo=self)
def __repr__(self):
return "<ExceptionInfo %s tblen=%d>" % (self.typename, len(self.traceback))
@@ -427,6 +429,19 @@ class ExceptionInfo(object):
loc = ReprFileLocation(entry.path, entry.lineno + 1, self.exconly())
return unicode(loc)
def match(self, regexp):
"""
Match the regular expression 'regexp' on the string representation of
the exception. If it matches then True is returned (so that it is
possible to write 'assert excinfo.match()'). If it doesn't match an
AssertionError is raised.
"""
__tracebackhide__ = True
if not re.search(regexp, str(self.value)):
assert 0, "Pattern '{0!s}' not found in '{1!s}'".format(
regexp, self.value)
return True
class FormattedExcinfo(object):
""" presenting information about failing Functions and Generators. """
@@ -593,12 +608,36 @@ class FormattedExcinfo(object):
break
return ReprTraceback(entries, extraline, style=self.style)
def repr_excinfo(self, excinfo):
reprtraceback = self.repr_traceback(excinfo)
reprcrash = excinfo._getreprcrash()
return ReprExceptionInfo(reprtraceback, reprcrash)
class TerminalRepr:
def repr_excinfo(self, excinfo):
if sys.version_info[0] < 3:
reprtraceback = self.repr_traceback(excinfo)
reprcrash = excinfo._getreprcrash()
return ReprExceptionInfo(reprtraceback, reprcrash)
else:
repr_chain = []
e = excinfo.value
descr = None
while e is not None:
reprtraceback = self.repr_traceback(excinfo)
reprcrash = excinfo._getreprcrash()
repr_chain += [(reprtraceback, reprcrash, descr)]
if e.__cause__ is not None:
e = e.__cause__
excinfo = ExceptionInfo((type(e), e, e.__traceback__))
descr = 'The above exception was the direct cause of the following exception:'
elif e.__context__ is not None:
e = e.__context__
excinfo = ExceptionInfo((type(e), e, e.__traceback__))
descr = 'During handling of the above exception, another exception occurred:'
else:
e = None
repr_chain.reverse()
return ExceptionChainRepr(repr_chain)
class TerminalRepr(object):
def __str__(self):
s = self.__unicode__()
if sys.version_info[0] < 3:
@@ -617,21 +656,47 @@ class TerminalRepr:
return "<%s instance at %0x>" %(self.__class__, id(self))
class ReprExceptionInfo(TerminalRepr):
def __init__(self, reprtraceback, reprcrash):
self.reprtraceback = reprtraceback
self.reprcrash = reprcrash
class ExceptionRepr(TerminalRepr):
def __init__(self):
self.sections = []
def addsection(self, name, content, sep="-"):
self.sections.append((name, content, sep))
def toterminal(self, tw):
self.reprtraceback.toterminal(tw)
for name, content, sep in self.sections:
tw.sep(sep, name)
tw.line(content)
class ExceptionChainRepr(ExceptionRepr):
def __init__(self, chain):
super(ExceptionChainRepr, self).__init__()
self.chain = chain
# reprcrash and reprtraceback of the outermost (the newest) exception
# in the chain
self.reprtraceback = chain[-1][0]
self.reprcrash = chain[-1][1]
def toterminal(self, tw):
for element in self.chain:
element[0].toterminal(tw)
if element[2] is not None:
tw.line("")
tw.line(element[2], yellow=True)
super(ExceptionChainRepr, self).toterminal(tw)
class ReprExceptionInfo(ExceptionRepr):
def __init__(self, reprtraceback, reprcrash):
super(ReprExceptionInfo, self).__init__()
self.reprtraceback = reprtraceback
self.reprcrash = reprcrash
def toterminal(self, tw):
self.reprtraceback.toterminal(tw)
super(ReprExceptionInfo, self).toterminal(tw)
class ReprTraceback(TerminalRepr):
entrysep = "_ "
@@ -720,7 +785,8 @@ class ReprFileLocation(TerminalRepr):
i = msg.find("\n")
if i != -1:
msg = msg[:i]
tw.line("%s:%s: %s" %(self.path, self.lineno, msg))
tw.write(self.path, bold=True, red=True)
tw.line(":%s: %s" % (self.lineno, msg))
class ReprLocals(TerminalRepr):
def __init__(self, lines):
@@ -753,29 +819,6 @@ class ReprFuncArgs(TerminalRepr):
tw.line("")
oldbuiltins = {}
def patch_builtins(assertion=True, compile=True):
""" put compile and AssertionError builtins to Python's builtins. """
if assertion:
from _pytest.assertion import reinterpret
l = oldbuiltins.setdefault('AssertionError', [])
l.append(py.builtin.builtins.AssertionError)
py.builtin.builtins.AssertionError = reinterpret.AssertionError
if compile:
import _pytest._code
l = oldbuiltins.setdefault('compile', [])
l.append(py.builtin.builtins.compile)
py.builtin.builtins.compile = _pytest._code.compile
def unpatch_builtins(assertion=True, compile=True):
""" remove compile and AssertionError builtins from Python builtins. """
if assertion:
py.builtin.builtins.AssertionError = oldbuiltins['AssertionError'].pop()
if compile:
py.builtin.builtins.compile = oldbuiltins['compile'].pop()
def getrawcode(obj, trycall=True):
""" return code object for given function. """
try:

View File

@@ -4,8 +4,9 @@ support for presenting detailed information in failing assertions.
import py
import os
import sys
from _pytest.monkeypatch import monkeypatch
from _pytest.assertion import util
from _pytest.assertion import rewrite
def pytest_addoption(parser):
@@ -13,25 +14,49 @@ def pytest_addoption(parser):
group.addoption('--assert',
action="store",
dest="assertmode",
choices=("rewrite", "reinterp", "plain",),
choices=("rewrite", "plain",),
default="rewrite",
metavar="MODE",
help="""control assertion debugging tools. 'plain'
performs no assertion debugging. 'reinterp'
reinterprets assert statements after they failed
to provide assertion expression information.
'rewrite' (the default) rewrites assert
statements in test modules on import to
provide assert expression information. """)
group.addoption('--no-assert',
action="store_true",
default=False,
dest="noassert",
help="DEPRECATED equivalent to --assert=plain")
group.addoption('--nomagic', '--no-magic',
action="store_true",
default=False,
help="DEPRECATED equivalent to --assert=plain")
help="""Control assertion debugging tools. 'plain'
performs no assertion debugging. 'rewrite'
(the default) rewrites assert statements in
test modules on import to provide assert
expression information.""")
def pytest_namespace():
return {'register_assert_rewrite': register_assert_rewrite}
def register_assert_rewrite(*names):
"""Register a module name to be rewritten on import.
This function will make sure that this module or all modules inside
the package will get their assert statements rewritten.
Thus you should make sure to call this before the module is
actually imported, usually in your __init__.py if you are a plugin
using a package.
:raise TypeError: if the given module names are not strings.
"""
for name in names:
if not isinstance(name, str):
msg = 'expected module names as *args, got {0} instead'
raise TypeError(msg.format(repr(names)))
for hook in sys.meta_path:
if isinstance(hook, rewrite.AssertionRewritingHook):
importhook = hook
break
else:
importhook = DummyRewriteHook()
importhook.mark_rewrite(*names)
class DummyRewriteHook(object):
"""A no-op import hook for when rewriting is disabled."""
def mark_rewrite(self, *names):
pass
class AssertionState:
@@ -40,51 +65,37 @@ class AssertionState:
def __init__(self, config, mode):
self.mode = mode
self.trace = config.trace.root.get("assertion")
self.hook = None
def pytest_configure(config):
mode = config.getvalue("assertmode")
if config.getvalue("noassert") or config.getvalue("nomagic"):
mode = "plain"
if mode == "rewrite":
try:
import ast # noqa
except ImportError:
mode = "reinterp"
else:
# Both Jython and CPython 2.6.0 have AST bugs that make the
# assertion rewriting hook malfunction.
if (sys.platform.startswith('java') or
sys.version_info[:3] == (2, 6, 0)):
mode = "reinterp"
if mode != "plain":
_load_modules(mode)
m = monkeypatch()
config._cleanup.append(m.undo)
m.setattr(py.builtin.builtins, 'AssertionError',
reinterpret.AssertionError) # noqa
hook = None
if mode == "rewrite":
hook = rewrite.AssertionRewritingHook() # noqa
sys.meta_path.insert(0, hook)
warn_about_missing_assertion(mode)
config._assertstate = AssertionState(config, mode)
config._assertstate.hook = hook
config._assertstate.trace("configured with mode set to %r" % (mode,))
def install_importhook(config):
"""Try to install the rewrite hook, raise SystemError if it fails."""
# Both Jython and CPython 2.6.0 have AST bugs that make the
# assertion rewriting hook malfunction.
if (sys.platform.startswith('java') or
sys.version_info[:3] == (2, 6, 0)):
raise SystemError('rewrite not supported')
config._assertstate = AssertionState(config, 'rewrite')
config._assertstate.hook = hook = rewrite.AssertionRewritingHook(config)
sys.meta_path.insert(0, hook)
config._assertstate.trace('installed rewrite import hook')
def undo():
hook = config._assertstate.hook
if hook is not None and hook in sys.meta_path:
sys.meta_path.remove(hook)
config.add_cleanup(undo)
return hook
def pytest_collection(session):
# this hook is only called when test modules are collected
# so for example not in the master process of pytest-xdist
# (which does not collect test modules)
hook = session.config._assertstate.hook
if hook is not None:
hook.set_session(session)
assertstate = getattr(session.config, '_assertstate', None)
if assertstate:
if assertstate.hook is not None:
assertstate.hook.set_session(session)
def _running_on_ci():
@@ -141,35 +152,10 @@ def pytest_runtest_teardown(item):
def pytest_sessionfinish(session):
hook = session.config._assertstate.hook
if hook is not None:
hook.session = None
def _load_modules(mode):
"""Lazily import assertion related code."""
global rewrite, reinterpret
from _pytest.assertion import reinterpret # noqa
if mode == "rewrite":
from _pytest.assertion import rewrite # noqa
def warn_about_missing_assertion(mode):
try:
assert False
except AssertionError:
pass
else:
if mode == "rewrite":
specifically = ("assertions which are not in test modules "
"will be ignored")
else:
specifically = "failing tests may report as passing"
sys.stderr.write("WARNING: " + specifically +
" because assert statements are not executed "
"by the underlying Python interpreter "
"(are you using python -O?)\n")
assertstate = getattr(session.config, '_assertstate', None)
if assertstate:
if assertstate.hook is not None:
assertstate.hook.set_session(None)
# Expose this plugin's implementation for the pytest_assertrepr_compare hook

View File

@@ -1,407 +0,0 @@
"""
Find intermediate evalutation results in assert statements through builtin AST.
"""
import ast
import sys
import _pytest._code
import py
from _pytest.assertion import util
u = py.builtin._totext
class AssertionError(util.BuiltinAssertionError):
def __init__(self, *args):
util.BuiltinAssertionError.__init__(self, *args)
if args:
# on Python2.6 we get len(args)==2 for: assert 0, (x,y)
# on Python2.7 and above we always get len(args) == 1
# with args[0] being the (x,y) tuple.
if len(args) > 1:
toprint = args
else:
toprint = args[0]
try:
self.msg = u(toprint)
except Exception:
self.msg = u(
"<[broken __repr__] %s at %0xd>"
% (toprint.__class__, id(toprint)))
else:
f = _pytest._code.Frame(sys._getframe(1))
try:
source = f.code.fullsource
if source is not None:
try:
source = source.getstatement(f.lineno, assertion=True)
except IndexError:
source = None
else:
source = str(source.deindent()).strip()
except py.error.ENOENT:
source = None
# this can also occur during reinterpretation, when the
# co_filename is set to "<run>".
if source:
self.msg = reinterpret(source, f, should_fail=True)
else:
self.msg = "<could not determine information>"
if not self.args:
self.args = (self.msg,)
if sys.version_info > (3, 0):
AssertionError.__module__ = "builtins"
if sys.platform.startswith("java"):
# See http://bugs.jython.org/issue1497
_exprs = ("BoolOp", "BinOp", "UnaryOp", "Lambda", "IfExp", "Dict",
"ListComp", "GeneratorExp", "Yield", "Compare", "Call",
"Repr", "Num", "Str", "Attribute", "Subscript", "Name",
"List", "Tuple")
_stmts = ("FunctionDef", "ClassDef", "Return", "Delete", "Assign",
"AugAssign", "Print", "For", "While", "If", "With", "Raise",
"TryExcept", "TryFinally", "Assert", "Import", "ImportFrom",
"Exec", "Global", "Expr", "Pass", "Break", "Continue")
_expr_nodes = set(getattr(ast, name) for name in _exprs)
_stmt_nodes = set(getattr(ast, name) for name in _stmts)
def _is_ast_expr(node):
return node.__class__ in _expr_nodes
def _is_ast_stmt(node):
return node.__class__ in _stmt_nodes
else:
def _is_ast_expr(node):
return isinstance(node, ast.expr)
def _is_ast_stmt(node):
return isinstance(node, ast.stmt)
try:
_Starred = ast.Starred
except AttributeError:
# Python 2. Define a dummy class so isinstance() will always be False.
class _Starred(object): pass
class Failure(Exception):
"""Error found while interpreting AST."""
def __init__(self, explanation=""):
self.cause = sys.exc_info()
self.explanation = explanation
def reinterpret(source, frame, should_fail=False):
mod = ast.parse(source)
visitor = DebugInterpreter(frame)
try:
visitor.visit(mod)
except Failure:
failure = sys.exc_info()[1]
return getfailure(failure)
if should_fail:
return ("(assertion failed, but when it was re-run for "
"printing intermediate values, it did not fail. Suggestions: "
"compute assert expression before the assert or use --assert=plain)")
def run(offending_line, frame=None):
if frame is None:
frame = _pytest._code.Frame(sys._getframe(1))
return reinterpret(offending_line, frame)
def getfailure(e):
explanation = util.format_explanation(e.explanation)
value = e.cause[1]
if str(value):
lines = explanation.split('\n')
lines[0] += " << %s" % (value,)
explanation = '\n'.join(lines)
text = "%s: %s" % (e.cause[0].__name__, explanation)
if text.startswith('AssertionError: assert '):
text = text[16:]
return text
operator_map = {
ast.BitOr : "|",
ast.BitXor : "^",
ast.BitAnd : "&",
ast.LShift : "<<",
ast.RShift : ">>",
ast.Add : "+",
ast.Sub : "-",
ast.Mult : "*",
ast.Div : "/",
ast.FloorDiv : "//",
ast.Mod : "%",
ast.Eq : "==",
ast.NotEq : "!=",
ast.Lt : "<",
ast.LtE : "<=",
ast.Gt : ">",
ast.GtE : ">=",
ast.Pow : "**",
ast.Is : "is",
ast.IsNot : "is not",
ast.In : "in",
ast.NotIn : "not in"
}
unary_map = {
ast.Not : "not %s",
ast.Invert : "~%s",
ast.USub : "-%s",
ast.UAdd : "+%s"
}
class DebugInterpreter(ast.NodeVisitor):
"""Interpret AST nodes to gleam useful debugging information. """
def __init__(self, frame):
self.frame = frame
def generic_visit(self, node):
# Fallback when we don't have a special implementation.
if _is_ast_expr(node):
mod = ast.Expression(node)
co = self._compile(mod)
try:
result = self.frame.eval(co)
except Exception:
raise Failure()
explanation = self.frame.repr(result)
return explanation, result
elif _is_ast_stmt(node):
mod = ast.Module([node])
co = self._compile(mod, "exec")
try:
self.frame.exec_(co)
except Exception:
raise Failure()
return None, None
else:
raise AssertionError("can't handle %s" %(node,))
def _compile(self, source, mode="eval"):
return compile(source, "<assertion interpretation>", mode)
def visit_Expr(self, expr):
return self.visit(expr.value)
def visit_Module(self, mod):
for stmt in mod.body:
self.visit(stmt)
def visit_Name(self, name):
explanation, result = self.generic_visit(name)
# See if the name is local.
source = "%r in locals() is not globals()" % (name.id,)
co = self._compile(source)
try:
local = self.frame.eval(co)
except Exception:
# have to assume it isn't
local = None
if local is None or not self.frame.is_true(local):
return name.id, result
return explanation, result
def visit_Compare(self, comp):
left = comp.left
left_explanation, left_result = self.visit(left)
for op, next_op in zip(comp.ops, comp.comparators):
next_explanation, next_result = self.visit(next_op)
op_symbol = operator_map[op.__class__]
explanation = "%s %s %s" % (left_explanation, op_symbol,
next_explanation)
source = "__exprinfo_left %s __exprinfo_right" % (op_symbol,)
co = self._compile(source)
try:
result = self.frame.eval(co, __exprinfo_left=left_result,
__exprinfo_right=next_result)
except Exception:
raise Failure(explanation)
try:
if not self.frame.is_true(result):
break
except KeyboardInterrupt:
raise
except:
break
left_explanation, left_result = next_explanation, next_result
if util._reprcompare is not None:
res = util._reprcompare(op_symbol, left_result, next_result)
if res:
explanation = res
return explanation, result
def visit_BoolOp(self, boolop):
is_or = isinstance(boolop.op, ast.Or)
explanations = []
for operand in boolop.values:
explanation, result = self.visit(operand)
explanations.append(explanation)
if result == is_or:
break
name = is_or and " or " or " and "
explanation = "(" + name.join(explanations) + ")"
return explanation, result
def visit_UnaryOp(self, unary):
pattern = unary_map[unary.op.__class__]
operand_explanation, operand_result = self.visit(unary.operand)
explanation = pattern % (operand_explanation,)
co = self._compile(pattern % ("__exprinfo_expr",))
try:
result = self.frame.eval(co, __exprinfo_expr=operand_result)
except Exception:
raise Failure(explanation)
return explanation, result
def visit_BinOp(self, binop):
left_explanation, left_result = self.visit(binop.left)
right_explanation, right_result = self.visit(binop.right)
symbol = operator_map[binop.op.__class__]
explanation = "(%s %s %s)" % (left_explanation, symbol,
right_explanation)
source = "__exprinfo_left %s __exprinfo_right" % (symbol,)
co = self._compile(source)
try:
result = self.frame.eval(co, __exprinfo_left=left_result,
__exprinfo_right=right_result)
except Exception:
raise Failure(explanation)
return explanation, result
def visit_Call(self, call):
func_explanation, func = self.visit(call.func)
arg_explanations = []
ns = {"__exprinfo_func" : func}
arguments = []
for arg in call.args:
arg_explanation, arg_result = self.visit(arg)
if isinstance(arg, _Starred):
arg_name = "__exprinfo_star"
ns[arg_name] = arg_result
arguments.append("*%s" % (arg_name,))
arg_explanations.append("*%s" % (arg_explanation,))
else:
arg_name = "__exprinfo_%s" % (len(ns),)
ns[arg_name] = arg_result
arguments.append(arg_name)
arg_explanations.append(arg_explanation)
for keyword in call.keywords:
arg_explanation, arg_result = self.visit(keyword.value)
if keyword.arg:
arg_name = "__exprinfo_%s" % (len(ns),)
keyword_source = "%s=%%s" % (keyword.arg)
arguments.append(keyword_source % (arg_name,))
arg_explanations.append(keyword_source % (arg_explanation,))
else:
arg_name = "__exprinfo_kwds"
arguments.append("**%s" % (arg_name,))
arg_explanations.append("**%s" % (arg_explanation,))
ns[arg_name] = arg_result
if getattr(call, 'starargs', None):
arg_explanation, arg_result = self.visit(call.starargs)
arg_name = "__exprinfo_star"
ns[arg_name] = arg_result
arguments.append("*%s" % (arg_name,))
arg_explanations.append("*%s" % (arg_explanation,))
if getattr(call, 'kwargs', None):
arg_explanation, arg_result = self.visit(call.kwargs)
arg_name = "__exprinfo_kwds"
ns[arg_name] = arg_result
arguments.append("**%s" % (arg_name,))
arg_explanations.append("**%s" % (arg_explanation,))
args_explained = ", ".join(arg_explanations)
explanation = "%s(%s)" % (func_explanation, args_explained)
args = ", ".join(arguments)
source = "__exprinfo_func(%s)" % (args,)
co = self._compile(source)
try:
result = self.frame.eval(co, **ns)
except Exception:
raise Failure(explanation)
pattern = "%s\n{%s = %s\n}"
rep = self.frame.repr(result)
explanation = pattern % (rep, rep, explanation)
return explanation, result
def _is_builtin_name(self, name):
pattern = "%r not in globals() and %r not in locals()"
source = pattern % (name.id, name.id)
co = self._compile(source)
try:
return self.frame.eval(co)
except Exception:
return False
def visit_Attribute(self, attr):
if not isinstance(attr.ctx, ast.Load):
return self.generic_visit(attr)
source_explanation, source_result = self.visit(attr.value)
explanation = "%s.%s" % (source_explanation, attr.attr)
source = "__exprinfo_expr.%s" % (attr.attr,)
co = self._compile(source)
try:
try:
result = self.frame.eval(co, __exprinfo_expr=source_result)
except AttributeError:
# Maybe the attribute name needs to be mangled?
if not attr.attr.startswith("__") or attr.attr.endswith("__"):
raise
source = "getattr(__exprinfo_expr.__class__, '__name__', '')"
co = self._compile(source)
class_name = self.frame.eval(co, __exprinfo_expr=source_result)
mangled_attr = "_" + class_name + attr.attr
source = "__exprinfo_expr.%s" % (mangled_attr,)
co = self._compile(source)
result = self.frame.eval(co, __exprinfo_expr=source_result)
except Exception:
raise Failure(explanation)
explanation = "%s\n{%s = %s.%s\n}" % (self.frame.repr(result),
self.frame.repr(result),
source_explanation, attr.attr)
# Check if the attr is from an instance.
source = "%r in getattr(__exprinfo_expr, '__dict__', {})"
source = source % (attr.attr,)
co = self._compile(source)
try:
from_instance = self.frame.eval(co, __exprinfo_expr=source_result)
except Exception:
from_instance = None
if from_instance is None or self.frame.is_true(from_instance):
rep = self.frame.repr(result)
pattern = "%s\n{%s = %s\n}"
explanation = pattern % (rep, rep, explanation)
return explanation, result
def visit_Assert(self, assrt):
test_explanation, test_result = self.visit(assrt.test)
explanation = "assert %s" % (test_explanation,)
if not self.frame.is_true(test_result):
try:
raise util.BuiltinAssertionError
except Exception:
raise Failure(explanation)
return explanation, test_result
def visit_Assign(self, assign):
value_explanation, value_result = self.visit(assign.value)
explanation = "... = %s" % (value_explanation,)
name = ast.Name("__exprinfo_expr", ast.Load(),
lineno=assign.value.lineno,
col_offset=assign.value.col_offset)
new_assign = ast.Assign(assign.targets, name, lineno=assign.lineno,
col_offset=assign.col_offset)
mod = ast.Module([new_assign])
co = self._compile(mod, "exec")
try:
self.frame.exec_(co, __exprinfo_expr=value_result)
except Exception:
raise Failure(explanation)
return explanation, value_result

View File

@@ -1,6 +1,7 @@
"""Rewrite assertion AST to produce nice error messages"""
import ast
import _ast
import errno
import itertools
import imp
@@ -10,6 +11,7 @@ import re
import struct
import sys
import types
from fnmatch import fnmatch
import py
from _pytest.assertion import util
@@ -44,20 +46,19 @@ else:
class AssertionRewritingHook(object):
"""PEP302 Import hook which rewrites asserts."""
def __init__(self):
def __init__(self, config):
self.config = config
self.fnpats = config.getini("python_files")
self.session = None
self.modules = {}
self._register_with_pkg_resources()
self._must_rewrite = set()
def set_session(self, session):
self.fnpats = session.config.getini("python_files")
self.session = session
def find_module(self, name, path=None):
if self.session is None:
return None
sess = self.session
state = sess.config._assertstate
state = self.config._assertstate
state.trace("find_module called for: %s" % name)
names = name.rsplit(".", 1)
lastname = names[-1]
@@ -86,24 +87,11 @@ class AssertionRewritingHook(object):
return None
else:
fn = os.path.join(pth, name.rpartition(".")[2] + ".py")
fn_pypath = py.path.local(fn)
# Is this a test file?
if not sess.isinitpath(fn):
# We have to be very careful here because imports in this code can
# trigger a cycle.
self.session = None
try:
for pat in self.fnpats:
if fn_pypath.fnmatch(pat):
state.trace("matched test file %r" % (fn,))
break
else:
return None
finally:
self.session = sess
else:
state.trace("matched test file (was specified on cmdline): %r" %
(fn,))
if not self._should_rewrite(name, fn_pypath, state):
return None
# The requested module looks like a test file, so rewrite it. This is
# the most magical part of the process: load the source, rewrite the
# asserts, and load the rewritten source. We also cache the rewritten
@@ -140,7 +128,7 @@ class AssertionRewritingHook(object):
co = _read_pyc(fn_pypath, pyc, state.trace)
if co is None:
state.trace("rewriting %r" % (fn,))
source_stat, co = _rewrite_test(state, fn_pypath)
source_stat, co = _rewrite_test(self.config, fn_pypath)
if co is None:
# Probably a SyntaxError in the test.
return None
@@ -151,6 +139,54 @@ class AssertionRewritingHook(object):
self.modules[name] = co, pyc
return self
def _should_rewrite(self, name, fn_pypath, state):
# always rewrite conftest files
fn = str(fn_pypath)
if fn_pypath.basename == 'conftest.py':
state.trace("rewriting conftest file: %r" % (fn,))
return True
if self.session is not None:
if self.session.isinitpath(fn):
state.trace("matched test file (was specified on cmdline): %r" %
(fn,))
return True
# modules not passed explicitly on the command line are only
# rewritten if they match the naming convention for test files
for pat in self.fnpats:
# use fnmatch instead of fn_pypath.fnmatch because the
# latter might trigger an import to fnmatch.fnmatch
# internally, which would cause this method to be
# called recursively
if fnmatch(fn_pypath.basename, pat):
state.trace("matched test file %r" % (fn,))
return True
for marked in self._must_rewrite:
if name.startswith(marked):
state.trace("matched marked file %r (from %r)" % (name, marked))
return True
return False
def mark_rewrite(self, *names):
"""Mark import names as needing to be re-written.
The named module or package as well as any nested modules will
be re-written on import.
"""
already_imported = set(names).intersection(set(sys.modules))
if already_imported:
self._warn_already_imported(already_imported)
self._must_rewrite.update(names)
def _warn_already_imported(self, names):
self.config.warn(
'P1',
'Modules are already imported so can not be re-written: %s' %
','.join(names))
def load_module(self, name):
# If there is an existing module object named 'fullname' in
# sys.modules, the loader must use that existing module. (Otherwise,
@@ -241,8 +277,9 @@ N = "\n".encode("utf-8")
cookie_re = re.compile(r"^[ \t\f]*#.*coding[:=][ \t]*[-\w.]+")
BOM_UTF8 = '\xef\xbb\xbf'
def _rewrite_test(state, fn):
def _rewrite_test(config, fn):
"""Try to read and rewrite *fn* and return the code object."""
state = config._assertstate
try:
stat = fn.stat()
source = fn.read("rb")
@@ -287,7 +324,7 @@ def _rewrite_test(state, fn):
# Let this pop up again in the real import.
state.trace("failed to parse: %r" % (fn,))
return None, None
rewrite_asserts(tree)
rewrite_asserts(tree, fn, config)
try:
co = compile(tree, fn.strpath, "exec")
except SyntaxError:
@@ -343,9 +380,9 @@ def _read_pyc(source, pyc, trace=lambda x: None):
return co
def rewrite_asserts(mod):
def rewrite_asserts(mod, module_path=None, config=None):
"""Rewrite the assert statements in mod."""
AssertionRewriter().run(mod)
AssertionRewriter(module_path, config).run(mod)
def _saferepr(obj):
@@ -532,6 +569,11 @@ class AssertionRewriter(ast.NodeVisitor):
"""
def __init__(self, module_path, config):
super(AssertionRewriter, self).__init__()
self.module_path = module_path
self.config = config
def run(self, mod):
"""Find all assert statements in *mod* and rewrite them."""
if not mod.body:
@@ -672,6 +714,10 @@ class AssertionRewriter(ast.NodeVisitor):
the expression is false.
"""
if isinstance(assert_.test, ast.Tuple) and self.config is not None:
fslocation = (self.module_path, assert_.lineno)
self.config.warn('R1', 'assertion is always true, perhaps '
'remove parentheses?', fslocation=fslocation)
self.statements = []
self.variables = []
self.variable_counter = itertools.count()
@@ -855,6 +901,8 @@ class AssertionRewriter(ast.NodeVisitor):
def visit_Compare(self, comp):
self.push_format_context()
left_res, left_expl = self.visit(comp.left)
if isinstance(comp.left, (_ast.Compare, _ast.BoolOp)):
left_expl = "({0})".format(left_expl)
res_variables = [self.variable() for i in range(len(comp.ops))]
load_names = [ast.Name(v, ast.Load()) for v in res_variables]
store_names = [ast.Name(v, ast.Store()) for v in res_variables]
@@ -864,6 +912,8 @@ class AssertionRewriter(ast.NodeVisitor):
results = [left_res]
for i, op, next_operand in it:
next_res, next_expl = self.visit(next_operand)
if isinstance(next_operand, (_ast.Compare, _ast.BoolOp)):
next_expl = "({0})".format(next_expl)
results.append(next_res)
sym = binop_map[op.__class__]
syms.append(ast.Str(sym))

View File

@@ -38,44 +38,11 @@ def format_explanation(explanation):
displaying diffs.
"""
explanation = ecu(explanation)
explanation = _collapse_false(explanation)
lines = _split_explanation(explanation)
result = _format_lines(lines)
return u('\n').join(result)
def _collapse_false(explanation):
"""Collapse expansions of False
So this strips out any "assert False\n{where False = ...\n}"
blocks.
"""
where = 0
while True:
start = where = explanation.find("False\n{False = ", where)
if where == -1:
break
level = 0
prev_c = explanation[start]
for i, c in enumerate(explanation[start:]):
if prev_c + c == "\n{":
level += 1
elif prev_c + c == "\n}":
level -= 1
if not level:
break
prev_c = c
else:
raise AssertionError("unbalanced braces: %r" % (explanation,))
end = start + i
where = end
if explanation[end - 1] == '\n':
explanation = (explanation[:start] + explanation[start+15:end-1] +
explanation[end+1:])
where -= 17
return explanation
def _split_explanation(explanation):
"""Return a list of individual lines in the explanation
@@ -225,9 +192,10 @@ def _diff_text(left, right, verbose=False):
'characters in diff, use -v to show') % i]
left = left[:-i]
right = right[:-i]
keepends = True
explanation += [line.strip('\n')
for line in ndiff(left.splitlines(),
right.splitlines())]
for line in ndiff(left.splitlines(keepends),
right.splitlines(keepends))]
return explanation

View File

@@ -4,6 +4,7 @@ per-test stdout/stderr capturing mechanism.
"""
from __future__ import with_statement
import contextlib
import sys
import os
from tempfile import TemporaryFile
@@ -146,8 +147,8 @@ class CaptureManager:
def pytest_internalerror(self, excinfo):
self.reset_capturings()
def suspendcapture_item(self, item, when):
out, err = self.suspendcapture()
def suspendcapture_item(self, item, when, in_=False):
out, err = self.suspendcapture(in_=in_)
item.add_report_section(when, "stdout", out)
item.add_report_section(when, "stderr", err)
@@ -156,36 +157,37 @@ error_capsysfderror = "cannot use capsys and capfd at the same time"
@pytest.fixture
def capsys(request):
"""enables capturing of writes to sys.stdout/sys.stderr and makes
"""Enable capturing of writes to sys.stdout/sys.stderr and make
captured output available via ``capsys.readouterr()`` method calls
which return a ``(out, err)`` tuple.
"""
if "capfd" in request._funcargs:
if "capfd" in request.fixturenames:
raise request.raiseerror(error_capsysfderror)
request.node._capfuncarg = c = CaptureFixture(SysCapture)
request.node._capfuncarg = c = CaptureFixture(SysCapture, request)
return c
@pytest.fixture
def capfd(request):
"""enables capturing of writes to file descriptors 1 and 2 and makes
"""Enable capturing of writes to file descriptors 1 and 2 and make
captured output available via ``capfd.readouterr()`` method calls
which return a ``(out, err)`` tuple.
"""
if "capsys" in request._funcargs:
if "capsys" in request.fixturenames:
request.raiseerror(error_capsysfderror)
if not hasattr(os, 'dup'):
pytest.skip("capfd funcarg needs os.dup")
request.node._capfuncarg = c = CaptureFixture(FDCapture)
request.node._capfuncarg = c = CaptureFixture(FDCapture, request)
return c
class CaptureFixture:
def __init__(self, captureclass):
def __init__(self, captureclass, request):
self.captureclass = captureclass
self.request = request
def _start(self):
self._capture = MultiCapture(out=True, err=True, in_=False,
Capture=self.captureclass)
Capture=self.captureclass)
self._capture.start_capturing()
def close(self):
@@ -200,6 +202,15 @@ class CaptureFixture:
except AttributeError:
return self._outerr
@contextlib.contextmanager
def disabled(self):
capmanager = self.request.config.pluginmanager.getplugin('capturemanager')
capmanager.suspendcapture_item(self.request.node, "call", in_=True)
try:
yield
finally:
capmanager.resumecapture()
def safe_text_dupfile(f, mode, default_encoding="UTF8"):
""" return a open text file object that's a duplicate of f on the
@@ -444,6 +455,13 @@ class DontReadFromInput:
def close(self):
pass
@property
def buffer(self):
if sys.version_info >= (3,0):
return self
else:
raise AttributeError('redirected stdin has no attribute buffer')
def _readline_workaround():
"""
@@ -452,7 +470,7 @@ def _readline_workaround():
Pdb uses readline support where available--when not running from the Python
prompt, the readline module is not imported until running the pdb REPL. If
running py.test with the --pdb option this means the readline module is not
running pytest with the --pdb option this means the readline module is not
imported until after I/O capture has been started.
This is a problem for pyreadline, which is often used to implement readline

216
_pytest/compat.py Normal file
View File

@@ -0,0 +1,216 @@
"""
python version compatibility code
"""
import sys
import inspect
import types
import re
import functools
import py
import _pytest
try:
import enum
except ImportError: # pragma: no cover
# Only available in Python 3.4+ or as a backport
enum = None
_PY3 = sys.version_info > (3, 0)
_PY2 = not _PY3
NoneType = type(None)
NOTSET = object()
if hasattr(inspect, 'signature'):
def _format_args(func):
return str(inspect.signature(func))
else:
def _format_args(func):
return inspect.formatargspec(*inspect.getargspec(func))
isfunction = inspect.isfunction
isclass = inspect.isclass
# used to work around a python2 exception info leak
exc_clear = getattr(sys, 'exc_clear', lambda: None)
# The type of re.compile objects is not exposed in Python.
REGEX_TYPE = type(re.compile(''))
def is_generator(func):
try:
return _pytest._code.getrawcode(func).co_flags & 32 # generator function
except AttributeError: # builtin functions have no bytecode
# assume them to not be generators
return False
def getlocation(function, curdir):
import inspect
fn = py.path.local(inspect.getfile(function))
lineno = py.builtin._getcode(function).co_firstlineno
if fn.relto(curdir):
fn = fn.relto(curdir)
return "%s:%d" %(fn, lineno+1)
def num_mock_patch_args(function):
""" return number of arguments used up by mock arguments (if any) """
patchings = getattr(function, "patchings", None)
if not patchings:
return 0
mock = sys.modules.get("mock", sys.modules.get("unittest.mock", None))
if mock is not None:
return len([p for p in patchings
if not p.attribute_name and p.new is mock.DEFAULT])
return len(patchings)
def getfuncargnames(function, startindex=None):
# XXX merge with main.py's varnames
#assert not isclass(function)
realfunction = function
while hasattr(realfunction, "__wrapped__"):
realfunction = realfunction.__wrapped__
if startindex is None:
startindex = inspect.ismethod(function) and 1 or 0
if realfunction != function:
startindex += num_mock_patch_args(function)
function = realfunction
if isinstance(function, functools.partial):
argnames = inspect.getargs(_pytest._code.getrawcode(function.func))[0]
partial = function
argnames = argnames[len(partial.args):]
if partial.keywords:
for kw in partial.keywords:
argnames.remove(kw)
else:
argnames = inspect.getargs(_pytest._code.getrawcode(function))[0]
defaults = getattr(function, 'func_defaults',
getattr(function, '__defaults__', None)) or ()
numdefaults = len(defaults)
if numdefaults:
return tuple(argnames[startindex:-numdefaults])
return tuple(argnames[startindex:])
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))
if _PY3:
import codecs
STRING_TYPES = bytes, str
def _escape_strings(val):
"""If val is pure ascii, returns it as a str(). Otherwise, escapes
bytes objects into a sequence of escaped bytes:
b'\xc3\xb4\xc5\xd6' -> u'\\xc3\\xb4\\xc5\\xd6'
and escapes unicode objects into a sequence of escaped unicode
ids, e.g.:
'4\\nV\\U00043efa\\x0eMXWB\\x1e\\u3028\\u15fd\\xcd\\U0007d944'
note:
the obvious "v.decode('unicode-escape')" will return
valid utf-8 unicode if it finds them in bytes, but we
want to return escaped bytes for any byte, even if they match
a utf-8 string.
"""
if isinstance(val, bytes):
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:
return val.encode('unicode_escape').decode('ascii')
else:
STRING_TYPES = bytes, str, unicode
def _escape_strings(val):
"""In py2 bytes and str are the same type, so return if it's a bytes
object, return it unchanged if it is a full ascii string,
otherwise escape it into its binary form.
If it's a unicode string, change the unicode characters into
unicode escapes.
"""
if isinstance(val, bytes):
try:
return val.encode('ascii')
except UnicodeDecodeError:
return val.encode('string-escape')
else:
return val.encode('unicode-escape')
def get_real_func(obj):
""" gets the real function object of the (possibly) wrapped object by
functools.wraps or functools.partial.
"""
while hasattr(obj, "__wrapped__"):
obj = obj.__wrapped__
if isinstance(obj, functools.partial):
obj = obj.func
return obj
def getfslineno(obj):
# xxx let decorators etc specify a sane ordering
obj = get_real_func(obj)
if hasattr(obj, 'place_as'):
obj = obj.place_as
fslineno = _pytest._code.getfslineno(obj)
assert isinstance(fslineno[1], int), obj
return fslineno
def getimfunc(func):
try:
return func.__func__
except AttributeError:
try:
return func.im_func
except AttributeError:
return func
def safe_getattr(object, name, default):
""" Like getattr but return default upon any Exception.
Attribute access can potentially fail for 'evil' Python objects.
See issue214
"""
try:
return getattr(object, name, default)
except Exception:
return default
def _is_unittest_unexpected_success_a_failure():
"""Return if the test suite should fail if a @expectedFailure unittest test PASSES.
From https://docs.python.org/3/library/unittest.html?highlight=unittest#unittest.TestResult.wasSuccessful:
Changed in version 3.4: Returns False if there were any
unexpectedSuccesses from tests marked with the expectedFailure() decorator.
"""
return sys.version_info >= (3, 4)

View File

@@ -5,11 +5,13 @@ import traceback
import types
import warnings
import pkg_resources
import py
# DON't import pytest here because it causes import cycle troubles
import sys, os
import _pytest._code
import _pytest.hookspec # the extension point definitions
import _pytest.assertion
from _pytest._pluggy import PluginManager, HookimplMarker, HookspecMarker
hookimpl = HookimplMarker("pytest")
@@ -25,6 +27,12 @@ class ConftestImportFailure(Exception):
self.path = path
self.excinfo = excinfo
def __str__(self):
etype, evalue, etb = self.excinfo
formatted = traceback.format_tb(etb)
# The level of the tracebacks we want to print is hand crafted :(
return repr(evalue) + '\n' + ''.join(formatted[2:])
def main(args=None, plugins=None):
""" return exit code, after performing an in-process test run.
@@ -63,9 +71,10 @@ class UsageError(Exception):
_preinit = []
default_plugins = (
"mark main terminal runner python pdb unittest capture skipping "
"tmpdir monkeypatch recwarn pastebin helpconfig nose assertion genscript "
"junitxml resultlog doctest cacheprovider").split()
"mark main terminal runner python fixtures debugging unittest capture skipping "
"tmpdir monkeypatch recwarn pastebin helpconfig nose assertion "
"junitxml resultlog doctest cacheprovider freeze_support "
"setuponly setupplan").split()
builtin_plugins = set(default_plugins)
builtin_plugins.add("pytester")
@@ -97,6 +106,7 @@ def get_plugin_manager():
return get_config().pluginmanager
def _prepareconfig(args=None, plugins=None):
warning = None
if args is None:
args = sys.argv[1:]
elif isinstance(args, py.path.local):
@@ -105,6 +115,8 @@ def _prepareconfig(args=None, plugins=None):
if not isinstance(args, str):
raise ValueError("not a string or argument list: %r" % (args,))
args = shlex.split(args, posix=sys.platform != "win32")
from _pytest import deprecated
warning = deprecated.MAIN_STR_ARGS
config = get_config()
pluginmanager = config.pluginmanager
try:
@@ -114,6 +126,8 @@ def _prepareconfig(args=None, plugins=None):
pluginmanager.consider_pluginarg(plugin)
else:
pluginmanager.register(plugin)
if warning:
config.warn('C1', warning)
return pluginmanager.hook.pytest_cmdline_parse(
pluginmanager=pluginmanager, args=args)
except BaseException:
@@ -139,6 +153,7 @@ class PytestPluginManager(PluginManager):
self._conftestpath2mod = {}
self._confcutdir = None
self._noconftest = False
self._duplicatepaths = set()
self.add_hookspecs(_pytest.hookspec)
self.register(self)
@@ -152,6 +167,9 @@ class PytestPluginManager(PluginManager):
self.trace.root.setwriter(err.write)
self.enable_tracing()
# Config._consider_importhook will set a real object if required.
self.rewrite_hook = _pytest.assertion.DummyRewriteHook()
def addhooks(self, module_or_class):
"""
.. deprecated:: 2.8
@@ -360,7 +378,11 @@ class PytestPluginManager(PluginManager):
self._import_plugin_specs(os.environ.get("PYTEST_PLUGINS"))
def consider_module(self, mod):
self._import_plugin_specs(getattr(mod, "pytest_plugins", None))
plugins = getattr(mod, 'pytest_plugins', [])
if isinstance(plugins, str):
plugins = [plugins]
self.rewrite_hook.mark_rewrite(*plugins)
self._import_plugin_specs(plugins)
def _import_plugin_specs(self, spec):
if spec:
@@ -537,13 +559,18 @@ class ArgumentError(Exception):
class Argument:
"""class that mimics the necessary behaviour of optparse.Option """
"""class that mimics the necessary behaviour of optparse.Option
its currently a least effort implementation
and ignoring choices and integer prefixes
https://docs.python.org/3/library/optparse.html#optparse-standard-option-types
"""
_typ_map = {
'int': int,
'string': str,
}
# enable after some grace period for plugin writers
TYPE_WARN = False
'float': float,
'complex': complex,
}
def __init__(self, *names, **attrs):
"""store parms in private vars for use in add_argument"""
@@ -551,17 +578,12 @@ class Argument:
self._short_opts = []
self._long_opts = []
self.dest = attrs.get('dest')
if self.TYPE_WARN:
try:
help = attrs['help']
if '%default' in help:
warnings.warn(
'pytest now uses argparse. "%default" should be'
' changed to "%(default)s" ',
FutureWarning,
stacklevel=3)
except KeyError:
pass
if '%default' in (attrs.get('help') or ''):
warnings.warn(
'pytest now uses argparse. "%default" should be'
' changed to "%(default)s" ',
DeprecationWarning,
stacklevel=3)
try:
typ = attrs['type']
except KeyError:
@@ -570,25 +592,23 @@ class Argument:
# this might raise a keyerror as well, don't want to catch that
if isinstance(typ, py.builtin._basestring):
if typ == 'choice':
if self.TYPE_WARN:
warnings.warn(
'type argument to addoption() is a string %r.'
' For parsearg this is optional and when supplied '
' should be a type.'
' (options: %s)' % (typ, names),
FutureWarning,
stacklevel=3)
warnings.warn(
'type argument to addoption() is a string %r.'
' For parsearg this is optional and when supplied '
' should be a type.'
' (options: %s)' % (typ, names),
DeprecationWarning,
stacklevel=3)
# argparse expects a type here take it from
# the type of the first element
attrs['type'] = type(attrs['choices'][0])
else:
if self.TYPE_WARN:
warnings.warn(
'type argument to addoption() is a string %r.'
' For parsearg this should be a type.'
' (options: %s)' % (typ, names),
FutureWarning,
stacklevel=3)
warnings.warn(
'type argument to addoption() is a string %r.'
' For parsearg this should be a type.'
' (options: %s)' % (typ, names),
DeprecationWarning,
stacklevel=3)
attrs['type'] = Argument._typ_map[typ]
# used in test_parseopt -> test_parse_defaultgetter
self.type = attrs['type']
@@ -655,20 +675,17 @@ class Argument:
self._long_opts.append(opt)
def __repr__(self):
retval = 'Argument('
args = []
if self._short_opts:
retval += '_short_opts: ' + repr(self._short_opts) + ', '
args += ['_short_opts: ' + repr(self._short_opts)]
if self._long_opts:
retval += '_long_opts: ' + repr(self._long_opts) + ', '
retval += 'dest: ' + repr(self.dest) + ', '
args += ['_long_opts: ' + repr(self._long_opts)]
args += ['dest: ' + repr(self.dest)]
if hasattr(self, 'type'):
retval += 'type: ' + repr(self.type) + ', '
args += ['type: ' + repr(self.type)]
if hasattr(self, 'default'):
retval += 'default: ' + repr(self.default) + ', '
if retval[-2:] == ', ': # always long enough to test ("Argument(" )
retval = retval[:-2]
retval += ')'
return retval
args += ['default: ' + repr(self.default)]
return 'Argument({0})'.format(', '.join(args))
class OptionGroup:
@@ -686,6 +703,10 @@ class OptionGroup:
results in help showing '--two-words' only, but --twowords gets
accepted **and** the automatic destination is in args.twowords
"""
conflict = set(optnames).intersection(
name for opt in self.options for name in opt.names())
if conflict:
raise ValueError("option names %s already added" % conflict)
option = Argument(*optnames, **attrs)
self._addoption_instance(option, shortupper=False)
@@ -908,7 +929,7 @@ class Config(object):
def _initini(self, args):
ns, unknown_args = self._parser.parse_known_and_unknown_args(args, namespace=self.option.copy())
r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args)
r = determine_setup(ns.inifilename, ns.file_or_dir + unknown_args, warnfunc=self.warn)
self.rootdir, self.inifile, self.inicfg = r
self._parser.extra_info['rootdir'] = self.rootdir
self._parser.extra_info['inifile'] = self.inifile
@@ -916,17 +937,62 @@ class Config(object):
self._parser.addini('addopts', 'extra command line options', 'args')
self._parser.addini('minversion', 'minimally required pytest version')
def _consider_importhook(self, args, entrypoint_name):
"""Install the PEP 302 import hook if using assertion re-writing.
Needs to parse the --assert=<mode> option from the commandline
and find all the installed plugins to mark them for re-writing
by the importhook.
"""
ns, unknown_args = self._parser.parse_known_and_unknown_args(args)
mode = ns.assertmode
if mode == 'rewrite':
try:
hook = _pytest.assertion.install_importhook(self)
except SystemError:
mode = 'plain'
else:
self.pluginmanager.rewrite_hook = hook
for entrypoint in pkg_resources.iter_entry_points('pytest11'):
for entry in entrypoint.dist._get_metadata('RECORD'):
fn = entry.split(',')[0]
is_simple_module = os.sep not in fn and fn.endswith('.py')
is_package = fn.count(os.sep) == 1 and fn.endswith('__init__.py')
if is_simple_module:
module_name, ext = os.path.splitext(fn)
hook.mark_rewrite(module_name)
elif is_package:
package_name = os.path.dirname(fn)
hook.mark_rewrite(package_name)
self._warn_about_missing_assertion(mode)
def _warn_about_missing_assertion(self, mode):
try:
assert False
except AssertionError:
pass
else:
if mode == 'plain':
sys.stderr.write("WARNING: ASSERTIONS ARE NOT EXECUTED"
" and FAILING TESTS WILL PASS. Are you"
" using python -O?")
else:
sys.stderr.write("WARNING: assertions not in test modules or"
" plugins will be ignored"
" because assert statements are not executed "
"by the underlying Python interpreter "
"(are you using python -O?)\n")
def _preparse(self, args, addopts=True):
self._initini(args)
if addopts:
args[:] = shlex.split(os.environ.get('PYTEST_ADDOPTS', '')) + args
args[:] = self.getini("addopts") + args
self._checkversion()
entrypoint_name = 'pytest11'
self._consider_importhook(args, entrypoint_name)
self.pluginmanager.consider_preparse(args)
try:
self.pluginmanager.load_setuptools_entrypoints("pytest11")
except ImportError as e:
self.warn("I2", "could not load setuptools entry import: %s" % (e,))
self.pluginmanager.load_setuptools_entrypoints(entrypoint_name)
self.pluginmanager.consider_env()
self.known_args_namespace = ns = self._parser.parse_known_args(args, namespace=self.option.copy())
if self.known_args_namespace.confcutdir is None and self.inifile:
@@ -999,14 +1065,16 @@ class Config(object):
description, type, default = self._parser._inidict[name]
except KeyError:
raise ValueError("unknown configuration value: %r" %(name,))
try:
value = self.inicfg[name]
except KeyError:
if default is not None:
return default
if type is None:
return ''
return []
value = self._get_override_ini_value(name)
if value is None:
try:
value = self.inicfg[name]
except KeyError:
if default is not None:
return default
if type is None:
return ''
return []
if type == "pathlist":
dp = py.path.local(self.inicfg.config.path).dirpath()
l = []
@@ -1037,6 +1105,20 @@ class Config(object):
l.append(relroot)
return l
def _get_override_ini_value(self, name):
value = None
# override_ini is a list of list, to support both -o foo1=bar1 foo2=bar2 and
# and -o foo1=bar1 -o foo2=bar2 options
# always use the last item if multiple value set for same ini-name,
# e.g. -o foo=bar1 -o foo=bar2 will set foo to bar2
if self.getoption("override_ini", None):
for ini_config_list in self.option.override_ini:
for ini_config in ini_config_list:
(key, user_ini_value) = ini_config.split("=", 1)
if key == name:
value = user_ini_value
return value
def getoption(self, name, default=notset, skip=False):
""" return command line option value.
@@ -1074,7 +1156,18 @@ def exists(path, ignore=EnvironmentError):
except ignore:
return False
def getcfg(args, inibasenames):
def getcfg(args, warnfunc=None):
"""
Search the list of arguments for a valid ini-file for pytest,
and return a tuple of (rootdir, inifile, cfg-dict).
note: warnfunc is an optional function used to warn
about ini-files that use deprecated features.
This parameter should be removed when pytest
adopts standard deprecation warnings (#1804).
"""
from _pytest.deprecated import SETUP_CFG_PYTEST
inibasenames = ["pytest.ini", "tox.ini", "setup.cfg"]
args = [x for x in args if not str(x).startswith("-")]
if not args:
args = [py.path.local()]
@@ -1086,7 +1179,11 @@ def getcfg(args, inibasenames):
if exists(p):
iniconfig = py.iniconfig.IniConfig(p)
if 'pytest' in iniconfig.sections:
if inibasename == 'setup.cfg' and warnfunc:
warnfunc('C1', SETUP_CFG_PYTEST)
return base, p, iniconfig['pytest']
if inibasename == 'setup.cfg' and 'tool:pytest' in iniconfig.sections:
return base, p, iniconfig['tool:pytest']
elif inibasename == "pytest.ini":
# allowed to be empty
return base, p, {}
@@ -1101,6 +1198,8 @@ def get_common_ancestor(args):
if str(arg)[0] == "-":
continue
p = py.path.local(arg)
if not p.exists():
continue
if common_ancestor is None:
common_ancestor = p
else:
@@ -1114,29 +1213,40 @@ def get_common_ancestor(args):
common_ancestor = shared
if common_ancestor is None:
common_ancestor = py.path.local()
elif not common_ancestor.isdir():
elif common_ancestor.isfile():
common_ancestor = common_ancestor.dirpath()
return common_ancestor
def determine_setup(inifile, args):
def get_dirs_from_args(args):
return [d for d in (py.path.local(x) for x in args
if not str(x).startswith("-"))
if d.exists()]
def determine_setup(inifile, args, warnfunc=None):
dirs = get_dirs_from_args(args)
if inifile:
iniconfig = py.iniconfig.IniConfig(inifile)
try:
inicfg = iniconfig["pytest"]
except KeyError:
inicfg = None
rootdir = get_common_ancestor(args)
rootdir = get_common_ancestor(dirs)
else:
ancestor = get_common_ancestor(args)
rootdir, inifile, inicfg = getcfg(
[ancestor], ["pytest.ini", "tox.ini", "setup.cfg"])
ancestor = get_common_ancestor(dirs)
rootdir, inifile, inicfg = getcfg([ancestor], warnfunc=warnfunc)
if rootdir is None:
for rootdir in ancestor.parts(reverse=True):
if rootdir.join("setup.py").exists():
break
else:
rootdir = ancestor
rootdir, inifile, inicfg = getcfg(dirs, warnfunc=warnfunc)
if rootdir is None:
rootdir = get_common_ancestor([py.path.local(), ancestor])
is_fs_root = os.path.splitdrive(str(rootdir))[1] == os.sep
if is_fs_root:
rootdir = ancestor
return rootdir, inifile, inicfg or {}

View File

@@ -8,21 +8,33 @@ import pytest
def pytest_addoption(parser):
group = parser.getgroup("general")
group._addoption('--pdb',
action="store_true", dest="usepdb", default=False,
help="start the interactive Python debugger on errors.")
group._addoption(
'--pdb', dest="usepdb", action="store_true",
help="start the interactive Python debugger on errors.")
group._addoption(
'--pdbcls', dest="usepdb_cls", metavar="modulename:classname",
help="start a custom interactive Python debugger on errors. "
"For example: --pdbcls=IPython.terminal.debugger:TerminalPdb")
def pytest_namespace():
return {'set_trace': pytestPDB().set_trace}
def pytest_configure(config):
if config.getvalue("usepdb"):
if config.getvalue("usepdb") or config.getvalue("usepdb_cls"):
config.pluginmanager.register(PdbInvoke(), 'pdbinvoke')
if config.getvalue("usepdb_cls"):
modname, classname = config.getvalue("usepdb_cls").split(":")
__import__(modname)
pdb_cls = getattr(sys.modules[modname], classname)
else:
pdb_cls = pdb.Pdb
pytestPDB._pdb_cls = pdb_cls
old = (pdb.set_trace, pytestPDB._pluginmanager)
def fin():
pdb.set_trace, pytestPDB._pluginmanager = old
pytestPDB._config = None
pytestPDB._pdb_cls = pdb.Pdb
pdb.set_trace = pytest.set_trace
pytestPDB._pluginmanager = config.pluginmanager
pytestPDB._config = config
@@ -32,6 +44,7 @@ class pytestPDB:
""" Pseudo PDB that defers to the real pdb. """
_pluginmanager = None
_config = None
_pdb_cls = pdb.Pdb
def set_trace(self):
""" invoke PDB set_trace debugging, dropping any IO capturing. """
@@ -45,7 +58,7 @@ class pytestPDB:
tw.line()
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
self._pluginmanager.hook.pytest_enter_pdb(config=self._config)
pdb.Pdb().set_trace(frame)
self._pdb_cls().set_trace(frame)
class PdbInvoke:
@@ -98,7 +111,7 @@ def _find_last_non_hidden_frame(stack):
def post_mortem(t):
class Pdb(pdb.Pdb):
class Pdb(pytestPDB._pdb_cls):
def get_stack(self, f, t):
stack, i = pdb.Pdb.get_stack(self, f, t)
if f is None:

24
_pytest/deprecated.py Normal file
View File

@@ -0,0 +1,24 @@
"""
This module contains deprecation messages and bits of code used elsewhere in the codebase
that is planned to be removed in the next pytest release.
Keeping it in a central location makes it easy to track what is deprecated and should
be removed when the time comes.
"""
MAIN_STR_ARGS = 'passing a string to pytest.main() is deprecated, ' \
'pass a list of arguments instead.'
YIELD_TESTS = 'yield tests are deprecated, and scheduled to be removed in pytest 4.0'
FUNCARG_PREFIX = (
'{name}: declaring fixtures using "pytest_funcarg__" prefix is deprecated '
'and scheduled to be removed in pytest 4.0. '
'Please remove the prefix and use the @pytest.fixture decorator instead.')
SETUP_CFG_PYTEST = '[pytest] section in setup.cfg files is deprecated, use [tool:pytest] instead.'
GETFUNCARGVALUE = "use of getfuncargvalue is deprecated, use getfixturevalue"
RESULT_LOG = '--result-log is deprecated and scheduled for removal in pytest 4.0'

View File

@@ -4,10 +4,23 @@ from __future__ import absolute_import
import traceback
import pytest
from _pytest._code.code import TerminalRepr, ReprFileLocation, ExceptionInfo
from _pytest.python import FixtureRequest
from _pytest._code.code import ExceptionInfo, ReprFileLocation, TerminalRepr
from _pytest.fixtures import FixtureRequest
DOCTEST_REPORT_CHOICE_NONE = 'none'
DOCTEST_REPORT_CHOICE_CDIFF = 'cdiff'
DOCTEST_REPORT_CHOICE_NDIFF = 'ndiff'
DOCTEST_REPORT_CHOICE_UDIFF = 'udiff'
DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE = 'only_first_failure'
DOCTEST_REPORT_CHOICES = (
DOCTEST_REPORT_CHOICE_NONE,
DOCTEST_REPORT_CHOICE_CDIFF,
DOCTEST_REPORT_CHOICE_NDIFF,
DOCTEST_REPORT_CHOICE_UDIFF,
DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE,
)
def pytest_addoption(parser):
parser.addini('doctest_optionflags', 'option flags for doctests',
@@ -17,6 +30,11 @@ def pytest_addoption(parser):
action="store_true", default=False,
help="run doctests in all .py modules",
dest="doctestmodules")
group.addoption("--doctest-report",
type=str.lower, default="udiff",
help="choose another output format for diffs on doctest failure",
choices=DOCTEST_REPORT_CHOICES,
dest="doctestreport")
group.addoption("--doctest-glob",
action="append", default=[], metavar="pat",
help="doctests file matching pattern, default: test*.txt",
@@ -59,7 +77,6 @@ class ReprFailDoctest(TerminalRepr):
class DoctestItem(pytest.Item):
def __init__(self, name, parent, runner=None, dtest=None):
super(DoctestItem, self).__init__(name, parent)
self.runner = runner
@@ -70,7 +87,9 @@ class DoctestItem(pytest.Item):
def setup(self):
if self.dtest is not None:
self.fixture_request = _setup_fixtures(self)
globs = dict(getfixture=self.fixture_request.getfuncargvalue)
globs = dict(getfixture=self.fixture_request.getfixturevalue)
for name, value in self.fixture_request.getfixturevalue('doctest_namespace').items():
globs[name] = value
self.dtest.globs.update(globs)
def runtest(self):
@@ -92,7 +111,7 @@ class DoctestItem(pytest.Item):
message = excinfo.type.__name__
reprlocation = ReprFileLocation(filename, lineno, message)
checker = _get_checker()
REPORT_UDIFF = doctest.REPORT_UDIFF
report_choice = _get_report_choice(self.config.getoption("doctestreport"))
if lineno is not None:
lines = doctestfailure.test.docstring.splitlines(False)
# add line numbers to the left of the error message
@@ -108,7 +127,7 @@ class DoctestItem(pytest.Item):
indent = '...'
if excinfo.errisinstance(doctest.DocTestFailure):
lines += checker.output_difference(example,
doctestfailure.got, REPORT_UDIFF).split("\n")
doctestfailure.got, report_choice).split("\n")
else:
inner_excinfo = ExceptionInfo(excinfo.value.exc_info)
lines += ["UNEXPECTED EXCEPTION: %s" %
@@ -144,20 +163,19 @@ def get_optionflags(parent):
return flag_acc
class DoctestTextfile(DoctestItem, pytest.Module):
class DoctestTextfile(pytest.Module):
obj = None
def runtest(self):
def collect(self):
import doctest
fixture_request = _setup_fixtures(self)
# inspired by doctest.testfile; ideally we would use it directly,
# but it doesn't support passing a custom checker
text = self.fspath.read()
filename = str(self.fspath)
name = self.fspath.basename
globs = dict(getfixture=fixture_request.getfuncargvalue)
if '__name__' not in globs:
globs['__name__'] = '__main__'
globs = {'__name__': '__main__'}
optionflags = get_optionflags(self)
runner = doctest.DebugRunner(verbose=0, optionflags=optionflags,
@@ -165,8 +183,8 @@ class DoctestTextfile(DoctestItem, pytest.Module):
parser = doctest.DocTestParser()
test = parser.get_doctest(text, globs, name, filename, 0)
_check_all_skipped(test)
runner.run(test)
if test.examples:
yield DoctestItem(test.name, self, runner, test)
def _check_all_skipped(test):
@@ -288,3 +306,26 @@ def _get_allow_bytes_flag():
"""
import doctest
return doctest.register_optionflag('ALLOW_BYTES')
def _get_report_choice(key):
"""
This function returns the actual `doctest` module flag value, we want to do it as late as possible to avoid
importing `doctest` and all its dependencies when parsing options, as it adds overhead and breaks tests.
"""
import doctest
return {
DOCTEST_REPORT_CHOICE_UDIFF: doctest.REPORT_UDIFF,
DOCTEST_REPORT_CHOICE_CDIFF: doctest.REPORT_CDIFF,
DOCTEST_REPORT_CHOICE_NDIFF: doctest.REPORT_NDIFF,
DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE: doctest.REPORT_ONLY_FIRST_FAILURE,
DOCTEST_REPORT_CHOICE_NONE: 0,
}[key]
@pytest.fixture(scope='session')
def doctest_namespace():
"""
Inject names into the doctest namespace.
"""
return dict()

1110
_pytest/fixtures.py Normal file

File diff suppressed because it is too large Load Diff

45
_pytest/freeze_support.py Normal file
View File

@@ -0,0 +1,45 @@
"""
Provides a function to report all internal modules for using freezing tools
pytest
"""
def pytest_namespace():
return {'freeze_includes': freeze_includes}
def freeze_includes():
"""
Returns a list of module names used by py.test that should be
included by cx_freeze.
"""
import py
import _pytest
result = list(_iter_all_modules(py))
result += list(_iter_all_modules(_pytest))
return result
def _iter_all_modules(package, prefix=''):
"""
Iterates over the names of all modules that can be found in the given
package, recursively.
Example:
_iter_all_modules(_pytest) ->
['_pytest.assertion.newinterpret',
'_pytest.capture',
'_pytest.core',
...
]
"""
import os
import pkgutil
if type(package) is not str:
path, prefix = package.__path__[0], package.__name__ + '.'
else:
path = package
for _, name, is_package in pkgutil.iter_modules([path]):
if is_package:
for m in _iter_all_modules(os.path.join(path, name), prefix=name + '.'):
yield prefix + m
else:
yield prefix + name

View File

@@ -1,132 +0,0 @@
""" (deprecated) generate a single-file self-contained version of pytest """
import os
import sys
import pkgutil
import py
import _pytest
def find_toplevel(name):
for syspath in sys.path:
base = py.path.local(syspath)
lib = base/name
if lib.check(dir=1):
return lib
mod = base.join("%s.py" % name)
if mod.check(file=1):
return mod
raise LookupError(name)
def pkgname(toplevel, rootpath, path):
parts = path.parts()[len(rootpath.parts()):]
return '.'.join([toplevel] + [x.purebasename for x in parts])
def pkg_to_mapping(name):
toplevel = find_toplevel(name)
name2src = {}
if toplevel.check(file=1): # module
name2src[toplevel.purebasename] = toplevel.read()
else: # package
for pyfile in toplevel.visit('*.py'):
pkg = pkgname(name, toplevel, pyfile)
name2src[pkg] = pyfile.read()
# with wheels py source code might be not be installed
# and the resulting genscript is useless, just bail out.
assert name2src, "no source code found for %r at %r" %(name, toplevel)
return name2src
def compress_mapping(mapping):
import base64, pickle, zlib
data = pickle.dumps(mapping, 2)
data = zlib.compress(data, 9)
data = base64.encodestring(data)
data = data.decode('ascii')
return data
def compress_packages(names):
mapping = {}
for name in names:
mapping.update(pkg_to_mapping(name))
return compress_mapping(mapping)
def generate_script(entry, packages):
data = compress_packages(packages)
tmpl = py.path.local(__file__).dirpath().join('standalonetemplate.py')
exe = tmpl.read()
exe = exe.replace('@SOURCES@', data)
exe = exe.replace('@ENTRY@', entry)
return exe
def pytest_addoption(parser):
group = parser.getgroup("debugconfig")
group.addoption("--genscript", action="store", default=None,
dest="genscript", metavar="path",
help="create standalone pytest script at given target path.")
def pytest_cmdline_main(config):
import _pytest.config
genscript = config.getvalue("genscript")
if genscript:
tw = _pytest.config.create_terminal_writer(config)
tw.line("WARNING: usage of genscript is deprecated.",
red=True)
deps = ['py', '_pytest', 'pytest'] # pluggy is vendored
if sys.version_info < (2,7):
deps.append("argparse")
tw.line("generated script will run on python2.6-python3.3++")
else:
tw.line("WARNING: generated script will not run on python2.6 "
"due to 'argparse' dependency. Use python2.6 "
"to generate a python2.6 compatible script", red=True)
script = generate_script(
'import pytest; raise SystemExit(pytest.cmdline.main())',
deps,
)
genscript = py.path.local(genscript)
genscript.write(script)
tw.line("generated pytest standalone script: %s" % genscript,
bold=True)
return 0
def pytest_namespace():
return {'freeze_includes': freeze_includes}
def freeze_includes():
"""
Returns a list of module names used by py.test that should be
included by cx_freeze.
"""
result = list(_iter_all_modules(py))
result += list(_iter_all_modules(_pytest))
return result
def _iter_all_modules(package, prefix=''):
"""
Iterates over the names of all modules that can be found in the given
package, recursively.
Example:
_iter_all_modules(_pytest) ->
['_pytest.assertion.newinterpret',
'_pytest.capture',
'_pytest.core',
...
]
"""
if type(package) is not str:
path, prefix = package.__path__[0], package.__name__ + '.'
else:
path = package
for _, name, is_package in pkgutil.iter_modules([path]):
if is_package:
for m in _iter_all_modules(os.path.join(path, name), prefix=name + '.'):
yield prefix + m
else:
yield prefix + name

View File

@@ -20,6 +20,10 @@ def pytest_addoption(parser):
group.addoption('--debug',
action="store_true", dest="debug", default=False,
help="store internal tracing debug information in 'pytestdebug.log'.")
group._addoption(
'-o', '--override-ini', nargs='*', dest="override_ini",
action="append",
help="override config option, e.g. `-o xfail_strict=True`.")
@pytest.hookimpl(hookwrapper=True)
@@ -67,7 +71,6 @@ def showhelp(config):
tw.write(config._parser.optparser.format_help())
tw.line()
tw.line()
#tw.sep( "=", "config file settings")
tw.line("[pytest] ini-options in the next "
"pytest.ini|tox.ini|setup.cfg file:")
tw.line()
@@ -92,8 +95,8 @@ def showhelp(config):
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("to see available markers type: pytest --markers")
tw.line("to see available fixtures type: pytest --fixtures")
tw.line("(shown according to specified file_or_dir or current dir "
"if not specified)")

View File

@@ -34,7 +34,7 @@ def pytest_addoption(parser):
.. note::
This function should be implemented only in plugins or ``conftest.py``
files situated at the tests root directory due to how py.test
files situated at the tests root directory due to how pytest
:ref:`discovers plugins during startup <pluginorder>`.
:arg parser: To add command line options, call
@@ -156,6 +156,12 @@ def pytest_pyfunc_call(pyfuncitem):
def pytest_generate_tests(metafunc):
""" generate (multiple) parametrized calls to a test function."""
@hookspec(firstresult=True)
def pytest_make_parametrize_id(config, val):
"""Return a user-friendly string representation of the given ``val`` that will be used
by @pytest.mark.parametrize calls. Return None if the hook doesn't know about ``val``.
"""
# -------------------------------------------------------------------------
# generic runtest related hooks
# -------------------------------------------------------------------------
@@ -212,6 +218,19 @@ def pytest_runtest_logreport(report):
""" process a test setup/call/teardown report relating to
the respective phase of executing a test. """
# -------------------------------------------------------------------------
# Fixture related hooks
# -------------------------------------------------------------------------
@hookspec(firstresult=True)
def pytest_fixture_setup(fixturedef, request):
""" performs fixture setup execution. """
def pytest_fixture_post_finalizer(fixturedef):
""" called after fixture teardown, but before the cache is cleared so
the fixture result cache ``fixturedef.cached_result`` can
still be accessed."""
# -------------------------------------------------------------------------
# test session related hooks
# -------------------------------------------------------------------------
@@ -250,7 +269,7 @@ def pytest_report_header(config, startdir):
def pytest_report_teststatus(report):
""" return result-category, shortletter and verbose word for reporting."""
def pytest_terminal_summary(terminalreporter):
def pytest_terminal_summary(terminalreporter, exitstatus):
""" add additional section in terminal summary reporting. """

View File

@@ -118,13 +118,10 @@ class _NodeReporter(object):
def _write_captured_output(self, report):
for capname in ('out', 'err'):
allcontent = ""
for name, content in report.get_sections("Captured std%s" %
capname):
allcontent += content
if allcontent:
content = getattr(report, 'capstd' + capname)
if content:
tag = getattr(Junit, 'system-' + capname)
self.append(tag(bin_xml_escape(allcontent)))
self.append(tag(bin_xml_escape(content)))
def append_pass(self, report):
self.add_stats('passed')
@@ -186,8 +183,8 @@ class _NodeReporter(object):
@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
"""Add 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(
@@ -265,6 +262,7 @@ class LogXML(object):
], 0)
self.node_reporters = {} # nodeid -> _NodeReporter
self.node_reporters_ordered = []
self.global_properties = []
def finalize(self, report):
nodeid = getattr(report, 'nodeid', report)
@@ -284,9 +282,12 @@ class LogXML(object):
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):
@@ -369,10 +370,12 @@ class LogXML(object):
suite_stop_time = time.time()
suite_time_delta = suite_stop_time - self.suite_start_time
numtests = self.stats['passed'] + self.stats['failure'] + self.stats['skipped']
numtests = self.stats['passed'] + self.stats['failure'] + self.stats['skipped'] + self.stats['error']
logfile.write('<?xml version="1.0" encoding="utf-8"?>')
logfile.write(Junit.testsuite(
self._get_global_properties_node(),
[x.to_xml() for x in self.node_reporters_ordered],
name="pytest",
errors=self.stats['error'],
@@ -385,3 +388,18 @@ class LogXML(object):
def pytest_terminal_summary(self, terminalreporter):
terminalreporter.write_sep("-",
"generated xml file: %s" % (self.logfile))
def add_global_property(self, name, value):
self.global_properties.append((str(name), bin_xml_escape(value)))
def _get_global_properties_node(self):
"""Return a Junit node containing custom properties, if any.
"""
if self.global_properties:
return Junit.properties(
[
Junit.property(name=name, value=value)
for name, value in self.global_properties
]
)
return ''

View File

@@ -1,7 +1,5 @@
""" core implementation of testing process: init, session, runtest loop. """
import imp
import os
import re
import sys
import _pytest
@@ -25,11 +23,9 @@ EXIT_INTERNALERROR = 3
EXIT_USAGEERROR = 4
EXIT_NOTESTSCOLLECTED = 5
name_re = re.compile("^[a-zA-Z_]\w*$")
def pytest_addoption(parser):
parser.addini("norecursedirs", "directory patterns to avoid for recursion",
type="args", default=['.*', 'CVS', '_darcs', '{arch}', '*.egg'])
type="args", default=['.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg'])
parser.addini("testpaths", "directories to search for tests when no files or directories are given in the command line.",
type="args", default=[])
#parser.addini("dirpatterns",
@@ -38,8 +34,8 @@ def pytest_addoption(parser):
# "**/test_*.py", "**/*_test.py"]
#)
group = parser.getgroup("general", "running and selection options")
group._addoption('-x', '--exitfirst', action="store_true", default=False,
dest="exitfirst",
group._addoption('-x', '--exitfirst', action="store_const",
dest="maxfail", const=1,
help="exit instantly on first error or failed test."),
group._addoption('--maxfail', metavar="num",
action="store", type=int, dest="maxfail", default=0,
@@ -48,6 +44,9 @@ def pytest_addoption(parser):
help="run pytest in strict mode, warnings become errors.")
group._addoption("-c", metavar="file", type=str, dest="inifilename",
help="load configuration from `file` instead of trying to locate one of the implicit configuration files.")
group._addoption("--continue-on-collection-errors", action="store_true",
default=False, dest="continue_on_collection_errors",
help="Force test execution even if collection errors occur.")
group = parser.getgroup("collect", "collection")
group.addoption('--collectonly', '--collect-only', action="store_true",
@@ -64,6 +63,9 @@ def pytest_addoption(parser):
group.addoption('--noconftest', action="store_true",
dest="noconftest", default=False,
help="Don't load any conftest.py files.")
group.addoption('--keepduplicates', '--keep-duplicates', action="store_true",
dest="keepduplicates", default=False,
help="Keep duplicate tests.")
group = parser.getgroup("debugconfig",
"test session debugging and configuration")
@@ -75,10 +77,10 @@ def pytest_namespace():
collect = dict(Item=Item, Collector=Collector, File=File, Session=Session)
return dict(collect=collect)
def pytest_configure(config):
pytest.config = config # compatibiltiy
if config.option.exitfirst:
config.option.maxfail = 1
def wrap_session(config, doit):
"""Skeleton command line program"""
@@ -96,6 +98,10 @@ def wrap_session(config, doit):
raise
except KeyboardInterrupt:
excinfo = _pytest._code.ExceptionInfo()
if initstate < 2 and isinstance(
excinfo.value, pytest.exit.Exception):
sys.stderr.write('{0}: {1}\n'.format(
excinfo.typename, excinfo.value.msg))
config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
session.exitstatus = EXIT_INTERRUPTED
except:
@@ -133,20 +139,16 @@ def pytest_collection(session):
return session.perform_collect()
def pytest_runtestloop(session):
if (session.testsfailed and
not session.config.option.continue_on_collection_errors):
raise session.Interrupted(
"%d errors during collection" % session.testsfailed)
if session.config.option.collectonly:
return True
def getnextitem(i):
# this is a function to avoid python2
# keeping sys.exc_info set when calling into a test
# python2 keeps sys.exc_info till the frame is left
try:
return session.items[i+1]
except IndexError:
return None
for i, item in enumerate(session.items):
nextitem = getnextitem(i)
nextitem = session.items[i+1] if i+1 < len(session.items) else None
item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
if session.shouldstop:
raise session.Interrupted(session.shouldstop)
@@ -159,7 +161,21 @@ def pytest_ignore_collect(path, config):
excludeopt = config.getoption("ignore")
if excludeopt:
ignore_paths.extend([py.path.local(x) for x in excludeopt])
return path in ignore_paths
if path in ignore_paths:
return True
# Skip duplicate paths.
keepduplicates = config.getoption("keepduplicates")
duplicate_paths = config.pluginmanager._duplicatepaths
if not keepduplicates:
if path in duplicate_paths:
return True
else:
duplicate_paths.add(path)
return False
class FSHookProxy:
def __init__(self, fspath, pm, remove_mods):
@@ -276,7 +292,7 @@ class Node(object):
if fslocation is None:
fslocation = getattr(self, "fspath", None)
else:
fslocation = "%s:%s" % fslocation[:2]
fslocation = "%s:%s" % (fslocation[0], fslocation[1] + 1)
self.ihook.pytest_logwarning.call_historic(kwargs=dict(
code=code, message=message,
@@ -392,7 +408,10 @@ class Node(object):
if self.config.option.fulltrace:
style="long"
else:
tb = _pytest._code.Traceback([excinfo.traceback[-1]])
self._prunetraceback(excinfo)
if len(excinfo.traceback) == 0:
excinfo.traceback = tb
tbfilter = False # prunetraceback already does it
if style == "auto":
style = "long"
@@ -403,7 +422,13 @@ class Node(object):
else:
style = "long"
return excinfo.getrepr(funcargs=True,
try:
os.getcwd()
abspath = False
except OSError:
abspath = True
return excinfo.getrepr(funcargs=True, abspath=abspath,
showlocals=self.config.option.showlocals,
style=style, tbfilter=tbfilter)
@@ -649,36 +674,32 @@ class Session(FSCollector):
return True
def _tryconvertpyarg(self, x):
mod = None
path = [os.path.abspath('.')] + sys.path
for name in x.split('.'):
# ignore anything that's not a proper name here
# else something like --pyargs will mess up '.'
# since imp.find_module will actually sometimes work for it
# but it's supposed to be considered a filesystem path
# not a package
if name_re.match(name) is None:
return x
try:
fd, mod, type_ = imp.find_module(name, path)
except ImportError:
return x
else:
if fd is not None:
fd.close()
"""Convert a dotted module name to path.
if type_[2] != imp.PKG_DIRECTORY:
path = [os.path.dirname(mod)]
else:
path = [mod]
return mod
"""
import pkgutil
try:
loader = pkgutil.find_loader(x)
except ImportError:
return x
if loader is None:
return x
# This method is sometimes invoked when AssertionRewritingHook, which
# does not define a get_filename method, is already in place:
try:
path = loader.get_filename(x)
except AttributeError:
# Retrieve path from AssertionRewritingHook:
path = loader.modules[x][0].co_filename
if loader.is_package(x):
path = os.path.dirname(path)
return path
def _parsearg(self, arg):
""" return (fspath, names) tuple after checking the file exists. """
arg = str(arg)
if self.config.option.pyargs:
arg = self._tryconvertpyarg(arg)
parts = str(arg).split("::")
if self.config.option.pyargs:
parts[0] = self._tryconvertpyarg(parts[0])
relpath = parts[0].replace("/", os.sep)
path = self.config.invocation_dir.join(relpath, abs=True)
if not path.check():

View File

@@ -283,6 +283,21 @@ class MarkDecorator:
return self.__class__(self.name, args=args, kwargs=kw)
def extract_argvalue(maybe_marked_args):
# TODO: incorrect mark data, the old code wanst able to collect lists
# individual parametrized argument sets can be wrapped in a series
# of markers in which case we unwrap the values and apply the mark
# at Function init
newmarks = {}
argval = maybe_marked_args
while isinstance(argval, MarkDecorator):
newmark = MarkDecorator(argval.markname,
argval.args[:-1], argval.kwargs)
newmarks[newmark.markname] = newmark
argval = argval.args[-1]
return argval, newmarks
class MarkInfo:
""" Marking object created by :class:`MarkDecorator` instances. """
def __init__(self, name, args, kwargs):

View File

@@ -5,11 +5,14 @@ import re
from py.builtin import _basestring
import pytest
RE_IMPORT_ERROR_NAME = re.compile("^No module named (.*)$")
def pytest_funcarg__monkeypatch(request):
"""The returned ``monkeypatch`` funcarg provides these
@pytest.fixture
def monkeypatch(request):
"""The returned ``monkeypatch`` fixture provides these
helper methods to modify objects, dictionaries or os.environ::
monkeypatch.setattr(obj, name, value, raising=True)
@@ -22,11 +25,11 @@ def pytest_funcarg__monkeypatch(request):
monkeypatch.chdir(path)
All modifications will be undone after the requesting
test function has finished. The ``raising``
test function or fixture has finished. The ``raising``
parameter determines if a KeyError or AttributeError
will be raised if the set/deletion operation has no target.
"""
mpatch = monkeypatch()
mpatch = MonkeyPatch()
request.addfinalizer(mpatch.undo)
return mpatch
@@ -93,8 +96,9 @@ class Notset:
notset = Notset()
class monkeypatch:
""" Object keeping a record of setattr/item/env/syspath changes. """
class MonkeyPatch:
""" Object returned by the ``monkeypatch`` fixture keeping a record of setattr/item/env/syspath changes.
"""
def __init__(self):
self._setattr = []
@@ -220,10 +224,10 @@ class monkeypatch:
""" Undo previous changes. This call consumes the
undo stack. Calling it a second time has no effect unless
you do more monkeypatching after the undo call.
There is generally no need to call `undo()`, since it is
called automatically during tear-down.
Note that the same `monkeypatch` fixture is used across a
single test function invocation. If `monkeypatch` is used both by
the test function itself and one of the test fixtures,

View File

@@ -16,6 +16,7 @@ from _pytest._code import Source
import py
import pytest
from _pytest.main import Session, EXIT_OK
from _pytest.assertion.rewrite import AssertionRewritingHook
def pytest_addoption(parser):
@@ -123,15 +124,18 @@ def getexecutable(name, cache={}):
except KeyError:
executable = py.path.local.sysfind(name)
if executable:
import subprocess
popen = subprocess.Popen([str(executable), "--version"],
universal_newlines=True, stderr=subprocess.PIPE)
out, err = popen.communicate()
if name == "jython":
import subprocess
popen = subprocess.Popen([str(executable), "--version"],
universal_newlines=True, stderr=subprocess.PIPE)
out, err = popen.communicate()
if not err or "2.5" not in err:
executable = None
if "2.5.2" in err:
executable = None # http://bugs.jython.org/issue1790
elif popen.returncode != 0:
# Handle pyenv's 127.
executable = None
cache[name] = executable
return executable
@@ -318,7 +322,8 @@ def linecomp(request):
return LineComp()
def pytest_funcarg__LineMatcher(request):
@pytest.fixture(name='LineMatcher')
def LineMatcher_fixture(request):
return LineMatcher
@@ -374,10 +379,10 @@ class RunResult:
class Testdir:
"""Temporary test directory with tools to test/run py.test itself.
"""Temporary test directory with tools to test/run pytest itself.
This is based on the ``tmpdir`` fixture but provides a number of
methods which aid with testing py.test itself. Unless
methods which aid with testing pytest itself. Unless
:py:meth:`chdir` is used all methods will use :py:attr:`tmpdir` as
current working directory.
@@ -588,7 +593,7 @@ class Testdir:
"""Return the collection node of a file.
This is like :py:meth:`getnode` but uses
:py:meth:`parseconfigure` to create the (configured) py.test
:py:meth:`parseconfigure` to create the (configured) pytest
Config instance.
:param path: A :py:class:`py.path.local` instance of the file.
@@ -656,7 +661,7 @@ class Testdir:
:py:class:`HookRecorder` instance.
This runs the :py:func:`pytest.main` function to run all of
py.test inside the test process itself like
pytest inside the test process itself like
:py:meth:`inline_run`. However the return value is a tuple of
the collection items and a :py:class:`HookRecorder` instance.
@@ -669,7 +674,7 @@ class Testdir:
"""Run ``pytest.main()`` in-process, returning a HookRecorder.
This runs the :py:func:`pytest.main` function to run all of
py.test inside the test process itself. This means it can
pytest inside the test process itself. This means it can
return a :py:class:`HookRecorder` instance which gives more
detailed results from then run then can be done by matching
stdout/stderr from :py:meth:`runpytest`.
@@ -681,8 +686,17 @@ class Testdir:
``pytest.main()`` instance should use.
:return: A :py:class:`HookRecorder` instance.
"""
# When running py.test inline any plugins active in the main
# test process are already imported. So this disables the
# warning which will trigger to say they can no longer be
# re-written, which is fine as they are already re-written.
orig_warn = AssertionRewritingHook._warn_already_imported
def revert():
AssertionRewritingHook._warn_already_imported = orig_warn
self.request.addfinalizer(revert)
AssertionRewritingHook._warn_already_imported = lambda *a: None
rec = []
class Collect:
def pytest_configure(x, config):
@@ -755,9 +769,9 @@ class Testdir:
return args
def parseconfig(self, *args):
"""Return a new py.test Config instance from given commandline args.
"""Return a new pytest Config instance from given commandline args.
This invokes the py.test bootstrapping code in _pytest.config
This invokes the pytest bootstrapping code in _pytest.config
to create a new :py:class:`_pytest.core.PluginManager` and
call the pytest_cmdline_parse hook to create new
:py:class:`_pytest.config.Config` instance.
@@ -777,7 +791,7 @@ class Testdir:
return config
def parseconfigure(self, *args):
"""Return a new py.test configured Config instance.
"""Return a new pytest configured Config instance.
This returns a new :py:class:`_pytest.config.Config` instance
like :py:meth:`parseconfig`, but also calls the
@@ -792,7 +806,7 @@ class Testdir:
def getitem(self, source, funcname="test_func"):
"""Return the test item for a test function.
This writes the source to a python file and runs py.test's
This writes the source to a python file and runs pytest's
collection on the resulting module, returning the test item
for the requested function name.
@@ -812,7 +826,7 @@ class Testdir:
def getitems(self, source):
"""Return all test items collected from the module.
This writes the source to a python file and runs py.test's
This writes the source to a python file and runs pytest's
collection on the resulting module, returning all test items
contained within.
@@ -824,7 +838,7 @@ class Testdir:
"""Return the module collection node for ``source``.
This writes ``source`` to a file using :py:meth:`makepyfile`
and then runs the py.test collection on it, returning the
and then runs the pytest collection on it, returning the
collection node for the test module.
:param source: The source code of the module to collect.
@@ -924,7 +938,7 @@ class Testdir:
def _getpytestargs(self):
# we cannot use "(sys.executable,script)"
# because on windows the script is e.g. a py.test.exe
# because on windows the script is e.g. a pytest.exe
return (sys.executable, _pytest_fullpath,) # noqa
def runpython(self, script):
@@ -939,7 +953,7 @@ class Testdir:
return self.run(sys.executable, "-c", command)
def runpytest_subprocess(self, *args, **kwargs):
"""Run py.test as a subprocess with given arguments.
"""Run pytest as a subprocess with given arguments.
Any plugins added to the :py:attr:`plugins` list will added
using the ``-p`` command line option. Addtionally
@@ -967,9 +981,9 @@ class Testdir:
return self.run(*args)
def spawn_pytest(self, string, expect_timeout=10.0):
"""Run py.test using pexpect.
"""Run pytest using pexpect.
This makes sure to use the right py.test and sets up the
This makes sure to use the right pytest and sets up the
temporary directory locations.
The pexpect child is returned.
@@ -1035,6 +1049,7 @@ class LineMatcher:
def __init__(self, lines):
self.lines = lines
self._log_output = []
def str(self):
"""Return the entire original text."""
@@ -1058,10 +1073,11 @@ class LineMatcher:
for line in lines2:
for x in self.lines:
if line == x or fnmatch(x, line):
print_("matched: ", repr(line))
self._log("matched: ", repr(line))
break
else:
raise ValueError("line %r not found in output" % line)
self._log("line %r not found in output" % line)
raise ValueError(self._log_text)
def get_lines_after(self, fnline):
"""Return all lines following the given line in the text.
@@ -1073,6 +1089,13 @@ class LineMatcher:
return self.lines[i+1:]
raise ValueError("line %r not found in output" % fnline)
def _log(self, *args):
self._log_output.append(' '.join((str(x) for x in args)))
@property
def _log_text(self):
return '\n'.join(self._log_output)
def fnmatch_lines(self, lines2):
"""Search the text for matching lines.
@@ -1082,8 +1105,6 @@ class LineMatcher:
stdout.
"""
def show(arg1, arg2):
py.builtin.print_(arg1, arg2, file=sys.stderr)
lines2 = self._getlines(lines2)
lines1 = self.lines[:]
nextline = None
@@ -1094,17 +1115,18 @@ class LineMatcher:
while lines1:
nextline = lines1.pop(0)
if line == nextline:
show("exact match:", repr(line))
self._log("exact match:", repr(line))
break
elif fnmatch(nextline, line):
show("fnmatch:", repr(line))
show(" with:", repr(nextline))
self._log("fnmatch:", repr(line))
self._log(" with:", repr(nextline))
break
else:
if not nomatchprinted:
show("nomatch:", repr(line))
self._log("nomatch:", repr(line))
nomatchprinted = True
show(" and:", repr(nextline))
self._log(" and:", repr(nextline))
extralines.append(nextline)
else:
pytest.fail("remains unmatched: %r, see stderr" % (line,))
self._log("remains unmatched: %r" % (line,))
pytest.fail(self._log_text)

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@ def pytest_addoption(parser):
group = parser.getgroup("terminal reporting", "resultlog plugin options")
group.addoption('--resultlog', '--result-log', action="store",
metavar="path", default=None,
help="path for machine-readable result log.")
help="DEPRECATED path for machine-readable result log.")
def pytest_configure(config):
resultlog = config.option.resultlog
@@ -22,6 +22,9 @@ def pytest_configure(config):
config._resultlog = ResultLog(config, logfile)
config.pluginmanager.register(config._resultlog)
from _pytest.deprecated import RESULT_LOG
config.warn('C1', RESULT_LOG)
def pytest_unconfigure(config):
resultlog = getattr(config, '_resultlog', None)
if resultlog:

View File

@@ -73,7 +73,10 @@ def runtestprotocol(item, log=True, nextitem=None):
rep = call_and_report(item, "setup", log)
reports = [rep]
if rep.passed:
reports.append(call_and_report(item, "call", log))
if item.config.option.setupshow:
show_test_item(item)
if not item.config.option.setuponly:
reports.append(call_and_report(item, "call", log))
reports.append(call_and_report(item, "teardown", log,
nextitem=nextitem))
# after all teardown hooks have been called
@@ -83,6 +86,16 @@ def runtestprotocol(item, log=True, nextitem=None):
item.funcargs = None
return reports
def show_test_item(item):
"""Show test function, parameters and the fixtures of the test item."""
tw = item.config.get_terminal_writer()
tw.line()
tw.write(' ' * 8)
tw.write(item._nodeid)
used_fixtures = sorted(item._fixtureinfo.name2fixturedefs.keys())
if used_fixtures:
tw.write(' (fixtures used: {0})'.format(', '.join(used_fixtures)))
def pytest_runtest_setup(item):
item.session._setupstate.prepare(item)
@@ -198,6 +211,36 @@ class BaseReport(object):
if name.startswith(prefix):
yield prefix, content
@property
def longreprtext(self):
"""
Read-only property that returns the full string representation
of ``longrepr``.
.. versionadded:: 3.0
"""
tw = py.io.TerminalWriter(stringio=True)
tw.hasmarkup = False
self.toterminal(tw)
exc = tw.stringio.getvalue()
return exc.strip()
@property
def capstdout(self):
"""Return captured text from stdout, if capturing is enabled
.. versionadded:: 3.0
"""
return ''.join(content for (prefix, content) in self.get_sections('Captured stdout'))
@property
def capstderr(self):
"""Return captured text from stderr, if capturing is enabled
.. versionadded:: 3.0
"""
return ''.join(content for (prefix, content) in self.get_sections('Captured stderr'))
passed = property(lambda x: x.outcome == "passed")
failed = property(lambda x: x.outcome == "failed")
skipped = property(lambda x: x.outcome == "skipped")
@@ -263,8 +306,10 @@ class TestReport(BaseReport):
#: one of 'setup', 'call', 'teardown' to indicate runtest phase.
self.when = when
#: list of (secname, data) extra information which needs to
#: marshallable
#: list of pairs ``(str, str)`` of extra information which needs to
#: marshallable. Used by pytest to add captured text
#: from ``stdout`` and ``stderr``, but may be used by other plugins
#: to add arbitrary information to reports.
self.sections = list(sections)
#: time it took to run just the test
@@ -447,10 +492,16 @@ class Skipped(OutcomeException):
# in order to have Skipped exception printing shorter/nicer
__module__ = 'builtins'
def __init__(self, msg=None, pytrace=True, allow_module_level=False):
OutcomeException.__init__(self, msg=msg, pytrace=pytrace)
self.allow_module_level = allow_module_level
class Failed(OutcomeException):
""" raised from an explicit call to pytest.fail() """
__module__ = 'builtins'
class Exit(KeyboardInterrupt):
""" raised for immediate program exits (no tracebacks/summaries)"""
def __init__(self, msg="unknown reason"):
@@ -494,10 +545,14 @@ def importorskip(modname, minversion=None):
"""
__tracebackhide__ = True
compile(modname, '', 'eval') # to catch syntaxerrors
should_skip = False
try:
__import__(modname)
except ImportError:
skip("could not import %r" %(modname,))
# Do not raise chained exception here(#1485)
should_skip = True
if should_skip:
raise Skipped("could not import %r" %(modname,), allow_module_level=True)
mod = sys.modules[modname]
if minversion is None:
return mod
@@ -506,10 +561,11 @@ def importorskip(modname, minversion=None):
try:
from pkg_resources import parse_version as pv
except ImportError:
skip("we have a required version for %r but can not import "
"no pkg_resources to parse version strings." %(modname,))
raise Skipped("we have a required version for %r but can not import "
"pkg_resources to parse version strings." % (modname,),
allow_module_level=True)
if verattr is None or pv(verattr) < pv(minversion):
skip("module %r has __version__ %r, required is: %r" %(
modname, verattr, minversion))
raise Skipped("module %r has __version__ %r, required is: %r" %(
modname, verattr, minversion), allow_module_level=True)
return mod

72
_pytest/setuponly.py Normal file
View File

@@ -0,0 +1,72 @@
import pytest
import sys
def pytest_addoption(parser):
group = parser.getgroup("debugconfig")
group.addoption('--setuponly', '--setup-only', action="store_true",
help="only setup fixtures, don't execute the tests.")
group.addoption('--setupshow', '--setup-show', action="store_true",
help="show setup fixtures while executing the tests.")
@pytest.hookimpl(hookwrapper=True)
def pytest_fixture_setup(fixturedef, request):
yield
config = request.config
if config.option.setupshow:
if hasattr(request, 'param'):
# Save the fixture parameter so ._show_fixture_action() can
# display it now and during the teardown (in .finish()).
if fixturedef.ids:
if callable(fixturedef.ids):
fixturedef.cached_param = fixturedef.ids(request.param)
else:
fixturedef.cached_param = fixturedef.ids[
request.param_index]
else:
fixturedef.cached_param = request.param
_show_fixture_action(fixturedef, 'SETUP')
def pytest_fixture_post_finalizer(fixturedef):
if hasattr(fixturedef, "cached_result"):
config = fixturedef._fixturemanager.config
if config.option.setupshow:
_show_fixture_action(fixturedef, 'TEARDOWN')
if hasattr(fixturedef, "cached_param"):
del fixturedef.cached_param
def _show_fixture_action(fixturedef, msg):
config = fixturedef._fixturemanager.config
capman = config.pluginmanager.getplugin('capturemanager')
if capman:
out, err = capman.suspendcapture()
tw = config.get_terminal_writer()
tw.line()
tw.write(' ' * 2 * fixturedef.scopenum)
tw.write('{step} {scope} {fixture}'.format(
step=msg.ljust(8), # align the output to TEARDOWN
scope=fixturedef.scope[0].upper(),
fixture=fixturedef.argname))
if msg == 'SETUP':
deps = sorted(arg for arg in fixturedef.argnames if arg != 'request')
if deps:
tw.write(' (fixtures used: {0})'.format(', '.join(deps)))
if hasattr(fixturedef, 'cached_param'):
tw.write('[{0}]'.format(fixturedef.cached_param))
if capman:
capman.resumecapture()
sys.stdout.write(out)
sys.stderr.write(err)
@pytest.hookimpl(tryfirst=True)
def pytest_cmdline_main(config):
if config.option.setuponly:
config.option.setupshow = True

23
_pytest/setupplan.py Normal file
View File

@@ -0,0 +1,23 @@
import pytest
def pytest_addoption(parser):
group = parser.getgroup("debugconfig")
group.addoption('--setupplan', '--setup-plan', action="store_true",
help="show what fixtures and tests would be executed but "
"don't execute anything.")
@pytest.hookimpl(tryfirst=True)
def pytest_fixture_setup(fixturedef, request):
# Will return a dummy fixture if the setuponly option is provided.
if request.config.option.setupplan:
fixturedef.cached_result = (None, None, None)
return fixturedef.cached_result
@pytest.hookimpl(tryfirst=True)
def pytest_cmdline_main(config):
if config.option.setupplan:
config.option.setuponly = True
config.option.setupshow = True

View File

@@ -108,11 +108,7 @@ class MarkEvaluator:
def _getglobals(self):
d = {'os': os, 'sys': sys, 'config': self.item.config}
func = self.item.obj
try:
d.update(func.__globals__)
except AttributeError:
d.update(func.func_globals)
d.update(self.item.obj.__globals__)
return d
def _istrue(self):
@@ -228,9 +224,16 @@ def pytest_runtest_makereport(item, call):
evalskip = getattr(item, '_evalskip', None)
# unitttest special case, see setting of _unexpectedsuccess
if hasattr(item, '_unexpectedsuccess') and rep.when == "call":
# we need to translate into how pytest encodes xpass
rep.wasxfail = "reason: " + repr(item._unexpectedsuccess)
rep.outcome = "failed"
from _pytest.compat import _is_unittest_unexpected_success_a_failure
if item._unexpectedsuccess:
rep.longrepr = "Unexpected success: {0}".format(item._unexpectedsuccess)
else:
rep.longrepr = "Unexpected success"
if _is_unittest_unexpected_success_a_failure():
rep.outcome = "failed"
else:
rep.outcome = "passed"
rep.wasxfail = rep.longrepr
elif item.config.option.runxfail:
pass # don't interefere
elif call.excinfo and call.excinfo.errisinstance(pytest.xfail.Exception):
@@ -245,8 +248,15 @@ def pytest_runtest_makereport(item, call):
rep.outcome = "skipped"
rep.wasxfail = evalxfail.getexplanation()
elif call.when == "call":
rep.outcome = "failed" # xpass outcome
rep.wasxfail = evalxfail.getexplanation()
strict_default = item.config.getini('xfail_strict')
is_strict_xfail = evalxfail.get('strict', strict_default)
explanation = evalxfail.getexplanation()
if is_strict_xfail:
rep.outcome = "failed"
rep.longrepr = "[XPASS(strict)] {0}".format(explanation)
else:
rep.outcome = "passed"
rep.wasxfail = explanation
elif evalskip is not None and rep.skipped and type(rep.longrepr) is tuple:
# skipped by mark.skipif; change the location of the failure
# to point to the item definition, otherwise it will display
@@ -260,7 +270,7 @@ def pytest_report_teststatus(report):
if hasattr(report, "wasxfail"):
if report.skipped:
return "xfailed", "x", "xfail"
elif report.failed:
elif report.passed:
return "xpassed", "X", ("XPASS", {'yellow': True})
# called by the terminalreporter instance/plugin

View File

@@ -1,89 +0,0 @@
#! /usr/bin/env python
# Hi There!
# You may be wondering what this giant blob of binary data here is, you might
# even be worried that we're up to something nefarious (good for you for being
# paranoid!). This is a base64 encoding of a zip file, this zip file contains
# a fully functional basic pytest script.
#
# Pytest is a thing that tests packages, pytest itself is a package that some-
# one might want to install, especially if they're looking to run tests inside
# some package they want to install. Pytest has a lot of code to collect and
# execute tests, and other such sort of "tribal knowledge" that has been en-
# coded in its code base. Because of this we basically include a basic copy
# of pytest inside this blob. We do this because it let's you as a maintainer
# or application developer who wants people who don't deal with python much to
# easily run tests without installing the complete pytest package.
#
# If you're wondering how this is created: you can create it yourself if you
# have a complete pytest installation by using this command on the command-
# line: ``py.test --genscript=runtests.py``.
sources = """
@SOURCES@"""
import sys
import base64
import zlib
class DictImporter(object):
def __init__(self, sources):
self.sources = sources
def find_module(self, fullname, path=None):
if fullname == "argparse" and sys.version_info >= (2,7):
# we were generated with <python2.7 (which pulls in argparse)
# but we are running now on a stdlib which has it, so use that.
return None
if fullname in self.sources:
return self
if fullname + '.__init__' in self.sources:
return self
return None
def load_module(self, fullname):
# print "load_module:", fullname
from types import ModuleType
try:
s = self.sources[fullname]
is_pkg = False
except KeyError:
s = self.sources[fullname + '.__init__']
is_pkg = True
co = compile(s, fullname, 'exec')
module = sys.modules.setdefault(fullname, ModuleType(fullname))
module.__file__ = "%s/%s" % (__file__, fullname)
module.__loader__ = self
if is_pkg:
module.__path__ = [fullname]
do_exec(co, module.__dict__) # noqa
return sys.modules[fullname]
def get_source(self, name):
res = self.sources.get(name)
if res is None:
res = self.sources.get(name + '.__init__')
return res
if __name__ == "__main__":
try:
import pkg_resources # noqa
except ImportError:
sys.stderr.write("ERROR: setuptools not installed\n")
sys.exit(2)
if sys.version_info >= (3, 0):
exec("def do_exec(co, loc): exec(co, loc)\n")
import pickle
sources = sources.encode("ascii") # ensure bytes
sources = pickle.loads(zlib.decompress(base64.decodebytes(sources)))
else:
import cPickle as pickle
exec("def do_exec(co, loc): exec co in loc\n")
sources = pickle.loads(zlib.decompress(base64.decodestring(sources)))
importer = DictImporter(sources)
sys.meta_path.insert(0, importer)
entry = "@ENTRY@"
do_exec(entry, locals()) # noqa

View File

@@ -20,16 +20,18 @@ def pytest_addoption(parser):
group._addoption('-q', '--quiet', action="count",
dest="quiet", default=0, help="decrease verbosity."),
group._addoption('-r',
action="store", dest="reportchars", default=None, metavar="chars",
action="store", dest="reportchars", default='', metavar="chars",
help="show extra test summary info as specified by chars (f)ailed, "
"(E)error, (s)skipped, (x)failed, (X)passed (w)pytest-warnings "
"(p)passed, (P)passed with output, (a)all except pP.")
"(E)error, (s)skipped, (x)failed, (X)passed, "
"(p)passed, (P)passed with output, (a)all except pP. "
"The pytest warnings are displayed at all times except when "
"--disable-pytest-warnings is set")
group._addoption('--disable-pytest-warnings', default=False,
dest='disablepytestwarnings', action='store_true',
help='disable warnings summary, overrides -r w flag')
group._addoption('-l', '--showlocals',
action="store_true", dest="showlocals", default=False,
help="show locals in tracebacks (disabled by default).")
group._addoption('--report',
action="store", dest="report", default=None, metavar="opts",
help="(deprecated, use -r)")
group._addoption('--tb', metavar="style",
action="store", dest="tbstyle", default='auto',
choices=['auto', 'long', 'short', 'no', 'line', 'native'],
@@ -54,18 +56,11 @@ def pytest_configure(config):
def getreportopt(config):
reportopts = ""
optvalue = config.option.report
if optvalue:
py.builtin.print_("DEPRECATED: use -r instead of --report option.",
file=sys.stderr)
if optvalue:
for setting in optvalue.split(","):
setting = setting.strip()
if setting == "skipped":
reportopts += "s"
elif setting == "xfailed":
reportopts += "x"
reportchars = config.option.reportchars
if not config.option.disablepytestwarnings and 'w' not in reportchars:
reportchars += 'w'
elif config.option.disablepytestwarnings and 'w' in reportchars:
reportchars = reportchars.replace('w', '')
if reportchars:
for char in reportchars:
if char not in reportopts and char != 'a':
@@ -366,7 +361,8 @@ class TerminalReporter:
EXIT_OK, EXIT_TESTSFAILED, EXIT_INTERRUPTED, EXIT_USAGEERROR,
EXIT_NOTESTSCOLLECTED)
if exitstatus in summary_exit_codes:
self.config.hook.pytest_terminal_summary(terminalreporter=self)
self.config.hook.pytest_terminal_summary(terminalreporter=self,
exitstatus=exitstatus)
self.summary_errors()
self.summary_failures()
self.summary_warnings()
@@ -517,16 +513,8 @@ class TerminalReporter:
def summary_deselected(self):
if 'deselected' in self.stats:
l = []
k = self.config.option.keyword
if k:
l.append("-k%s" % k)
m = self.config.option.markexpr
if m:
l.append("-m %r" % m)
if l:
self.write_sep("=", "%d tests deselected by %r" % (
len(self.stats['deselected']), " ".join(l)), bold=True)
self.write_sep("=", "%d tests deselected" % (
len(self.stats['deselected'])), bold=True)
def repr_pythonversion(v=None):
if v is None:

View File

@@ -3,7 +3,7 @@ import re
import pytest
import py
from _pytest.monkeypatch import monkeypatch
from _pytest.monkeypatch import MonkeyPatch
class TempdirFactory:
@@ -92,7 +92,7 @@ def pytest_configure(config):
available at pytest_configure time, but ideally should be moved entirely
to the tmpdir_factory session fixture.
"""
mp = monkeypatch()
mp = MonkeyPatch()
t = TempdirFactory(config)
config._cleanup.extend([mp.undo, t.finish])
mp.setattr(config, '_tmpdirhandler', t, raising=False)
@@ -108,7 +108,7 @@ def tmpdir_factory(request):
@pytest.fixture
def tmpdir(request, tmpdir_factory):
"""return a temporary directory path object
"""Return a temporary directory path object
which is unique to each test function invocation,
created as a sub directory of the base temporary
directory. The returned object is a `py.path.local`_

View File

@@ -50,6 +50,8 @@ class UnitTestCase(pytest.Class):
foundsomething = False
for name in loader.getTestCaseNames(self.obj):
x = getattr(self.obj, name)
if not getattr(x, '__test__', True):
continue
funcobj = getattr(x, 'im_func', x)
transfer_markers(funcobj, cls, module)
yield TestCaseFunction(name, parent=self)
@@ -148,7 +150,12 @@ class TestCaseFunction(pytest.Function):
pass
def runtest(self):
self._testcase(result=self)
if self.config.pluginmanager.get_plugin("pdbinvoke") is None:
self._testcase(result=self)
else:
# disables tearDown and cleanups for post mortem debugging (see #1890)
self._testcase.debug()
def _prunetraceback(self, excinfo):
pytest.Function._prunetraceback(self, excinfo)

View File

@@ -5,6 +5,13 @@ environment:
# using pytestbot account as detailed here:
# https://www.appveyor.com/docs/build-configuration#secure-variables
matrix:
# create multiple jobs to execute a set of tox runs on each; this is to workaround having
# builds timing out in AppVeyor
- TOXENV: "linting,py26,py27,py33,py34,py35,pypy"
- TOXENV: "py27-pexpect,py27-xdist,py27-trial,py35-pexpect,py35-xdist,py35-trial"
- TOXENV: "py27-nobyte,doctesting,freeze,docs"
install:
- echo Installed Pythons
- dir c:\Python*

View File

@@ -1,19 +1,5 @@
{% extends "!layout.html" %}
{% block header %}
<div align="center" xmlns="http://www.w3.org/1999/html" style="background-color: lightgreen; padding: .5em">
<h4>
Want to help improve pytest? Please
<a href="https://www.indiegogo.com/projects/python-testing-sprint-mid-2016#/">
contribute to
</a>
or
<a href="announce/sprint2016.html">
join
</a>
our upcoming sprint in June 2016!
</h4>
</div>
{{super()}}
{% endblock %}
{% block footer %}

View File

@@ -1,10 +1,5 @@
<h3>Useful Links</h3>
<ul>
<li>
<a href="https://www.indiegogo.com/projects/python-testing-sprint-mid-2016#/">
<b>Sprint funding campaign</b>
</a>
</li>
<li><a href="{{ pathto('index') }}">The pytest Website</a></li>
<li><a href="{{ pathto('contributing') }}">Contribution Guide</a></li>
<li><a href="https://pypi.python.org/pypi/pytest">pytest @ PyPI</a></li>

View File

@@ -1,3 +1,7 @@
:orphan:
.. warnings about this file not being included in any toctree will be suppressed by :orphan:
April 2015 is "adopt pytest month"
=============================================

View File

@@ -5,9 +5,12 @@ Release announcements
.. toctree::
:maxdepth: 2
release-3.0.2
release-3.0.1
release-3.0.0
sprint2016
release-2.9.1
release-2.9.2
release-2.9.1
release-2.9.0
release-2.8.7

View File

@@ -41,7 +41,7 @@ Changes 2.6.3
dep). Thanks Charles Cloud for analysing the issue.
- fix conftest related fixture visibility issue: when running with a
CWD outside a test package pytest would get fixture discovery wrong.
CWD outside of a test package pytest would get fixture discovery wrong.
Thanks to Wolfgang Schnerring for figuring out a reproducable example.
- Introduce pytest_enter_pdb hook (needed e.g. by pytest_timeout to cancel the

View File

@@ -63,3 +63,5 @@ The py.test Development Team
.. _#649: https://github.com/pytest-dev/pytest/issues/649
.. _@asottile: https://github.com/asottile
.. _@nicoddemus: https://github.com/nicoddemus
.. _@tomviner: https://github.com/tomviner

View File

@@ -1,4 +1,4 @@
pytest-2.9.1
pytest-2.9.2
============
pytest is a mature Python testing tool with more than a 1100 tests
@@ -69,5 +69,10 @@ The py.test Development Team
.. _#1496: https://github.com/pytest-dev/pytest/issue/1496
.. _#1524: https://github.com/pytest-dev/pytest/issue/1524
.. _@prusse-martin: https://github.com/prusse-martin
.. _@astraw38: https://github.com/astraw38
.. _@hackebrot: https://github.com/hackebrot
.. _@omarkohl: https://github.com/omarkohl
.. _@pquentin: https://github.com/pquentin
.. _@prusse-martin: https://github.com/prusse-martin
.. _@RonnyPfannschmidt: https://github.com/RonnyPfannschmidt
.. _@tomviner: https://github.com/tomviner

View File

@@ -0,0 +1,82 @@
pytest-3.0.0
============
The pytest team is proud to announce the 3.0.0 release!
pytest is a mature Python testing tool with more than a 1600 tests
against itself, passing on many different interpreters and platforms.
This release contains a lot of bugs fixes and improvements, and much of
the work done on it was possible because of the 2016 Sprint[1], which
was funded by an indiegogo campaign which raised over US$12,000 with
nearly 100 backers.
There's a "What's new in pytest 3.0" [2] blog post highlighting the
major features in this release.
To see the complete changelog and documentation, please visit:
http://docs.pytest.org
As usual, you can upgrade from pypi via:
pip install -U pytest
Thanks to all who contributed to this release, among them:
AbdealiJK
Ana Ribeiro
Antony Lee
Brandon W Maister
Brianna Laugher
Bruno Oliveira
Ceridwen
Christian Boelsen
Daniel Hahler
Danielle Jenkins
Dave Hunt
Diego Russo
Dmitry Dygalo
Edoardo Batini
Eli Boyarski
Florian Bruhin
Floris Bruynooghe
Greg Price
Guyzmo
HEAD KANGAROO
JJ
Javi Romero
Javier Domingo Cansino
Kale Kundert
Kalle Bronsen
Marius Gedminas
Matt Williams
Mike Lundy
Oliver Bestwalter
Omar Kohl
Raphael Pierzina
RedBeardCode
Roberto Polli
Romain Dorgueil
Roman Bolshakov
Ronny Pfannschmidt
Stefan Zimmermann
Steffen Allner
Tareq Alayan
Ted Xiao
Thomas Grainger
Tom Viner
TomV
Vasily Kuznetsov
aostr
marscher
palaviv
satoru
taschini
Happy testing,
The Pytest Development Team
[1] http://blog.pytest.org/2016/pytest-development-sprint/
[2] http://blog.pytest.org/2016/whats-new-in-pytest-30/

View File

@@ -0,0 +1,26 @@
pytest-3.0.1
============
pytest 3.0.1 has just been released to PyPI.
This release fixes some regressions reported in version 3.0.0, being a
drop-in replacement. To upgrade:
pip install --upgrade pytest
The changelog is available at http://doc.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
Adam Chainz
Andrew Svetlov
Bruno Oliveira
Daniel Hahler
Dmitry Dygalo
Florian Bruhin
Marcin Bachry
Ronny Pfannschmidt
matthiasha
Happy testing,
The py.test Development Team

View File

@@ -0,0 +1,26 @@
pytest-3.0.2
============
pytest 3.0.2 has just been released to PyPI.
This release fixes some regressions and bugs reported in version 3.0.1, being a
drop-in replacement. To upgrade::
pip install --upgrade pytest
The changelog is available at http://doc.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Adam Chainz
* Andrew Svetlov
* Bruno Oliveira
* Daniel Hahler
* Dmitry Dygalo
* Florian Bruhin
* Marcin Bachry
* Ronny Pfannschmidt
* matthiasha
Happy testing,
The pytest Development Team

View File

@@ -4,9 +4,9 @@ python testing sprint June 20th-26th 2016
.. image:: ../img/freiburg2.jpg
:width: 400
The pytest core group is heading towards the biggest sprint
in its history, to take place in the black forest town Freiburg
in Germany. As of February 2016 we have started a `funding
The pytest core group held the biggest sprint
in its history in June 2016, taking place in the black forest town Freiburg
in Germany. In February 2016 we started a `funding
campaign on Indiegogo to cover expenses
<http://igg.me/at/pytest-sprint/x/4034848>`_ The page also mentions
some preliminary topics:
@@ -35,71 +35,30 @@ some preliminary topics:
Participants
--------------
Here are preliminary participants who said they are likely to come,
given some expenses funding::
Anatoly Bubenkoff, Netherlands
Andreas Pelme, Personalkollen, Sweden
Anthony Wang, Splunk, US
Brianna Laugher, Australia
Bruno Oliveira, Brazil
Danielle Jenkins, Splunk, US
Dave Hunt, UK
Florian Bruhin, Switzerland
Floris Bruynooghe, Cobe.io, UK
Holger Krekel, merlinux, Germany
Oliver Bestwalter, Avira, Germany
Omar Kohl, Germany
Raphael Pierzina, FanDuel, UK
Tom Viner, UK
<your name here?>
Other contributors and experienced newcomers are invited to join as well
but please send a mail to the pytest-dev mailing list if you intend to
do so somewhat soon, also how much funding you need if so. And if you
are working for a company and using pytest heavily you are welcome to
join and we encourage your company to provide some funding for the
sprint. They may see it, and rightfully so, as a very cheap and deep
training which brings you together with the experts in the field :)
Over 20 participants took part from 4 continents, including employees
from Splunk, Personalkollen, Cobe.io, FanDuel and Dolby. Some newcomers
mixed with developers who have worked on pytest since its beginning, and
of course everyone in between.
Sprint organisation, schedule
-------------------------------
tentative schedule:
People arrived in Freiburg on the 19th, with sprint development taking
place on 20th, 21st, 22nd, 24th and 25th. On the 23rd we took a break
day for some hot hiking in the Black Forest.
- 19/20th arrival in Freiburg
- 20th social get together, initial hacking
- 21/22th full sprint days
- 23rd break day, hiking
- 24/25th full sprint days
- 26th departure
Sprint activity was organised heavily around pairing, with plenty of group
discusssions to take advantage of the high bandwidth, and lightning talks
as well.
We might adjust according to weather to make sure that if
we do some hiking or excursion we'll have good weather.
Freiburg is one of the sunniest places in Germany so
it shouldn't be too much of a constraint.
Accomodation
----------------
We'll see to arrange for renting a flat with multiple
beds/rooms. Hotels are usually below 100 per night.
The earlier we book the better.
Money / funding
---------------
The Indiegogo campaign asks for 11000 USD which should cover
the costs for flights and accomodation, renting a sprint place
and maybe a bit of food as well.
If your organisation wants to support the sprint but prefers
to give money according to an invoice, get in contact with
holger at http://merlinux.eu who can invoice your organisation
properly.
The Indiegogo campaign aimed for 11000 USD and in the end raised over
12000, to reimburse travel costs, pay for a sprint venue and catering.
If we have excess money we'll use for further sprint/travel
funding for pytest/tox contributors.
Excess money is reserved for further sprint/travel funding for pytest/tox
contributors.

View File

@@ -24,9 +24,9 @@ following::
to assert that your function returns a certain value. If this assertion fails
you will see the return value of the function call::
$ py.test test_assert1.py
$ pytest test_assert1.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -85,6 +85,15 @@ and if you need to have access to the actual exception info you may use::
the actual exception raised. The main attributes of interest are
``.type``, ``.value`` and ``.traceback``.
.. versionchanged:: 3.0
In the context manager form you may use the keyword argument
``message`` to specify a custom failure message::
>>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"):
... pass
... Failed: Expecting ZeroDivisionError
If you want to write test code that works on Python 2.4 as well,
you may also use two other ways to test for an expected exception::
@@ -110,6 +119,24 @@ exceptions your own code is deliberately raising, whereas using
like documenting unfixed bugs (where the test describes what "should" happen)
or bugs in dependencies.
If you want to test that a regular expression matches on the string
representation of an exception (like the ``TestCase.assertRaisesRegexp`` method
from ``unittest``) you can use the ``ExceptionInfo.match`` method::
import pytest
def myfunc():
raise ValueError("Exception 123 raised")
def test_match():
with pytest.raises(ValueError) as excinfo:
myfunc()
excinfo.match(r'.* 123 .*')
The regexp parameter of the ``match`` method is matched with the ``re.search``
function. So in the above example ``excinfo.match('123')`` would have worked as
well.
.. _`assertwarns`:
@@ -141,9 +168,9 @@ when it encounters comparisons. For example::
if you run this module::
$ py.test test_assert2.py
$ pytest test_assert2.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -181,6 +208,7 @@ It is possible to add your own detailed explanations by implementing
the ``pytest_assertrepr_compare`` hook.
.. autofunction:: _pytest.hookspec.pytest_assertrepr_compare
:noindex:
As an example consider adding the following hook in a conftest.py which
provides an alternative explanation for ``Foo`` objects::
@@ -210,7 +238,7 @@ now, given this test module::
you can run the test module and get the custom output defined in
the conftest file::
$ py.test -q test_foocompare.py
$ pytest -q test_foocompare.py
F
======= FAILURES ========
_______ test_compare ________
@@ -287,3 +315,6 @@ For further information, Benjamin Peterson wrote up `Behind the scenes of pytest
.. versionchanged:: 2.1
Introduce the ``--assert`` option. Deprecate ``--no-assert`` and
``--nomagic``.
.. versionchanged:: 3.0
Removes the ``--no-assert`` and``--nomagic`` options.

View File

@@ -0,0 +1,12 @@
.. _backwards-compatibility:
Backwards Compatibility Policy
==============================
Keeping backwards compatibility has a very high priority in the pytest project. Although we have deprecated functionality over the years, most of it is still supported. All deprecations in pytest were done because simpler or more efficient ways of accomplishing the same tasks have emerged, making the old way of doing things unnecessary.
With the pytest 3.0 release we introduced a clear communication scheme for when we will actually remove the old busted joint and politely ask you to use the new hotness instead, while giving you enough time to adjust your tests or raise concerns if there are valid reasons to keep deprecated functionality around.
To communicate changes we are already issuing deprecation warnings, but they are not displayed by default. In pytest 3.0 we changed the default setting so that pytest deprecation warnings are displayed if not explicitly silenced (with ``--disable-pytest-warnings``).
We will only remove deprecated functionality in major releases (e.g. if we deprecate something in 3.0 we will remove it in 4.0), and keep it around for at least two minor releases (e.g. if we deprecate something in 3.9 and 4.0 is the next release, we will not remove it in 4.0 but in 5.0).

View File

@@ -18,11 +18,11 @@ For global activation of all argcomplete enabled python applications run::
For permanent (but not global) ``pytest`` activation, use::
register-python-argcomplete py.test >> ~/.bashrc
register-python-argcomplete pytest >> ~/.bashrc
For one-time activation of argcomplete for ``pytest`` only, use::
eval "$(register-python-argcomplete py.test)"
eval "$(register-python-argcomplete pytest)"

View File

@@ -35,6 +35,11 @@ Examples at :ref:`assertraises`.
.. autofunction:: deprecated_call
Comparing floating point numbers
--------------------------------
.. autoclass:: approx
Raising a specific test outcome
--------------------------------------
@@ -48,18 +53,18 @@ you can rather use declarative marks, see :ref:`skipping`.
.. autofunction:: _pytest.skipping.xfail
.. autofunction:: _pytest.runner.exit
fixtures and requests
Fixtures and requests
-----------------------------------------------------
To mark a fixture function:
.. autofunction:: _pytest.python.fixture
.. autofunction:: _pytest.fixtures.fixture
Tutorial at :ref:`fixtures`.
The ``request`` object that can be used from fixture functions.
.. autoclass:: _pytest.python.FixtureRequest()
.. autoclass:: _pytest.fixtures.FixtureRequest()
:members:
@@ -72,7 +77,7 @@ Builtin fixtures/function arguments
You can ask for available builtin or project-custom
:ref:`fixtures <fixtures>` by typing::
$ py.test -q --fixtures
$ pytest -q --fixtures
cache
Return a cache object that can persist state between testing sessions.
@@ -84,19 +89,23 @@ You can ask for available builtin or project-custom
Values can be any object handled by the json stdlib module.
capsys
enables capturing of writes to sys.stdout/sys.stderr and makes
Enable capturing of writes to sys.stdout/sys.stderr and make
captured output available via ``capsys.readouterr()`` method calls
which return a ``(out, err)`` tuple.
capfd
enables capturing of writes to file descriptors 1 and 2 and makes
Enable capturing of writes to file descriptors 1 and 2 and make
captured output available via ``capfd.readouterr()`` method calls
which return a ``(out, err)`` tuple.
doctest_namespace
Inject names into the doctest namespace.
pytestconfig
the pytest config object with access to command line opts.
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
Add 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
The returned ``monkeypatch`` fixture provides these
helper methods to modify objects, dictionaries or os.environ::
monkeypatch.setattr(obj, name, value, raising=True)
@@ -109,11 +118,9 @@ You can ask for available builtin or project-custom
monkeypatch.chdir(path)
All modifications will be undone after the requesting
test function has finished. The ``raising``
test function or fixture has finished. The ``raising``
parameter determines if a KeyError or AttributeError
will be raised if the set/deletion operation has no target.
pytestconfig
the pytest config object with access to command line opts.
recwarn
Return a WarningsRecorder instance that provides these methods:
@@ -125,7 +132,7 @@ You can ask for available builtin or project-custom
tmpdir_factory
Return a TempdirFactory instance for the test session.
tmpdir
return a temporary directory path object
Return a temporary directory path object
which is unique to each test function invocation,
created as a sub directory of the base temporary
directory. The returned object is a `py.path.local`_

View File

@@ -15,7 +15,7 @@ Usage
---------
The plugin provides two command line options to rerun failures from the
last ``py.test`` invocation:
last ``pytest`` invocation:
* ``--lf``, ``--last-failed`` - to only re-run the failures.
* ``--ff``, ``--failed-first`` - to run the failures first and then the rest of
@@ -25,7 +25,7 @@ For cleanup (usually not needed), a ``--cache-clear`` option allows to remove
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.
**json encodable** values between ``pytest`` invocations.
.. note::
@@ -49,7 +49,7 @@ First, let's create 50 test invocation of which only 2 fail::
If you run this for the first time you will see two failures::
$ py.test -q
$ pytest -q
.................F.......F........................
======= FAILURES ========
_______ test_num[17] ________
@@ -78,9 +78,9 @@ If you run this for the first time you will see two failures::
If you then run it with ``--lf``::
$ py.test --lf
$ pytest --lf
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
run-last-failure: rerun last 2 failures
rootdir: $REGENDOC_TMPDIR, inifile:
collected 50 items
@@ -110,6 +110,7 @@ If you then run it with ``--lf``::
E Failed: bad luck
test_50.py:6: Failed
======= 48 tests deselected ========
======= 2 failed, 48 deselected in 0.12 seconds ========
You have run only the two failing test from the last run, while 48 tests have
@@ -119,9 +120,9 @@ Now, if you run with the ``--ff`` option, all tests will be run but the first
previous failures will be executed first (as can be seen from the series
of ``FF`` and dots)::
$ py.test --ff
$ pytest --ff
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
run-last-failure: rerun last 2 failures first
rootdir: $REGENDOC_TMPDIR, inifile:
collected 50 items
@@ -163,7 +164,7 @@ The new config.cache object
Plugins or conftest.py support code can get a cached value using the
pytest ``config`` object. Here is a basic example plugin which
implements a :ref:`fixture` which re-uses previously created state
across py.test invocations::
across pytest invocations::
# content of test_caching.py
import pytest
@@ -184,7 +185,7 @@ across py.test invocations::
If you run this command once, it will take a while because
of the sleep::
$ py.test -q
$ pytest -q
F
======= FAILURES ========
_______ test_function ________
@@ -201,7 +202,7 @@ of the sleep::
If you run it a second time the value will be retrieved from
the cache and this will be quick::
$ py.test -q
$ pytest -q
F
======= FAILURES ========
_______ test_function ________
@@ -222,27 +223,20 @@ Inspecting Cache content
-------------------------------
You can always peek at the content of the cache using the
``--cache-clear`` command line option::
``--cache-show`` command line option::
$ py.test --cache-clear
$ py.test --cache-show
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
cachedir: $REGENDOC_TMPDIR/.cache
------------------------------- cache values -------------------------------
example/value contains:
42
cache/lastfailed contains:
{'test_caching.py::test_function': True}
test_caching.py F
======= FAILURES ========
_______ test_function ________
mydata = 42
def test_function(mydata):
> assert mydata == 23
E assert 42 == 23
test_caching.py:14: AssertionError
======= 1 failed in 0.12 seconds ========
======= no tests ran in 0.12 seconds ========
Clearing Cache content
-------------------------------
@@ -250,7 +244,7 @@ Clearing Cache content
You can instruct pytest to clear all cache files and values
by adding the ``--cache-clear`` option like this::
py.test --cache-clear
pytest --cache-clear
This is recommended for invocations from Continous Integration
servers where isolation and correctness is more important

View File

@@ -36,9 +36,9 @@ There are two ways in which ``pytest`` can perform capturing:
You can influence output capturing mechanisms from the command line::
py.test -s # disable all capturing
py.test --capture=sys # replace sys.stdout/stderr with in-mem files
py.test --capture=fd # also point filedescriptors 1 and 2 to temp file
pytest -s # disable all capturing
pytest --capture=sys # replace sys.stdout/stderr with in-mem files
pytest --capture=fd # also point filedescriptors 1 and 2 to temp file
.. _printdebugging:
@@ -62,9 +62,9 @@ is that you can use print statements for debugging::
and running this module will show you precisely the output
of the failing function and hide the other one::
$ py.test
$ pytest
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items
@@ -97,7 +97,7 @@ that performs some output related checks:
out, err = capsys.readouterr()
assert out == "hello\n"
assert err == "world\n"
print "next"
print ("next")
out, err = capsys.readouterr()
assert out == "next\n"
@@ -115,4 +115,19 @@ same interface but allows to also capture output from
libraries or subprocesses that directly write to operating
system level output streams (FD1 and FD2).
.. versionadded:: 3.0
To temporarily disable capture within a test, both ``capsys``
and ``capfd`` have a ``disabled()`` method that can be used
as a context manager, disabling capture inside the ``with`` block:
.. code-block:: python
def test_disabling_capturing(capsys):
print('this output is captured')
with capsys.disabled():
print('output not captured, going directly to sys.stdout')
print('this output is also captured')
.. include:: links.inc

View File

@@ -127,7 +127,7 @@ html_theme_options = {
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
html_title = None
html_title = 'pytest documentation'
# A shorter title for the navigation bar. Default is the same as html_title.
html_short_title = "pytest-%s" % release
@@ -144,7 +144,7 @@ html_favicon = "img/pytest1favi.ico"
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.

View File

@@ -3,37 +3,58 @@
Full pytest documentation
===========================
`Download latest version as PDF <pytest.pdf>`_
`Download latest version as PDF <https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf>`_
.. `Download latest version as EPUB <http://media.readthedocs.org/epub/pytest/latest/pytest.epub>`_
.. toctree::
:maxdepth: 2
overview
apiref
example/index
getting-started
usage
assert
builtin
fixture
monkeypatch
tmpdir
capture
recwarn
doctest
mark
skipping
parametrize
cache
unittest
nose
xunit_setup
plugins
writing_plugins
example/index
goodpractices
customize
bash-completion
backwards-compatibility
license
contributing
talks
projects
faq
contact
.. only:: html
.. toctree::
:maxdepth: 1
funcarg_compare
announce/index
.. only:: html
.. toctree::
:hidden:
:maxdepth: 1
changelog

View File

@@ -7,7 +7,7 @@ Command line options and configuration file settings
You can get help on command line options and values in INI-style
configurations files by using the general help option::
py.test -h # prints options _and_ config file settings
pytest -h # prints options _and_ config file settings
This will display command line and configuration file settings
which were registered by installed plugins.
@@ -29,25 +29,39 @@ project/testrun-specific information.
Here is the algorithm which finds the rootdir from ``args``:
- determine the common ancestor directory for the specified ``args``.
- determine the common ancestor directory for the specified ``args`` that are
recognised as paths that exist in the file system. If no such paths are
found, the common ancestor directory is set to the current working directory.
- look for ``pytest.ini``, ``tox.ini`` and ``setup.cfg`` files in the
ancestor directory and upwards. If one is matched, it becomes the
ini-file and its directory becomes the rootdir. An existing
``pytest.ini`` file will always be considered a match whereas
``tox.ini`` and ``setup.cfg`` will only match if they contain
a ``[pytest]`` section.
- look for ``pytest.ini``, ``tox.ini`` and ``setup.cfg`` files in the ancestor
directory and upwards. If one is matched, it becomes the ini-file and its
directory becomes the rootdir.
- if no ini-file was found, look for ``setup.py`` upwards from
the common ancestor directory to determine the ``rootdir``.
- if no ini-file was found, look for ``setup.py`` upwards from the common
ancestor directory to determine the ``rootdir``.
- if no ini-file and no ``setup.py`` was found, use the already
determined common ancestor as root directory. This allows to
work with pytest in structures that are not part of a package
and don't have any particular ini-file configuration.
- if no ``setup.py`` was found, look for ``pytest.ini``, ``tox.ini`` and
``setup.cfg`` in each of the specified ``args`` and upwards. If one is
matched, it becomes the ini-file and its directory becomes the rootdir.
Note that options from multiple ini-files candidates are never merged,
the first one wins (``pytest.ini`` always wins even if it does not
- if no ini-file was found, use the already determined common ancestor as root
directory. This allows to work with pytest in structures that are not part of
a package and don't have any particular ini-file configuration.
If no ``args`` are given, pytest collects test below the current working
directory and also starts determining the rootdir from there.
:warning: custom pytest plugin commandline arguments may include a path, as in
``pytest --log-output ../../test.log args``. Then ``args`` is mandatory,
otherwise pytest uses the folder of test.log for rootdir determination
(see also `issue 1435 <https://github.com/pytest-dev/pytest/issues/1435>`_).
A dot ``.`` for referencing to the current working directory is also
possible.
Note that an existing ``pytest.ini`` file will always be considered a match,
whereas ``tox.ini`` and ``setup.cfg`` will only match if they contain a
``[pytest]`` or ``[tool:pytest]`` section, respectively. Options from multiple ini-files candidates are never
merged - the first one wins (``pytest.ini`` always wins, even if it does not
contain a ``[pytest]`` section).
The ``config`` object will subsequently carry these attributes:
@@ -62,14 +76,14 @@ per-testrun information.
Example::
py.test path/to/testdir path/other/
pytest path/to/testdir path/other/
will determine the common ancestor as ``path`` and then
check for ini-files as follows::
# first look for pytest.ini files
path/pytest.ini
path/setup.cfg # must also contain [pytest] section to match
path/setup.cfg # must also contain [tool:pytest] section to match
path/tox.ini # must also contain [pytest] section to match
pytest.ini
... # all the way down to the root
@@ -126,9 +140,9 @@ Builtin configuration file options
[pytest]
addopts = --maxfail=2 -rf # exit after 2 failures, report fail info
issuing ``py.test test_hello.py`` actually means::
issuing ``pytest test_hello.py`` actually means::
py.test --maxfail=2 -rf test_hello.py
pytest --maxfail=2 -rf test_hello.py
Default is to add no options.
@@ -144,13 +158,13 @@ Builtin configuration file options
[seq] matches any character in seq
[!seq] matches any char not in seq
Default patterns are ``'.*', 'CVS', '_darcs', '{arch}', '*.egg'``.
Default patterns are ``'.*', 'build', 'dist', 'CVS', '_darcs', '{arch}', '*.egg'``.
Setting a ``norecursedirs`` replaces the default. Here is an example of
how to avoid certain directories:
.. code-block:: ini
# content of setup.cfg
# content of pytest.ini
[pytest]
norecursedirs = .svn _build tmp*
@@ -218,7 +232,7 @@ Builtin configuration file options
.. confval:: doctest_optionflags
One or more doctest flag names from the standard ``doctest`` module.
:doc:`See how py.test handles doctests <doctest>`.
:doc:`See how pytest handles doctests <doctest>`.
.. confval:: confcutdir

View File

@@ -6,7 +6,7 @@ By default all files matching the ``test*.txt`` pattern will
be run through the python standard ``doctest`` module. You
can change the pattern by issuing::
py.test --doctest-glob='*.rst'
pytest --doctest-glob='*.rst'
on the command line. Since version ``2.9``, ``--doctest-glob``
can be given multiple times in the command-line.
@@ -15,7 +15,7 @@ You can also trigger running of doctests
from docstrings in all python modules (including regular
python test modules)::
py.test --doctest-modules
pytest --doctest-modules
You can make these changes permanent in your project by
putting them into a pytest.ini file like this:
@@ -45,11 +45,11 @@ and another like this::
"""
return 42
then you can just invoke ``py.test`` without command line options::
then you can just invoke ``pytest`` without command line options::
$ py.test
$ pytest
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
collected 1 items
@@ -68,7 +68,7 @@ Also, :ref:`usefixtures` and :ref:`autouse` fixtures are supported
when executing text doctest files.
The standard ``doctest`` module provides some setting flags to configure the
strictness of doctest tests. In py.test You can enable those flags those flags
strictness of doctest tests. In pytest You can enable those flags those flags
using the configuration file. To make pytest ignore trailing whitespaces and
ignore lengthy exception stack traces you can just write:
@@ -77,7 +77,7 @@ ignore lengthy exception stack traces you can just write:
[pytest]
doctest_optionflags= NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL
py.test also introduces new options to allow doctests to run in Python 2 and
pytest also introduces new options to allow doctests to run in Python 2 and
Python 3 unchanged:
* ``ALLOW_UNICODE``: when enabled, the ``u`` prefix is stripped from unicode
@@ -103,3 +103,50 @@ itself::
'Hello'
The 'doctest_namespace' fixture
-------------------------------
.. versionadded:: 3.0
The ``doctest_namespace`` fixture can be used to inject items into the
namespace in which your doctests run. It is intended to be used within
your own fixtures to provide the tests that use them with context.
``doctest_namespace`` is a standard ``dict`` object into which you
place the objects you want to appear in the doctest namespace::
# content of conftest.py
import numpy
@pytest.fixture(autouse=True)
def add_np(doctest_namespace):
doctest_namespace['np'] = numpy
which can then be used in your doctests directly::
# content of numpy.py
def arange():
"""
>>> a = np.arange(10)
>>> len(a)
10
"""
pass
Output format
-------------
.. versionadded:: 3.0
You can change the diff output format on failure for your doctests
by using one of standard doctest modules format in options
(see :data:`python:doctest.REPORT_UDIFF`, :data:`python:doctest.REPORT_CDIFF`,
:data:`python:doctest.REPORT_NDIFF`, :data:`python:doctest.REPORT_ONLY_FIRST_FAILURE`)::
pytest --doctest-modules --doctest-report none
pytest --doctest-modules --doctest-report udiff
pytest --doctest-modules --doctest-report cdiff
pytest --doctest-modules --doctest-report ndiff
pytest --doctest-modules --doctest-report only_first_failure

View File

@@ -4,8 +4,8 @@ import pytest
@pytest.fixture("session")
def setup(request):
setup = CostlySetup()
request.addfinalizer(setup.finalize)
return setup
yield setup
setup.finalize()
class CostlySetup:
def __init__(self):

View File

@@ -1,4 +0,0 @@
[pytest]
testfilepatterns =
${topdir}/tests/unit/test_${basename}
${topdir}/tests/functional/*.py

View File

@@ -29,23 +29,23 @@ You can "mark" a test function with custom metadata like this::
You can then restrict a test run to only run tests marked with ``webtest``::
$ py.test -v -m webtest
$ pytest -v -m webtest
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items
test_server.py::test_send_http PASSED
======= 3 tests deselected by "-m 'webtest'" ========
======= 3 tests deselected ========
======= 1 passed, 3 deselected in 0.12 seconds ========
Or the inverse, running all tests except the webtest ones::
$ py.test -v -m "not webtest"
$ pytest -v -m "not webtest"
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items
@@ -54,7 +54,7 @@ Or the inverse, running all tests except the webtest ones::
test_server.py::test_another PASSED
test_server.py::TestClass::test_method PASSED
======= 1 tests deselected by "-m 'not webtest'" ========
======= 1 tests deselected ========
======= 3 passed, 1 deselected in 0.12 seconds ========
Selecting tests based on their node ID
@@ -64,9 +64,9 @@ You can provide one or more :ref:`node IDs <node-id>` as positional
arguments to select only specified tests. This makes it easy to select
tests based on their module, class, method, or function name::
$ py.test -v test_server.py::TestClass::test_method
$ pytest -v test_server.py::TestClass::test_method
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 5 items
@@ -77,9 +77,9 @@ tests based on their module, class, method, or function name::
You can also select on the class::
$ py.test -v test_server.py::TestClass
$ pytest -v test_server.py::TestClass
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items
@@ -90,9 +90,9 @@ You can also select on the class::
Or select multiple nodes::
$ py.test -v test_server.py::TestClass test_server.py::test_send_http
$ pytest -v test_server.py::TestClass test_server.py::test_send_http
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 8 items
@@ -115,8 +115,8 @@ Or select multiple nodes::
``module.py::function[param]``.
Node IDs for failing tests are displayed in the test summary info
when running py.test with the ``-rf`` option. You can also
construct Node IDs from the output of ``py.test --collectonly``.
when running pytest with the ``-rf`` option. You can also
construct Node IDs from the output of ``pytest --collectonly``.
Using ``-k expr`` to select tests based on their name
-------------------------------------------------------
@@ -128,23 +128,23 @@ which implements a substring match on the test names instead of the
exact match on markers that ``-m`` provides. This makes it easy to
select tests based on their names::
$ py.test -v -k http # running with the above defined example module
$ pytest -v -k http # running with the above defined example module
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items
test_server.py::test_send_http PASSED
======= 3 tests deselected by '-khttp' ========
======= 3 tests deselected ========
======= 1 passed, 3 deselected in 0.12 seconds ========
And you can also run all tests except the ones that match the keyword::
$ py.test -k "not send_http" -v
$ pytest -k "not send_http" -v
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items
@@ -153,14 +153,14 @@ And you can also run all tests except the ones that match the keyword::
test_server.py::test_another PASSED
test_server.py::TestClass::test_method PASSED
======= 1 tests deselected by '-knot send_http' ========
======= 1 tests deselected ========
======= 3 passed, 1 deselected in 0.12 seconds ========
Or to select "http" and "quick" tests::
$ py.test -k "http or quick" -v
$ pytest -k "http or quick" -v
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items
@@ -168,7 +168,7 @@ Or to select "http" and "quick" tests::
test_server.py::test_send_http PASSED
test_server.py::test_something_quick PASSED
======= 2 tests deselected by '-khttp or quick' ========
======= 2 tests deselected ========
======= 2 passed, 2 deselected in 0.12 seconds ========
.. note::
@@ -198,7 +198,7 @@ Registering markers for your test suite is simple::
You can ask which markers exist for your test suite - the list includes our just defined ``webtest`` markers::
$ py.test --markers
$ pytest --markers
@pytest.mark.webtest: mark a test as a webtest.
@pytest.mark.skip(reason=None): skip the given test function with an optional reason. Example: skip(reason="no way of currently testing this") skips the test.
@@ -225,7 +225,7 @@ For an example on how to add and work with markers from a plugin, see
* there is one place in your test suite defining your markers
* asking for existing markers via ``py.test --markers`` gives good output
* asking for existing markers via ``pytest --markers`` gives good output
* typos in function markers are treated as an error if you use
the ``--strict`` option. Future versions of ``pytest`` are probably
@@ -350,9 +350,9 @@ A test file using this local plugin::
and an example invocations specifying a different environment than what
the test needs::
$ py.test -E stage2
$ pytest -E stage2
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -362,9 +362,9 @@ the test needs::
and here is one that specifies exactly the environment needed::
$ py.test -E stage1
$ pytest -E stage1
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -374,7 +374,7 @@ and here is one that specifies exactly the environment needed::
The ``--markers`` option always gives you a list of available markers::
$ py.test --markers
$ pytest --markers
@pytest.mark.env(name): mark test to run only on named environment
@pytest.mark.skip(reason=None): skip the given test function with an optional reason. Example: skip(reason="no way of currently testing this") skips the test.
@@ -427,7 +427,7 @@ test function. From a conftest file we can read it like this::
Let's run this without capturing output and see what we get::
$ py.test -q -s
$ pytest -q -s
glob args=('function',) kwargs={'x': 3}
glob args=('class',) kwargs={'x': 2}
glob args=('module',) kwargs={'x': 1}
@@ -483,9 +483,9 @@ Let's do a little test file to show how this looks like::
then you will see two test skipped and two executed tests as expected::
$ py.test -rs # this option reports skip reasons
$ pytest -rs # this option reports skip reasons
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
@@ -497,15 +497,15 @@ then you will see two test skipped and two executed tests as expected::
Note that if you specify a platform via the marker-command line option like this::
$ py.test -m linux2
$ pytest -m linux2
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
test_plat.py s
======= 3 tests deselected by "-m 'linux2'" ========
======= 3 tests deselected ========
======= 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.
@@ -549,9 +549,9 @@ We want to dynamically define two markers and can do it in a
We can now use the ``-m option`` to select one set::
$ py.test -m interface --tb=short
$ pytest -m interface --tb=short
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
@@ -566,14 +566,14 @@ We can now use the ``-m option`` to select one set::
test_module.py:6: in test_interface_complex
assert 0
E assert 0
======= 2 tests deselected by "-m 'interface'" ========
======= 2 tests deselected ========
======= 2 failed, 2 deselected in 0.12 seconds ========
or to select both "event" and "interface" tests::
$ py.test -m "interface or event" --tb=short
$ pytest -m "interface or event" --tb=short
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
@@ -592,5 +592,5 @@ or to select both "event" and "interface" tests::
test_module.py:9: in test_event_simple
assert 0
E assert 0
======= 1 tests deselected by "-m 'interface or event'" ========
======= 1 tests deselected ========
======= 3 failed, 1 deselected in 0.12 seconds ========

View File

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

View File

@@ -25,13 +25,13 @@ You can create a simple example file:
and if you installed `PyYAML`_ or a compatible YAML-parser you can
now execute the test specification::
nonpython $ py.test test_simple.yml
nonpython $ pytest test_simple.yml
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, 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 ________
@@ -57,15 +57,15 @@ your own domain specific testing language this way.
``reportinfo()`` is used for representing the test location and is also
consulted when reporting in ``verbose`` mode::
nonpython $ py.test -v
nonpython $ pytest -v
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
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 ________
@@ -79,13 +79,13 @@ consulted when reporting in ``verbose`` mode::
While developing your custom test collection and execution it's also
interesting to just look at the collection tree::
nonpython $ py.test --collect-only
nonpython $ pytest --collect-only
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR/nonpython, inifile:
collected 2 items
<YamlFile 'test_simple.yml'>
<YamlItem 'ok'>
<YamlItem 'hello'>
<YamlItem 'ok'>
======= no tests ran in 0.12 seconds ========

View File

@@ -10,7 +10,7 @@ class YamlFile(pytest.File):
def collect(self):
import yaml # we need a yaml parser, e.g. PyYAML
raw = yaml.safe_load(self.fspath.open())
for name, spec in raw.items():
for name, spec in sorted(raw.items()):
yield YamlItem(name, self, spec)
class YamlItem(pytest.Item):
@@ -19,7 +19,7 @@ class YamlItem(pytest.Item):
self.spec = spec
def runtest(self):
for name, value in self.spec.items():
for name, value in sorted(self.spec.items()):
# some custom test execution (dumb example follows)
if name != value:
raise YamlException(self, name, value)

View File

@@ -44,14 +44,14 @@ Now we add a test configuration like this::
This means that we only run 2 tests if we do not pass ``--all``::
$ py.test -q test_compute.py
$ pytest -q test_compute.py
..
2 passed in 0.12 seconds
We run only two computations, so we see two dots.
let's run the full monty::
$ py.test -q --all
$ pytest -q --all
....F
======= FAILURES ========
_______ test_compute[4] ________
@@ -128,9 +128,9 @@ label generated by ``idfn``, but because we didn't generate a label for ``timede
objects, they are still using the default pytest representation::
$ py.test test_time.py --collect-only
$ pytest test_time.py --collect-only
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 6 items
<Module 'test_time.py'>
@@ -179,9 +179,9 @@ only have to work a bit to construct the correct arguments for pytest's
this is a fully self-contained example which you can run with::
$ py.test test_scenarios.py
$ pytest test_scenarios.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
@@ -192,9 +192,9 @@ this is a fully self-contained example which you can run with::
If you just collect tests you'll also nicely see 'advanced' and 'basic' as variants for the test function::
$ py.test --collect-only test_scenarios.py
$ pytest --collect-only test_scenarios.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
<Module 'test_scenarios.py'>
@@ -257,9 +257,9 @@ creates a database object for the actual test invocations::
Let's first see how it looks like at collection time::
$ py.test test_backends.py --collect-only
$ pytest test_backends.py --collect-only
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items
<Module 'test_backends.py'>
@@ -270,7 +270,7 @@ Let's first see how it looks like at collection time::
And then when we run the test::
$ py.test -q test_backends.py
$ pytest -q test_backends.py
.F
======= FAILURES ========
_______ test_db_initialized[d2] ________
@@ -318,9 +318,9 @@ will be passed to respective fixture function::
The result of this test will be successful::
$ py.test test_indirect_list.py --collect-only
$ pytest test_indirect_list.py --collect-only
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
<Module 'test_indirect_list.py'>
@@ -346,7 +346,7 @@ parametrizer`_ but in a lot less code::
def pytest_generate_tests(metafunc):
# called once per each test function
funcarglist = metafunc.cls.params[metafunc.function.__name__]
argnames = list(funcarglist[0])
argnames = sorted(funcarglist[0])
metafunc.parametrize(argnames, [[funcargs[name] for name in argnames]
for funcargs in funcarglist])
@@ -366,7 +366,7 @@ parametrizer`_ but in a lot less code::
Our test generator looks up a class-level definition which specifies which
argument sets to use for each test function. Let's run it::
$ py.test -q
$ pytest -q
F..
======= FAILURES ========
_______ TestClass.test_equals[1-2] ________
@@ -396,9 +396,11 @@ is to be run with different sets of arguments for its three arguments:
Running it results in some skips if we don't have all the python interpreters installed and otherwise runs all combinations (5 interpreters times 5 interpreters times 3 objects to serialize/deserialize)::
. $ py.test -rs -q multipython.py
...........................
27 passed in 0.12 seconds
. $ pytest -rs -q multipython.py
sssssssssssssss.........sss.........sss.........
======= short test summary info ========
SKIP [21] $REGENDOC_TMPDIR/CWD/multipython.py:23: 'python2.6' not found
27 passed, 21 skipped in 0.12 seconds
Indirect parametrization of optional implementations/imports
--------------------------------------------------------------------
@@ -443,9 +445,9 @@ And finally a little test module::
If you run this with reporting for skips enabled::
$ py.test -rs test_module.py
$ pytest -rs test_module.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items

View File

@@ -1,5 +1,5 @@
# run this with $ py.test --collect-only test_collectonly.py
# run this with $ pytest --collect-only test_collectonly.py
#
def test_function():
pass

View File

@@ -40,12 +40,46 @@ you will see that ``pytest`` only collects test-modules, which do not match the
======= 5 passed in 0.02 seconds =======
Keeping duplicate paths specified from command line
----------------------------------------------------
Default behavior of ``pytest`` is to ignore duplicate paths specified from the command line.
Example::
py.test path_a path_a
...
collected 1 item
...
Just collect tests once.
To collect duplicate tests, use the ``--keep-duplicates`` option on the cli.
Example::
py.test --keep-duplicates path_a path_a
...
collected 2 items
...
As the collector just works on directories, if you specify twice a single test file, ``pytest`` will
still collect it twice, no matter if the ``--keep-duplicates`` is not specified.
Example::
py.test test_a.py test_a.py
...
collected 2 items
...
Changing directory recursion
-----------------------------------------------------
You can set the :confval:`norecursedirs` option in an ini-file, for example your ``setup.cfg`` in the project root directory::
You can set the :confval:`norecursedirs` option in an ini-file, for example your ``pytest.ini`` in the project root directory::
# content of setup.cfg
# content of pytest.ini
[pytest]
norecursedirs = .svn _build tmp*
@@ -60,8 +94,9 @@ You can configure different naming conventions by setting
the :confval:`python_files`, :confval:`python_classes` and
:confval:`python_functions` configuration options. Example::
# content of setup.cfg
# can also be defined in in tox.ini or pytest.ini file
# content of pytest.ini
# can also be defined in in tox.ini or setup.cfg file, although the section
# name in setup.cfg files should be "tool:pytest"
[pytest]
python_files=check_*.py
python_classes=Check
@@ -80,10 +115,10 @@ that match ``*_check``. For example, if we have::
then the test collection looks like this::
$ py.test --collect-only
$ pytest --collect-only
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: setup.cfg
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
collected 2 items
<Module 'check_myapp.py'>
<Class 'CheckMyApp'>
@@ -107,7 +142,7 @@ interpreting arguments as python package names, deriving
their file system path and then running the test. For
example if you have unittest2 installed you can type::
py.test --pyargs unittest2.test.test_skipping -q
pytest --pyargs unittest2.test.test_skipping -q
which would run the respective test module. Like with
other options, through an ini-file and the :confval:`addopts` option you
@@ -117,7 +152,7 @@ can make this change more permanently::
[pytest]
addopts = --pyargs
Now a simple invocation of ``py.test NAME`` will check
Now a simple invocation of ``pytest NAME`` will check
if NAME exists as an importable package/module and otherwise
treat it as a filesystem path.
@@ -126,9 +161,9 @@ Finding out what is collected
You can always peek at the collection tree without running tests like this::
. $ py.test --collect-only pythoncollection.py
. $ pytest --collect-only pythoncollection.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
collected 3 items
<Module 'CWD/pythoncollection.py'>
@@ -180,7 +215,7 @@ and a setup.py dummy file like this::
then a pytest run on Python2 will find the one test and will leave out the
setup.py file::
#$ py.test --collect-only
#$ pytest --collect-only
====== test session starts ======
platform linux2 -- Python 2.7.10, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
@@ -193,9 +228,9 @@ setup.py file::
If you run with a Python3 interpreter both the one test and the setup.py file
will be left out::
$ py.test --collect-only
$ pytest --collect-only
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
collected 0 items

View File

@@ -7,13 +7,11 @@ Demo of Python failure reports with pytest
Here is a nice run of several tens of failures
and how ``pytest`` presents things (unfortunately
not showing the nice colors here in the HTML that you
get on the terminal - we are working on that):
get on the terminal - we are working on that)::
.. code-block:: python
assertion $ py.test failure_demo.py
assertion $ pytest failure_demo.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR/assertion, inifile:
collected 42 items
@@ -361,7 +359,7 @@ get on the terminal - we are working on that):
> int(s)
E ValueError: invalid literal for int() with base 10: 'qwe'
<0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python.py:1309>:1: ValueError
<0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python.py:1190>:1: ValueError
_______ TestRaises.test_raises_doesnt ________
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -427,7 +425,7 @@ get on the terminal - we are working on that):
def foo():
> assert 1 == 0
E assert 1 == 0
E AssertionError
<2-codegen 'abc-123' $REGENDOC_TMPDIR/assertion/failure_demo.py:163>:2: AssertionError
_______ TestMoreErrors.test_complex_error ________
@@ -482,8 +480,9 @@ get on the terminal - we are working on that):
s = "123"
g = "456"
> assert s.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 assert False
E + where False = <built-in method startswith of str object at 0xdeadbeef>('456')
E + where <built-in method startswith of str object at 0xdeadbeef> = '123'.startswith
failure_demo.py:189: AssertionError
_______ TestMoreErrors.test_startswith_nested ________
@@ -496,10 +495,11 @@ get on the terminal - we are working on that):
def g():
return "456"
> assert f().startswith(g())
E assert <built-in method startswith of str object at 0xdeadbeef>('456')
E + where <built-in method startswith of str object at 0xdeadbeef> = '123'.startswith
E + where '123' = <function TestMoreErrors.test_startswith_nested.<locals>.f at 0xdeadbeef>()
E + and '456' = <function TestMoreErrors.test_startswith_nested.<locals>.g at 0xdeadbeef>()
E assert False
E + where False = <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 TestMoreErrors.test_startswith_nested.<locals>.f at 0xdeadbeef>()
E + and '456' = <function TestMoreErrors.test_startswith_nested.<locals>.g at 0xdeadbeef>()
failure_demo.py:196: AssertionError
_______ TestMoreErrors.test_global_func ________
@@ -508,8 +508,9 @@ get on the terminal - we are working on that):
def test_global_func(self):
> assert isinstance(globf(42), float)
E assert isinstance(43, float)
E + where 43 = globf(42)
E assert False
E + where False = isinstance(43, float)
E + where 43 = globf(42)
failure_demo.py:199: AssertionError
_______ TestMoreErrors.test_instance ________

View File

@@ -1,5 +1,4 @@
.. highlightlang:: python
Basic patterns and examples
==========================================================
@@ -10,7 +9,9 @@ Pass different values to a test function, depending on command line options
.. regendoc:wipe
Suppose we want to write a test that depends on a command line option.
Here is a basic pattern to achieve this::
Here is a basic pattern to achieve this:
.. code-block:: python
# content of test_sample.py
def test_answer(cmdopt):
@@ -22,7 +23,9 @@ Here is a basic pattern to achieve this::
For this to work we need to add a command line option and
provide the ``cmdopt`` through a :ref:`fixture function <fixture function>`::
provide the ``cmdopt`` through a :ref:`fixture function <fixture function>`:
.. code-block:: python
# content of conftest.py
import pytest
@@ -37,7 +40,7 @@ provide the ``cmdopt`` through a :ref:`fixture function <fixture function>`::
Let's run this without supplying our new option::
$ py.test -q test_sample.py
$ pytest -q test_sample.py
F
======= FAILURES ========
_______ test_answer ________
@@ -59,7 +62,7 @@ Let's run this without supplying our new option::
And now with supplying a command line option::
$ py.test -q --cmdopt=type2
$ pytest -q --cmdopt=type2
F
======= FAILURES ========
_______ test_answer ________
@@ -91,7 +94,9 @@ Dynamically adding command line options
Through :confval:`addopts` you can statically add command line
options for your project. You can also dynamically modify
the command line arguments before they get processed::
the command line arguments before they get processed:
.. code-block:: python
# content of conftest.py
import sys
@@ -101,14 +106,14 @@ the command line arguments before they get processed::
num = max(multiprocessing.cpu_count() / 2, 1)
args[:] = ["-n", str(num)] + args
If you have the :ref:`xdist plugin <xdist>` installed
If you have the `xdist plugin <https://pypi.python.org/pypi/pytest-xdist>`_ installed
you will now always perform test runs using a number
of subprocesses close to your CPU. Running in an empty
directory with the above conftest.py::
$ py.test
$ pytest
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 0 items
@@ -122,7 +127,9 @@ Control skipping of tests according to command line option
.. regendoc:wipe
Here is a ``conftest.py`` file adding a ``--runslow`` command
line option to control skipping of ``slow`` marked tests::
line option to control skipping of ``slow`` marked tests:
.. code-block:: python
# content of conftest.py
@@ -131,10 +138,11 @@ line option to control skipping of ``slow`` marked tests::
parser.addoption("--runslow", action="store_true",
help="run slow tests")
We can now write a test module like this::
We can now write a test module like this:
.. code-block:: python
# content of test_module.py
import pytest
@@ -154,23 +162,23 @@ We can now write a test module like this::
and when running it will see a skipped "slow" test::
$ py.test -rs # "-rs" means report details on the little 's'
$ pytest -rs # "-rs" means report details on the little 's'
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, 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] test_module.py:14: need --runslow option to run
SKIP [1] test_module.py:13: need --runslow option to run
======= 1 passed, 1 skipped in 0.12 seconds ========
Or run it including the ``slow`` marked test::
$ py.test --runslow
$ pytest --runslow
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items
@@ -187,7 +195,9 @@ If you have a test helper function called from a test you can
use the ``pytest.fail`` marker to fail a test with a certain message.
The test support function will not show up in the traceback if you
set the ``__tracebackhide__`` option somewhere in the helper function.
Example::
Example:
.. code-block:: python
# content of test_checkconfig.py
import pytest
@@ -204,7 +214,7 @@ of tracebacks: the ``checkconfig`` function will not be shown
unless the ``--full-trace`` command line option is specified.
Let's run our little function::
$ py.test -q test_checkconfig.py
$ pytest -q test_checkconfig.py
F
======= FAILURES ========
_______ test_something ________
@@ -216,6 +226,30 @@ Let's run our little function::
test_checkconfig.py:8: Failed
1 failed in 0.12 seconds
If you only want to hide certain exceptions, you can set ``__tracebackhide__``
to a callable which gets the ``ExceptionInfo`` object. You can for example use
this to make sure unexpected exception types aren't hidden:
.. code-block:: python
import operator
import pytest
class ConfigException(Exception):
pass
def checkconfig(x):
__tracebackhide__ = operator.methodcaller('errisinstance', ConfigException)
if not hasattr(x, "config"):
raise ConfigException("not configured: %s" %(x,))
def test_something():
checkconfig(42)
This will avoid hiding the exception traceback on unrelated exceptions (i.e.
bugs in assertion helpers).
Detect if running from within a pytest run
--------------------------------------------------------------
@@ -224,7 +258,9 @@ Detect if running from within a pytest run
Usually it is a bad idea to make application code
behave differently if called from a test. But if you
absolutely must find out if your application code is
running from a test you can do something like this::
running from a test you can do something like this:
.. code-block:: python
# content of conftest.py
@@ -235,7 +271,9 @@ running from a test you can do something like this::
def pytest_unconfigure(config):
del sys._called_from_test
and then check for the ``sys._called_from_test`` flag::
and then check for the ``sys._called_from_test`` flag:
.. code-block:: python
if hasattr(sys, '_called_from_test'):
# called from within a test run
@@ -251,7 +289,9 @@ Adding info to test report header
.. regendoc:wipe
It's easy to present extra information in a ``pytest`` run::
It's easy to present extra information in a ``pytest`` run:
.. code-block:: python
# content of conftest.py
@@ -260,9 +300,9 @@ It's easy to present extra information in a ``pytest`` run::
which will add the string to the test header accordingly::
$ py.test
$ pytest
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
project deps: mylib-1.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 0 items
@@ -271,22 +311,23 @@ which will add the string to the test header accordingly::
.. regendoc:wipe
You can also return a list of strings which will be considered as several
lines of information. You can of course also make the amount of reporting
information on e.g. the value of ``config.option.verbose`` so that
you present more information appropriately::
It is also possible to return a list of strings which will be considered as several
lines of information. You may consider ``config.getoption('verbose')`` in order to
display more information if applicable:
.. code-block:: python
# content of conftest.py
def pytest_report_header(config):
if config.option.verbose > 0:
if config.getoption('verbose') > 0:
return ["info1: did you know that ...", "did you?"]
which will add info only when run with "--v"::
$ py.test -v
$ pytest -v
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
cachedir: .cache
info1: did you know that ...
did you?
@@ -297,9 +338,9 @@ which will add info only when run with "--v"::
and nothing when run plainly::
$ py.test
$ pytest
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 0 items
@@ -313,10 +354,11 @@ 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 artificial test suite::
out which tests are the slowest. Let's make an artificial test suite:
.. code-block:: python
# content of test_some_are_slow.py
import time
def test_funcfast():
@@ -330,9 +372,9 @@ out which tests are the slowest. Let's make an artificial test suite::
Now we can profile which test functions execute the slowest::
$ py.test --durations=3
$ pytest --durations=3
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 3 items
@@ -341,7 +383,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 teardown test_some_are_slow.py::test_funcslow2
0.00s setup test_some_are_slow.py::test_funcfast
======= 3 passed in 0.12 seconds ========
incremental testing - test steps
@@ -353,7 +395,9 @@ Sometimes you may have a testing situation which consists of a series
of test steps. If one step fails it makes no sense to execute further
steps as they are all expected to fail anyway and their tracebacks
add no insight. Here is a simple ``conftest.py`` file which introduces
an ``incremental`` marker which is to be used on classes::
an ``incremental`` marker which is to be used on classes:
.. code-block:: python
# content of conftest.py
@@ -372,7 +416,9 @@ an ``incremental`` marker which is to be used on classes::
pytest.xfail("previous test failed (%s)" %previousfailed.name)
These two hook implementations work together to abort incremental-marked
tests in a class. Here is a test module example::
tests in a class. Here is a test module example:
.. code-block:: python
# content of test_step.py
@@ -392,9 +438,9 @@ tests in a class. Here is a test module example::
If we run this::
$ py.test -rx
$ pytest -rx
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 4 items
@@ -430,7 +476,9 @@ concept. It's however recommended to have explicit fixture references in your
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::
Here is a an example for making a ``db`` fixture available in a directory:
.. code-block:: python
# content of a/conftest.py
import pytest
@@ -442,20 +490,26 @@ Here is a an example for making a ``db`` fixture available in a directory::
def db():
return DB()
and then a test module in that directory::
and then a test module in that directory:
.. code-block:: python
# content of a/test_db.py
def test_a1(db):
assert 0, db # to show value
another test module::
another test module:
.. code-block:: python
# content of a/test_db2.py
def test_a2(db):
assert 0, db # to show value
and then a module in a sister directory which will not see
the ``db`` fixture::
the ``db`` fixture:
.. code-block:: python
# content of b/test_error.py
def test_root(db): # no db here, will error out
@@ -463,9 +517,9 @@ the ``db`` fixture::
We can run this::
$ py.test
$ pytest
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 7 items
@@ -478,9 +532,9 @@ We can run this::
_______ ERROR at setup of test_root ________
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: tmpdir_factory, cache, tmpdir, pytestconfig, recwarn, monkeypatch, capfd, record_xml_property, capsys
use 'py.test --fixtures [testpath]' for help on them.
E fixture 'db' not found
> available fixtures: cache, capfd, capsys, doctest_namespace, monkeypatch, pytestconfig, record_xml_property, recwarn, tmpdir, tmpdir_factory
> use 'pytest --fixtures [testpath]' for help on them.
$REGENDOC_TMPDIR/b/test_error.py:1
======= FAILURES ========
@@ -531,7 +585,9 @@ environment you can implement a hook that gets called when the test
"report" object is about to be created. Here we write out all failing
test calls and also access a fixture (if it was used by the test) in
case you want to query/look at it during your post processing. In our
case we just write some informations out to a ``failures`` file::
case we just write some informations out to a ``failures`` file:
.. code-block:: python
# content of conftest.py
@@ -557,7 +613,9 @@ case we just write some informations out to a ``failures`` file::
f.write(rep.nodeid + extra + "\n")
if you then have failing tests::
if you then have failing tests:
.. code-block:: python
# content of test_module.py
def test_fail1(tmpdir):
@@ -567,9 +625,9 @@ if you then have failing tests::
and run them::
$ py.test test_module.py
$ pytest test_module.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items
@@ -606,7 +664,9 @@ Making test result information available in fixtures
.. regendoc:wipe
If you want to make test result reports available in fixture finalizers
here is a little example implemented via a local plugin::
here is a little example implemented via a local plugin:
.. code-block:: python
# content of conftest.py
@@ -626,18 +686,19 @@ here is a little example implemented via a local plugin::
@pytest.fixture
def something(request):
def fin():
# request.node is an "item" because we use the default
# "function" scope
if request.node.rep_setup.failed:
print ("setting up a test failed!", request.node.nodeid)
elif request.node.rep_setup.passed:
if request.node.rep_call.failed:
print ("executing test failed", request.node.nodeid)
request.addfinalizer(fin)
yield
# request.node is an "item" because we use the default
# "function" scope
if request.node.rep_setup.failed:
print ("setting up a test failed!", request.node.nodeid)
elif request.node.rep_setup.passed:
if request.node.rep_call.failed:
print ("executing test failed", request.node.nodeid)
if you then have failing tests::
if you then have failing tests:
.. code-block:: python
# content of test_module.py
@@ -658,9 +719,9 @@ if you then have failing tests::
and run it::
$ py.test -s test_module.py
$ pytest -s test_module.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 3 items
@@ -699,40 +760,29 @@ and run it::
You'll see that the fixture finalizers could use the precise reporting
information.
Integrating pytest runner and cx_freeze
-----------------------------------------------------------
Freezing pytest
---------------
If you freeze your application using a tool like
`cx_freeze <https://cx-freeze.readthedocs.io>`_ in order to distribute it
to your end-users, it is a good idea to also package your test runner and run
your tests using the frozen application.
`PyInstaller <https://pyinstaller.readthedocs.io>`_
in order to distribute it to your end-users, it is a good idea to also package
your test runner and run your tests using the frozen application. This way packaging
errors such as dependencies not being included into the executable can be detected early
while also allowing you to send test files to users so they can run them in their
machines, which can be useful to obtain more information about a hard to reproduce bug.
This way packaging errors such as dependencies not being
included into the executable can be detected early while also allowing you to
send test files to users so they can run them in their machines, which can be
invaluable to obtain more information about a hard to reproduce bug.
Fortunately recent ``PyInstaller`` releases already have a custom hook
for pytest, but if you are using another tool to freeze executables
such as ``cx_freeze`` or ``py2exe``, you can use ``pytest.freeze_includes()``
to obtain the full list of internal pytest modules. How to configure the tools
to find the internal modules varies from tool to tool, however.
Unfortunately ``cx_freeze`` can't discover them
automatically because of ``pytest``'s use of dynamic module loading, so you
must declare them explicitly by using ``pytest.freeze_includes()``::
Instead of freezing the pytest runner as a separate executable, you can make
your frozen program work as the pytest runner by some clever
argument handling during program startup. This allows you to
have a single executable, which is usually more convenient.
# contents of setup.py
from cx_Freeze import setup, Executable
import pytest
setup(
name="app_main",
executables=[Executable("app_main.py")],
options={"build_exe":
{
'includes': pytest.freeze_includes()}
},
# ... other options
)
If you don't want to ship a different executable just in order to run your tests,
you can make your program check for a certain flag and pass control
over to ``pytest`` instead. For example::
.. code-block:: python
# contents of app_main.py
import sys
@@ -745,7 +795,8 @@ over to ``pytest`` instead. For example::
# by your argument-parsing library of choice as usual
...
This makes it convenient to execute your tests from within your frozen
application, using standard ``py.test`` command-line options::
This allows you to execute tests using the frozen
application with standard ``pytest`` command-line options::
./app_main --pytest --verbose --tb=long --junitxml=results.xml test-suite/

View File

@@ -59,7 +59,7 @@ will be called ahead of running any tests::
If you run this without output capturing::
$ py.test -q -s test_module.py
$ pytest -q -s test_module.py
callattr_ahead_of_alltests called
callme called!
callme other called

View File

@@ -81,18 +81,17 @@ You can also turn off all assertion interaction using the
.. _`py/__init__.py`: http://bitbucket.org/hpk42/py-trunk/src/trunk/py/__init__.py
Why a ``py.test`` instead of a ``pytest`` command?
++++++++++++++++++++++++++++++++++++++++++++++++++
Why can I use both ``pytest`` and ``py.test`` commands?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Some of the reasons are historic, others are practical. ``pytest``
used to be part of the ``py`` package which provided several developer
utilities, all starting with ``py.<TAB>``, thus providing nice
TAB-completion. If
you install ``pip install pycmd`` you get these tools from a separate
package. These days the command line tool could be called ``pytest``
but since many people have gotten used to the old name and there
is another tool named "pytest" we just decided to stick with
``py.test`` for now.
pytest used to be part of the py package, which provided several developer
utilities, all starting with ``py.<TAB>``, thus providing nice TAB-completion.
If you install ``pip install pycmd`` you get these tools from a separate
package. Once ``pytest`` became a separate package, the ``py.test`` name was
retained due to avoid a naming conflict with another tool. This conflict was
eventually resolved, and the ``pytest`` command was therefore introduced. In
future versions of pytest, we may deprecate and later remove the ``py.test``
command to avoid perpetuating the confusion.
pytest fixtures, parametrized tests
-------------------------------------------------------

View File

@@ -1,8 +0,0 @@
What users say:
`py.test is pretty much the best thing ever`_ (Alex Gaynor)
.. _`py.test is pretty much the best thing ever`_ (Alex Gaynor)
http://twitter.com/#!/alex_gaynor/status/22389410366

View File

@@ -34,11 +34,6 @@ both styles, moving incrementally from classic to new style, as you
prefer. You can also start out from existing :ref:`unittest.TestCase
style <unittest.TestCase>` or :ref:`nose based <nosestyle>` projects.
.. note::
pytest-2.4 introduced an additional :ref:`yield fixture mechanism
<yieldfixture>` for easier context manager integration and more linear
writing of teardown code.
.. _`funcargs`:
.. _`funcarg mechanism`:
@@ -73,9 +68,9 @@ Here, the ``test_ehlo`` needs the ``smtp`` fixture value. pytest
will discover and call the :py:func:`@pytest.fixture <_pytest.python.fixture>`
marked ``smtp`` fixture function. Running the test looks like this::
$ py.test test_smtpsimple.py
$ pytest test_smtpsimple.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -118,7 +113,7 @@ with a list of available function arguments.
You can always issue::
py.test --fixtures test_simplefactory.py
pytest --fixtures test_simplefactory.py
to see available fixtures.
@@ -191,9 +186,9 @@ function (in or below the directory where ``conftest.py`` is located)::
We deliberately insert failing ``assert 0`` statements in order to
inspect what is going on and can now run the tests::
$ py.test test_module.py
$ pytest test_module.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 2 items
@@ -247,9 +242,8 @@ Fixture finalization / executing teardown code
-------------------------------------------------------------
pytest supports execution of fixture specific finalization code
when the fixture goes out of scope. By accepting a ``request`` object
into your fixture function you can call its ``request.addfinalizer`` one
or multiple times::
when the fixture goes out of scope. By using a ``yield`` statement instead of ``return``, all
the code after the *yield* statement serves as the teardown code.::
# content of conftest.py
@@ -259,18 +253,16 @@ or multiple times::
@pytest.fixture(scope="module")
def smtp(request):
smtp = smtplib.SMTP("smtp.gmail.com")
def fin():
print ("teardown smtp")
smtp.close()
request.addfinalizer(fin)
return smtp # provide the fixture value
yield smtp # provide the fixture value
print("teardown smtp")
smtp.close()
The ``fin`` function will execute when the last test using
the fixture in the module has finished execution.
The ``print`` and ``smtp.close()`` statements will execute when the last test using
the fixture in the module has finished execution, regardless of the exception status of the tests.
Let's execute it::
$ py.test -s -q --tb=no
$ pytest -s -q --tb=no
FFteardown smtp
2 failed in 0.12 seconds
@@ -282,14 +274,55 @@ occur around each single test. In either case the test
module itself does not need to change or know about these details
of fixture setup.
Note that we can also seamlessly use the ``yield`` syntax with ``with`` statements::
Finalization/teardown with yield fixtures
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# content of test_yield2.py
Another alternative to the *request.addfinalizer()* method is to use *yield
fixtures*. All the code after the *yield* statement serves as the teardown
code. See the :ref:`yield fixture documentation <yieldfixture>`.
import pytest
@pytest.fixture
def passwd():
with open("/etc/passwd") as f:
yield f.readlines()
def test_has_lines(passwd):
assert len(passwd) >= 1
The file ``f`` will be closed after the test finished execution
because the Python ``file`` object supports finalization when
the ``with`` statement ends.
.. note::
Prior to version 2.10, in order to use a ``yield`` statement to execute teardown code one
had to mark a fixture using the ``yield_fixture`` marker. From 2.10 onward, normal
fixtures can use ``yield`` directly so the ``yield_fixture`` decorator is no longer needed
and considered deprecated.
.. note::
As historical note, another way to write teardown code is
by accepting a ``request`` object into your fixture function and can call its
``request.addfinalizer`` one or multiple times::
# content of conftest.py
import smtplib
import pytest
@pytest.fixture(scope="module")
def smtp(request):
smtp = smtplib.SMTP("smtp.gmail.com")
def fin():
print ("teardown smtp")
smtp.close()
request.addfinalizer(fin)
return smtp # provide the fixture value
The ``fin`` function will execute when the last test using
the fixture in the module has finished execution.
This method is still fully supported, but ``yield`` is recommended from 2.10 onward because
it is considered simpler and better describes the natural code flow.
.. _`request-context`:
@@ -309,21 +342,18 @@ read an optional server URL from the test module which uses our fixture::
def smtp(request):
server = getattr(request.module, "smtpserver", "smtp.gmail.com")
smtp = smtplib.SMTP(server)
def fin():
print ("finalizing %s (%s)" % (smtp, server))
smtp.close()
request.addfinalizer(fin)
return smtp
yield smtp
print ("finalizing %s (%s)" % (smtp, server))
smtp.close()
We use the ``request.module`` attribute to optionally obtain an
``smtpserver`` attribute from the test module. If we just execute
again, nothing much has changed::
$ py.test -s -q --tb=no
$ pytest -s -q --tb=no
FFfinalizing <smtplib.SMTP object at 0xdeadbeef> (smtp.gmail.com)
2 failed in 0.12 seconds
.
2 failed, 1 passed in 0.12 seconds
Let's quickly create another test module that actually sets the
server URL in its module namespace::
@@ -337,7 +367,7 @@ server URL in its module namespace::
Running it::
$ py.test -qq --tb=short test_anothersmtp.py
$ pytest -qq --tb=short test_anothersmtp.py
F
======= FAILURES ========
_______ test_showhelo ________
@@ -351,7 +381,7 @@ from the module namespace.
.. _`fixture-parametrize`:
Parametrizing a fixture
Parametrizing fixtures
-----------------------------------------------------------------
Fixture functions can be parametrized in which case they will be called
@@ -374,11 +404,9 @@ through the special :py:class:`request <FixtureRequest>` object::
params=["smtp.gmail.com", "mail.python.org"])
def smtp(request):
smtp = smtplib.SMTP(request.param)
def fin():
print ("finalizing %s" % smtp)
smtp.close()
request.addfinalizer(fin)
return smtp
yield smtp
print ("finalizing %s" % smtp)
smtp.close()
The main change is the declaration of ``params`` with
:py:func:`@pytest.fixture <_pytest.python.fixture>`, a list of values
@@ -386,7 +414,7 @@ for each of which the fixture function will execute and can access
a value via ``request.param``. No test function code needs to change.
So let's just do another run::
$ py.test -q test_module.py
$ pytest -q test_module.py
FFFF
======= FAILURES ========
_______ test_ehlo[smtp.gmail.com] ________
@@ -486,11 +514,11 @@ return ``None`` then pytest's auto-generated ID will be used.
Running the above tests results in the following test IDs being used::
$ py.test --collect-only
$ pytest --collect-only
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 10 items
collected 11 items
<Module 'test_anothersmtp.py'>
<Function 'test_showhelo[smtp.gmail.com]'>
<Function 'test_showhelo[mail.python.org]'>
@@ -504,6 +532,8 @@ Running the above tests results in the following test IDs being used::
<Function 'test_noop[smtp.gmail.com]'>
<Function 'test_ehlo[mail.python.org]'>
<Function 'test_noop[mail.python.org]'>
<Module 'test_yield2.py'>
<Function 'test_has_lines'>
======= no tests ran in 0.12 seconds ========
@@ -537,9 +567,9 @@ and instantiate an object ``app`` where we stick the already defined
Here we declare an ``app`` fixture which receives the previously defined
``smtp`` fixture and instantiates an ``App`` object with it. Let's run it::
$ py.test -v test_appsetup.py
$ pytest -v test_appsetup.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 2 items
@@ -575,7 +605,7 @@ first execute with one instance and then finalizers are called
before the next fixture instance is created. Among other things,
this eases testing of applications which create and use global state.
The following example uses two parametrized funcargs, one of which is
The following example uses two parametrized fixture, one of which is
scoped on a per-module basis, and all the functions perform ``print`` calls
to show the setup/teardown flow::
@@ -586,19 +616,15 @@ to show the setup/teardown flow::
def modarg(request):
param = request.param
print (" SETUP modarg %s" % param)
def fin():
print (" TEARDOWN modarg %s" % param)
request.addfinalizer(fin)
return param
yield param
print (" TEARDOWN modarg %s" % param)
@pytest.fixture(scope="function", params=[1,2])
def otherarg(request):
param = request.param
print (" SETUP otherarg %s" % param)
def fin():
print (" TEARDOWN otherarg %s" % param)
request.addfinalizer(fin)
return param
yield param
print (" TEARDOWN otherarg %s" % param)
def test_0(otherarg):
print (" RUN test0 with otherarg %s" % otherarg)
@@ -610,9 +636,9 @@ to show the setup/teardown flow::
Let's run the tests in verbose mode and with looking at the print-output::
$ py.test -v -s test_module.py
$ pytest -v -s test_module.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1 -- $PYTHON_PREFIX/bin/python3.5
cachedir: .cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 8 items
@@ -712,7 +738,7 @@ will be required for the execution of each test method, just as if
you specified a "cleandir" function argument to each of them. Let's run it
to verify our fixture is activated and the tests pass::
$ py.test -q
$ pytest -q
..
2 passed in 0.12 seconds
@@ -777,7 +803,8 @@ self-contained implementation of this idea::
@pytest.fixture(autouse=True)
def transact(self, request, db):
db.begin(request.function.__name__)
request.addfinalizer(db.rollback)
yield
db.rollback()
def test_method1(self, db):
assert db.intransaction == ["test_method1"]
@@ -792,12 +819,16 @@ class-level ``usefixtures`` decorator.
If we run it, we get two passing tests::
$ py.test -q
$ pytest -q
..
2 passed in 0.12 seconds
Here is how autouse fixtures work in other scopes:
- autouse fixtures obey the ``scope=`` keyword-argument: if an autouse fixture
has ``scope='session'`` it will only be run once, no matter where it is
defined. ``scope='class'`` means it will be run once per class, etc.
- if an autouse fixture is defined in a test module, all its test
functions automatically use it.
@@ -817,10 +848,11 @@ active. The canonical way to do that is to put the transact definition
into a conftest.py file **without** using ``autouse``::
# content of conftest.py
@pytest.fixture()
@pytest.fixture
def transact(self, request, db):
db.begin()
request.addfinalizer(db.rollback)
yield
db.rollback()
and then e.g. have a TestClass using it by declaring the need::
@@ -833,6 +865,7 @@ All test methods in this TestClass will use the transaction fixture while
other test classes or functions in the module will not use it unless
they also add a ``transact`` reference.
Shifting (visibility of) fixture functions
----------------------------------------------------

View File

@@ -1,3 +1,4 @@
:orphan:
.. _`funcargcompare`:
@@ -172,17 +173,17 @@ to do this with parametrization as ``pytest_runtest_setup()`` is called
during test execution and parametrization happens at collection time.
It follows that pytest_configure/session/runtest_setup are often not
appropriate for implementing common fixture needs. Therefore,
appropriate for implementing common fixture needs. Therefore,
pytest-2.3 introduces :ref:`autouse fixtures` which fully
integrate with the generic :ref:`fixture mechanism <fixture>`
integrate with the generic :ref:`fixture mechanism <fixture>`
and obsolete many prior uses of pytest hooks.
funcargs/fixture discovery now happens at collection time
---------------------------------------------------------------------
pytest-2.3 takes care to discover fixture/funcarg factories
at collection time. This is more efficient especially for large test suites.
Moreover, a call to "py.test --collect-only" should be able to in the future
Since pytest-2.3, discovery of fixture/funcarg factories are taken care of
at collection time. This is more efficient especially for large test suites.
Moreover, a call to "pytest --collect-only" should be able to in the future
show a lot of setup-information and thus presents a nice method to get an
overview of fixture management in your project.

View File

@@ -32,7 +32,7 @@ class Writer:
def pytest_funcarg__a(request):
with Writer("request") as writer:
writer.docmethod(request.getfuncargvalue)
writer.docmethod(request.getfixturevalue)
writer.docmethod(request.cached_setup)
writer.docmethod(request.addfinalizer)
writer.docmethod(request.applymarker)

View File

@@ -11,7 +11,7 @@ Installation and Getting Started
`colorama (Windows) <http://pypi.python.org/pypi/colorama>`_,
`argparse (py26) <http://pypi.python.org/pypi/argparse>`_.
**documentation as PDF**: `download latest <http://pytest.org/latest/pytest.pdf>`_
**documentation as PDF**: `download latest <https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf>`_
.. _`getstarted`:
.. _installation:
@@ -19,17 +19,14 @@ Installation and Getting Started
Installation
----------------------------------------
Installation options::
Installation::
pip install -U pytest # or
easy_install -U pytest
pip install -U pytest
To check your installation has installed the correct version::
$ py.test --version
This is pytest version 2.9.2, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py
If you get an error checkout :ref:`installation issues`.
$ pytest --version
This is pytest version 3.0.2, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py
.. _`simpletest`:
@@ -47,9 +44,9 @@ Let's create a first test file with a simple test function::
That's it. You can execute the test function now::
$ py.test
$ pytest
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
@@ -102,7 +99,7 @@ use the ``raises`` helper::
Running it with, this time in "quiet" reporting mode::
$ py.test -q test_sysexit.py
$ pytest -q test_sysexit.py
.
1 passed in 0.12 seconds
@@ -127,7 +124,7 @@ The two tests are found because of the standard :ref:`test discovery`.
There is no need to subclass anything. We can simply
run the module by passing its filename::
$ py.test -q test_class.py
$ pytest -q test_class.py
.F
======= FAILURES ========
_______ TestClass.test_two ________
@@ -137,7 +134,8 @@ run the module by passing its filename::
def test_two(self):
x = "hello"
> assert hasattr(x, 'check')
E assert hasattr('hello', 'check')
E assert False
E + where False = hasattr('hello', 'check')
test_class.py:8: AssertionError
1 failed, 1 passed in 0.12 seconds
@@ -163,7 +161,7 @@ We list the name ``tmpdir`` in the test function signature and
``pytest`` will lookup and call a fixture factory to create the resource
before performing the test function call. Let's just run it::
$ py.test -q test_tmpdir.py
$ pytest -q test_tmpdir.py
F
======= FAILURES ========
_______ test_needsfiles ________
@@ -185,7 +183,7 @@ was created. More info at :ref:`tmpdir handling`.
You can find out what kind of builtin :ref:`fixtures` exist by typing::
py.test --fixtures # shows builtin and custom fixtures
pytest --fixtures # shows builtin and custom fixtures
Where to go next
-------------------------------------
@@ -193,45 +191,8 @@ Where to go next
Here are a few suggestions where to go next:
* :ref:`cmdline` for command line invocation examples
* :ref:`good practices <goodpractices>` for virtualenv, test layout, genscript support
* :ref:`good practices <goodpractices>` for virtualenv, test layout
* :ref:`fixtures` for providing a functional baseline to your tests
* :ref:`apiref` for documentation and examples on using ``pytest``
* :ref:`plugins` managing and writing plugins
.. _`installation issues`:
Known Installation issues
------------------------------
easy_install or pip not found?
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.. _`install pip`: http://www.pip-installer.org/en/latest/index.html
`Install pip`_ for a state of the art python package installer.
Install `setuptools`_ to get ``easy_install`` which allows to install
``.egg`` binary format packages in addition to source-based ones.
py.test not found on Windows despite installation?
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.. _`Python for Windows`: http://www.imladris.com/Scripts/PythonForWindows.html
- **Windows**: If "easy_install" or "py.test" are not found
you need to add the Python script path to your ``PATH``, see here:
`Python for Windows`_. You may alternatively use an `ActivePython install`_
which does this for you automatically.
.. _`ActivePython install`: http://www.activestate.com/activepython/downloads
.. _`Jython does not create command line launchers`: http://bugs.jython.org/issue1491
- **Jython2.5.1 on Windows XP**: `Jython does not create command line launchers`_
so ``py.test`` will not work correctly. You may install py.test on
CPython and type ``py.test --genscript=mytest`` and then use
``jython mytest`` to run your tests with Jython using ``pytest``.
:ref:`examples` for more complex examples
.. include:: links.inc

View File

@@ -72,17 +72,17 @@ Important notes relating to both schemes:
- With inlined tests you might put ``__init__.py`` into test
directories and make them installable as part of your application.
Using the ``py.test --pyargs mypkg`` invocation pytest will
Using the ``pytest --pyargs mypkg`` invocation pytest will
discover where mypkg is installed and collect tests from there.
With the "external" test you can still distribute tests but they
will not be installed or become importable.
Typically you can run tests by pointing to test directories or modules::
py.test tests/test_app.py # for external test dirs
py.test mypkg/test/test_app.py # for inlined test dirs
py.test mypkg # run tests in all below test directories
py.test # run all tests below current dir
pytest tests/test_app.py # for external test dirs
pytest mypkg/test/test_app.py # for inlined test dirs
pytest mypkg # run tests in all below test directories
pytest # run all tests below current dir
...
Because of the above ``editable install`` mode you can change your
@@ -193,9 +193,27 @@ If you now type::
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 py.test such as your test directory or other
arguments to pytest such as your test directory or other
options using ``--addopts``.
You can also specify other pytest-ini options in your ``setup.cfg`` file
by putting them into a ``[tool:pytest]`` section:
.. code-block:: ini
[tool:pytest]
addopts = --verbose
python_files = testing/*/*.py
.. note::
Prior to 3.0, the supported section name was ``[pytest]``. Due to how
this may collide with some distutils commands, the recommended
section name for ``setup.cfg`` files is now ``[tool:pytest]``.
Note that for ``pytest.ini`` and ``tox.ini`` files the section
name is ``[pytest]``.
Manual Integration
^^^^^^^^^^^^^^^^^^
@@ -211,7 +229,7 @@ your own setuptools Test command for invoking pytest.
class PyTest(TestCommand):
user_options = [('pytest-args=', 'a', "Arguments to pass to py.test")]
user_options = [('pytest-args=', 'a', "Arguments to pass to pytest")]
def initialize_options(self):
TestCommand.initialize_options(self)
@@ -240,41 +258,7 @@ using the ``--pytest-args`` or ``-a`` command-line option. For example::
python setup.py test -a "--durations=5"
is equivalent to running ``py.test --durations=5``.
.. _standalone:
.. _`genscript method`:
(deprecated) Create a pytest standalone script
-----------------------------------------------
.. deprecated:: 2.8
.. note::
``genscript`` has been deprecated because:
* 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
is equivalent to running ``pytest --durations=5``.
.. include:: links.inc

View File

@@ -1,61 +1,90 @@
:orphan:
.. _features:
pytest: helps you write better programs
=============================================
**a mature full-featured Python testing tool**
- runs on Posix/Windows, Python 2.6-3.5, PyPy and (possibly still) Jython-2.5.1
- free and open source software, distributed under the terms of the :ref:`MIT license <license>`
- **well tested** with more than a thousand tests against itself
- **strict backward compatibility policy** for safe pytest upgrades
- :ref:`comprehensive online <toc>` and `PDF documentation <pytest.pdf>`_
- many :ref:`third party plugins <extplugins>` and :ref:`builtin helpers <pytest helpers>`,
- used in :ref:`many small and large projects and organisations <projects>`
- comes with many :ref:`tested examples <examples>`
**provides easy no-boilerplate testing**
- makes it :ref:`easy to get started <getstarted>`,
has many :ref:`usage options <usage>`
- :ref:`assert with the assert statement`
- helpful :ref:`traceback and failing assertion reporting <tbreportdemo>`
- :ref:`print debugging <printdebugging>` and :ref:`the
capturing of standard output during test execution <captures>`
**scales from simple unit to complex functional testing**
- :ref:`modular parametrizeable fixtures <fixture>` (new in 2.3,
continuously improved)
- :ref:`parametrized test functions <parametrized test functions>`
- :ref:`mark`
- :ref:`skipping` (improved in 2.4)
- :ref:`distribute tests to multiple CPUs <xdistcpu>` through :ref:`xdist plugin <xdist>`
- :ref:`continuously re-run failing tests <looponfailing>`
- :doc:`cache`
- flexible :ref:`Python test discovery`
**integrates with other testing methods and tools**:
- multi-paradigm: pytest can run ``nose``, ``unittest`` and
``doctest`` style test suites, including running testcases made for
Django and trial
- supports :ref:`good integration practices <goodpractices>`
- supports extended :ref:`xUnit style setup <xunitsetup>`
- supports domain-specific :ref:`non-python tests`
- supports generating `test coverage reports
<https://pypi.python.org/pypi/pytest-cov>`_
- supports :pep:`8` compliant coding styles in tests
**extensive plugin and customization system**:
- all collection, reporting, running aspects are delegated to hook functions
- customizations can be per-directory, per-project or per PyPI released plugin
- it is easy to add command line options or customize existing behaviour
- :ref:`easy to write your own plugins <writing-plugins>`
=======================================
.. _`easy`: http://bruynooghe.blogspot.com/2009/12/skipping-slow-test-by-default-in-pytest.html
The ``pytest`` framework makes it easy to write small tests, yet
scales to support complex functional testing for applications and libraries.
An example of a simple test:
.. code-block:: python
# content of test_sample.py
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
To execute it::
$ pytest
======= test session starts ========
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 items
test_sample.py F
======= FAILURES ========
_______ test_answer ________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:5: AssertionError
======= 1 failed in 0.12 seconds ========
Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used.
See :ref:`Getting Started <getstarted>` for more examples.
Features
--------
- Detailed info on failing :ref:`assert statements <assert>` (no need to remember ``self.assert*`` names);
- :ref:`Auto-discovery <test discovery>` of test modules and functions;
- :ref:`Modular fixtures <fixture>` for managing small or parametrized long-lived test resources;
- Can run :ref:`unittest <unittest>` (including trial) and :ref:`nose <noseintegration>` test suites out of the box;
- Python2.6+, Python3.3+, PyPy-2.3, Jython-2.5 (untested);
- Rich plugin architecture, with over 150+ :ref:`external plugins <extplugins>` and thriving community;
Documentation
-------------
Please see :ref:`Contents <toc>` for full documentation, including installation, tutorials and PDF documents.
Bugs/Requests
-------------
Please use the `GitHub issue tracker <https://github.com/pytest-dev/pytest/issues>`_ to submit bugs or request features.
Changelog
---------
Consult the :ref:`Changelog <changelog>` page for fixes and enhancements of each version.
License
-------
Copyright Holger Krekel and others, 2004-2016.
Distributed under the terms of the `MIT`_ license, pytest is free and open source software.
.. _`MIT`: https://github.com/pytest-dev/pytest/blob/master/LICENSE

View File

@@ -6,7 +6,7 @@ Monkeypatching/mocking modules and environments
Sometimes tests need to invoke functionality which depends
on global settings or which invokes code which cannot be easily
tested such as network access. The ``monkeypatch`` function argument
tested such as network access. The ``monkeypatch`` fixture
helps you to safely set/delete an attribute, dictionary item or
environment variable or to modify ``sys.path`` for importing.
See the `monkeypatch blog post`_ for some introduction material
@@ -14,6 +14,7 @@ and a discussion of its motivation.
.. _`monkeypatch blog post`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/
Simple example: monkeypatching functions
---------------------------------------------------
@@ -53,28 +54,11 @@ This autouse fixture will be executed for each test function and it
will delete the method ``request.session.Session.request``
so that any attempts within tests to create http requests will fail.
example: setting an attribute on some class
------------------------------------------------------
If you need to patch out ``os.getcwd()`` to return an artificial
value::
Method reference of the monkeypatch fixture
-------------------------------------------
def test_some_interaction(monkeypatch):
monkeypatch.setattr("os.getcwd", lambda: "/")
which is equivalent to the long form::
def test_some_interaction(monkeypatch):
import os
monkeypatch.setattr(os, "getcwd", lambda: "/")
Method reference of the monkeypatch function argument
-----------------------------------------------------
.. autoclass:: monkeypatch
:members: setattr, replace, delattr, setitem, delitem, setenv, delenv, syspath_prepend, chdir, undo
.. autoclass:: MonkeyPatch
``monkeypatch.setattr/delattr/delitem/delenv()`` all
by default raise an Exception if the target does not exist.

View File

@@ -1,3 +1,5 @@
.. _`noseintegration`:
Running tests written for nose
=======================================
@@ -13,7 +15,7 @@ Usage
After :ref:`installation` type::
python setup.py develop # make sure tests can import our package
py.test # instead of 'nosetests'
pytest # instead of 'nosetests'
and you should be able to run your nose style tests and
make use of pytest's capabilities.
@@ -24,7 +26,7 @@ Supported nose Idioms
* setup and teardown at module/class/method level
* SkipTest exceptions and markers
* setup/teardown decorators
* yield-based tests and their setup
* ``yield``-based tests and their setup
* ``__test__`` attribute on modules/classes/functions
* general usage of nose utilities
@@ -51,5 +53,12 @@ Unsupported idioms / known issues
- nose-style doctests are not collected and executed correctly,
also doctest fixtures don't work.
- no nose-configuration is recognized
- no nose-configuration is recognized.
- ``yield``-based methods don't support ``setup`` properly because
the ``setup`` method is always called in the same class instance.
There are no plans to fix this currently because ``yield``-tests
are deprecated in pytest 3.0, with ``pytest.mark.parametrize``
being the recommended alternative.

View File

@@ -1,13 +0,0 @@
==================================================
Getting started basics
==================================================
.. toctree::
:maxdepth: 2
getting-started
usage
goodpractices
projects
faq

View File

@@ -53,9 +53,9 @@ Here, the ``@parametrize`` decorator defines three different ``(test_input,expec
tuples so that the ``test_eval`` function will run three times using
them in turn::
$ py.test
$ pytest
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 3 items
@@ -101,9 +101,9 @@ for example with the builtin ``mark.xfail``::
Let's run this::
$ py.test
$ pytest
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile:
collected 3 items
@@ -171,13 +171,13 @@ command line option and the parametrization of our test function::
If we now pass two stringinput values, our test will run twice::
$ py.test -q --stringinput="hello" --stringinput="world" test_strings.py
$ pytest -q --stringinput="hello" --stringinput="world" test_strings.py
..
2 passed in 0.12 seconds
Let's also run with a stringinput that will lead to a failing test::
$ py.test -q --stringinput="!" test_strings.py
$ pytest -q --stringinput="!" test_strings.py
F
======= FAILURES ========
_______ test_valid_string[!] ________
@@ -186,8 +186,9 @@ Let's also run with a stringinput that will lead to a failing test::
def test_valid_string(stringinput):
> assert stringinput.isalpha()
E assert <built-in method isalpha of str object at 0xdeadbeef>()
E + where <built-in method isalpha of str object at 0xdeadbeef> = '!'.isalpha
E assert False
E + where False = <built-in method isalpha of str object at 0xdeadbeef>()
E + where <built-in method isalpha of str object at 0xdeadbeef> = '!'.isalpha
test_strings.py:3: AssertionError
1 failed in 0.12 seconds
@@ -198,7 +199,7 @@ If you don't specify a stringinput it will be skipped because
``metafunc.parametrize()`` will be called with an empty parameter
list::
$ py.test -q -rs test_strings.py
$ pytest -q -rs test_strings.py
s
======= short test summary info ========
SKIP [1] test_strings.py:1: got empty parameter set ['stringinput'], function test_valid_string at $REGENDOC_TMPDIR/test_strings.py:1
@@ -214,6 +215,7 @@ The **metafunc** object
.. currentmodule:: _pytest.python
.. autoclass:: Metafunc
:members:
.. automethod:: Metafunc.parametrize
.. automethod:: Metafunc.addcall(funcargs=None,id=_notexists,param=_notexists)

View File

@@ -37,7 +37,7 @@ Here is a little annotated list for some popular plugins:
to distribute tests to CPUs and remote hosts, to run in boxed
mode which allows to survive segmentation faults, to run in
looponfailing mode, automatically re-running failing tests
on file changes, see also :ref:`xdist`
on file changes.
* `pytest-instafail <http://pypi.python.org/pypi/pytest-instafail>`_:
to report failures while the test run is happening.
@@ -59,7 +59,7 @@ Here is a little annotated list for some popular plugins:
a plugin to run javascript unittests in live browsers.
To see a complete list of all plugins with their latest testing
status against different py.test and Python versions, please visit
status against different pytest and Python versions, please visit
`plugincompat <http://plugincompat.herokuapp.com/>`_.
You may also discover more plugins through a `pytest- pypi.python.org search`_.
@@ -90,7 +90,7 @@ Finding out which plugins are active
If you want to find out which plugins are active in your
environment you can type::
py.test --trace-config
pytest --trace-config
and will get an extended test header which shows activated plugins
and their names. It will also print local plugins aka
@@ -103,7 +103,7 @@ Deactivating / unregistering a plugin by name
You can prevent plugins from loading or unregister them::
py.test -p no:NAME
pytest -p no:NAME
This means that any subsequent try to activate/load the named
plugin will not work.
@@ -138,14 +138,13 @@ in the `pytest repository <https://github.com/pytest-dev/pytest>`_.
_pytest.capture
_pytest.config
_pytest.doctest
_pytest.genscript
_pytest.helpconfig
_pytest.junitxml
_pytest.mark
_pytest.monkeypatch
_pytest.nose
_pytest.pastebin
_pytest.pdb
_pytest.debugging
_pytest.pytester
_pytest.python
_pytest.recwarn

View File

@@ -0,0 +1,150 @@
:orphan:
=========================
Parametrize with fixtures
=========================
Problem
-------
As a user I have functional tests that I would like to run against various
scenarios.
In this particular example we want to generate a new project based on a
cookiecutter template. We want to test default values but also data that
emulates user input.
- use default values
- emulate user input
- specify 'author'
- specify 'project_slug'
- specify 'author' and 'project_slug'
This is how a functional test could look like:
.. code-block:: python
import pytest
@pytest.fixture
def default_context():
return {'extra_context': {}}
@pytest.fixture(params=[
{'author': 'alice'},
{'project_slug': 'helloworld'},
{'author': 'bob', 'project_slug': 'foobar'},
])
def extra_context(request):
return {'extra_context': request.param}
@pytest.fixture(params=['default', 'extra'])
def context(request):
if request.param == 'default':
return request.getfuncargvalue('default_context')
else:
return request.getfuncargvalue('extra_context')
def test_generate_project(cookies, context):
"""Call the cookiecutter API to generate a new project from a
template.
"""
result = cookies.bake(extra_context=context)
assert result.exit_code == 0
assert result.exception is None
assert result.project.isdir()
Issues
------
* By using ``request.getfuncargvalue()`` we rely on actual fixture function
execution to know what fixtures are involved, due to it's dynamic nature
* More importantly, ``request.getfuncargvalue()`` cannot be combined with
parametrized fixtures, such as ``extra_context``
* This is very inconvenient if you wish to extend an existing test suite by
certain parameters for fixtures that are already used by tests
pytest version 3.0 reports an error if you try to run above code::
Failed: The requested fixture has no parameter defined for the current
test.
Requested fixture 'extra_context'
Proposed solution
-----------------
A new function that can be used in modules can be used to dynamically define
fixtures from existing ones.
.. code-block:: python
pytest.define_combined_fixture(
name='context',
fixtures=['default_context', 'extra_context'],
)
The new fixture ``context`` inherits the scope from the used fixtures and yield
the following values.
- ``{}``
- ``{'author': 'alice'}``
- ``{'project_slug': 'helloworld'}``
- ``{'author': 'bob', 'project_slug': 'foobar'}``
Alternative approach
--------------------
A new helper function named ``fixture_request`` tells pytest to yield all
parameters of a fixture.
.. code-block:: python
@pytest.fixture(params=[
pytest.fixture_request('default_context'),
pytest.fixture_request('extra_context'),
])
def context(request):
"""Returns all values for ``default_context``, one-by-one before it
does the same for ``extra_context``.
request.param:
- {}
- {'author': 'alice'}
- {'project_slug': 'helloworld'}
- {'author': 'bob', 'project_slug': 'foobar'}
"""
return request.param
The same helper can be used in combination with ``pytest.mark.parametrize``.
.. code-block:: python
@pytest.mark.parametrize(
'context, expected_response_code',
[
(pytest.fixture_request('default_context'), 0),
(pytest.fixture_request('extra_context'), 0),
],
)
def test_generate_project(cookies, context, exit_code):
"""Call the cookiecutter API to generate a new project from a
template.
"""
result = cookies.bake(extra_context=context)
assert result.exit_code == exit_code

View File

@@ -1,3 +1,4 @@
.. _assertwarnings:
Asserting Warnings
=====================================================

View File

@@ -19,7 +19,7 @@ information about skipped/xfailed tests is not shown by default to avoid
cluttering the output. You can use the ``-r`` option to see details
corresponding to the "short" letters shown in the test progress::
py.test -rxs # show extra info on skips and xfails
pytest -rxs # show extra info on skips and xfails
(See :ref:`how to change command line options defaults`)
@@ -222,9 +222,9 @@ Here is a simple test file with the several usages:
Running it with the report-on-xfail option gives this output::
example $ py.test -rx xfail_demo.py
example $ pytest -rx xfail_demo.py
======= test session starts ========
platform linux -- Python 3.5.1, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
platform linux -- Python 3.5.2, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR/example, inifile:
collected 7 items
@@ -368,6 +368,6 @@ The equivalent with "boolean conditions" is::
.. note::
You cannot use ``pytest.config.getvalue()`` in code
imported before py.test's argument parsing takes place. For example,
imported before pytest's argument parsing takes place. For example,
``conftest.py`` files are imported before command line parsing and thus
``config.getvalue()`` will not execute correctly.

View File

@@ -1,5 +0,0 @@
pytest development status
================================
https://travis-ci.org/pytest-dev/pytest

View File

@@ -11,9 +11,6 @@ Talks and Tutorials
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
- `pytest - Rapid Simple Testing, Florian Bruhin, Swiss Python Summit 2016
<https://www.youtube.com/watch?v=rCBHkQ_LVIs>`_.
@@ -52,12 +49,14 @@ Talks and blog postings
- `pytest introduction from Brian Okken (January 2013)
<http://pythontesting.net/framework/pytest-introduction/>`_
- `monkey patching done right`_ (blog post, consult `monkeypatch
plugin`_ for up-to-date API)
- pycon australia 2012 pytest talk from Brianna Laugher (`video <http://www.youtube.com/watch?v=DTNejE9EraI>`_, `slides <http://www.slideshare.net/pfctdayelise/funcargs-other-fun-with-pytest>`_, `code <https://gist.github.com/3386951>`_)
- `pycon 2012 US talk video from Holger Krekel <http://www.youtube.com/watch?v=9LVqBQcFmyw>`_
- `monkey patching done right`_ (blog post, consult `monkeypatch plugin`_ for up-to-date API)
Test parametrization:
- `generating parametrized tests with funcargs`_ (uses deprecated ``addcall()`` API.
- `generating parametrized tests with fixtures`_.
- `test generators and cached setup`_
- `parametrizing tests, generalized`_ (blog post)
- `putting test-hooks into local or global plugins`_ (blog post)
@@ -78,39 +77,17 @@ Plugin specific examples:
- `many examples in the docs for plugins`_
.. _`skipping slow tests by default in pytest`: http://bruynooghe.blogspot.com/2009/12/skipping-slow-test-by-default-in-pytest.html
.. _`many examples in the docs for plugins`: plugin/index.html
.. _`monkeypatch plugin`: plugin/monkeypatch.html
.. _`application setup in test functions with funcargs`: funcargs.html#appsetup
.. _`many examples in the docs for plugins`: plugins.html
.. _`monkeypatch plugin`: monkeypatch.html
.. _`application setup in test functions with fixtures`: fixture.html#interdependent-fixtures
.. _`simultaneously test your code on all platforms`: http://tetamap.wordpress.com/2009/03/23/new-simultanously-test-your-code-on-all-platforms/
.. _`monkey patching done right`: http://tetamap.wordpress.com/2009/03/03/monkeypatching-in-unit-tests-done-right/
.. _`putting test-hooks into local or global plugins`: http://tetamap.wordpress.com/2009/05/14/putting-test-hooks-into-local-and-global-plugins/
.. _`parametrizing tests, generalized`: http://tetamap.wordpress.com/2009/05/13/parametrizing-python-tests-generalized/
.. _`generating parametrized tests with funcargs`: funcargs.html#test-generators
.. _`generating parametrized tests with fixtures`: parametrize.html#test-generators
.. _`test generators and cached setup`: http://bruynooghe.blogspot.com/2010/06/pytest-test-generators-and-cached-setup.html
Older conference talks and tutorials
----------------------------------------
- `pycon australia 2012 pytest talk from Brianna Laugher
<http://2012.pycon-au.org/schedule/52/view_talk?day=sunday>`_ (`video <http://www.youtube.com/watch?v=DTNejE9EraI>`_, `slides <http://www.slideshare.net/pfctdayelise/funcargs-other-fun-with-pytest>`_, `code <https://gist.github.com/3386951>`_)
- `pycon 2012 US talk video from Holger Krekel <http://www.youtube.com/watch?v=9LVqBQcFmyw>`_
- `pycon 2010 tutorial PDF`_ and `tutorial1 repository`_
- `ep2009-rapidtesting.pdf`_ tutorial slides (July 2009):
- testing terminology
- basic pytest usage, file system layout
- test function arguments (funcargs_) and test fixtures
- existing plugins
- distributed testing
- `ep2009-pytest.pdf`_ 60 minute pytest talk, highlighting unique features and a roadmap (July 2009)
- `pycon2009-pytest-introduction.zip`_ slides and files, extended version of pytest basic introduction, discusses more options, also introduces old-style xUnit setup, looponfailing and other features.
- `pycon2009-pytest-advanced.pdf`_ contain a slightly older version of funcargs and distributed testing, compared to the EuroPython 2009 slides.
.. _`ep2009-rapidtesting.pdf`: http://codespeak.net/download/py/ep2009-rapidtesting.pdf
.. _`ep2009-pytest.pdf`: http://codespeak.net/download/py/ep2009-pytest.pdf
.. _`pycon2009-pytest-introduction.zip`: http://codespeak.net/download/py/pycon2009-pytest-introduction.zip
.. _`pycon2009-pytest-advanced.pdf`: http://codespeak.net/download/py/pycon2009-pytest-advanced.pdf

View File

@@ -21,7 +21,7 @@ but note that project specific settings will be considered
first. There is a flag that helps you debugging your
conftest.py configurations::
py.test --trace-config
pytest --trace-config
customizing the collecting and running process

View File

@@ -5,7 +5,7 @@ Mission
``pytest`` strives to make testing a fun and no-boilerplate effort.
The tool is distributed as a `pytest` package. Its project independent
``py.test`` command line tool helps you to:
``pytest`` command line tool helps you to:
* rapidly collect and run tests
* run unit- or doctests, functional or integration tests

View File

@@ -53,7 +53,7 @@ subprocesses.
Running centralised testing::
py.test --cov myproj tests/
pytest --cov myproj tests/
Shows a terminal report::
@@ -76,7 +76,7 @@ file system. Each slave will have it's subprocesses measured.
Running distributed testing with dist mode set to load::
py.test --cov myproj -n 2 tests/
pytest --cov myproj -n 2 tests/
Shows a terminal report::
@@ -92,7 +92,7 @@ Shows a terminal report::
Again but spread over different hosts and different directories::
py.test --cov myproj --dist load
pytest --cov myproj --dist load
--tx ssh=memedough@host1//chdir=testenv1
--tx ssh=memedough@host2//chdir=/tmp/testenv2//python=/tmp/env1/bin/python
--rsyncdir myproj --rsyncdir tests --rsync examples
@@ -119,7 +119,7 @@ environments.
Running distributed testing with dist mode set to each::
py.test --cov myproj --dist each
pytest --cov myproj --dist each
--tx popen//chdir=/tmp/testenv3//python=/usr/local/python27/bin/python
--tx ssh=memedough@host2//chdir=/tmp/testenv4//python=/tmp/env2/bin/python
--rsyncdir myproj --rsyncdir tests --rsync examples
@@ -149,7 +149,7 @@ annotated source code.
The terminal report without line numbers (default)::
py.test --cov-report term --cov myproj tests/
pytest --cov-report term --cov myproj tests/
-------------------- coverage: platform linux2, python 2.6.4-final-0 ---------------------
Name Stmts Miss Cover
@@ -163,7 +163,7 @@ The terminal report without line numbers (default)::
The terminal report with line numbers::
py.test --cov-report term-missing --cov myproj tests/
pytest --cov-report term-missing --cov myproj tests/
-------------------- coverage: platform linux2, python 2.6.4-final-0 ---------------------
Name Stmts Miss Cover Missing
@@ -178,7 +178,7 @@ The terminal report with line numbers::
The remaining three reports output to files without showing anything on the terminal (useful for
when the output is going to a continuous integration server)::
py.test --cov-report html --cov-report xml --cov-report annotate --cov myproj tests/
pytest --cov-report html --cov-report xml --cov-report annotate --cov myproj tests/
Coverage Data File

View File

@@ -26,7 +26,7 @@ Usage
To get full test coverage reports for a particular package type::
py.test --cover-report=report
pytest --cover-report=report
command line options
--------------------

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