Compare commits

...

162 Commits
5.3.0 ... 5.3.3

Author SHA1 Message Date
Bruno Oliveira
544b4a14d5 Fix Hugo van Kemenade name in release announcement
Co-Authored-By: Hugo van Kemenade <hugovk@users.noreply.github.com>
2020-01-17 07:18:57 -03:00
Bruno Oliveira
56dc301c50 Preparing release version 5.3.3 2020-01-16 18:55:41 -05:00
Bruno Oliveira
aa05334984 Remove broken link for user @jgsonesen 2020-01-16 18:51:33 -05:00
Bruno Oliveira
4806878a7f Drop deploy from Travis in favor of GitHub actions (#6480)
Drop deploy from Travis in favor of GitHub actions
2020-01-16 18:34:44 -03:00
Bruno Oliveira
d1d7e5d41b Drop deploy from Travis in favor of GitHub actions
GitHub actions already should deploy.

This is a stop gap while we figure out why coverage dropped
when removing Travis builds in #6470
2020-01-16 18:12:47 -03:00
Daniel Hahler
5b0e255e85 Merge pull request #6465 from blueyed/doc-rootdir
doc: revisit section about rootdir
2020-01-16 21:55:12 +01:00
Daniel Hahler
f0fdafeddc Merge pull request #6477 from blueyed/tests-cleanup-unused-fixtures
tests: cleanup unused fixtures
2020-01-16 21:53:56 +01:00
Daniel Hahler
5049e25a6a tests: cleanup unused fixtures 2020-01-16 21:12:48 +01:00
Daniel Hahler
d36c712bb0 Merge pull request #6479 from blueyed/tests-fix-master
[master] Use a dummy RemoteTraceback for test in Python 3.5 Windows
2020-01-16 21:12:04 +01:00
Bruno Oliveira
7a0d1b387d Use a dummy RemoteTraceback for test in Python 3.5 Windows
Somehow in Python 3.5 on Windows this test fails with:
   File "c:\hostedtoolcache\windows\python\3.5.4\x64\Lib\multiprocessing\connection.py", line 302, in _recv_bytes
     overlapped=True)
OSError: [WinError 6] The handle is invalid

This only happens in this platform and Python version, decided to use
a dummy traceback as originally done in #6412.

(cherry picked from commit b9c136b809)
2020-01-16 20:03:16 +01:00
Daniel Hahler
749752d440 Merge pull request #6435 from blueyed/type_checking
Use TYPE_CHECKING instead of False
2020-01-16 19:45:00 +01:00
Bruno Oliveira
b91c721262 ci: github actions: only deploy pytest-dev/pytest (#6474)
ci: github actions: only deploy pytest-dev/pytest
2020-01-16 12:48:29 -03:00
Daniel Hahler
4630e2725e Use TYPE_CHECKING instead of False
This allows for e.g. Jedi to infer types (it checks the name).

It was only used to support Python 3.5.0/3.5.1, where this is is not
available in the `typing` module.

Ref: https://github.com/davidhalter/jedi/issues/1472

Uses `TYPE_CHECKING = False` in `_pytest.outcomes` to avoid having to
work around circular import.
2020-01-16 16:11:39 +01:00
Daniel Hahler
ea31649062 ci: github actions: only deploy pytest-dev/pytest 2020-01-16 13:57:46 +01:00
Bruno Oliveira
715f56dfbc Fixtures now register finalizers with all fixtures before them… (#6438)
Fixtures now register finalizers with all fixtures before them in the stack
2020-01-16 07:33:55 -03:00
Chris NeJame
99180939fe fixtures register finalizers with all fixtures before them in the stack 2020-01-15 11:00:42 -05:00
Bruno Oliveira
1ec5befdb7 Merge pull request #6468 from nicoddemus/deploy-release-notes-6369
Add deploy step: publish package and release notes
2020-01-15 09:05:23 -03:00
Bruno Oliveira
1d3f27cef0 Add deploy step: publish package and release notes
Fix #6369
2020-01-15 08:11:35 -03:00
Daniel Hahler
29703a5f51 Merge pull request #6466 from blueyed/cover-safe_getattr
tests: cover safe_getattr
2020-01-15 11:20:42 +01:00
Daniel Hahler
6f7a95c32e tests: cover safe_getattr 2020-01-15 11:20:00 +01:00
Daniel Hahler
bebfd28da3 doc: revisit section about rootdir
Ref: https://github.com/pytest-dev/pytest/issues/6376
2020-01-15 09:43:35 +01:00
Daniel Hahler
f5844449a8 Merge pull request #6442 from blueyed/rP
terminal: summary_passes: handle teardown sections
2020-01-15 03:02:09 +01:00
Daniel Hahler
4a265ba38b Merge pull request #6446 from blueyed/tox-mypy
tox: add mypy toxenv
2020-01-14 18:26:35 +01:00
Daniel Hahler
910d5df6a8 Merge pull request #6456 from blueyed/fix-doc-_splitnode
minor: fix doc/example for _pytest.nodes._splitnode
2020-01-14 15:22:01 +01:00
Bruno Oliveira
00adb4e42f Implement code coverage in GitHub actions (#6441)
Implement code coverage in GitHub actions
2020-01-14 09:14:57 -03:00
Daniel Hahler
b2cb87fae6 Merge pull request #6440 from blueyed/py351
ci: Travis: Python 3.5.1 via Trusty
2020-01-14 12:41:16 +01:00
Daniel Hahler
189fe3ba1d minor: fix doc/example for _pytest.nodes._splitnode 2020-01-14 12:40:36 +01:00
Bruno Oliveira
d291905825 Append token to codecov.yml instead of duplicating the file 2020-01-14 07:47:21 -03:00
Daniel Hahler
f0c7f21312 Remove "pragma: no cover" comments 2020-01-14 09:15:36 +01:00
Daniel Hahler
4ff7453b48 ci: Travis: Python 3.5.1 via Trusty
Python 3.5.0 caused flaky failures before
(https://github.com/pytest-dev/pytest/issues/5795).

This is pulled out of https://github.com/pytest-dev/pytest/pull/6435,
which adds code specific for Python < 3.5.2.

It only runs a specific test, while collecting everything to get
coverage of the version specific code around typing.
2020-01-14 09:15:36 +01:00
Daniel Hahler
0e70acab79 tox: add mypy toxenv
This is different from what pre-commit (in "linting") runs in that it
uses stubs from (test) dependencies.

It would make sense to run this on CI additionally (since there is no
"pre-commit --skip mypy", and a separate config is not worth it).
But currently it triggers a false positive though anyway
(https://github.com/erikrose/more-itertools/pull/374).
2020-01-14 08:59:48 +01:00
Daniel Hahler
8eec42f040 Merge pull request #6455 from blueyed/mypy-master
master: update mypy 0.740 -> 0.761
2020-01-14 08:56:51 +01:00
Daniel Hahler
3adaa3d87b Merge pull request #6447 from blueyed/fix-determine_setup
typing: fix _pytest.config.findpaths.determine_setup
2020-01-14 08:56:28 +01:00
Ran Benita
090e260517 master: update mypy 0.740 -> 0.761
(cherry picked from commit 16ff9f591e)
(cherry picked from commit 4848bbdf9a)
2020-01-14 06:31:41 +01:00
Daniel Hahler
117072d64c typing: fix _pytest.config.findpaths.determine_setup 2020-01-13 11:45:20 +01:00
Daniel Hahler
90740007a8 Merge pull request #6445 from blueyed/tox-pre-commit-posargs
tox: linting: pass posargs
2020-01-12 21:17:14 +01:00
Daniel Hahler
5e1c6ce630 tox: linting: pass posargs 2020-01-12 20:09:51 +01:00
Daniel Hahler
61d04d3084 terminal: summary_passes: handle teardown sections
Fixes https://github.com/pytest-dev/pytest/issues/2780.
2020-01-11 21:58:19 +01:00
Bruno Oliveira
a3bc6df950 Implement code coverage in GitHub actions
This overwrites the `codecov.yml` file in the root of the repository with
`codecov-upstream.yml` file (which contains the code-cov token)´, so PRs
and branches on the repository can upload coverage.

Suggestion from here:

https://github.com/pytest-dev/pytest/pull/6421#issuecomment-571934112

Security concerns: the token might be misused, but only to upload bogus coverage
to `codecov.io`, so the team believe this is harmless. If we decide to fallback
from this decision , we just need to revoke the token.

Related to #6369
2020-01-11 12:21:20 -03:00
Bruno Oliveira
622995a501 Fix grammar in README (#6427)
Fix grammar in README
2020-01-09 20:22:05 -03:00
Ryan Barner
36531599a4 Fix grammar in README
Corrects grammar error in "Support pytest" section.
2020-01-09 14:12:57 -08:00
Bruno Oliveira
24f8002de8 Fix wrong 'changelog' and 'reference' links in docs (#6424)
Fix wrong 'changelog' and 'reference' links in docs
2020-01-09 19:09:35 -03:00
Bruno Oliveira
23475b6ab9 Fix wrong 'changelog' and 'reference' links in docs
Both references were referencing links from Python because of our intersphinx
mapping in `conf.py`:

    intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}

Because Python's docs explicitly define both references, Sphinx fallbacks to
them instead of generating implicit references as was expected.

Fix #6397
2020-01-09 18:06:15 -03:00
Anthony Sottile
cff7843f3b Merge pull request #6412 from nicoddemus/remote-tb-5971
Fix serialization of 'None' reprcrashes
2020-01-07 11:08:28 -05:00
Bruno Oliveira
356d865ad7 Use concurrent.futures for fidelity to the original report
As requested in review
2020-01-07 12:45:18 -03:00
Bruno Oliveira
f46ad8d114 Unifying black version in pre-commit config file (#6413)
Unifying black version in pre-commit config file
2020-01-07 09:07:47 -03:00
Marcelo Duarte Trevisani
8dbf6a4b2d Unifying black version 2020-01-07 11:07:05 +00:00
Bruno Oliveira
0e00069340 Fix serialization of 'None' reprcrashes
Tracebacks coming from remote processes crated by the multiprocess module
will contain "RemoteTracebacks" which don't have a 'reprcrash' attribute

Fix #5971
2020-01-06 22:04:38 -03:00
Anthony Sottile
26a2e1aba7 Merge pull request #6401 from nicoddemus/4.6-maintenance-docs-onward
Update py27/py34 deprecation docs
2020-01-04 16:24:56 -05:00
Bruno Oliveira
7c80335c6b Merge pull request #6391 from asottile/release-4.6.9 (#6403)
Merge pull request #6391 from asottile/release-4.6.9
2020-01-04 18:13:56 -03:00
Anthony Sottile
75f964c08d Merge pull request #6391 from asottile/release-4.6.9
Preparing release version 4.6.9
2020-01-04 13:01:46 -08:00
Bruno Oliveira
4fa819e535 Update py27/py34 deprecation docs
I've updated the text and incorporated the topics from #5275, so this
can now be part of the official docs, and #5275 can be closed/unpinned.

Closes #5275
2020-01-04 17:52:02 -03:00
Bruno Oliveira
61061d2147 Update copyright year to 2020 (#6400)
Update copyright year to 2020
2020-01-04 09:41:53 -03:00
Bruno Oliveira
deb4287d1c Update copyright year to 2020
Merge pull request #6392 from hugovk/4.6-maintenance-2020
2020-01-04 08:46:58 -03:00
Daniel Hahler
7aac48c418 Merge pull request #6382 from blueyed/fix-parseoutcomes
Fix `RunResult.parseoutcomes` (follow-up to #6353)
2020-01-04 00:49:24 +01:00
Daniel Hahler
3b60e36dbb Merge pull request #6380 from blueyed/doc
minor: split doc with _early_rewrite_bailout
2020-01-01 14:16:22 +01:00
Anthony Sottile
162d737f68 Merge pull request #6385 from betchern0t/master
Added how to reserve an issue to yourself when contributing
2019-12-31 11:53:50 -05:00
PaulC
d884164160 removed trailing whitespace to fix linting issue 2019-12-31 12:49:37 +11:00
PaulC
9811ebdc57 Added how to reserve an issue to yourself when contributing 2019-12-31 10:32:31 +11:00
Daniel Hahler
1c0242dec1 Fix RunResult.parseoutcomes (follow-up to #6353) 2019-12-30 17:08:52 +01:00
Daniel Hahler
a5863ca760 minor: split doc with _early_rewrite_bailout 2019-12-30 09:41:36 +01:00
Bruno Oliveira
8077168387 pytester: quick fix error introduced in #5990 (#6353)
pytester: quick fix error introduced in #5990
2019-12-27 13:28:11 -03:00
Bruno Oliveira
afa899d5e1 Azure Pipelines: Test on Python 3.8 (#6159)
Azure Pipelines: Test on Python 3.8
2019-12-27 13:27:17 -03:00
Hugo
8de9b1be56 Test on Python 3.8 2019-12-27 13:10:43 -03:00
Bruno Oliveira
b532d15fe7 Improve warnings docs (#6366)
Improve warnings docs
2019-12-26 19:52:15 -03:00
Adam Johnson
73702ca88b Improve warnings docs
* Rearrange section about context manager to be in order
* Link to `pytest.warns` and `recwarn` since a reader going top to bottom won't have seen about those yet.
* Used only context manager form in the example; the call form is somewhat obsolete
  and is mentioned in the reference docs already.
* Reuse the 'myfunction' from first example on the second one

Co-Authored-By: Hugo van Kemenade <hugovk@users.noreply.github.com>
Co-Authored-By: Hugo van Kemenade <hugovk@users.noreply.github.com>
2019-12-26 19:16:19 -03:00
Anthony Sottile
d7b0389d1a Merge pull request #6347 from noviluni/delete_deprecated_function
delete inspect.getargspect() as is deprecated since Python 3.0
2019-12-26 13:45:46 -05:00
Bruno Oliveira
06206bcf37 Merge pull request #6355 from nicoddemus/add-gh-actions
Add GitHub actions for CI
2019-12-26 13:32:17 -03:00
Bruno Oliveira
9924432a2e Improve docs so regen doesn't leak temp directories (#6364)
Improve docs so regen doesn't leak temp directories
2019-12-21 13:23:08 -03:00
Bruno Oliveira
c7ac3379e7 Update release notes script after CHANGELOG changed location (#6362)
Update release notes script after CHANGELOG changed location
2019-12-21 13:22:42 -03:00
Anthony Sottile
6cd61390c2 Improve docs so regen doesn't leak temp directories 2019-12-20 13:18:49 -08:00
Bruno Oliveira
994909270f Update release notes script after CHANGELOG changed location 2019-12-20 08:54:44 -03:00
Bruno Oliveira
e1df9dbf0d Merge pull request #6360 from asottile/release-4.6.8 (#6361)
Merge pull request #6360 from asottile/release-4.6.8
2019-12-19 22:46:55 -03:00
Anthony Sottile
ab44d3d733 Merge pull request #6360 from asottile/release-4.6.8
Preparing release version 4.6.8
2019-12-19 16:01:04 -08:00
Bruno Oliveira
d76aa8b428 Add GitHub actions for CI
This includes our current full matrix (windows, linux and macos), for evaluting
purposes.

We should disconsider failures when evaluating PRs.

TODO:

- deploy
- coverage
- github release notes

Even with the above missing, I still believe it would be nice to merge
this and have GitHub actions working in parallel so we can evaluate performance
and usability from now on.
2019-12-19 11:06:57 -03:00
Bruno Oliveira
4dfd2947bc fix typos in docs (#6356)
fix typos in docs
2019-12-19 09:31:08 -03:00
marc
536177bb56 fix typos in docs 2019-12-19 10:35:15 +01:00
Alexandre Mulatinho
dc7bf518b3 pytester: quick fix error introduced in #5990
- added a test to check this condition

Signed-off-by: Alexandre Mulatinho <alex@mulatinho.net>
2019-12-18 16:36:24 -03:00
Bruno Oliveira
8be9684ab2 Optimized renaming of test parameter ids (#6350)
Optimized renaming of test parameter ids
2019-12-16 18:54:35 -03:00
Seth Junot
d4879c7afb Optimized renaming of test parameter ids
While using pytest-repeat, I noticed the previous implementation is slow
for a large number of duplicate test ids. To optimize, this commit
reduces the amount of data copied and avoids using `in` with List
(unhashable type, and therefore is very slow for many elements).
2019-12-16 18:53:48 -03:00
marc
d42f5a41a5 delete inspect.getargspect() as is deprecated since Python 3.0 2019-12-14 19:52:17 +01:00
Bruno Oliveira
a176ff77bc Release 5.3.2 (#6342)
Release 5.3.2
2019-12-14 10:39:19 -03:00
Bruno Oliveira
7f24cc2feb Remove duplicated user from announcement 2019-12-14 10:06:59 -03:00
Bruno Oliveira
d0c663a628 Improve warning about incoming change to 'junitxml_family' defa… (#6343)
Improve warning about incoming change to 'junitxml_family' default
2019-12-13 12:57:21 -03:00
Bruno Oliveira
f7409f8685 Improve warning about incoming change to 'junitxml_family' default
Fix #6265
2019-12-13 09:17:12 -03:00
Bruno Oliveira
10fcac7f90 Preparing release version 5.3.2 2019-12-13 08:51:15 -03:00
Bruno Oliveira
8942a05cfe Change 4639 from feature to improvement
An improvement seems more adequate here.
2019-12-13 08:46:47 -03:00
Bruno Oliveira
66c1a120ba Bugfix 5430 pass logs to junit report (#6274)
Bugfix 5430 pass logs to junit report
2019-12-12 09:35:25 -03:00
Zac Hatfield-Dodds
8cdf9d43a9 Fixes #6326: Typo in the Security section docs home page. (#6327)
Fixes #6326: Typo in the Security section docs home page.
2019-12-09 17:28:06 +11:00
Michael Rose
2ddc330b62 Fixes #6326: Typo in the Security section docs home page. 2019-12-08 22:26:53 -05:00
Bruno Oliveira
1c0ab3c2a3 Add 4.6.7 changelog to master (Wait until #6318) (#6319)
Add 4.6.7 changelog to master (Wait until #6318)
2019-12-05 22:45:12 -03:00
Anthony Sottile
7ff91d8127 Merge pull request #6313 from nicoddemus/egg-rewrite-6301
Fix assertion rewriting module detection for egg dists
2019-12-05 16:24:13 -08:00
Bruno Oliveira
64c71daa21 Add 4.6.7 changelog to master 2019-12-05 17:32:45 -03:00
Bruno Oliveira
c7f9fda42d Fix assertion rewriting module detection for egg dists
Fix #6301
2019-12-04 15:30:45 -03:00
Ran Benita
42fb1f7ede Merge pull request #6309 from jaredvasquez/fix-cafd-docs
Fix typo in documentation of capfd fixture
2019-12-03 12:15:40 +02:00
Jared Vasquez
c00a43a17d fix typo 2019-12-02 22:29:22 -08:00
Bruno Oliveira
1dc612f7d4 Merge pull request #6304 from nicoddemus/pytest-as-pkg
Convert pytest.py into a package
2019-12-02 21:10:15 -03:00
Bruno Oliveira
e5bd7fb053 Convert pytest.py into a package
As discussed in https://github.com/pytest-dev/pytest/issues/3342, this
is the first step to make pytest support static typing fully
2019-12-02 19:27:11 -03:00
Bruno Oliveira
256a9e0027 Remove outdated py2py3 example (#6306)
Remove outdated py2py3 example
2019-12-02 16:54:12 -03:00
Ran Benita
d2d7b97a70 Remove outdated py2py3 example 2019-12-02 21:16:15 +02:00
Bruno Oliveira
23f6adc760 Ensure cache supporting files still exist after --cache-clear (#6296)
Ensure cache supporting files still exist after --cache-clear
2019-12-01 10:37:22 -03:00
Bruno Oliveira
172b82875a Ensure cache supporting files still exist after --cache-clear
Fix #6290
2019-12-01 10:36:47 -03:00
Bruno Oliveira
277857b026 docs: move changelog to docs/en and allow sphinx directives (#6287)
docs: move changelog to docs/en and allow sphinx directives
2019-11-29 10:51:01 -03:00
Daniel Hahler
d3ab56f531 docs: move changelog to docs/en and allow sphinx directives
Now `tox -e docs` will also include the draft changelog for the
next version (locally only).

`CHANGELOG.rst` now only points to the changelog on READTHEDOCS so
sphinx diretives can be used.

Followup to https://github.com/pytest-dev/pytest/pull/6272
2019-11-28 21:23:58 -03:00
Anthony Sottile
209d99102d Merge pull request #6234 from asottile/remove_none_warning
Revert "A warning is now issued when assertions are made for `None`"
2019-11-26 13:04:42 -08:00
Ronny Pfannschmidt
6d31684da5 Merge pull request #6279 from nicoddemus/fix-changelog
Remove duplicated changelog entry for 5.3.1
2019-11-26 19:22:07 +01:00
Bruno Oliveira
4ee280ae1f Remove duplicated changelog entry for 5.3.1 2019-11-26 12:01:12 -03:00
Bruno Oliveira
8b8cba369c Preparing release version 5.3.1 (#6277)
Preparing release version 5.3.1
2019-11-26 11:56:56 -03:00
Bruno Oliveira
05008f6b55 Preparing release version 5.3.1 2019-11-25 14:32:37 -03:00
Claudio Madotto
83182b82ea Merge branch 'bugfix-5430-pass-logs-to-junit-report' of https://github.com/zupermanzupereroe/pytest into bugfix-5430-pass-logs-to-junit-report 2019-11-25 13:00:04 +01:00
Claudio Madotto
31d5cedc6d Avoid duplicating system-out and system-error tags 2019-11-25 12:59:03 +01:00
Claudio Madotto
91b3ff1bb7 Create changelog file and update AUTHORS 2019-11-25 12:59:03 +01:00
Claudio Madotto
b66dc80008 Fix for issue #5430 - junit-xml: logs are not passed to junit report for tests failed not in a teardown phase 2019-11-25 12:59:03 +01:00
zupermanzupereroe
69ad2026f6 Merge pull request #1 from pytest-dev/master
Update repository
2019-11-25 12:56:54 +01:00
Anthony Sottile
9d900930db Merge pull request #6242 from nicoddemus/testdir-changelog
Add link to testdir fixture in CHANGELOG entry
2019-11-24 17:23:02 -08:00
Daniel Hahler
a8230d77f4 Merge pull request #6270 from blueyed/docs-log_cli
docs: add missing `log_cli` confval
2019-11-24 23:21:49 +01:00
Daniel Hahler
b7d908f4a5 Merge pull request #6269 from blueyed/docs
tox: docs: --keep-going and posargs
2019-11-24 23:21:26 +01:00
Daniel Hahler
b9dd0e6210 docs: add missing log_cli confval 2019-11-24 22:34:15 +01:00
Daniel Hahler
57f3dc19b9 tox: docs: --keep-going and posargs
`--keep-going` makes sense with `-W` to see all warnings/errors.

`{posargs:}` is useful for passing in custom args.
2019-11-24 22:21:08 +01:00
Florian Bruhin
ed67312bca Merge pull request #6268 from felixonmars/patch-2
Correct a typo in _pytest/config/__init__.py
2019-11-24 17:04:26 +01:00
Claudio Madotto
2d24c062b6 Avoid duplicating system-out and system-error tags 2019-11-24 16:33:17 +01:00
Claudio Madotto
d940d0b657 Create changelog file and update AUTHORS 2019-11-24 16:08:45 +01:00
Claudio Madotto
f9f092a5e6 Fix for issue #5430 - junit-xml: logs are not passed to junit report for tests failed not in a teardown phase 2019-11-24 15:20:02 +01:00
Felix Yan
b7bc52f770 Correct a typo in _pytest/config/__init__.py 2019-11-24 20:28:10 +08:00
Daniel Hahler
d1eb89d694 Merge pull request #6086 from kondratyev-nv/master
Fix line detection for properties in doctest tests
2019-11-22 23:09:10 +01:00
Nikolay Kondratyev
5e097970df Fix line detection for properties in doctest tests
Co-Authored-By: Daniel Hahler <github@thequod.de>
2019-11-22 23:50:20 +03:00
Daniel Hahler
0601f5cdad Merge pull request #6261 from blueyed/stats-keys
terminal: _get_main_color: help pytest-parallel
2019-11-22 17:12:33 +01:00
Daniel Hahler
a7268aaa5d Merge pull request #6258 from blueyed/notify_exception-handle-exit-exc-upstream
main: wrap_session: handle exit.Exception with notify_exception
2019-11-22 05:49:04 +01:00
Daniel Hahler
1f736a663d terminal: _get_main_color: help pytest-parallel
Use `dict.keys()` to work around `__iter__` not working with a
multiprocessing DictProxy.

Ref: https://github.com/python/cpython/pull/17333
Fixes https://github.com/pytest-dev/pytest/issues/6254.
Ref: https://github.com/browsertron/pytest-parallel/issues/36
2019-11-22 05:48:10 +01:00
Daniel Hahler
2344982d7f main: wrap_session: handle exit.Exception with notify_exception
Fixes https://github.com/pytest-dev/pytest/issues/6257.
Via https://github.com/blueyed/pytest/pull/132.
2019-11-21 22:50:33 +01:00
Daniel Hahler
63c9ad02f4 Merge pull request #6252 from blueyed/minor-changelog
CHANGELOG: two minor fixes/improvements
2019-11-21 18:44:41 +01:00
Daniel Hahler
8b7aeefd7d Merge pull request #6248 from blueyed/default-role
docs: configure default_role=literal
2019-11-21 18:44:17 +01:00
Bruno Oliveira
f1ac0eeef0 Remove sys.last_traceback attribute using del instead of settin… (#6256)
Remove sys.last_traceback attribute using del instead of setting to None
2019-11-21 11:16:19 -03:00
Mark Dickinson
82424c9270 Fix reST markup. 2019-11-21 13:37:17 +00:00
Mark Dickinson
dbb8c146f0 Use proper reST attribute markup. 2019-11-21 13:22:34 +00:00
Mark Dickinson
8d686a8e46 Add self to AUTHORS 2019-11-21 13:14:19 +00:00
Mark Dickinson
9d1082bd30 Add changelog file. 2019-11-21 13:13:36 +00:00
Bruno Oliveira
490c7c7262 Add develop instructions to CONTRIBUTING (#6249)
Add develop instructions to CONTRIBUTING
2019-11-21 10:07:00 -03:00
Mark Dickinson
2ffbe41ae5 clear sys.last_traceback via del instead of = None 2019-11-21 13:06:47 +00:00
Bruno Oliveira
8f2fd8ffc0 Add develop instructions to CONTRIBUTING
From: https://github.com/pytest-dev/pytest/pull/6244
2019-11-21 10:06:32 -03:00
Mark Dickinson
64eb9ea670 Modify test for new expected behaviour 2019-11-21 11:50:40 +00:00
Zac Hatfield-Dodds
7e10c8191d Added link checking to tox and release.py (#5614)
Added link checking to tox and release.py
2019-11-21 16:46:13 +11:00
Daniel Hahler
6659fe0edc CHANGELOG: two minor fixes/improvements 2019-11-21 06:20:57 +01:00
Daniel Hahler
4ee984ff0a Merge pull request #6250 from blueyed/tbh
pytester: LineMatcher: __tracebackhide__ with _fail
2019-11-21 04:26:20 +01:00
Daniel Hahler
b96e0a71a6 pytester: LineMatcher: __tracebackhide__ with _fail
Follow-up to 2228ccb (gone lost in resolving the conflict).
2019-11-21 01:23:36 +01:00
Daniel Hahler
be722652f0 docs: configure default_role=literal
This configures the default role for interpreted text (single
backticks), avoiding the need to check for / enforce double backticks.

Fixes also one instance in the existing changelog:

    - Detect `pytest_` prefixed hooks using the internal plugin manager since
      ``pluggy`` is deprecating the ``implprefix`` argument to ``PluginManager``.
      (`#3487 <https://github.com/pytest-dev/pytest/issues/3487>`_)
2019-11-21 00:35:00 +01:00
Daniel Hahler
58ec5bea35 Merge pull request #6237 from blueyed/fix-no_fnmatch_line
pytester: reset log output in _match_lines
2019-11-20 18:44:37 +01:00
Bruno Oliveira
0be03d7fe4 Add link to testdir fixture in CHANGELOG entry
As per https://github.com/pytest-dev/pytest/pull/5914#issuecomment-556063975
2019-11-20 13:14:17 -03:00
Bruno Oliveira
2879d25812 Fix rendering of Before/After in changelog (#6238)
Fix rendering of Before/After in changelog
2019-11-20 07:32:17 -03:00
Bruno Oliveira
fe69a2cfb7 Delete 5934.feature.rst included in the wrong folder by accident 2019-11-20 07:06:11 -03:00
Bruno Oliveira
af9dfc604d Introduce 5934 in CHANGELOG and fix "pytest" blocks 2019-11-20 07:05:31 -03:00
Anthony Sottile
8c65eae5f4 Fix rendering of Before/After in changelog
Apparently the version of sphinx that rtd uses is a little more strict about whether an anonymous `code-block` can happen
2019-11-19 21:12:30 -08:00
Daniel Hahler
2228ccbfb4 pytester: reset log output in _match_lines (#70)
This is necessary for when using e.g. `no_fnmatch_line` after it.
Factor it out into `_fail`.

(cherry picked from commit aade7ed0045ba32557ef8565cbab28a2c91053a7)

Ref: https://github.com/pytest-dev/pytest/pull/5914#issuecomment-549182242
2019-11-20 05:24:18 +01:00
Bruno Oliveira
7e5ad31428 Merge features into master after 5.3 (#6236)
Merge features into master after 5.3
2019-11-19 19:17:06 -03:00
Bruno Oliveira
688bbefed1 Improve instructions on how to write CHANGELOG entries (#6235)
Improve instructions on how to write CHANGELOG entries
2019-11-19 19:10:41 -03:00
Bruno Oliveira
5b3867fd65 Release 5.3.0 (#6233)
Release 5.3.0
2019-11-19 18:49:14 -03:00
Bruno Oliveira
36ef545b2d Improve instructions on how to write CHANGELOG entries
This makes easier for contributors to get the CHANGELOG entry
right the first time.
2019-11-19 14:15:55 -03:00
Daniel Hahler
1d368e0ed4 Merge pull request #6231 from blueyed/param-spell
Improve check for misspelling of parametrize
2019-11-19 17:57:28 +01:00
Anthony Sottile
faea273c93 Revert "A warning is now issued when assertions are made for None" 2019-11-19 08:24:08 -08:00
Daniel Hahler
4ad61cbcf6 Improve check for misspelling of parametrize
- there is no need to do this with `--strict-markers`
- it can be done when looking up marks, instead of for every generated
  test
2019-11-19 16:05:52 +01:00
Steffen Schroeder
ceeb7bd085 Fixed broken links 2019-11-06 20:54:41 +01:00
Steffen Schroeder
1cecdf6619 Added checklinks to tox and release.py 2019-11-06 20:54:41 +01:00
112 changed files with 9185 additions and 7975 deletions

View File

@@ -24,3 +24,5 @@ exclude_lines =
\#\s*pragma: no cover
^\s*raise NotImplementedError\b
^\s*return NotImplemented\b
^\s*if TYPE_CHECKING:

View File

@@ -11,5 +11,13 @@ Here is a quick checklist that should be present in PRs.
Unless your change is trivial or a small documentation fix (e.g., a typo or reword of a small section) please:
- [ ] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](https://github.com/pytest-dev/pytest/blob/master/changelog/README.rst) for details.
Write sentences in the **past or present tense**, examples:
* *Improved verbose diff output with sequences.*
* *Terminal summary statistics now use multiple colors.*
Also make sure to end the sentence with a `.`.
- [ ] Add yourself to `AUTHORS` in alphabetical order.
-->

191
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,191 @@
# evaluating GitHub actions for CI, disregard failures when evaluating PRs
#
# this is still missing:
# - deploy
# - upload github notes
#
name: main
on:
push:
branches:
- master
tags:
- "*"
pull_request:
branches:
- master
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
name: [
"windows-py35",
"windows-py36",
"windows-py37",
"windows-py37-pluggy",
"windows-py38",
"ubuntu-py35",
"ubuntu-py36",
"ubuntu-py37",
"ubuntu-py37-pluggy",
"ubuntu-py37-freeze",
"ubuntu-py38",
"ubuntu-pypy3",
"macos-py37",
"macos-py38",
"linting",
]
include:
- name: "windows-py35"
python: "3.5"
os: windows-latest
tox_env: "py35-xdist"
- name: "windows-py36"
python: "3.6"
os: windows-latest
tox_env: "py36-xdist"
- name: "windows-py37"
python: "3.7"
os: windows-latest
tox_env: "py37-twisted-numpy"
- name: "windows-py37-pluggy"
python: "3.7"
os: windows-latest
tox_env: "py37-pluggymaster-xdist"
- name: "windows-py38"
python: "3.8"
os: windows-latest
tox_env: "py38"
- name: "ubuntu-py35"
python: "3.5"
os: ubuntu-latest
tox_env: "py35-xdist"
- name: "ubuntu-py36"
python: "3.6"
os: ubuntu-latest
tox_env: "py36-xdist"
- name: "ubuntu-py37"
python: "3.7"
os: ubuntu-latest
tox_env: "py37-lsof-numpy-oldattrs-pexpect-twisted"
- name: "ubuntu-py37-pluggy"
python: "3.7"
os: ubuntu-latest
tox_env: "py37-pluggymaster-xdist"
- name: "ubuntu-py37-freeze"
python: "3.7"
os: ubuntu-latest
tox_env: "py37-freeze"
# coverage does not apply for freeze test, skip it
skip_coverage: true
- name: "ubuntu-py38"
python: "3.8"
os: ubuntu-latest
tox_env: "py38-xdist"
- name: "ubuntu-pypy3"
python: "pypy3"
os: ubuntu-latest
tox_env: "pypy3-xdist"
# coverage too slow with pypy3, skip it
skip_coverage: true
- name: "macos-py37"
python: "3.7"
os: macos-latest
tox_env: "py37-xdist"
- name: "macos-py38"
python: "3.8"
os: macos-latest
tox_env: "py38-xdist"
- name: "linting"
python: "3.7"
os: ubuntu-latest
tox_env: "linting,docs,doctesting"
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install tox coverage
- name: Test without coverage
if: "matrix.skip_coverage"
run: "tox -e ${{ matrix.tox_env }}"
- name: Test with coverage
if: "! matrix.skip_coverage"
env:
_PYTEST_TOX_COVERAGE_RUN: "coverage run -m"
COVERAGE_PROCESS_START: ".coveragerc"
_PYTEST_TOX_EXTRA_DEP: "coverage-enable-subprocess"
run: "tox -e ${{ matrix.tox_env }}"
- name: Prepare coverage token
if: success() && !matrix.skip_coverage && ( github.repository == 'pytest-dev/pytest' || github.event_name == 'pull_request' )
run: |
python scripts/append_codecov_token.py
- name: Combine coverage
if: success() && !matrix.skip_coverage
run: |
python -m coverage combine
python -m coverage xml
- name: Codecov upload
if: success() && !matrix.skip_coverage
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.codecov }}
file: ./coverage.xml
flags: ${{ runner.os }}
fail_ci_if_error: false
name: ${{ matrix.name }}
deploy:
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') && github.repository == 'pytest-dev/pytest'
runs-on: ubuntu-latest
needs: [build]
steps:
- uses: actions/checkout@v1
- name: Set up Python
uses: actions/setup-python@v1
with:
python-version: "3.7"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install --upgrade wheel setuptools tox
- name: Build package
run: |
python setup.py sdist bdist_wheel
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.pypi_token }}
- name: Publish GitHub release notes
env:
GH_RELEASE_NOTES_TOKEN: ${{ secrets.release_notes }}
run: |
sudo apt-get install pandoc
tox -e publish-gh-release-notes

2
.gitignore vendored
View File

@@ -25,12 +25,14 @@ src/_pytest/_version.py
doc/*/_build
doc/*/.doctrees
doc/*/_changelog_towncrier_draft.rst
build/
dist/
*.egg-info
issue/
env/
.env/
.venv/
3rdparty/
.tox
.cache

View File

@@ -1,4 +1,3 @@
exclude: doc/en/example/py2py3/test_py2.py
repos:
- repo: https://github.com/psf/black
rev: 19.10b0
@@ -9,7 +8,7 @@ repos:
rev: v1.0.0
hooks:
- id: blacken-docs
additional_dependencies: [black==19.3b0]
additional_dependencies: [black==19.10b0]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.2.3
hooks:
@@ -37,12 +36,8 @@ repos:
hooks:
- id: pyupgrade
args: [--py3-plus]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.4.0
hooks:
- id: rst-backticks
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.740
rev: v0.761 # NOTE: keep this in sync with setup.py.
hooks:
- id: mypy
files: ^(src/|testing/)
@@ -52,7 +47,7 @@ repos:
- id: rst
name: rst
entry: rst-lint --encoding utf-8
files: ^(CHANGELOG.rst|HOWTORELEASE.rst|README.rst|TIDELIFT.rst|changelog/.*)$
files: ^(HOWTORELEASE.rst|README.rst|TIDELIFT.rst)$
language: python
additional_dependencies: [pygments, restructuredtext_lint]
- id: changelogs-rst

View File

@@ -2,10 +2,8 @@ language: python
dist: xenial
stages:
- baseline
- name: test
if: repo = pytest-dev/pytest AND tag IS NOT present
- name: deploy
if: repo = pytest-dev/pytest AND tag IS present
- test
python: '3.7'
cache: false
@@ -52,8 +50,10 @@ jobs:
- env: TOXENV=pypy3-xdist
python: 'pypy3'
- env: TOXENV=py35-xdist
python: '3.5'
# Coverage for Python 3.5.{0,1} specific code, mostly typing related.
- env: TOXENV=py35 PYTEST_COVERAGE=1 PYTEST_ADDOPTS="-k test_raises_cyclic_reference"
python: '3.5.1'
dist: trusty
# Specialized factors for py37.
- env: TOXENV=py37-pluggymaster-xdist
@@ -70,30 +70,6 @@ jobs:
directories:
- $HOME/.cache/pre-commit
- stage: deploy
python: '3.6'
install: pip install -U setuptools setuptools_scm tox
script: skip
# token to upload github release notes: GH_RELEASE_NOTES_TOKEN
env:
- secure: "OjOeL7/0JUDkV00SsTs732e8vQjHynpbG9FKTNtZZJ+1Zn4Cib+hAlwmlBnvVukML0X60YpcfjnC4quDOIGLPsh5zeXnvJmYtAIIUNQXjWz8NhcGYrhyzuP1rqV22U68RTCdmOq3lMYU/W2acwHP7T49PwJtOiUM5kF120UAQ0Zi5EmkqkIvH8oM5mO9Dlver+/U7Htpz9rhKrHBXQNCMZI6yj2aUyukqB2PN2fjAlDbCF//+FmvYw9NjT4GeFOSkTCf4ER9yfqs7yglRfwiLtOCZ2qKQhWZNsSJDB89rxIRXWavJUjJKeY2EW2/NkomYJDpqJLIF4JeFRw/HhA47CYPeo6BJqyyNV+0CovL1frpWfi9UQw2cMbgFUkUIUk3F6DD59PHNIOX2R/HX56dQsw7WKl3QuHlCOkICXYg8F7Ta684IoKjeTX03/6QNOkURfDBwfGszY0FpbxrjCSWKom6RyZdyidnESaxv9RzjcIRZVh1rp8KMrwS1OrwRSdG0zjlsPr49hWMenN/8fKgcHTV4/r1Tj6mip0dorSRCrgUNIeRBKgmui6FS8642ab5JNKOxMteVPVR2sFuhjOQ0Jy+PmvceYY9ZMWc3+/B/KVh0dZ3hwvLGZep/vxDS2PwCA5/xw31714vT5LxidKo8yECjBynMU/wUTTS695D3NY="
addons:
apt:
packages:
# required by publish_gh_release_notes
- pandoc
after_deploy: tox -e publish_gh_release_notes
deploy:
provider: pypi
user: nicoddemus
distributions: sdist bdist_wheel
skip_upload_docs: true
password:
secure: xanTgTUu6XDQVqB/0bwJQXoDMnU5tkwZc5koz6mBkkqZhKdNOi2CLoC1XhiSZ+ah24l4V1E0GAqY5kBBcy9d7NVe4WNg4tD095LsHw+CRU6/HCVIFfyk2IZ+FPAlguesCcUiJSXOrlBF+Wj68wEvLoK7EoRFbJeiZ/f91Ww1sbtDlqXABWGHrmhPJL5Wva7o7+wG7JwJowqdZg1pbQExsCc7b53w4v2RBu3D6TJaTAzHiVsW+nUSI67vKI/uf+cR/OixsTfy37wlHgSwihYmrYLFls3V0bSpahCim3bCgMaFZx8S8xrdgJ++PzBCof2HeflFKvW+VCkoYzGEG4NrTWJoNz6ni4red9GdvfjGH3YCjAKS56h9x58zp2E5rpsb/kVq5/45xzV+dq6JRuhQ1nJWjBC6fSKAc/bfwnuFK3EBxNLkvBssLHvsNjj5XG++cB8DdS9wVGUqjpoK4puaXUWFqy4q3S9F86HEsKNgExtieA9qNx+pCIZVs6JCXZNjr0I5eVNzqJIyggNgJG6RyravsU35t9Zd9doL5g4Y7UKmAGTn1Sz24HQ4sMQgXdm2SyD8gEK5je4tlhUvfGtDvMSlstq71kIn9nRpFnqB6MFlbYSEAZmo8dGbCquoUc++6Rum208wcVbrzzVtGlXB/Ow9AbFMYeAGA0+N/K1e59c=
on:
tags: true
repo: pytest-dev/pytest
before_script:
- |
# Do not (re-)upload coverage with cron runs.

View File

@@ -54,6 +54,7 @@ Ceridwen
Charles Cloud
Charnjit SiNGH (CCSJ)
Chris Lamb
Chris NeJame
Christian Boelsen
Christian Fetzer
Christian Neumüller
@@ -61,6 +62,7 @@ Christian Theunert
Christian Tismer
Christopher Gilling
Christopher Dignam
Claudio Madotto
CrazyMerlyn
Cyrus Maden
Damian Skrzypczak
@@ -165,6 +167,7 @@ Marcelo Duarte Trevisani
Marcin Bachry
Marco Gorelli
Mark Abramowitz
Mark Dickinson
Markus Unterwaditzer
Martijn Faassen
Martin Altmayer
@@ -233,6 +236,7 @@ Samuele Pedroni
Sankt Petersbug
Segev Finer
Serhii Mozghovyi
Seth Junot
Simon Gomizelj
Skylar Downes
Srinivas Reddy Thatiparthy

File diff suppressed because it is too large Load Diff

View File

@@ -51,7 +51,8 @@ Fix bugs
Look through the `GitHub issues for bugs <https://github.com/pytest-dev/pytest/labels/type:%20bug>`_.
:ref:`Talk <contact>` to developers to find out how you can fix specific bugs.
:ref:`Talk <contact>` to developers to find out how you can fix specific bugs. To indicate that you are going
to work on a particular issue, add a comment to that effect on the specific issue.
Don't forget to check the issue trackers of your favourite plugins, too!
@@ -262,6 +263,19 @@ Here is a simple overview, with pytest-specific bits:
When committing, ``pre-commit`` will re-format the files if necessary.
#. If instead of using ``tox`` you prefer to run the tests directly, then we suggest to create a virtual environment and use
an editable install with the ``testing`` extra::
$ python3 -m venv .venv
$ source .venv/bin/activate # Linux
$ .venv/Scripts/activate.bat # Windows
$ pip install -e ".[testing]"
Afterwards, you can edit the files and run pytest normally::
$ pytest 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>"

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2004-2019 Holger Krekel and others
Copyright (c) 2004-2020 Holger Krekel and others
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@@ -112,12 +112,12 @@ Support pytest
--------------
`Open Collective`_ is an online funding platform for open and transparent communities.
It provide tools to raise money and share your finances in full transparency.
It provides tools to raise money and share your finances in full transparency.
It is the platform of choice for individuals and companies that want to make one-time or
monthly donations directly to the project.
See more datails in the `pytest collective`_.
See more details in the `pytest collective`_.
.. _Open Collective: https://opencollective.com
.. _pytest collective: https://opencollective.com/pytest
@@ -137,7 +137,7 @@ Save time, reduce risk, and improve code health, while paying the maintainers of
Security
^^^^^^^^
pytest has never been associated with a security vunerability, but in any case, to report a
pytest has never been associated with a security vulnerability, but in any case, to report a
security vulnerability please use the `Tidelift security contact <https://tidelift.com/security>`_.
Tidelift will coordinate the fix and disclosure.
@@ -145,7 +145,7 @@ Tidelift will coordinate the fix and disclosure.
License
-------
Copyright Holger Krekel and others, 2004-2019.
Copyright Holger Krekel and others, 2004-2020.
Distributed under the terms of the `MIT`_ license, pytest is free and open source software.

View File

@@ -39,6 +39,9 @@ jobs:
py37-pluggymaster-xdist:
python.version: '3.7'
tox.env: 'py37-pluggymaster-xdist'
py38-xdist:
python.version: '3.8'
tox.env: 'py38-xdist'
maxParallel: 10
steps:

View File

@@ -1,12 +1,14 @@
This directory contains "newsfragments" which are short files that contain a small **ReST**-formatted
text that will be added to the next ``CHANGELOG``.
The ``CHANGELOG`` will be read by users, so this description should be aimed to pytest users
The ``CHANGELOG`` will be read by **users**, so this description should be aimed to pytest users
instead of describing internal changes which are only relevant to the developers.
Make sure to use full sentences with correct case and punctuation, for example::
Make sure to use full sentences in the **past or present tense** and use punctuation, examples::
Fix issue with non-ascii messages from the ``warnings`` module.
Improved verbose diff output with sequences.
Terminal summary statistics now use multiple colors.
Each file should be named like ``<ISSUE>.<TYPE>.rst``, where
``<ISSUE>`` is an issue number, and ``<TYPE>`` is one of:
@@ -29,6 +31,7 @@ changelog using that instead.
If you are not sure what issue type to use, don't hesitate to ask in your PR.
``towncrier`` preserves multiple paragraphs and formatting (code blocks, lists, and so on), but for entries
other than ``features`` it is usually better to stick to a single paragraph to keep it concise. You can install
``towncrier`` and then run ``towncrier --draft``
if you want to get a preview of how your change will look in the final release notes.
other than ``features`` it is usually better to stick to a single paragraph to keep it concise.
You can also run ``tox -e docs`` to build the documentation
with the draft changelog (``doc/en/_build/changelog.html``) if you want to get a preview of how your change will look in the final release notes.

View File

@@ -1 +0,0 @@
``repr`` of ``ExceptionInfo`` objects has been improved to honor the ``__repr__`` method of the underlying exception.

View File

@@ -6,6 +6,9 @@ Release announcements
:maxdepth: 2
release-5.3.3
release-5.3.2
release-5.3.1
release-5.3.0
release-5.2.4
release-5.2.3
@@ -18,6 +21,10 @@ Release announcements
release-5.1.0
release-5.0.1
release-5.0.0
release-4.6.9
release-4.6.8
release-4.6.7
release-4.6.6
release-4.6.5
release-4.6.4
release-4.6.3

View File

@@ -7,7 +7,7 @@ see below for summary and detailed lists. A lot of long-deprecated code
has been removed, resulting in a much smaller and cleaner
implementation. See the new docs with examples here:
http://pytest.org/2.0.0/index.html
http://pytest.org/en/latest/index.html
A note on packaging: pytest used to part of the "py" distribution up
until version py-1.3.4 but this has changed now: pytest-2.0.0 only
@@ -36,12 +36,12 @@ New Features
import pytest ; pytest.main(arglist, pluginlist)
see http://pytest.org/2.0.0/usage.html for details.
see http://pytest.org/en/latest/usage.html for details.
- new and better reporting information in assert expressions
if comparing lists, sequences or strings.
see http://pytest.org/2.0.0/assert.html#newreport
see http://pytest.org/en/latest/assert.html#newreport
- new configuration through ini-files (setup.cfg or tox.ini recognized),
for example::
@@ -50,7 +50,7 @@ New Features
norecursedirs = .hg data* # don't ever recurse in such dirs
addopts = -x --pyargs # add these command line options by default
see http://pytest.org/2.0.0/customize.html
see http://pytest.org/en/latest/customize.html
- improved standard unittest support. In general py.test should now
better be able to run custom unittest.TestCases like twisted trial

View File

@@ -57,7 +57,7 @@ Changes between 2.0.0 and 2.0.1
- refinements to "collecting" output on non-ttys
- refine internal plugin registration and --traceconfig output
- introduce a mechanism to prevent/unregister plugins from the
command line, see http://pytest.org/latest/plugins.html#cmdunregister
command line, see http://pytest.org/en/latest/plugins.html#cmdunregister
- activate resultlog plugin by default
- fix regression wrt yielded tests which due to the
collection-before-running semantics were not

View File

@@ -9,7 +9,7 @@ with these improvements:
- new @pytest.mark.parametrize decorator to run tests with different arguments
- new metafunc.parametrize() API for parametrizing arguments independently
- see examples at http://pytest.org/latest/example/parametrize.html
- see examples at http://pytest.org/en/latest/example/parametrize.html
- NOTE that parametrize() related APIs are still a bit experimental
and might change in future releases.
@@ -18,7 +18,7 @@ with these improvements:
- "-m markexpr" option for selecting tests according to their mark
- a new "markers" ini-variable for registering test markers for your project
- the new "--strict" bails out with an error if using unregistered markers.
- see examples at http://pytest.org/latest/example/markers.html
- see examples at http://pytest.org/en/latest/example/markers.html
* duration profiling: new "--duration=N" option showing the N slowest test
execution or setup/teardown calls. This is most useful if you want to
@@ -78,7 +78,7 @@ Changes between 2.1.3 and 2.2.0
or through plugin hooks. Also introduce a "--strict" option which
will treat unregistered markers as errors
allowing to avoid typos and maintain a well described set of markers
for your test suite. See examples at http://pytest.org/latest/mark.html
for your test suite. See examples at http://pytest.org/en/latest/mark.html
and its links.
- issue50: introduce "-m marker" option to select tests based on markers
(this is a stricter and more predictable version of "-k" in that "-m"

View File

@@ -3,22 +3,22 @@ pytest-2.3: improved fixtures / better unittest integration
pytest-2.3 comes with many major improvements for fixture/funcarg management
and parametrized testing in Python. It is now easier, more efficient and
more predicatable to re-run the same tests with different fixture
more predictable to re-run the same tests with different fixture
instances. Also, you can directly declare the caching "scope" of
fixtures so that dependent tests throughout your whole test suite can
re-use database or other expensive fixture objects with ease. Lastly,
it's possible for fixture functions (formerly known as funcarg
factories) to use other fixtures, allowing for a completely modular and
re-useable fixture design.
re-usable fixture design.
For detailed info and tutorial-style examples, see:
http://pytest.org/latest/fixture.html
http://pytest.org/en/latest/fixture.html
Moreover, there is now support for using pytest fixtures/funcargs with
unittest-style suites, see here for examples:
http://pytest.org/latest/unittest.html
http://pytest.org/en/latest/unittest.html
Besides, more unittest-test suites are now expected to "simply work"
with pytest.
@@ -29,11 +29,11 @@ pytest-2.2.4.
If you are interested in the precise reasoning (including examples) of the
pytest-2.3 fixture evolution, please consult
http://pytest.org/latest/funcarg_compare.html
http://pytest.org/en/latest/funcarg_compare.html
For general info on installation and getting started:
http://pytest.org/latest/getting-started.html
http://pytest.org/en/latest/getting-started.html
Docs and PDF access as usual at:
@@ -94,7 +94,7 @@ Changes between 2.2.4 and 2.3.0
- pluginmanager.register(...) now raises ValueError if the
plugin has been already registered or the name is taken
- fix issue159: improve http://pytest.org/latest/faq.html
- fix issue159: improve http://pytest.org/en/latest/faq.html
especially with respect to the "magic" history, also mention
pytest-django, trial and unittest integration.

View File

@@ -16,7 +16,7 @@ comes with the following fixes and features:
- yielded test functions will now have autouse-fixtures active but
cannot accept fixtures as funcargs - it's anyway recommended to
rather use the post-2.0 parametrize features instead of yield, see:
http://pytest.org/latest/example/parametrize.html
http://pytest.org/en/latest/example/parametrize.html
- fix autouse-issue where autouse-fixtures would not be discovered
if defined in an a/conftest.py file and tests in a/tests/test_some.py
- fix issue226 - LIFO ordering for fixture teardowns

View File

@@ -7,7 +7,7 @@ from a few supposedly very minor incompatibilities. See below for
a full list of details. A few feature highlights:
- new yield-style fixtures `pytest.yield_fixture
<http://pytest.org/latest/yieldfixture.html>`_, allowing to use
<http://pytest.org/en/latest/yieldfixture.html>`_, allowing to use
existing with-style context managers in fixture functions.
- improved pdb support: ``import pdb ; pdb.set_trace()`` now works

View File

@@ -91,7 +91,7 @@ holger krekel
it might be the cause for other finalizers to fail.
- fix ordering when mock.patch or other standard decorator-wrappings
are used with test methods. This fixues issue346 and should
are used with test methods. This fixes issue346 and should
help with random "xdist" collection failures. Thanks to
Ronny Pfannschmidt and Donald Stufft for helping to isolate it.

View File

@@ -35,7 +35,7 @@ holger krekel
- fix issue435: make reload() work when assert rewriting is active.
Thanks Daniel Hahler.
- fix issue616: conftest.py files and their contained fixutres are now
- fix issue616: conftest.py files and their contained fixtures are now
properly considered for visibility, independently from the exact
current working directory and test arguments that are used.
Many thanks to Eric Siegerman and his PR235 which contains
@@ -52,7 +52,7 @@ holger krekel
- add ability to set command line options by environment variable PYTEST_ADDOPTS.
- added documentation on the new pytest-dev teams on bitbucket and
github. See https://pytest.org/latest/contributing.html .
github. See https://pytest.org/en/latest/contributing.html .
Thanks to Anatoly for pushing and initial work on this.
- fix issue650: new option ``--docttest-ignore-import-errors`` which

View File

@@ -131,7 +131,7 @@ The py.test Development Team
with same name.
.. _`traceback style docs`: https://pytest.org/latest/usage.html#modifying-python-traceback-printing
.. _`traceback style docs`: https://pytest.org/en/latest/usage.html#modifying-python-traceback-printing
.. _#1422: https://github.com/pytest-dev/pytest/issues/1422
.. _#1379: https://github.com/pytest-dev/pytest/issues/1379

View File

@@ -0,0 +1,20 @@
pytest-4.6.6
=======================================
pytest 4.6.6 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Anthony Sottile
* Bruno Oliveira
* Michael Goerz
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,19 @@
pytest-4.6.7
=======================================
pytest 4.6.7 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Bruno Oliveira
* Daniel Hahler
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,20 @@
pytest-4.6.8
=======================================
pytest 4.6.8 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Anthony Sottile
* Bruno Oliveira
* Ryan Mast
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,21 @@
pytest-4.6.9
=======================================
pytest 4.6.9 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Anthony Sottile
* Bruno Oliveira
* Felix Yan
* Hugo
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,26 @@
pytest-5.3.1
=======================================
pytest 5.3.1 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Anthony Sottile
* Bruno Oliveira
* Daniel Hahler
* Felix Yan
* Florian Bruhin
* Mark Dickinson
* Nikolay Kondratyev
* Steffen Schroeder
* Zac Hatfield-Dodds
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,26 @@
pytest-5.3.2
=======================================
pytest 5.3.2 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Anthony Sottile
* Bruno Oliveira
* Claudio Madotto
* Daniel Hahler
* Jared Vasquez
* Michael Rose
* Ran Benita
* Ronny Pfannschmidt
* Zac Hatfield-Dodds
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,30 @@
pytest-5.3.3
=======================================
pytest 5.3.3 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Adam Johnson
* Alexandre Mulatinho
* Anthony Sottile
* Bruno Oliveira
* Chris NeJame
* Daniel Hahler
* Hugo van Kemenade
* Marcelo Duarte Trevisani
* PaulC
* Ran Benita
* Ryan Barner
* Seth Junot
* marc
Happy testing,
The pytest Development Team

File diff suppressed because it is too large Load Diff

View File

@@ -19,6 +19,11 @@ import os
import sys
from _pytest import __version__ as version
from _pytest.compat import TYPE_CHECKING
if TYPE_CHECKING:
import sphinx.application
release = ".".join(version.split(".")[:2])
@@ -62,7 +67,7 @@ master_doc = "contents"
# General information about the project.
project = "pytest"
copyright = "20152019, holger krekel and pytest-dev team"
copyright = "20152020, holger krekel and pytest-dev team"
# The language for content autogenerated by Sphinx. Refer to documentation
@@ -92,7 +97,7 @@ exclude_patterns = [
# The reST default role (used for this markup: `text`) to use for all documents.
# default_role = None
default_role = "literal"
# If true, '()' will be appended to :func: etc. cross-reference text.
# add_function_parentheses = True
@@ -112,6 +117,19 @@ pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
# A list of regular expressions that match URIs that should not be checked when
# doing a linkcheck.
linkcheck_ignore = [
"https://github.com/numpy/numpy/blob/master/doc/release/1.16.0-notes.rst#new-deprecations",
"https://blogs.msdn.microsoft.com/bharry/2017/06/28/testing-in-a-cloud-delivery-cadence/",
"http://pythontesting.net/framework/pytest-introduction/",
r"https://github.com/pytest-dev/pytest/issues/\d+",
r"https://github.com/pytest-dev/pytest/pull/\d+",
]
# The number of worker threads to use when checking links (default=5).
linkcheck_workers = 5
# -- Options for HTML output ---------------------------------------------------
@@ -272,7 +290,7 @@ man_pages = [("usage", "pytest", "pytest usage", ["holger krekel at merlinux eu"
epub_title = "pytest"
epub_author = "holger krekel at merlinux eu"
epub_publisher = "holger krekel at merlinux eu"
epub_copyright = "2013, holger krekel et alii"
epub_copyright = "2013-2020, holger krekel et alii"
# The language of the text. It defaults to the language option
# or en if the language is not set.
@@ -329,7 +347,30 @@ texinfo_documents = [
intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}
def setup(app):
def configure_logging(app: "sphinx.application.Sphinx") -> None:
"""Configure Sphinx's WarningHandler to handle (expected) missing include."""
import sphinx.util.logging
import logging
class WarnLogFilter(logging.Filter):
def filter(self, record: logging.LogRecord) -> bool:
"""Ignore warnings about missing include with "only" directive.
Ref: https://github.com/sphinx-doc/sphinx/issues/2150."""
if (
record.msg.startswith('Problems with "include" directive path:')
and "_changelog_towncrier_draft.rst" in record.msg
):
return False
return True
logger = logging.getLogger(sphinx.util.logging.NAMESPACE)
warn_handler = [x for x in logger.handlers if x.level == logging.WARNING]
assert len(warn_handler) == 1, warn_handler
warn_handler[0].filters.insert(0, WarnLogFilter())
def setup(app: "sphinx.application.Sphinx") -> None:
# from sphinx.ext.autodoc import cut_lines
# app.connect('autodoc-process-docstring', cut_lines(4, what=['module']))
app.add_object_type(
@@ -338,3 +379,4 @@ def setup(app):
objname="configuration value",
indextemplate="pair: %s; configuration value",
)
configure_logging(app)

View File

@@ -20,8 +20,6 @@ which were registered by installed plugins.
Initialization: determining rootdir and inifile
-----------------------------------------------
pytest determines a ``rootdir`` for each test run which depends on
the command line arguments (specified test files, paths) and on
the existence of *ini-files*. The determined ``rootdir`` and *ini-file* are
@@ -30,17 +28,17 @@ printed as part of the pytest header during startup.
Here's a summary what ``pytest`` uses ``rootdir`` for:
* Construct *nodeids* during collection; each test is assigned
a unique *nodeid* which is rooted at the ``rootdir`` and takes in account full path,
class name, function name and parametrization (if any).
a unique *nodeid* which is rooted at the ``rootdir`` and takes into account
the full path, class name, function name and parametrization (if any).
* Is used by plugins as a stable location to store project/test run specific information;
for example, the internal :ref:`cache <cache>` plugin creates a ``.pytest_cache`` subdirectory
in ``rootdir`` to store its cross-test run state.
Important to emphasize that ``rootdir`` is **NOT** used to modify ``sys.path``/``PYTHONPATH`` or
``rootdir`` is **NOT** used to modify ``sys.path``/``PYTHONPATH`` or
influence how modules are imported. See :ref:`pythonpath` for more details.
``--rootdir=path`` command-line option can be used to force a specific directory.
The ``--rootdir=path`` command-line option can be used to force a specific directory.
The directory passed may contain environment variables when it is used in conjunction
with ``addopts`` in a ``pytest.ini`` file.

View File

@@ -475,10 +475,10 @@ Running it results in some skips if we don't have all the python interpreters in
.. code-block:: pytest
. $ pytest -rs -q multipython.py
ssssssssssss...ssssssssssss [100%]
ssssssssssssssssssssssss... [100%]
========================= short test summary info ==========================
SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.5' not found
SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.7' not found
SKIPPED [12] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.6' not found
3 passed, 24 skipped in 0.12s
Indirect parametrization of optional implementations/imports
@@ -604,13 +604,13 @@ Then run ``pytest`` with verbose mode and with only the ``basic`` marker:
platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: $PYTHON_PREFIX/.pytest_cache
rootdir: $REGENDOC_TMPDIR
collecting ... collected 18 items / 15 deselected / 3 selected
collecting ... collected 17 items / 14 deselected / 3 selected
test_pytest_param_example.py::test_eval[1+7-8] PASSED [ 33%]
test_pytest_param_example.py::test_eval[basic_2+4] PASSED [ 66%]
test_pytest_param_example.py::test_eval[basic_6*9] XFAIL [100%]
=============== 2 passed, 15 deselected, 1 xfailed in 0.12s ================
=============== 2 passed, 14 deselected, 1 xfailed in 0.12s ================
As the result:

View File

@@ -1,16 +0,0 @@
import sys
import pytest
py3 = sys.version_info[0] >= 3
class DummyCollector(pytest.collect.File):
def collect(self):
return []
def pytest_pycollect_makemodule(path, parent):
bn = path.basename
if "py3" in bn and not py3 or ("py2" in bn and py3):
return DummyCollector(path, parent=parent)

View File

@@ -1,5 +0,0 @@
def test_exception_syntax():
try:
0 / 0
except ZeroDivisionError, e:
assert e

View File

@@ -1,5 +0,0 @@
def test_exception_syntax():
try:
0 / 0
except ZeroDivisionError as e:
assert e

View File

@@ -436,7 +436,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
items = [1, 2, 3]
print("items is {!r}".format(items))
> a, b = items.pop()
E TypeError: 'int' object is not iterable
E TypeError: cannot unpack non-iterable int object
failure_demo.py:181: TypeError
--------------------------- Captured stdout call ---------------------------
@@ -516,7 +516,7 @@ Here is a nice run of several failures and how ``pytest`` presents things:
def test_z2_type_error(self):
items = 3
> a, b = items
E TypeError: 'int' object is not iterable
E TypeError: cannot unpack non-iterable int object
failure_demo.py:222: TypeError
______________________ TestMoreErrors.test_startswith ______________________

View File

@@ -442,7 +442,7 @@ Now we can profile which test functions execute the slowest:
========================= slowest 3 test durations =========================
0.30s call test_some_are_slow.py::test_funcslow2
0.20s call test_some_are_slow.py::test_funcslow1
0.21s call test_some_are_slow.py::test_funcslow1
0.11s call test_some_are_slow.py::test_funcfast
============================ 3 passed in 0.12s =============================

View File

@@ -9,9 +9,9 @@ pytest fixtures: explicit, modular, scalable
.. _`xUnit`: http://en.wikipedia.org/wiki/XUnit
.. _`purpose of test fixtures`: http://en.wikipedia.org/wiki/Test_fixture#Software
.. _`Dependency injection`: http://en.wikipedia.org/wiki/Dependency_injection
.. _`xUnit`: https://en.wikipedia.org/wiki/XUnit
.. _`purpose of test fixtures`: https://en.wikipedia.org/wiki/Test_fixture#Software
.. _`Dependency injection`: https://en.wikipedia.org/wiki/Dependency_injection
The `purpose of test fixtures`_ is to provide a fixed baseline
upon which tests can reliably and repeatedly execute. pytest fixtures
@@ -1035,15 +1035,19 @@ file:
# content of conftest.py
import pytest
import tempfile
import os
import shutil
import tempfile
import pytest
@pytest.fixture()
def cleandir():
newpath = tempfile.mkdtemp()
os.chdir(newpath)
yield
shutil.rmtree(newpath)
and declare its use in a test module via a ``usefixtures`` marker:

View File

@@ -28,7 +28,7 @@ Install ``pytest``
.. code-block:: bash
$ pytest --version
This is pytest version 5.x.y, imported from $PYTHON_PREFIX/lib/python3.6/site-packages/pytest.py
This is pytest version 5.x.y, imported from $PYTHON_PREFIX/lib/python3.7/site-packages/pytest/__init__.py
.. _`simpletest`:

View File

@@ -111,7 +111,7 @@ More details can be found in the `original PR <https://github.com/pytest-dev/pyt
.. note::
in a future major relase of pytest we will introduce class based markers,
in a future major release of pytest we will introduce class based markers,
at which point markers will no longer be limited to instances of :py:class:`Mark`.

View File

@@ -92,7 +92,7 @@ It provide tools to raise money and share your finances in full transparency.
It is the platform of choice for individuals and companies that want to make one-time or
monthly donations directly to the project.
See more datails in the `pytest collective`_.
See more details in the `pytest collective`_.
.. _Open Collective: https://opencollective.com
.. _pytest collective: https://opencollective.com/pytest
@@ -112,7 +112,7 @@ Save time, reduce risk, and improve code health, while paying the maintainers of
Security
^^^^^^^^
pytest has never been associated with a security vunerability, but in any case, to report a
pytest has never been associated with a security vulnerability, but in any case, to report a
security vulnerability please use the `Tidelift security contact <https://tidelift.com/security>`_.
Tidelift will coordinate the fix and disclosure.
@@ -120,7 +120,7 @@ Tidelift will coordinate the fix and disclosure.
License
-------
Copyright Holger Krekel and others, 2004-2017.
Copyright Holger Krekel and others, 2004-2020.
Distributed under the terms of the `MIT`_ license, pytest is free and open source software.

View File

@@ -9,7 +9,7 @@ Distributed under the terms of the `MIT`_ license, pytest is free and open sourc
The MIT License (MIT)
Copyright (c) 2004-2019 Holger Krekel and others
Copyright (c) 2004-2020 Holger Krekel and others
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@@ -73,7 +73,6 @@ Some organisations using pytest
* `Square Kilometre Array, Cape Town <http://ska.ac.za/>`_
* `Some Mozilla QA people <http://www.theautomatedtester.co.uk/blog/2011/pytest_and_xdist_plugin.html>`_ use pytest to distribute their Selenium tests
* `Tandberg <http://www.tandberg.com/>`_
* `Shootq <http://web.shootq.com/>`_
* `Stups department of Heinrich Heine University Duesseldorf <http://www.stups.uni-duesseldorf.de/projects.php>`_
* cellzome

View File

@@ -1,31 +1,97 @@
Python 2.7 and 3.4 support plan
===============================
Python 2.7 and 3.4 support
==========================
Python 2.7 EOL is fast approaching, with
upstream support `ending in 2020 <https://legacy.python.org/dev/peps/pep-0373/#id4>`__.
Python 3.4's last release is scheduled for
`March 2019 <https://www.python.org/dev/peps/pep-0429/#release-schedule>`__. pytest is one of
the participating projects of the https://python3statement.org.
It is demanding on the maintainers of an open source project to support many Python versions, as
there's extra cost of keeping code compatible between all versions, while holding back on
features only made possible on newer Python versions.
The **pytest 4.6** series is the last to support Python 2.7 and 3.4, and was released in
**June 2019**. **pytest 5.0** and onwards will support only Python 3.5+.
In case of Python 2 and 3, the difference between the languages makes it even more prominent,
because many new Python 3 features cannot be used in a Python 2/3 compatible code base.
Thanks to the `python_requires`_ ``setuptools`` option,
Python 2.7 and Python 3.4 users using a modern ``pip`` version
will install the last pytest ``4.6`` version automatically even if ``5.0`` or later
Python 2.7 EOL has been reached `in 2020 <https://legacy.python.org/dev/peps/pep-0373/#id4>`__, with
the last release planned for mid-April, 2020.
Python 3.4 EOL has been reached `in 2019 <https://www.python.org/dev/peps/pep-0429/#release-schedule>`__, with the last release made in March, 2019.
For those reasons, in Jun 2019 it was decided that **pytest 4.6** series will be the last to support Python 2.7 and 3.4.
What this means for general users
---------------------------------
Thanks to the `python_requires`_ setuptools option,
Python 2.7 and Python 3.4 users using a modern pip version
will install the last pytest 4.6.X version automatically even if 5.0 or later versions
are available on PyPI.
While pytest ``5.0`` will be the new mainstream and development version, until **January 2020**
the pytest core team plans to make bug-fix releases of the pytest ``4.6`` series by
back-porting patches to the ``4.6-maintenance`` branch that affect Python 2 users.
Users should ensure they are using the latest pip and setuptools versions for this to work.
**After 2020**, the core team will no longer actively backport patches, but the ``4.6-maintenance``
branch will continue to exist so the community itself can contribute patches. The core team will
be happy to accept those patches and make new ``4.6`` releases **until mid-2020**.
Maintenance of 4.6.X versions
-----------------------------
Until January 2020, the pytest core team ported many bug-fixes from the main release into the
``4.6-maintenance`` branch, with several 4.6.X releases being made along the year.
From now on, the core team will **no longer actively backport patches**, but the ``4.6-maintenance``
branch will continue to exist so the community itself can contribute patches.
The core team will be happy to accept those patches, and make new 4.6.X releases **until mid-2020**
(but consider that date as a ballpark, after that date the team might still decide to make new releases
for critical bugs).
.. _`python_requires`: https://packaging.python.org/guides/distributing-packages-using-setuptools/#python-requires
Technical Aspects
-----------------
Technical aspects
~~~~~~~~~~~~~~~~~
The technical aspects of the Python 2.7 and 3.4 support plan (such as when releases will occurr, how to backport fixes, etc) is described in issue `#5275 <https://github.com/pytest-dev/pytest/issues/5275>`__.
(This section is a transcript from `#5275 <https://github.com/pytest-dev/pytest/issues/5275>`__).
In this section we describe the technical aspects of the Python 2.7 and 3.4 support plan.
What goes into 4.6.X releases
+++++++++++++++++++++++++++++
New 4.6.X releases will contain bug fixes only.
When will 4.6.X releases happen
+++++++++++++++++++++++++++++++
New 4.6.X releases will happen after we have a few bugs in place to release, or if a few weeks have
passed (say a single bug has been fixed a month after the latest 4.6.X release).
No hard rules here, just ballpark.
Who will handle applying bug fixes
++++++++++++++++++++++++++++++++++
We core maintainers expect that people still using Python 2.7/3.4 and being affected by
bugs to step up and provide patches and/or port bug fixes from the active branches.
We will be happy to guide users interested in doing so, so please don't hesitate to ask.
**Backporting changes into 4.6**
Please follow these instructions:
#. ``git fetch --all --prune``
#. ``git checkout origin/4.6-maintenance -b backport-XXXX`` # use the PR number here
#. Locate the merge commit on the PR, in the *merged* message, for example:
nicoddemus merged commit 0f8b462 into pytest-dev:features
#. ``git cherry-pick -m1 REVISION`` # use the revision you found above (``0f8b462``).
#. Open a PR targeting ``4.6-maintenance``:
* Prefix the message with ``[4.6]`` so it is an obvious backport
* Delete the PR body, it usually contains a duplicate commit message.
**Providing new PRs to 4.6**
Fresh pull requests to ``4.6-maintenance`` will be accepted provided that
the equivalent code in the active branches does not contain that bug (for example, a bug is specific
to Python 2 only).
Bug fixes that also happen in the mainstream version should be first fixed
there, and then backported as per instructions above.

View File

@@ -1,3 +1,5 @@
.. _`reference`:
API Reference
=============
@@ -360,7 +362,7 @@ capfd
def test_system_echo(capfd):
os.system('echo "hello"')
captured = capsys.readouterr()
captured = capfd.readouterr()
assert captured.out == "hello\n"
@@ -463,6 +465,8 @@ monkeypatch
.. autoclass:: _pytest.monkeypatch.MonkeyPatch
:members:
.. _testdir:
testdir
~~~~~~~
@@ -1215,6 +1219,15 @@ passed multiple times. The expected format is ``name=value``. For example::
a specific entry in the log. ``extra`` kwarg overrides the value specified
on the command line or in the config.
.. confval:: log_cli
Enable log display during test run (also known as :ref:`"live logging" <live_logs>`).
The default is ``False``.
.. code-block:: ini
[pytest]
log_cli = True
.. confval:: log_cli_date_format

View File

@@ -17,7 +17,7 @@ It provide tools to raise money and share your finances in full transparency.
It is the platform of choice for individuals and companies that want to make one-time or
monthly donations directly to the project.
See more datails in the `pytest collective`_.
See more details in the `pytest collective`_.
.. _Tidelift: https://tidelift.com

View File

@@ -64,7 +64,7 @@ Talks and blog postings
- `pytest introduction from Brian Okken (January 2013)
<http://pythontesting.net/framework/pytest-introduction/>`_
- 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 australia 2012 pytest talk from Brianna Laugher (`video <http://www.youtube.com/watch?v=DTNejE9EraI>`_, `slides <https://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)

View File

@@ -198,7 +198,7 @@ the regular expression ``".*U.*mode is deprecated"``.
Ensuring code triggers a deprecation warning
--------------------------------------------
You can also call a global helper for checking
You can also use :func:`pytest.deprecated_call` for checking
that a certain function call triggers a ``DeprecationWarning`` or
``PendingDeprecationWarning``:
@@ -207,13 +207,18 @@ that a certain function call triggers a ``DeprecationWarning`` or
import pytest
def test_global():
pytest.deprecated_call(myfunction, 17)
def test_myfunction_deprecated():
with pytest.deprecated_call():
myfunction(17)
This test will fail if ``myfunction`` does not issue a deprecation warning
when called with a ``17`` argument.
By default, ``DeprecationWarning`` and ``PendingDeprecationWarning`` will not be
caught when using ``pytest.warns`` or ``recwarn`` because default Python warnings filters hide
them. If you wish to record them in your own code, use the
command ``warnings.simplefilter('always')``:
caught when using :func:`pytest.warns` or :ref:`recwarn <recwarn>` because
the default Python warnings filters hide
them. If you wish to record them in your own code, use
``warnings.simplefilter('always')``:
.. code-block:: python
@@ -223,19 +228,13 @@ command ``warnings.simplefilter('always')``:
def test_deprecation(recwarn):
warnings.simplefilter("always")
warnings.warn("deprecated", DeprecationWarning)
myfunction(17)
assert len(recwarn) == 1
assert recwarn.pop(DeprecationWarning)
You can also use it as a contextmanager:
.. code-block:: python
def test_global():
with pytest.deprecated_call():
myobject.deprecated_method()
The :ref:`recwarn <recwarn>` fixture automatically ensures to reset the warnings
filter at the end of the test, so no global state is leaked.
.. _`asserting warnings`:

View File

@@ -10,7 +10,7 @@ build-backend = "setuptools.build_meta"
[tool.towncrier]
package = "pytest"
package_dir = "src"
filename = "CHANGELOG.rst"
filename = "doc/en/changelog.rst"
directory = "changelog/"
title_format = "pytest {version} ({project_date})"
template = "changelog/_template.rst"

View File

@@ -0,0 +1,36 @@
"""
Appends the codecov token to the 'codecov.yml' file at the root of the repository.
This is done by CI during PRs and builds on the pytest-dev repository so we can upload coverage, at least
until codecov grows some native integration like it has with Travis and AppVeyor.
See discussion in https://github.com/pytest-dev/pytest/pull/6441 for more information.
"""
import os.path
from textwrap import dedent
def main():
this_dir = os.path.dirname(__file__)
cov_file = os.path.join(this_dir, "..", "codecov.yml")
assert os.path.isfile(cov_file), "{cov_file} does not exist".format(
cov_file=cov_file
)
with open(cov_file, "a") as f:
# token from: https://codecov.io/gh/pytest-dev/pytest/settings
# use same URL to regenerate it if needed
text = dedent(
"""
codecov:
token: "1eca3b1f-31a2-4fb8-a8c3-138b441b50a7"
"""
)
f.write(text)
print("Token updated:", cov_file)
if __name__ == "__main__":
main()

View File

@@ -6,7 +6,13 @@ This script is meant to be executed after a successful deployment in Travis.
Uses the following environment variables:
* GIT_TAG: the name of the tag of the current commit.
* GH_RELEASE_NOTES_TOKEN: a personal access token with 'repo' permissions. It should be encrypted using:
* GH_RELEASE_NOTES_TOKEN: a personal access token with 'repo' permissions.
Create one at:
https://github.com/settings/tokens
It should be encrypted using:
$travis encrypt GH_RELEASE_NOTES_TOKEN=<token> -r pytest-dev/pytest
@@ -33,7 +39,7 @@ def publish_github_release(slug, token, tag_name, body):
def parse_changelog(tag_name):
p = Path(__file__).parent.parent / "CHANGELOG.rst"
p = Path(__file__).parent.parent / "doc/en/changelog.rst"
changelog_lines = p.read_text(encoding="UTF-8").splitlines()
title_regex = re.compile(r"pytest (\d\.\d+\.\d+) \(\d{4}-\d{2}-\d{2}\)")
@@ -62,19 +68,21 @@ def main(argv):
if len(argv) > 1:
tag_name = argv[1]
else:
tag_name = os.environ.get("TRAVIS_TAG")
tag_name = os.environ.get("GITHUB_REF")
if not tag_name:
print("tag_name not given and $TRAVIS_TAG not set", file=sys.stderr)
print("tag_name not given and $GITHUB_REF not set", file=sys.stderr)
return 1
if tag_name.startswith("refs/tags/"):
tag_name = tag_name[len("refs/tags/") :]
token = os.environ.get("GH_RELEASE_NOTES_TOKEN")
if not token:
print("GH_RELEASE_NOTES_TOKEN not set", file=sys.stderr)
return 1
slug = os.environ.get("TRAVIS_REPO_SLUG")
slug = os.environ.get("GITHUB_REPOSITORY")
if not slug:
print("TRAVIS_REPO_SLUG not set", file=sys.stderr)
print("GITHUB_REPOSITORY not set", file=sys.stderr)
return 1
rst_body = parse_changelog(tag_name)

View File

@@ -79,12 +79,20 @@ def fix_formatting():
call(["pre-commit", "run", "--all-files"])
def pre_release(version):
def check_links():
"""Runs sphinx-build to check links"""
print(f"{Fore.CYAN}[generate.check_links] {Fore.RESET}Checking links")
check_call(["tox", "-e", "docs-checklinks"])
def pre_release(version, *, skip_check_links):
"""Generates new docs, release announcements and creates a local tag."""
announce(version)
regen()
changelog(version, write_out=True)
fix_formatting()
if not skip_check_links:
check_links()
msg = "Preparing release version {}".format(version)
check_call(["git", "commit", "-a", "-m", msg])
@@ -107,8 +115,9 @@ def main():
init(autoreset=True)
parser = argparse.ArgumentParser()
parser.add_argument("version", help="Release version")
parser.add_argument("--skip-check-links", action="store_true", default=False)
options = parser.parse_args()
pre_release(options.version)
pre_release(options.version, skip_check_links=options.skip_check_links)
if __name__ == "__main__":

View File

@@ -38,8 +38,8 @@ packages =
_pytest.assertion
_pytest.config
_pytest.mark
pytest
py_modules = pytest
python_requires = >=3.5
[options.entry_points]

View File

@@ -29,7 +29,10 @@ def main():
"nose",
"requests",
"xmlschema",
]
],
"checkqa-mypy": [
"mypy==v0.761", # keep this in sync with .pre-commit-config.yaml.
],
},
install_requires=INSTALL_REQUIRES,
)

View File

@@ -32,8 +32,9 @@ import _pytest
from _pytest._io.saferepr import safeformat
from _pytest._io.saferepr import saferepr
from _pytest.compat import overload
from _pytest.compat import TYPE_CHECKING
if False: # TYPE_CHECKING
if TYPE_CHECKING:
from typing import Type
from typing_extensions import Literal
from weakref import ReferenceType # noqa: F401
@@ -479,7 +480,7 @@ class ExceptionInfo(Generic[_E]):
assert tup[1] is not None, "no current exception"
assert tup[2] is not None, "no current exception"
exc_info = (tup[0], tup[1], tup[2])
return cls.from_exc_info(exc_info, exprinfo)
return ExceptionInfo.from_exc_info(exc_info, exprinfo)
@classmethod
def for_later(cls) -> "ExceptionInfo[_E]":

View File

@@ -33,7 +33,7 @@ def pytest_addoption(parser):
)
def register_assert_rewrite(*names):
def register_assert_rewrite(*names) -> None:
"""Register one or more module names to be rewritten on import.
This function will make sure that this module or all modules inside

View File

@@ -143,10 +143,12 @@ class AssertionRewritingHook(importlib.abc.MetaPathFinder):
exec(co, module.__dict__)
def _early_rewrite_bailout(self, name, state):
"""This is a fast way to get out of rewriting modules. Profiling has
shown that the call to PathFinder.find_spec (inside of the find_spec
from this class) is a major slowdown, so, this method tries to
filter what we're sure won't be rewritten before getting to it.
"""This is a fast way to get out of rewriting modules.
Profiling has shown that the call to PathFinder.find_spec (inside of
the find_spec from this class) is a major slowdown, so, this method
tries to filter what we're sure won't be rewritten before getting to
it.
"""
if self.session is not None and not self._session_paths_checked:
self._session_paths_checked = True
@@ -799,13 +801,6 @@ class AssertionRewriter(ast.NodeVisitor):
self.push_format_context()
# Rewrite assert into a bunch of statements.
top_condition, explanation = self.visit(assert_.test)
# If in a test module, check if directly asserting None, in order to warn [Issue #3191]
if self.module_path is not None:
self.statements.append(
self.warn_about_none_ast(
top_condition, module_path=self.module_path, lineno=assert_.lineno
)
)
negation = ast.UnaryOp(ast.Not(), top_condition)
@@ -887,30 +882,6 @@ class AssertionRewriter(ast.NodeVisitor):
set_location(stmt, assert_.lineno, assert_.col_offset)
return self.statements
def warn_about_none_ast(self, node, module_path, lineno):
"""
Returns an AST issuing a warning if the value of node is `None`.
This is used to warn the user when asserting a function that asserts
internally already.
See issue #3191 for more details.
"""
val_is_none = ast.Compare(node, [ast.Is()], [ast.NameConstant(None)])
send_warning = ast.parse(
"""\
from _pytest.warning_types import PytestAssertRewriteWarning
from warnings import warn_explicit
warn_explicit(
PytestAssertRewriteWarning('asserting the value None, please use "assert is None"'),
category=None,
filename={filename!r},
lineno={lineno},
)
""".format(
filename=fspath(module_path), lineno=lineno
)
).body
return ast.If(val_is_none, send_warning, [])
def visit_Name(self, name):
# Display the repr of the name if it's a local variable or
# _should_repr_global_name() thinks it's acceptable.
@@ -1074,14 +1045,13 @@ def try_makedirs(cache_dir) -> bool:
def get_cache_dir(file_path: Path) -> Path:
"""Returns the cache directory to write .pyc files for the given .py file path"""
# Type ignored until added in next mypy release.
if sys.version_info >= (3, 8) and sys.pycache_prefix: # type: ignore
if sys.version_info >= (3, 8) and sys.pycache_prefix:
# given:
# prefix = '/tmp/pycs'
# path = '/home/user/proj/test_app.py'
# we want:
# '/tmp/pycs/home/user/proj'
return Path(sys.pycache_prefix) / Path(*file_path.parts[1:-1]) # type: ignore
return Path(sys.pycache_prefix) / Path(*file_path.parts[1:-1])
else:
# classic pycache directory
return file_path.parent / "__pycache__"

View File

@@ -44,14 +44,27 @@ class Cache:
_cachedir = attr.ib(repr=False)
_config = attr.ib(repr=False)
# sub-directory under cache-dir for directories created by "makedir"
_CACHE_PREFIX_DIRS = "d"
# sub-directory under cache-dir for values created by "set"
_CACHE_PREFIX_VALUES = "v"
@classmethod
def for_config(cls, config):
cachedir = cls.cache_dir_from_config(config)
if config.getoption("cacheclear") and cachedir.exists():
rm_rf(cachedir)
cachedir.mkdir()
if config.getoption("cacheclear") and cachedir.is_dir():
cls.clear_cache(cachedir)
return cls(cachedir, config)
@classmethod
def clear_cache(cls, cachedir: Path):
"""Clears the sub-directories used to hold cached directories and values."""
for prefix in (cls._CACHE_PREFIX_DIRS, cls._CACHE_PREFIX_VALUES):
d = cachedir / prefix
if d.is_dir():
rm_rf(d)
@staticmethod
def cache_dir_from_config(config):
return resolve_from_str(config.getini("cache_dir"), config.rootdir)
@@ -79,12 +92,12 @@ class Cache:
name = Path(name)
if len(name.parts) > 1:
raise ValueError("name is not allowed to contain path separators")
res = self._cachedir.joinpath("d", name)
res = self._cachedir.joinpath(self._CACHE_PREFIX_DIRS, name)
res.mkdir(exist_ok=True, parents=True)
return py.path.local(res)
def _getvaluepath(self, key):
return self._cachedir.joinpath("v", Path(key))
return self._cachedir.joinpath(self._CACHE_PREFIX_VALUES, Path(key))
def get(self, key, default):
""" return cached value for the given key. If no value
@@ -417,7 +430,7 @@ def cacheshow(config, session):
dummy = object()
basedir = config.cache._cachedir
vdir = basedir / "v"
vdir = basedir / Cache._CACHE_PREFIX_VALUES
tw.sep("-", "cache values for %r" % glob)
for valpath in sorted(x for x in vdir.rglob(glob) if x.is_file()):
key = valpath.relative_to(vdir)
@@ -429,7 +442,7 @@ def cacheshow(config, session):
for line in pformat(val).splitlines():
tw.line(" " + line)
ddir = basedir / "d"
ddir = basedir / Cache._CACHE_PREFIX_DIRS
if ddir.is_dir():
contents = sorted(ddir.rglob(glob))
tw.sep("-", "cache directories for %r" % glob)

View File

@@ -27,7 +27,13 @@ from _pytest._io.saferepr import saferepr
from _pytest.outcomes import fail
from _pytest.outcomes import TEST_OUTCOME
if False: # TYPE_CHECKING
if sys.version_info < (3, 5, 2):
TYPE_CHECKING = False # type: bool
else:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from typing import Type # noqa: F401 (used in type string)
@@ -43,8 +49,7 @@ MODULE_NOT_FOUND_ERROR = (
if sys.version_info >= (3, 8):
# Type ignored until next mypy release.
from importlib import metadata as importlib_metadata # type: ignore
from importlib import metadata as importlib_metadata
else:
import importlib_metadata # noqa: F401
@@ -372,7 +377,7 @@ class CaptureIO(io.TextIOWrapper):
return self.buffer.getvalue().decode("UTF-8")
if sys.version_info < (3, 5, 2): # pragma: no cover
if sys.version_info < (3, 5, 2):
def overload(f): # noqa: F811
return f
@@ -385,9 +390,7 @@ else:
if sys.version_info >= (3, 8):
# TODO: Remove type ignore on next mypy update.
# https://github.com/python/typeshed/commit/add0b5e930a1db16560fde45a3b710eefc625709
from functools import cached_property # type: ignore
from functools import cached_property
else:
class cached_property(Generic[_S, _T]):

View File

@@ -37,12 +37,13 @@ from .findpaths import exists
from _pytest._code import ExceptionInfo
from _pytest._code import filter_traceback
from _pytest.compat import importlib_metadata
from _pytest.compat import TYPE_CHECKING
from _pytest.outcomes import fail
from _pytest.outcomes import Skipped
from _pytest.pathlib import Path
from _pytest.warning_types import PytestConfigWarning
if False: # TYPE_CHECKING
if TYPE_CHECKING:
from typing import Type
@@ -630,16 +631,67 @@ notset = Notset()
def _iter_rewritable_modules(package_files):
"""
Given an iterable of file names in a source distribution, return the "names" that should
be marked for assertion rewrite (for example the package "pytest_mock/__init__.py" should
be added as "pytest_mock" in the assertion rewrite mechanism.
This function has to deal with dist-info based distributions and egg based distributions
(which are still very much in use for "editable" installs).
Here are the file names as seen in a dist-info based distribution:
pytest_mock/__init__.py
pytest_mock/_version.py
pytest_mock/plugin.py
pytest_mock.egg-info/PKG-INFO
Here are the file names as seen in an egg based distribution:
src/pytest_mock/__init__.py
src/pytest_mock/_version.py
src/pytest_mock/plugin.py
src/pytest_mock.egg-info/PKG-INFO
LICENSE
setup.py
We have to take in account those two distribution flavors in order to determine which
names should be considered for assertion rewriting.
More information:
https://github.com/pytest-dev/pytest-mock/issues/167
"""
package_files = list(package_files)
seen_some = False
for fn in package_files:
is_simple_module = "/" not in fn and fn.endswith(".py")
is_package = fn.count("/") == 1 and fn.endswith("__init__.py")
if is_simple_module:
module_name, _ = os.path.splitext(fn)
yield module_name
# we ignore "setup.py" at the root of the distribution
if module_name != "setup":
seen_some = True
yield module_name
elif is_package:
package_name = os.path.dirname(fn)
seen_some = True
yield package_name
if not seen_some:
# at this point we did not find any packages or modules suitable for assertion
# rewriting, so we try again by stripping the first path component (to account for
# "src" based source trees for example)
# this approach lets us have the common case continue to be fast, as egg-distributions
# are rarer
new_package_files = []
for fn in package_files:
parts = fn.split("/")
new_fn = "/".join(parts[1:])
if new_fn:
new_package_files.append(new_fn)
if new_package_files:
yield from _iter_rewritable_modules(new_package_files)
class Config:
"""
@@ -784,7 +836,7 @@ class Config:
@classmethod
def fromdictargs(cls, option_dict, args):
""" constructor useable for subprocesses. """
""" constructor usable for subprocesses. """
config = get_config(args)
config.option.__dict__.update(option_dict)
config.parse(args, addopts=False)

View File

@@ -5,9 +5,10 @@ from typing import Optional
import py
from .exceptions import UsageError
from _pytest.compat import TYPE_CHECKING
from _pytest.outcomes import fail
if False:
if TYPE_CHECKING:
from . import Config # noqa: F401
@@ -108,7 +109,7 @@ CFG_PYTEST_SECTION = "[pytest] section in {filename} files is no longer supporte
def determine_setup(
inifile: str,
inifile: Optional[str],
args: List[str],
rootdir_cmd_arg: Optional[str] = None,
config: Optional["Config"] = None,

View File

@@ -37,5 +37,6 @@ FIXTURE_POSITIONAL_ARGUMENTS = PytestDeprecationWarning(
JUNIT_XML_DEFAULT_FAMILY = PytestDeprecationWarning(
"The 'junit_family' default value will change to 'xunit2' in pytest 6.0.\n"
"Add 'junit_family=legacy' to your pytest.ini file to silence this warning and make your suite compatible."
"Add 'junit_family=xunit1' to your pytest.ini file to keep the current format "
"in future versions of pytest and silence this warning."
)

View File

@@ -19,12 +19,13 @@ from _pytest._code.code import ExceptionInfo
from _pytest._code.code import ReprFileLocation
from _pytest._code.code import TerminalRepr
from _pytest.compat import safe_getattr
from _pytest.compat import TYPE_CHECKING
from _pytest.fixtures import FixtureRequest
from _pytest.outcomes import Skipped
from _pytest.python_api import approx
from _pytest.warning_types import PytestWarning
if False: # TYPE_CHECKING
if TYPE_CHECKING:
import doctest
from typing import Type
@@ -435,7 +436,19 @@ class DoctestModule(pytest.Module):
https://bugs.python.org/issue25532
"""
def _find(self, tests, obj, name, module, source_lines, globs, seen):
def _find_lineno(self, obj, source_lines):
"""
Doctest code does not take into account `@property`, this is a hackish way to fix it.
https://bugs.python.org/issue17446
"""
if isinstance(obj, property):
obj = getattr(obj, "fget", obj)
return doctest.DocTestFinder._find_lineno(self, obj, source_lines)
def _find(
self, tests, obj, name, module, source_lines, globs, seen
) -> None:
if _is_mocked(obj):
return
with _patch_unwrap_mock_aware():

View File

@@ -27,12 +27,13 @@ from _pytest.compat import getlocation
from _pytest.compat import is_generator
from _pytest.compat import NOTSET
from _pytest.compat import safe_getattr
from _pytest.compat import TYPE_CHECKING
from _pytest.deprecated import FIXTURE_POSITIONAL_ARGUMENTS
from _pytest.deprecated import FUNCARGNAMES
from _pytest.outcomes import fail
from _pytest.outcomes import TEST_OUTCOME
if False: # TYPE_CHECKING
if TYPE_CHECKING:
from typing import Type
from _pytest import nodes
@@ -882,9 +883,7 @@ class FixtureDef:
self._finalizers = []
def execute(self, request):
# get required arguments and register our own finish()
# with their finalization
for argname in self.argnames:
for argname in self._dependee_fixture_argnames(request):
fixturedef = request._get_active_fixturedef(argname)
if argname != "request":
fixturedef.addfinalizer(functools.partial(self.finish, request=request))
@@ -907,6 +906,61 @@ class FixtureDef:
hook = self._fixturemanager.session.gethookproxy(request.node.fspath)
return hook.pytest_fixture_setup(fixturedef=self, request=request)
def _dependee_fixture_argnames(self, request):
"""A list of argnames for fixtures that this fixture depends on.
Given a request, this looks at the currently known list of fixture argnames, and
attempts to determine what slice of the list contains fixtures that it can know
should execute before it. This information is necessary so that this fixture can
know what fixtures to register its finalizer with to make sure that if they
would be torn down, they would tear down this fixture before themselves. It's
crucial for fixtures to be torn down in the inverse order that they were set up
in so that they don't try to clean up something that another fixture is still
depending on.
When autouse fixtures are involved, it can be tricky to figure out when fixtures
should be torn down. To solve this, this method leverages the ``fixturenames``
list provided by the ``request`` object, as this list is at least somewhat
sorted (in terms of the order fixtures are set up in) by the time this method is
reached. It's sorted enough that the starting point of fixtures that depend on
this one can be found using the ``self._parent_request`` stack.
If a request in the ``self._parent_request`` stack has a ``:class:FixtureDef``
associated with it, then that fixture is dependent on this one, so any fixture
names that appear in the list of fixture argnames that come after it can also be
ruled out. The argnames of all fixtures associated with a request in the
``self._parent_request`` stack are found, and the lowest index argname is
considered the earliest point in the list of fixture argnames where everything
from that point onward can be considered to execute after this fixture.
Everything before this point can be considered fixtures that this fixture
depends on, and so this fixture should register its finalizer with all of them
to ensure that if any of them are to be torn down, they will tear this fixture
down first.
This is the first part of the list of fixture argnames that is returned. The last
part of the list is everything in ``self.argnames`` as those are explicit
dependees of this fixture, so this fixture should definitely register its
finalizer with them.
"""
all_fix_names = request.fixturenames
try:
current_fix_index = all_fix_names.index(self.argname)
except ValueError:
current_fix_index = len(request.fixturenames)
parent_fixture_indexes = set()
parent_request = request._parent_request
while hasattr(parent_request, "_parent_request"):
if hasattr(parent_request, "_fixturedef"):
parent_fix_name = parent_request._fixturedef.argname
if parent_fix_name in all_fix_names:
parent_fixture_indexes.add(all_fix_names.index(parent_fix_name))
parent_request = parent_request._parent_request
stack_slice_index = min([current_fix_index, *parent_fixture_indexes])
active_fixture_argnames = all_fix_names[:stack_slice_index]
return {*active_fixture_argnames, *self.argnames}
def cache_key(self, request):
return request.param_index if not hasattr(request, "param") else request.param

View File

@@ -591,6 +591,8 @@ class LogXML:
if report.when == "call":
reporter.append_failure(report)
self.open_reports.append(report)
if not self.log_passing_tests:
reporter.write_captured_output(report)
else:
reporter.append_error(report)
elif report.skipped:

View File

@@ -212,11 +212,17 @@ def wrap_session(config, doit):
config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
session.exitstatus = exitstatus
except: # noqa
excinfo = _pytest._code.ExceptionInfo.from_current()
config.notify_exception(excinfo, config.option)
session.exitstatus = ExitCode.INTERNAL_ERROR
if excinfo.errisinstance(SystemExit):
sys.stderr.write("mainloop: caught unexpected SystemExit!\n")
excinfo = _pytest._code.ExceptionInfo.from_current()
try:
config.notify_exception(excinfo, config.option)
except exit.Exception as exc:
if exc.returncode is not None:
session.exitstatus = exc.returncode
sys.stderr.write("{}: {}\n".format(type(exc).__name__, exc))
else:
if excinfo.errisinstance(SystemExit):
sys.stderr.write("mainloop: caught unexpected SystemExit!\n")
finally:
excinfo = None # Explicitly break reference cycle.

View File

@@ -314,13 +314,18 @@ class MarkGenerator:
"{!r} not found in `markers` configuration option".format(name),
pytrace=False,
)
else:
warnings.warn(
"Unknown pytest.mark.%s - is this a typo? You can register "
"custom marks to avoid this warning - for details, see "
"https://docs.pytest.org/en/latest/mark.html" % name,
PytestUnknownMarkWarning,
)
# Raise a specific error for common misspellings of "parametrize".
if name in ["parameterize", "parametrise", "parameterise"]:
__tracebackhide__ = True
fail("Unknown '{}' mark, did you mean 'parametrize'?".format(name))
warnings.warn(
"Unknown pytest.mark.%s - is this a typo? You can register "
"custom marks to avoid this warning - for details, see "
"https://docs.pytest.org/en/latest/mark.html" % name,
PytestUnknownMarkWarning,
)
return MarkDecorator(Mark(name, (), {}))

View File

@@ -17,6 +17,7 @@ from _pytest._code.code import ExceptionInfo
from _pytest._code.code import ReprExceptionInfo
from _pytest.compat import cached_property
from _pytest.compat import getfslineno
from _pytest.compat import TYPE_CHECKING
from _pytest.config import Config
from _pytest.fixtures import FixtureDef
from _pytest.fixtures import FixtureLookupError
@@ -26,7 +27,7 @@ from _pytest.mark.structures import MarkDecorator
from _pytest.mark.structures import NodeKeywords
from _pytest.outcomes import Failed
if False: # TYPE_CHECKING
if TYPE_CHECKING:
# Imported here due to circular import.
from _pytest.main import Session # noqa: F401
@@ -49,7 +50,7 @@ def _splitnode(nodeid):
[]
['testing', 'code']
['testing', 'code', 'test_excinfo.py']
['testing', 'code', 'test_excinfo.py', 'TestFormattedExcinfo', '()']
['testing', 'code', 'test_excinfo.py', 'TestFormattedExcinfo']
"""
if nodeid == "":
# If there is no root node at all, return an empty list so the caller's logic can remain sane

View File

@@ -8,7 +8,9 @@ from typing import Optional
from packaging.version import Version
if False: # TYPE_CHECKING
TYPE_CHECKING = False # avoid circular import through compat
if TYPE_CHECKING:
from typing import NoReturn

View File

@@ -28,6 +28,7 @@ from _pytest._code import Source
from _pytest._io.saferepr import saferepr
from _pytest.capture import MultiCapture
from _pytest.capture import SysCapture
from _pytest.compat import TYPE_CHECKING
from _pytest.fixtures import FixtureRequest
from _pytest.main import ExitCode
from _pytest.main import Session
@@ -35,7 +36,7 @@ from _pytest.monkeypatch import MonkeyPatch
from _pytest.pathlib import Path
from _pytest.reports import TestReport
if False: # TYPE_CHECKING
if TYPE_CHECKING:
from typing import Type
@@ -189,7 +190,7 @@ class ParsedCall:
del d["_name"]
return "<ParsedCall {!r}(**{!r})>".format(self._name, d)
if False: # TYPE_CHECKING
if TYPE_CHECKING:
# The class has undetermined attributes, this tells mypy about it.
def __getattr__(self, key):
raise NotImplementedError()
@@ -433,9 +434,14 @@ class RunResult:
for line in reversed(self.outlines):
if rex_session_duration.search(line):
outcomes = rex_outcome.findall(line)
return {noun: int(count) for (count, noun) in outcomes}
raise ValueError("Pytest terminal summary report not found")
ret = {noun: int(count) for (count, noun) in outcomes}
break
else:
raise ValueError("Pytest terminal summary report not found")
if "errors" in ret:
assert "error" not in ret
ret["error"] = ret.pop("errors")
return ret
def assert_outcomes(
self,
@@ -827,7 +833,7 @@ class Testdir:
items = [x.item for x in rec.getcalls("pytest_itemcollected")]
return items, rec
def inline_run(self, *args, plugins=(), no_reraise_ctrlc=False):
def inline_run(self, *args, plugins=(), no_reraise_ctrlc: bool = False):
"""Run ``pytest.main()`` in-process, returning a HookRecorder.
Runs the :py:func:`pytest.main` function to run all of pytest inside
@@ -1438,8 +1444,10 @@ class LineMatcher:
self._log("{:>{width}}".format("and:", width=wnick), repr(nextline))
extralines.append(nextline)
else:
self._log("remains unmatched: {!r}".format(line))
pytest.fail(self._log_text.lstrip())
msg = "remains unmatched: {!r}".format(line)
self._log(msg)
self._fail(msg)
self._log_output = []
def no_fnmatch_line(self, pat):
"""Ensure captured lines do not match the given pattern, using ``fnmatch.fnmatch``.
@@ -1465,18 +1473,21 @@ class LineMatcher:
__tracebackhide__ = True
nomatch_printed = False
wnick = len(match_nickname) + 1
try:
for line in self.lines:
if match_func(line, pat):
self._log("%s:" % match_nickname, repr(pat))
self._log("{:>{width}}".format("with:", width=wnick), repr(line))
pytest.fail(self._log_text.lstrip())
else:
if not nomatch_printed:
self._log(
"{:>{width}}".format("nomatch:", width=wnick), repr(pat)
)
nomatch_printed = True
self._log("{:>{width}}".format("and:", width=wnick), repr(line))
finally:
self._log_output = []
for line in self.lines:
if match_func(line, pat):
msg = "{}: {!r}".format(match_nickname, pat)
self._log(msg)
self._log("{:>{width}}".format("with:", width=wnick), repr(line))
self._fail(msg)
else:
if not nomatch_printed:
self._log("{:>{width}}".format("nomatch:", width=wnick), repr(pat))
nomatch_printed = True
self._log("{:>{width}}".format("and:", width=wnick), repr(line))
self._log_output = []
def _fail(self, msg):
__tracebackhide__ = True
log_text = self._log_text
self._log_output = []
pytest.fail(log_text)

View File

@@ -6,6 +6,7 @@ import os
import sys
import warnings
from collections import Counter
from collections import defaultdict
from collections.abc import Sequence
from functools import partial
from textwrap import dedent
@@ -120,17 +121,7 @@ def pytest_cmdline_main(config):
return 0
def _validate_parametrize_spelling(metafunc):
"""Raise a specific error for common misspellings of "parametrize"."""
for mark_name in ["parameterize", "parametrise", "parameterise"]:
if metafunc.definition.get_closest_marker(mark_name):
msg = "{0} has '{1}' mark, spelling should be 'parametrize'"
fail(msg.format(metafunc.function.__name__, mark_name), pytrace=False)
def pytest_generate_tests(metafunc):
_validate_parametrize_spelling(metafunc)
for marker in metafunc.definition.iter_markers(name="parametrize"):
metafunc.parametrize(*marker.args, **marker.kwargs)
@@ -1200,14 +1191,23 @@ def idmaker(argnames, parametersets, idfn=None, ids=None, config=None, item=None
_idvalset(valindex, parameterset, argnames, idfn, ids, config=config, item=item)
for valindex, parameterset in enumerate(parametersets)
]
if len(set(ids)) != len(ids):
# The ids are not unique
duplicates = [testid for testid in ids if ids.count(testid) > 1]
counters = Counter()
for index, testid in enumerate(ids):
if testid in duplicates:
ids[index] = testid + str(counters[testid])
counters[testid] += 1
# All IDs must be unique!
unique_ids = set(ids)
if len(unique_ids) != len(ids):
# Record the number of occurrences of each test ID
test_id_counts = Counter(ids)
# Map the test ID to its next suffix
test_id_suffixes = defaultdict(int)
# Suffix non-unique IDs to make them unique
for index, test_id in enumerate(ids):
if test_id_counts[test_id] > 1:
ids[index] = "{}{}".format(test_id, test_id_suffixes[test_id])
test_id_suffixes[test_id] += 1
return ids

View File

@@ -23,9 +23,10 @@ from more_itertools.more import always_iterable
import _pytest._code
from _pytest.compat import overload
from _pytest.compat import STRING_TYPES
from _pytest.compat import TYPE_CHECKING
from _pytest.outcomes import fail
if False: # TYPE_CHECKING
if TYPE_CHECKING:
from typing import Type # noqa: F401 (used in type string)

View File

@@ -12,10 +12,11 @@ from typing import Tuple
from typing import Union
from _pytest.compat import overload
from _pytest.compat import TYPE_CHECKING
from _pytest.fixtures import yield_fixture
from _pytest.outcomes import fail
if False: # TYPE_CHECKING
if TYPE_CHECKING:
from typing import Type

View File

@@ -259,7 +259,7 @@ class TestReport(BaseReport):
)
@classmethod
def from_item_and_call(cls, item, call):
def from_item_and_call(cls, item, call) -> "TestReport":
"""
Factory method to create and fill a TestReport with standard item and call info.
"""
@@ -374,8 +374,11 @@ def _report_to_json(report):
]
return result
def serialize_repr_crash(reprcrash):
return reprcrash.__dict__.copy()
def serialize_repr_crash(reprcrash: Optional[ReprFileLocation]):
if reprcrash is not None:
return reprcrash.__dict__.copy()
else:
return None
def serialize_longrepr(rep):
result = {
@@ -455,8 +458,11 @@ def _report_kwargs_from_json(reportdict):
]
return ReprTraceback(**repr_traceback_dict)
def deserialize_repr_crash(repr_crash_dict):
return ReprFileLocation(**repr_crash_dict)
def deserialize_repr_crash(repr_crash_dict: Optional[dict]):
if repr_crash_dict is not None:
return ReprFileLocation(**repr_crash_dict)
else:
return None
if (
reportdict["longrepr"]

View File

@@ -15,12 +15,13 @@ from .reports import CollectErrorRepr
from .reports import CollectReport
from .reports import TestReport
from _pytest._code.code import ExceptionInfo
from _pytest.compat import TYPE_CHECKING
from _pytest.nodes import Node
from _pytest.outcomes import Exit
from _pytest.outcomes import Skipped
from _pytest.outcomes import TEST_OUTCOME
if False: # TYPE_CHECKING
if TYPE_CHECKING:
from typing import Type
#
@@ -121,7 +122,12 @@ def pytest_runtest_setup(item):
def pytest_runtest_call(item):
_update_current_test_var(item, "call")
sys.last_type, sys.last_value, sys.last_traceback = (None, None, None)
try:
del sys.last_type
del sys.last_value
del sys.last_traceback
except AttributeError:
pass
try:
item.runtest()
except Exception:
@@ -245,7 +251,7 @@ def pytest_runtest_makereport(item, call):
return TestReport.from_item_and_call(item, call)
def pytest_make_collect_report(collector):
def pytest_make_collect_report(collector) -> CollectReport:
call = CallInfo.from_call(lambda: list(collector.collect()), "collect")
longrepr = None
if not call.excinfo:

View File

@@ -833,8 +833,20 @@ class TerminalReporter:
msg = self._getfailureheadline(rep)
self.write_sep("_", msg, green=True, bold=True)
self._outrep_summary(rep)
self._handle_teardown_sections(rep.nodeid)
def print_teardown_sections(self, rep):
def _get_teardown_reports(self, nodeid: str) -> List[TestReport]:
return [
report
for report in self.getreports("")
if report.when == "teardown" and report.nodeid == nodeid
]
def _handle_teardown_sections(self, nodeid: str) -> None:
for report in self._get_teardown_reports(nodeid):
self.print_teardown_sections(report)
def print_teardown_sections(self, rep: TestReport) -> None:
showcapture = self.config.option.showcapture
if showcapture == "no":
return
@@ -858,17 +870,11 @@ class TerminalReporter:
line = self._getcrashline(rep)
self.write_line(line)
else:
teardown_sections = {}
for report in self.getreports(""):
if report.when == "teardown":
teardown_sections.setdefault(report.nodeid, []).append(report)
for rep in reports:
msg = self._getfailureheadline(rep)
self.write_sep("_", msg, red=True, bold=True)
self._outrep_summary(rep)
for report in teardown_sections.get(rep.nodeid, []):
self.print_teardown_sections(report)
self._handle_teardown_sections(rep.nodeid)
def summary_errors(self):
if self.config.option.tbstyle != "no":
@@ -1099,7 +1105,7 @@ def _get_main_color(stats) -> Tuple[str, List[str]]:
"failed passed skipped deselected xfailed xpassed warnings error".split()
)
unknown_type_seen = False
for found_type in stats:
for found_type in stats.keys():
if found_type not in known_types:
if found_type: # setup/teardown reports have an empty key, ignore them
known_types.append(found_type)

View File

@@ -4,8 +4,9 @@ from typing import TypeVar
import attr
from _pytest.compat import TYPE_CHECKING
if False: # TYPE_CHECKING
if TYPE_CHECKING:
from typing import Type # noqa: F401 (used in type string)

View File

@@ -4,6 +4,7 @@ pytest: unit and functional testing with Python.
"""
from _pytest import __version__
from _pytest.assertion import register_assert_rewrite
from _pytest.compat import _setup_collect_fakemodule
from _pytest.config import cmdline
from _pytest.config import hookimpl
from _pytest.config import hookspec
@@ -93,14 +94,6 @@ __all__ = [
"yield_fixture",
]
if __name__ == "__main__":
# if run as a script or by 'python -m pytest'
# we trigger the below "else" condition by the following import
import pytest
raise SystemExit(pytest.main())
else:
from _pytest.compat import _setup_collect_fakemodule
_setup_collect_fakemodule()
_setup_collect_fakemodule()
del _setup_collect_fakemodule

7
src/pytest/__main__.py Normal file
View File

@@ -0,0 +1,7 @@
"""
pytest entry point
"""
import pytest
if __name__ == "__main__":
raise SystemExit(pytest.main())

View File

@@ -606,7 +606,7 @@ class TestInvocationVariants:
def test_equivalence_pytest_pytest(self):
assert pytest.main == py.test.cmdline.main
def test_invoke_with_invalid_type(self, capsys):
def test_invoke_with_invalid_type(self):
with pytest.raises(
TypeError, match="expected to be a list or tuple of strings, got: '-h'"
):
@@ -617,7 +617,7 @@ class TestInvocationVariants:
assert retcode == ExitCode.NO_TESTS_COLLECTED
out, err = capsys.readouterr()
def test_invoke_plugin_api(self, testdir, capsys):
def test_invoke_plugin_api(self, capsys):
class MyPlugin:
def pytest_addoption(self, parser):
parser.addoption("--myopt")

View File

@@ -318,16 +318,12 @@ class TestSourceParsingAndCompiling:
@pytest.mark.parametrize("name", ["", None, "my"])
def test_compilefuncs_and_path_sanity(self, name: Optional[str]) -> None:
def check(comp, name):
def check(comp, name) -> None:
co = comp(self.source, name)
if not name:
expected = "codegen %s:%d>" % (mypath, mylineno + 2 + 2) # type: ignore
else:
expected = "codegen %r %s:%d>" % (
name,
mypath, # type: ignore
mylineno + 2 + 2, # type: ignore
) # type: ignore
expected = "codegen %r %s:%d>" % (name, mypath, mylineno + 2 + 2) # type: ignore
fn = co.co_filename
assert fn.endswith(expected)

View File

@@ -17,7 +17,7 @@ if sys.gettrace():
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_collection_modifyitems(config, items):
def pytest_collection_modifyitems(items):
"""Prefer faster tests.
Use a hookwrapper to do this in the beginning, so e.g. --ff still works

View File

@@ -626,7 +626,7 @@ def test_log_cli_ini_level(testdir):
"cli_args",
["", "--log-level=WARNING", "--log-file-level=WARNING", "--log-cli-level=WARNING"],
)
def test_log_cli_auto_enable(testdir, request, cli_args):
def test_log_cli_auto_enable(testdir, cli_args):
"""Check that live logs are enabled if --log-level or --log-cli-level is passed on the CLI.
It should not be auto enabled if the same configs are set on the INI file.
"""

View File

@@ -286,7 +286,7 @@ class TestFunction:
return pytest.Function(config=config, parent=session, **kwargs)
def test_function_equality(self, testdir, tmpdir):
def test_function_equality(self, testdir):
def func1():
pass
@@ -492,7 +492,7 @@ class TestFunction:
)
assert "foo" in keywords[1] and "bar" in keywords[1] and "baz" in keywords[1]
def test_function_equality_with_callspec(self, testdir, tmpdir):
def test_function_equality_with_callspec(self, testdir):
items = testdir.getitems(
"""
import pytest
@@ -509,11 +509,11 @@ class TestFunction:
config = item.config
class MyPlugin1:
def pytest_pyfunc_call(self, pyfuncitem):
def pytest_pyfunc_call(self):
raise ValueError
class MyPlugin2:
def pytest_pyfunc_call(self, pyfuncitem):
def pytest_pyfunc_call(self):
return True
config.pluginmanager.register(MyPlugin1())
@@ -1015,7 +1015,7 @@ class TestTracebackCutting:
class TestReportInfo:
def test_itemreport_reportinfo(self, testdir, linecomp):
def test_itemreport_reportinfo(self, testdir):
testdir.makeconftest(
"""
import pytest

View File

@@ -1716,6 +1716,138 @@ class TestAutouseDiscovery:
reprec.assertoutcome(passed=3)
class TestMultiLevelAutouseAndParameterization:
def test_setup_and_teardown_order(self, testdir):
"""Tests that parameterized fixtures effect subsequent fixtures. (#6436)
If a fixture uses a parameterized fixture, or, for any other reason, is executed
after the parameterized fixture in the fixture stack, then it should be affected
by the parameterization, and as a result, should be torn down before the
parameterized fixture, every time the parameterized fixture is torn down. This
should be the case even if autouse is involved and/or the linear order of
fixture execution isn't deterministic. In other words, before any fixture can be
torn down, every fixture that was executed after it must also be torn down.
"""
testdir.makepyfile(
test_auto="""
import pytest
def f(param):
return param
@pytest.fixture(scope="session", autouse=True)
def s_fix(request):
yield
@pytest.fixture(scope="package", params=["p1", "p2"], ids=f, autouse=True)
def p_fix(request):
yield
@pytest.fixture(scope="module", params=["m1", "m2"], ids=f, autouse=True)
def m_fix(request):
yield
@pytest.fixture(scope="class", autouse=True)
def another_c_fix(m_fix):
yield
@pytest.fixture(scope="class")
def c_fix():
yield
@pytest.fixture(scope="function", params=["f1", "f2"], ids=f, autouse=True)
def f_fix(request):
yield
class TestFixtures:
def test_a(self, c_fix):
pass
def test_b(self, c_fix):
pass
"""
)
result = testdir.runpytest("--setup-plan")
test_fixtures_used = (
"(fixtures used: another_c_fix, c_fix, f_fix, m_fix, p_fix, request, s_fix)"
)
result.stdout.fnmatch_lines(
"""
SETUP S s_fix
SETUP P p_fix[p1]
SETUP M m_fix[m1]
SETUP C another_c_fix (fixtures used: m_fix)
SETUP C c_fix
SETUP F f_fix[f1]
test_auto.py::TestFixtures::test_a[p1-m1-f1] {0}
TEARDOWN F f_fix[f1]
SETUP F f_fix[f2]
test_auto.py::TestFixtures::test_a[p1-m1-f2] {0}
TEARDOWN F f_fix[f2]
SETUP F f_fix[f1]
test_auto.py::TestFixtures::test_b[p1-m1-f1] {0}
TEARDOWN F f_fix[f1]
SETUP F f_fix[f2]
test_auto.py::TestFixtures::test_b[p1-m1-f2] {0}
TEARDOWN F f_fix[f2]
TEARDOWN C c_fix
TEARDOWN C another_c_fix
TEARDOWN M m_fix[m1]
SETUP M m_fix[m2]
SETUP C another_c_fix (fixtures used: m_fix)
SETUP C c_fix
SETUP F f_fix[f1]
test_auto.py::TestFixtures::test_a[p1-m2-f1] {0}
TEARDOWN F f_fix[f1]
SETUP F f_fix[f2]
test_auto.py::TestFixtures::test_a[p1-m2-f2] {0}
TEARDOWN F f_fix[f2]
SETUP F f_fix[f1]
test_auto.py::TestFixtures::test_b[p1-m2-f1] {0}
TEARDOWN F f_fix[f1]
SETUP F f_fix[f2]
test_auto.py::TestFixtures::test_b[p1-m2-f2] {0}
TEARDOWN F f_fix[f2]
TEARDOWN C c_fix
TEARDOWN C another_c_fix
TEARDOWN M m_fix[m2]
TEARDOWN P p_fix[p1]
SETUP P p_fix[p2]
SETUP M m_fix[m1]
SETUP C another_c_fix (fixtures used: m_fix)
SETUP C c_fix
SETUP F f_fix[f1]
test_auto.py::TestFixtures::test_a[p2-m1-f1] {0}
TEARDOWN F f_fix[f1]
SETUP F f_fix[f2]
test_auto.py::TestFixtures::test_a[p2-m1-f2] {0}
TEARDOWN F f_fix[f2]
SETUP F f_fix[f1]
test_auto.py::TestFixtures::test_b[p2-m1-f1] {0}
TEARDOWN F f_fix[f1]
SETUP F f_fix[f2]
test_auto.py::TestFixtures::test_b[p2-m1-f2] {0}
TEARDOWN F f_fix[f2]
TEARDOWN C c_fix
TEARDOWN C another_c_fix
TEARDOWN M m_fix[m1]
SETUP M m_fix[m2]
SETUP C another_c_fix (fixtures used: m_fix)
SETUP C c_fix
SETUP F f_fix[f1]
test_auto.py::TestFixtures::test_a[p2-m2-f1] {0}
TEARDOWN F f_fix[f1]
SETUP F f_fix[f2]
test_auto.py::TestFixtures::test_a[p2-m2-f2] {0}
TEARDOWN F f_fix[f2]
SETUP F f_fix[f1]
test_auto.py::TestFixtures::test_b[p2-m2-f1] {0}
TEARDOWN F f_fix[f1]
SETUP F f_fix[f2]
test_auto.py::TestFixtures::test_b[p2-m2-f2] {0}
TEARDOWN F f_fix[f2]
TEARDOWN C c_fix
TEARDOWN C another_c_fix
TEARDOWN M m_fix[m2]
TEARDOWN P p_fix[p2]
TEARDOWN S s_fix
""".format(
test_fixtures_used
)
)
class TestAutouseManagement:
def test_autouse_conftest_mid_directory(self, testdir):
pkgdir = testdir.mkpydir("xyz123")
@@ -4106,7 +4238,7 @@ def test_fixture_named_request(testdir):
)
def test_fixture_duplicated_arguments(testdir):
def test_fixture_duplicated_arguments():
"""Raise error if there are positional and keyword arguments for the same parameter (#1682)."""
with pytest.raises(TypeError) as excinfo:
@@ -4121,7 +4253,7 @@ def test_fixture_duplicated_arguments(testdir):
)
def test_fixture_with_positionals(testdir):
def test_fixture_with_positionals():
"""Raise warning, but the positionals should still works (#1682)."""
from _pytest.deprecated import FIXTURE_POSITIONAL_ARGUMENTS

View File

@@ -31,7 +31,7 @@ class TestMetafunc:
definition = DefinitionMock(func)
return python.Metafunc(definition, fixtureinfo, config)
def test_no_funcargs(self, testdir):
def test_no_funcargs(self):
def function():
pass
@@ -61,7 +61,7 @@ class TestMetafunc:
pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5, 6]))
pytest.raises(ValueError, lambda: metafunc.parametrize("y", [5, 6]))
def test_parametrize_bad_scope(self, testdir):
def test_parametrize_bad_scope(self):
def func(x):
pass
@@ -153,7 +153,7 @@ class TestMetafunc:
ids = [x.id for x in metafunc._calls]
assert ids == ["basic", "advanced"]
def test_parametrize_with_wrong_number_of_ids(self, testdir):
def test_parametrize_with_wrong_number_of_ids(self):
def func(x, y):
pass
@@ -652,7 +652,7 @@ class TestMetafunc:
result = testdir.runpytest("-v")
result.stdout.fnmatch_lines(["*test_simple*a-b*", "*1 passed*"])
def test_parametrize_indirect_list_error(self, testdir):
def test_parametrize_indirect_list_error(self):
"""#714"""
def func(x, y):
@@ -1323,25 +1323,29 @@ class TestMetafuncFunctional:
reprec = testdir.runpytest()
reprec.assert_outcomes(passed=4)
@pytest.mark.parametrize("attr", ["parametrise", "parameterize", "parameterise"])
def test_parametrize_misspelling(self, testdir, attr):
def test_parametrize_misspelling(self, testdir):
"""#463"""
testdir.makepyfile(
"""
import pytest
@pytest.mark.{}("x", range(2))
@pytest.mark.parametrise("x", range(2))
def test_foo(x):
pass
""".format(
attr
)
"""
)
result = testdir.runpytest("--collectonly")
result.stdout.fnmatch_lines(
[
"test_foo has '{}' mark, spelling should be 'parametrize'".format(attr),
"*1 error in*",
"collected 0 items / 1 error",
"",
"*= ERRORS =*",
"*_ ERROR collecting test_parametrize_misspelling.py _*",
"test_parametrize_misspelling.py:3: in <module>",
' @pytest.mark.parametrise("x", range(2))',
"E Failed: Unknown 'parametrise' mark, did you mean 'parametrize'?",
"*! Interrupted: 1 error during collection !*",
"*= 1 error in *",
]
)

View File

@@ -166,7 +166,7 @@ class TestRaises:
# Early versions of Python 3.5 have some bug causing the
# __call__ frame to still refer to t even after everything
# is done. This makes the test pass for them.
if sys.version_info < (3, 5, 2): # pragma: no cover
if sys.version_info < (3, 5, 2):
del self
raise ValueError

View File

@@ -1299,7 +1299,7 @@ def test_AssertionError_message(testdir):
)
def test_diff_newline_at_end(monkeypatch, testdir):
def test_diff_newline_at_end(testdir):
testdir.makepyfile(
r"""
def test_diff():
@@ -1354,7 +1354,7 @@ def test_assert_indirect_tuple_no_warning(testdir):
assert "WR1" not in output
def test_assert_with_unicode(monkeypatch, testdir):
def test_assert_with_unicode(testdir):
testdir.makepyfile(
"""\
def test_unicode():

View File

@@ -270,6 +270,7 @@ class TestLastFailed:
)
result = testdir.runpytest(str(p), "--lf", "--cache-clear")
result.stdout.fnmatch_lines(["*1 failed*2 passed*"])
assert testdir.tmpdir.join(".pytest_cache", "README.md").isfile()
# Run this again to make sure clear-cache is robust
if os.path.isdir(".pytest_cache"):

View File

@@ -937,7 +937,7 @@ class TestFDCapture:
cap.done()
assert s == "hello\n"
def test_stdin(self, tmpfile):
def test_stdin(self):
cap = capture.FDCapture(0)
cap.start()
x = os.read(0, 100).strip()
@@ -958,7 +958,7 @@ class TestFDCapture:
stmp = stmp_file.read()
assert stmp == data2
def test_simple_resume_suspend(self, tmpfile):
def test_simple_resume_suspend(self):
with saved_fd(1):
cap = capture.FDCapture(1)
cap.start()

View File

@@ -243,7 +243,7 @@ class TestCollectPluginHookRelay:
wascalled = []
class Plugin:
def pytest_collect_file(self, path, parent):
def pytest_collect_file(self, path):
if not path.basename.startswith("."):
# Ignore hidden files, e.g. .testmondata.
wascalled.append(path)
@@ -257,7 +257,7 @@ class TestCollectPluginHookRelay:
wascalled = []
class Plugin:
def pytest_collect_directory(self, path, parent):
def pytest_collect_directory(self, path):
wascalled.append(path.basename)
testdir.mkdir("hello")
@@ -1173,7 +1173,7 @@ def test_collect_symlink_out_of_tree(testdir):
assert result.ret == 0
def test_collectignore_via_conftest(testdir, monkeypatch):
def test_collectignore_via_conftest(testdir):
"""collect_ignore in parent conftest skips importing child (issue #4592)."""
tests = testdir.mkpydir("tests")
tests.ensure("conftest.py").write("collect_ignore = ['ignore_me']")

View File

@@ -146,12 +146,16 @@ def test_is_generator_async_gen_syntax(testdir):
class ErrorsHelper:
@property
def raise_baseexception(self):
raise BaseException("base exception should be raised")
@property
def raise_exception(self):
raise Exception("exception should be catched")
@property
def raise_fail(self):
def raise_fail_outcome(self):
pytest.fail("fail should be catched")
@@ -160,13 +164,15 @@ def test_helper_failures():
with pytest.raises(Exception):
helper.raise_exception
with pytest.raises(OutcomeException):
helper.raise_fail
helper.raise_fail_outcome
def test_safe_getattr():
helper = ErrorsHelper()
assert safe_getattr(helper, "raise_exception", "default") == "default"
assert safe_getattr(helper, "raise_fail", "default") == "default"
assert safe_getattr(helper, "raise_fail_outcome", "default") == "default"
with pytest.raises(BaseException):
assert safe_getattr(helper, "raise_baseexception", "default")
def test_safe_isclass():

View File

@@ -422,15 +422,21 @@ class TestConfigAPI:
@pytest.mark.parametrize(
"names, expected",
[
# dist-info based distributions root are files as will be put in PYTHONPATH
(["bar.py"], ["bar"]),
(["foo", "bar.py"], []),
(["foo", "bar.pyc"], []),
(["foo", "__init__.py"], ["foo"]),
(["foo", "bar", "__init__.py"], []),
(["foo/bar.py"], ["bar"]),
(["foo/bar.pyc"], []),
(["foo/__init__.py"], ["foo"]),
(["bar/__init__.py", "xz.py"], ["bar", "xz"]),
(["setup.py"], []),
# egg based distributions root contain the files from the dist root
(["src/bar/__init__.py"], ["bar"]),
(["src/bar/__init__.py", "setup.py"], ["bar"]),
(["source/python/bar/__init__.py", "setup.py"], ["bar"]),
],
)
def test_iter_rewritable_modules(self, names, expected):
assert list(_iter_rewritable_modules(["/".join(names)])) == expected
assert list(_iter_rewritable_modules(names)) == expected
class TestConfigFromdictargs:
@@ -853,7 +859,7 @@ class TestRootdir:
assert get_common_ancestor([no_path.join("a")]) == tmpdir
@pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split())
def test_with_ini(self, tmpdir, name):
def test_with_ini(self, tmpdir, name) -> None:
inifile = tmpdir.join(name)
inifile.write("[pytest]\n" if name != "setup.cfg" else "[tool:pytest]\n")
@@ -868,7 +874,7 @@ class TestRootdir:
assert inifile == inifile
@pytest.mark.parametrize("name", "setup.cfg tox.ini".split())
def test_pytestini_overrides_empty_other(self, tmpdir, name):
def test_pytestini_overrides_empty_other(self, tmpdir, name) -> None:
inifile = tmpdir.ensure("pytest.ini")
a = tmpdir.mkdir("a")
a.ensure(name)
@@ -876,7 +882,7 @@ class TestRootdir:
assert rootdir == tmpdir
assert inifile == inifile
def test_setuppy_fallback(self, tmpdir):
def test_setuppy_fallback(self, tmpdir) -> None:
a = tmpdir.mkdir("a")
a.ensure("setup.cfg")
tmpdir.ensure("setup.py")
@@ -885,14 +891,14 @@ class TestRootdir:
assert inifile is None
assert inicfg == {}
def test_nothing(self, tmpdir, monkeypatch):
def test_nothing(self, tmpdir, monkeypatch) -> None:
monkeypatch.chdir(str(tmpdir))
rootdir, inifile, inicfg = determine_setup(None, [tmpdir])
assert rootdir == tmpdir
assert inifile is None
assert inicfg == {}
def test_with_specific_inifile(self, tmpdir):
def test_with_specific_inifile(self, tmpdir) -> None:
inifile = tmpdir.ensure("pytest.ini")
rootdir, inifile, inicfg = determine_setup(inifile, [tmpdir])
assert rootdir == tmpdir
@@ -1033,7 +1039,7 @@ class TestOverrideIniArgs:
result = testdir.runpytest("--override-ini", "python_files=unittest_*.py")
result.stdout.fnmatch_lines(["*1 passed in*"])
def test_with_arg_outside_cwd_without_inifile(self, tmpdir, monkeypatch):
def test_with_arg_outside_cwd_without_inifile(self, tmpdir, monkeypatch) -> None:
monkeypatch.chdir(str(tmpdir))
a = tmpdir.mkdir("a")
b = tmpdir.mkdir("b")
@@ -1041,7 +1047,7 @@ class TestOverrideIniArgs:
assert rootdir == tmpdir
assert inifile is None
def test_with_arg_outside_cwd_with_inifile(self, tmpdir):
def test_with_arg_outside_cwd_with_inifile(self, tmpdir) -> None:
a = tmpdir.mkdir("a")
b = tmpdir.mkdir("b")
inifile = a.ensure("pytest.ini")
@@ -1050,13 +1056,13 @@ class TestOverrideIniArgs:
assert inifile == parsed_inifile
@pytest.mark.parametrize("dirs", ([], ["does-not-exist"], ["a/does-not-exist"]))
def test_with_non_dir_arg(self, dirs, tmpdir):
def test_with_non_dir_arg(self, dirs, tmpdir) -> None:
with tmpdir.ensure(dir=True).as_cwd():
rootdir, inifile, inicfg = determine_setup(None, dirs)
assert rootdir == tmpdir
assert inifile is None
def test_with_existing_file_in_subdir(self, tmpdir):
def test_with_existing_file_in_subdir(self, tmpdir) -> None:
a = tmpdir.mkdir("a")
a.ensure("exist")
with tmpdir.as_cwd():

View File

@@ -357,7 +357,7 @@ def test_conftest_import_order(testdir, monkeypatch):
assert conftest._getconftestmodules(sub) == [ct1, ct2]
def test_fixture_dependency(testdir, monkeypatch):
def test_fixture_dependency(testdir):
ct1 = testdir.makeconftest("")
ct1 = testdir.makepyfile("__init__.py")
ct1.write("")

View File

@@ -287,13 +287,68 @@ class TestDoctests:
)
)
result = testdir.runpytest("--doctest-modules")
result.stdout.fnmatch_lines(
["*hello*", "006*>>> 1/0*", "*UNEXPECTED*ZeroDivision*", "*1 failed*"]
)
def test_doctest_linedata_on_property(self, testdir):
testdir.makepyfile(
"""
class Sample(object):
@property
def some_property(self):
'''
>>> Sample().some_property
'another thing'
'''
return 'something'
"""
)
result = testdir.runpytest("--doctest-modules")
result.stdout.fnmatch_lines(
[
"*hello*",
"*EXAMPLE LOCATION UNKNOWN, not showing all tests of that example*",
"*1/0*",
"*UNEXPECTED*ZeroDivision*",
"*1 failed*",
"*= FAILURES =*",
"*_ [[]doctest[]] test_doctest_linedata_on_property.Sample.some_property _*",
"004 ",
"005 >>> Sample().some_property",
"Expected:",
" 'another thing'",
"Got:",
" 'something'",
"",
"*/test_doctest_linedata_on_property.py:5: DocTestFailure",
"*= 1 failed in *",
]
)
def test_doctest_no_linedata_on_overriden_property(self, testdir):
testdir.makepyfile(
"""
class Sample(object):
@property
def some_property(self):
'''
>>> Sample().some_property
'another thing'
'''
return 'something'
some_property = property(some_property.__get__, None, None, some_property.__doc__)
"""
)
result = testdir.runpytest("--doctest-modules")
result.stdout.fnmatch_lines(
[
"*= FAILURES =*",
"*_ [[]doctest[]] test_doctest_no_linedata_on_overriden_property.Sample.some_property _*",
"EXAMPLE LOCATION UNKNOWN, not showing all tests of that example",
"[?][?][?] >>> Sample().some_property",
"Expected:",
" 'another thing'",
"Got:",
" 'something'",
"",
"*/test_doctest_no_linedata_on_overriden_property.py:None: DocTestFailure",
"*= 1 failed in *",
]
)

View File

@@ -82,7 +82,7 @@ def test_timeout(testdir, enabled):
@pytest.mark.parametrize("hook_name", ["pytest_enter_pdb", "pytest_exception_interact"])
def test_cancel_timeout_on_hook(monkeypatch, pytestconfig, hook_name):
def test_cancel_timeout_on_hook(monkeypatch, hook_name):
"""Make sure that we are cancelling any scheduled traceback dumping due
to timeout before entering pdb (pytest-dev/pytest-faulthandler#12) or any other interactive
exception (pytest-dev/pytest-faulthandler#14).

View File

@@ -57,7 +57,7 @@ def test_traceconfig(testdir):
result.stdout.fnmatch_lines(["*using*pytest*py*", "*active plugins*"])
def test_debug(testdir, monkeypatch):
def test_debug(testdir):
result = testdir.runpytest_subprocess("--debug")
assert result.ret == ExitCode.NO_TESTS_COLLECTED
p = testdir.tmpdir.join("pytestdebug.log")

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