Compare commits

...

546 Commits
3.8.1 ... 4.0.0

Author SHA1 Message Date
Bruno Oliveira
c2d6b3524c Preparing release version 4.0.0 2018-11-13 21:01:51 +00:00
Bruno Oliveira
e025974cbd Merge remote-tracking branch 'upstream/master' into release-4.0.0 2018-11-13 20:58:24 +00:00
Bruno Oliveira
fea09cda6c Merge pull request #4383 from nicoddemus/merge-master-into-features
Merge master into features (about to prepare 4.0)
2018-11-13 18:57:41 -02:00
Daniel Hahler
b7863a5f48 Merge pull request #4381 from blueyed/callinfo-repr
Fix CallInfo.__repr__ for unfinished call
2018-11-13 18:13:58 +01:00
Daniel Hahler
a72eff5a08 Merge pull request #4382 from blueyed/pytester-pop-TOX_ENV_DIR
pytester: pop TOX_ENV_DIR from os.environ
2018-11-13 12:42:51 +01:00
Daniel Hahler
46c8363e12 Merge pull request #4380 from blueyed/improve-ci
Travis: move faster builds to baseline
2018-11-13 12:40:26 +01:00
Bruno Oliveira
557cb6cffe Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2018-11-13 09:01:37 -02:00
Bruno Oliveira
8198e7cd33 Merge pull request #4349 from nicoddemus/pytest4-warnings-as-errors
Change RemovedInPytest4Warnings to errors by default
2018-11-13 08:31:47 -02:00
Daniel Hahler
a6a96469ca pytester: pop TOX_ENV_DIR from os.environ
Closes: https://github.com/pytest-dev/pytest/pull/4378
Fixes: https://github.com/pytest-dev/pytest/issues/4366
2018-11-13 09:02:52 +01:00
Daniel Hahler
27dab4e05f Fix CallInfo.__repr__ for unfinished call
Fixes https://github.com/pytest-dev/pytest/issues/3554
Ref: https://github.com/pytest-dev/pytest/pull/3560
Ref: https://github.com/pytest-dev/pytest/pull/3562
2018-11-13 08:51:43 +01:00
Daniel Hahler
3e05848ab9 AppVeyor: run py{27,37}-xdist first 2018-11-13 01:33:05 +01:00
Daniel Hahler
5902e5a2ce Travis: move faster builds to baseline
- use py27-pexpect,py27-trial,py27-numpy and py37-xdist in baseline,
  using pexpect there catches errors with pdb tests early, and
  py37-xdist is much faster than py37.
- move py34 and py36 out of baseline.
2018-11-13 01:26:22 +01:00
Bruno Oliveira
243d898b38 Merge pull request #4373 from blueyed/py37-by-default
CI: use py37 instead of py36 by default
2018-11-12 20:56:10 -02:00
Bruno Oliveira
f8f22d29ee Use a custom cache directory for test_stepwise tests
Otherwise the tests will use tox's env cache which makes them flaky
2018-11-12 16:57:39 -02:00
Bruno Oliveira
dc20dedbc7 Change RemovedInPytest4Warnings to errors by default
To keep existing tests which emit RemovedInPytest4Warnings running, decided
to go with a command line option because:

* Is harder to integrate an ini option with tests which already use an ini file
* It also marks tests which need to be removed/updated in 4.1, when
  RemovedInPytest4Warning and related functionality are removed.

Fix #3737
2018-11-12 16:10:57 -02:00
Bruno Oliveira
3cec1482eb Merge branch 'master' into py37-by-default 2018-11-12 14:03:59 -02:00
Bruno Oliveira
0df5ce4082 Fix basepython for linting testenv in tox.ini 2018-11-12 14:03:04 -02:00
Bruno Oliveira
93a9836962 Merge pull request #4374 from blueyed/doctesting
CI: doctesting uses coverage, fiy py37 on AppVeyor
2018-11-12 13:57:58 -02:00
Daniel Hahler
935b106213 CI: use py37 instead of py36 by default
Closes https://github.com/pytest-dev/pytest/issues/4370.
2018-11-12 03:16:52 +01:00
Daniel Hahler
74366426b9 Travis: use last TOXENV for PATH 2018-11-11 22:08:45 +01:00
Daniel Hahler
9628242423 CI: doctesting uses coverage, fiy py37 on AppVeyor 2018-11-11 21:49:59 +01:00
Bruno Oliveira
9af613bef2 Merge pull request #4372 from nicoddemus/release-3.10.1
Release version 3.10.1
2018-11-11 15:35:21 -02:00
Bruno Oliveira
7b833ce5f9 Merge pull request #4368 from blueyed/toxenv-coverage
Travis: use coverage from existing tox env  [skip appveyor]
2018-11-11 11:57:20 -02:00
Bruno Oliveira
11a9cbd50b Merge pull request #4365 from blueyed/xenial
Travis: use Xenial by default  [skip appveyor]
2018-11-11 11:55:06 -02:00
Bruno Oliveira
2626bd9afa Preparing release version 3.10.1 2018-11-11 13:43:04 +00:00
Bruno Oliveira
b6f16abfe0 Merge pull request #4369 from blueyed/cleanup
Cleanup/follow-up to #4319
2018-11-11 11:38:06 -02:00
Bruno Oliveira
e5a9f92dfb Merge pull request #4337 from blueyed/fix-sym
Fix collection of symlinked files
2018-11-11 11:36:31 -02:00
Daniel Hahler
a6ff5e6bfc Cleanup/follow-up to #4319 2018-11-11 01:38:34 +01:00
Daniel Hahler
be15ad8d25 Fix collection of direct symlinked files not in python_files
Fixes https://github.com/pytest-dev/pytest/issues/4325.
2018-11-11 01:37:06 +01:00
Daniel Hahler
dc9ceda5d2 Travis: use Xenial by default [skip appveyor] 2018-11-11 01:02:06 +01:00
Daniel Hahler
825085f699 Travis: use coverage from existing tox env [skip appveyor] 2018-11-11 00:59:46 +01:00
Daniel Hahler
b1312147e0 Merge pull request #4358 from blueyed/instance
Node: do not add "::()" to nodeid
2018-11-11 00:42:57 +01:00
Daniel Hahler
7ab3d818f0 Merge pull request #4356 from blueyed/fix-equal_with_bash
tests: fix equal_with_bash to handle appearing .coverage files
2018-11-11 00:42:23 +01:00
Daniel Hahler
f551cb9677 Skip Instances with --collect-only 2018-11-10 23:48:02 +01:00
Daniel Hahler
87254ca593 Add test for --deselect without "::()"
Closes: https://github.com/pytest-dev/pytest/issues/4127.
2018-11-10 23:46:41 +01:00
Daniel Hahler
ac8b9c6e9d Node: do not add "::()" to nodeid
Fixes https://github.com/pytest-dev/pytest/issues/4127.
2018-11-10 23:46:41 +01:00
Daniel Hahler
b51c1c3b8d tests: fix equal_with_bash for .coverage files
Fixes https://github.com/pytest-dev/pytest/issues/4162.
2018-11-10 03:24:02 +01:00
Daniel Hahler
e14ca19988 Merge pull request #4352 from blueyed/_check_initialpaths_for_relpath
Fix nodes._check_initialpaths_for_relpath for dirs
2018-11-10 03:18:36 +01:00
Ronny Pfannschmidt
10d27f412b Merge pull request #4360 from blueyed/merge-master
Merge master into features
2018-11-09 17:26:40 +01:00
Daniel Hahler
bee72a6622 Fix nodes._check_initialpaths_for_relpath for dirs
Ref: https://github.com/pytest-dev/pytest/issues/4321#issuecomment-436951894

Hardens some of the not many tests affected by this:

1. `testing/test_session.py::test_rootdir_option_arg` displayed:

> root/test_rootdir_option_arg2/test_rootdir_option_arg.py

2. `test_cmdline_python_namespace_package` displayed "hello/" prefix for:

> hello/test_hello.py::test_hello
> hello/test_hello.py::test_other
2018-11-09 13:16:59 +01:00
Daniel Hahler
1b260a844f Merge branch 'master' into features 2018-11-09 12:49:55 +01:00
Bruno Oliveira
e00f3a2fb7 Merge pull request #4353 from blueyed/test_fileimport
tests: test_fileimport: improve reporting on failure
2018-11-09 08:32:49 -02:00
Daniel Hahler
b92530de78 Merge pull request #4271 from blueyed/pytest_cache
cache_dir: use $TOX_ENV_DIR/ prefix if set
2018-11-09 09:09:45 +01:00
Daniel Hahler
afaad2f82b Merge pull request #4354 from blueyed/minor
A set of minor changes from my Git stashes
2018-11-09 08:25:17 +01:00
Daniel Hahler
a507f44465 cache_dir: use $TOX_ENV_DIR/ prefix if set
Fixes https://github.com/pytest-dev/pytest/issues/4270
2018-11-09 05:29:28 +01:00
Daniel Hahler
d4fdf793b5 Merge pull request #4350 from blueyed/fix-macos-py37
Travis: fix MacOS py37 build
2018-11-09 02:05:47 +01:00
Daniel Hahler
feccf532d2 doc: improve runpytest_subprocess 2018-11-09 02:03:44 +01:00
Daniel Hahler
859b322773 doc: improve/simplify doc for breakpoint behavior 2018-11-09 02:03:44 +01:00
Daniel Hahler
4a74d455de minor: typos 2018-11-09 02:03:44 +01:00
Daniel Hahler
c1bde8e0a2 minor: check bool before function call 2018-11-09 01:37:51 +01:00
Daniel Hahler
560c055b09 Session._collect: use reversed parts 2018-11-09 01:36:20 +01:00
Daniel Hahler
a0890f98d8 tests: harden test_config_error 2018-11-09 01:31:53 +01:00
Daniel Hahler
401a3cd1bc minor: improve FixtureDef.__repr__
Ref: https://github.com/pytest-dev/pytest/pull/4105#pullrequestreview-163486766
2018-11-09 01:27:18 +01:00
Daniel Hahler
b494d3d1c1 tests: test_fileimport: improve reporting on failure 2018-11-09 01:17:36 +01:00
Daniel Hahler
6c06057242 Merge pull request #4336 from blueyed/cwd2
Fix/improve handling of chdir with no-args and testpaths
2018-11-09 00:38:34 +01:00
Daniel Hahler
bb8a8495ff Revert "Attempt to fix macosx build setup"
This reverts commit 28dbffdaf2.

Appears to be not necessary anymore:
https://travis-ci.org/pytest-dev/pytest/jobs/452598885#L906

[skip appveyor]
2018-11-09 00:33:52 +01:00
Bruno Oliveira
423e19909e Merge pull request #4307 from fzarifian/fzarifian-pr4304
#4304 the stepwise plugin must be blocked on cacheprovider plugin block request
2018-11-08 20:42:04 -02:00
Daniel Hahler
f06fe43649 Merge pull request #4330 from blueyed/fix-report-last-write
Fix TypeError in report_collect with _collect_report_last_write
2018-11-08 21:06:17 +01:00
Daniel Hahler
3137c89cf1 Fix/improve handling of chdir with no-args and testpaths
Fixes https://github.com/pytest-dev/pytest/issues/4332.
2018-11-08 17:50:45 +01:00
Daniel Hahler
5dd509c963 Merge pull request #4338 from blueyed/merge-master
Merge master into features
2018-11-08 17:45:05 +01:00
Fabien ZARIFIAN
f48a26f59c Update AUTHORS 2018-11-08 08:12:08 +01:00
Daniel Hahler
9d838fa861 Merge branch 'master' into features
Conflicts:
	src/_pytest/main.py
2018-11-08 02:48:59 +01:00
Daniel Hahler
91404db284 Fix TypeError in report_collect with _collect_report_last_write
`_collect_report_last_write` might be None, when `pytest_collection` was
not called before.  Not sure if this indicates another problem, but it
can be reproduced with `testing/test_collection.py::TestCollector::()::test_getcustomfile_roundtrip`.

Fixes https://github.com/pytest-dev/pytest/issues/4329
2018-11-07 23:42:02 +01:00
Daniel Hahler
4c00552192 Merge pull request #4317 from blueyed/cwd
Handle os.chdir() during collection
2018-11-07 22:49:47 +01:00
Ronny Pfannschmidt
64762d2cfc Merge pull request #4319 from blueyed/harden-test_collect_init_tests
Fix handling of duplicate args with regard to Python packages
2018-11-07 21:48:54 +01:00
Bruno Oliveira
17b8e2d45b Fix linting 2018-11-07 18:32:23 -02:00
Bruno Oliveira
9a884f1ccb Improve changelog a bit 2018-11-07 18:30:13 -02:00
Daniel Hahler
827573c049 cleanup, TODO: use _node_cache 2018-11-07 20:14:07 +01:00
Daniel Hahler
6fce1f0ac7 pkg_roots per session 2018-11-07 20:06:35 +01:00
Daniel Hahler
bbb9d72c13 remove paths/parts 2018-11-07 19:36:19 +01:00
Daniel Hahler
f8b944dee0 pkg_roots 2018-11-07 19:35:25 +01:00
Daniel Hahler
f840521854 harden test_collect_init_tests 2018-11-07 19:29:55 +01:00
Daniel Hahler
134b103605 XXX: revert _collect_seen_pkgdirs 2018-11-07 11:01:39 +01:00
Daniel Hahler
fa35f650b5 Fix handling of duplicate args with regard to Python packages
Fixes https://github.com/pytest-dev/pytest/issues/4310.
2018-11-07 10:06:09 +01:00
Daniel Hahler
cb57159e01 Handle os.chdir() during collection 2018-11-05 23:18:47 +01:00
Bruno Oliveira
1752c7e710 Merge pull request #4314 from RonnyPfannschmidt/bestrelpath-cache-move-to-session
move Bestrelpath cache move to session
2018-11-05 17:51:49 -03:00
Anthony Sottile
176d27440c Merge pull request #4308 from asottile/compare_versions_with_loose_version
Don't string-compare version numbers
2018-11-05 12:42:26 -08:00
Bruno Oliveira
832b59b316 Merge pull request #4312 from Lothiraldan/patch-1
Add missing `-` in front of the new option `--sw`
2018-11-05 17:17:15 -03:00
Ronny Pfannschmidt
f521f5e012 move the _bestrelpathcache to session 2018-11-05 21:07:21 +01:00
Boris Feld
d42c490bc1 Add missing - in front of the new option --sw 2018-11-05 15:39:35 +01:00
Fabien ZARIFIAN
5f61f0d2cb Update __init__.py
As mentionned by @RonnyPfannschmidt, use set_blocked on module stepwise (and it's brother pytest_stepwise like consider_pluginarg method does)
2018-11-05 10:51:15 +01:00
Ronny Pfannschmidt
e253852e4b Merge pull request #4309 from asottile/less_unicode_hax
Use unicode/bytes literals instead of calls
2018-11-05 07:17:13 +01:00
Anthony Sottile
a4819844a4 Use unicode/bytes literals instead of calls 2018-11-04 17:43:24 -08:00
Anthony Sottile
db996335c8 Merge pull request #4302 from jdufresne/pypi
Update pypi.python.org reference to pypi.org
2018-11-04 17:32:56 -08:00
Anthony Sottile
85a3333824 Don't string-compare version numbers 2018-11-04 17:31:48 -08:00
Anthony Sottile
4bf6a07fe2 Merge pull request #4305 from RonnyPfannschmidt/cleanup-tobytes
replace byte/unicode helpers in test_capture with python level syntax
2018-11-04 17:29:41 -08:00
Fabien ZARIFIAN
db70c75807 Create 4304.bugfix.rst 2018-11-05 00:36:25 +01:00
Fabien ZARIFIAN
1793ac38a9 Update __init__.py 2018-11-05 00:21:12 +01:00
Bruno Oliveira
4aa3c4fa2b Merge pull request #4303 from blueyed/fix-changelog
doc: add lost changelog entry
2018-11-04 20:21:06 -03:00
Fabien ZARIFIAN
a447dc86fb Add test to branch 2018-11-05 00:14:35 +01:00
Ronny Pfannschmidt
7cb271b46f replace byte/unicode helpers in test_capture with python level syntax 2018-11-04 22:01:01 +01:00
Fabien ZARIFIAN
c55ca155e9 Update __init__.py
#4304
2018-11-04 21:55:56 +01:00
Ronny Pfannschmidt
5eb4016110 Merge pull request #4301 from nicoddemus/merge-master-into-features
Merge master into features
2018-11-04 20:23:33 +01:00
Daniel Hahler
34152445cf doc: add lost changelog entry
Closes https://github.com/pytest-dev/pytest/issues/4300.

[ci skip]
2018-11-04 18:26:09 +01:00
Jon Dufresne
5e0441d96e Update pypi.python.org reference to pypi.org 2018-11-04 09:02:54 -08:00
Bruno Oliveira
d1c9c54571 Merge pull request #4297 from nicoddemus/release-3.10.0
Release 3.10.0
2018-11-04 12:25:30 -03:00
Bruno Oliveira
bb2ed2f898 Merge pull request #4298 from blueyed/howto
doc: fix HOWTORELEASE.rst
2018-11-03 20:32:54 -03:00
Bruno Oliveira
3d88d1827b Fixed linting 2018-11-03 19:50:19 -03:00
Daniel Hahler
7b5f3fe83a doc: fix HOWTORELEASE.rst
Remove last step, because it was merged already before (changed in
77cad3c4).

[ci skip]
2018-11-03 21:26:08 +01:00
Daniel Hahler
f2b9bbdd4a Merge pull request #4287 from blueyed/pdb-unconfigure-twice
debugging: make pytest_configure re-entrant
2018-11-03 21:09:13 +01:00
Bruno Oliveira
c2e906ec97 Preparing release version 3.10.0 2018-11-03 13:51:39 +00:00
Bruno Oliveira
1ec6805112 Fix escape in code sample 2018-11-03 13:48:10 +00:00
Bruno Oliveira
6befdf8b46 Merge remote-tracking branch 'upstream/master' into release-3.10.0 2018-11-03 13:42:20 +00:00
Bruno Oliveira
4cb838d978 Merge pull request #4237 from boxed/master
Performance fixes
2018-11-03 10:39:29 -03:00
Daniel Hahler
e61e81a7b5 Make debugging's pytest_configure re-entrant
This is relevant when using runpytest in-process.

Fixes:

E             def test_1(testdir):
E                 testdir.runpytest()
E         >       __import__('pdb').set_trace()
E
E         ../../test_trace_after_runpytest.py:3:
E         …/Vcs/pytest/src/_pytest/debugging.py:81: in set_trace
E             tw = _pytest.config.create_terminal_writer(cls._config)
E
E         config = None, args = (), kwargs = {}, tw = <py._io.terminalwriter.TerminalWriter object at 0x7f1097088160>
E
E             def create_terminal_writer(config, *args, **kwargs):
E                 """Create a TerminalWriter instance configured according to the options
E                 in the config object. Every code which requires a TerminalWriter object
E                 and has access to a config object should use this function.
E                 """
E                 tw = py.io.TerminalWriter(*args, **kwargs)
E         >       if config.option.color == "yes":
E         E       AttributeError: 'NoneType' object has no attribute 'option'
2018-11-02 18:25:01 +01:00
Daniel Hahler
023e1c78df paths: use set and isdisjoint
Time: 5.36s => 4.85s (before rebase: 4.45s => 3.55s)
2018-11-02 17:43:04 +01:00
Daniel Hahler
6ffa347c77 Handle dirs only once
Time: 5.73s/5.88s => 5.36s

(Before rebase: 4.86s => 4.45s)
2018-11-02 17:43:04 +01:00
Anders Hovmöller
2b50911c9d Minor refactor for readability
Time: 5.73s => 5.88s/5.82s
2018-11-02 17:42:53 +01:00
Anders Hovmöller
a41820fbf0 collection: performance: use optimized parts function
Time: 8.53s => 5.73s
2018-11-02 17:42:53 +01:00
Bruno Oliveira
21725e9304 Merge pull request #4285 from kchmck/fix-4046
Fix problems with running tests in package `__init__` files (#4046)
2018-11-02 08:26:07 -03:00
Bruno Oliveira
48f52b1be0 Merge pull request #4279 from williamjamir/improve-warning-msg
Improve the warning message for the implicitly str conversion
2018-11-02 08:22:15 -03:00
Daniel Hahler
a5b3ad2e45 Merge pull request #4284 from blueyed/test-dunder-class
python: collect: ignore exceptions with isinstance
2018-11-01 22:15:29 +01:00
Daniel Hahler
e30f7094f3 python: collect: ignore exceptions with isinstance
Fixes https://github.com/pytest-dev/pytest/issues/4266.
2018-11-01 22:14:13 +01:00
Mick Koch
5197354375 Add changelog entry 2018-11-01 13:13:33 -04:00
Mick Koch
5ac4eff09b Fix __init__.py as argument also including other package files 2018-11-01 13:10:52 -04:00
Mick Koch
320e41b142 Add failing test for __init__.py also including other package files 2018-11-01 13:10:52 -04:00
Mick Koch
70976b04be Add test for __init__.py collection with package directory as argument 2018-11-01 13:10:17 -04:00
Daniel Hahler
d65f300988 Move handling of duplicate files
This removes the hack added in https://github.com/pytest-dev/pytest/pull/3802.

Adjusts test:

- it appears to not have been changed to 7 intentionally.
- removes XXX comment, likely not relevant anymore since 6dac7743.
2018-11-01 13:06:36 -04:00
Anthony Sottile
948fd7b8b0 fixup pyupgrade crlf incorrect fixes 2018-11-01 08:40:35 -07:00
Bruno Oliveira
f2cebce2eb Merge pull request #4272 from blueyed/cache-non-default
cacheprovider: display cachedir also in non-verbose mode if customized
2018-11-01 12:19:21 -03:00
Daniel Hahler
a192e6b430 Merge pull request #4247 from blueyed/lru
_getconftestmodules: use functools.lru_cache
2018-11-01 15:55:38 +01:00
Daniel Hahler
f8a2452247 changelog [ci skip] 2018-11-01 15:53:31 +01:00
Bruno Oliveira
56e6bb0ff6 Merge pull request #4282 from avallbona/patch-1
Update talks.rst
2018-10-31 22:33:45 -03:00
Bruno Oliveira
017e504a11 Merge pull request #4277 from blueyed/pdb-set_trace-capture-msg
pdb: improve msg about output capturing with set_trace
2018-10-31 21:48:47 -03:00
Andreu Vallbona Plazas
9871d5ec2d Updated the talks.rst
corrected the target name
2018-11-01 01:24:18 +01:00
Bruno Oliveira
642521a9b3 Merge pull request #4281 from asottile/bump_hooks
Upgrade pyupgrade for crlf fixes (again)
2018-10-31 20:58:05 -03:00
Bruno Oliveira
0994829afe Move pytest talk to the start of the section 2018-10-31 19:35:47 -03:00
Daniel Hahler
ce1cc3dddb _getconftestmodules: use functools.lru_cache
Also renames `_path2confmods` to `_dirpath2confmods` for clarity (it is
expected to be a dirpath in `_importconftest`).

Uses an explicit maxsize, since it appears to be only relevant for a
short period [1].

Removes the lru_cache on _getconftest_pathlist, which makes no
difference when caching _getconftestmodules, at least with the
performance test of 100x10 files (#4237).

1: https://github.com/pytest-dev/pytest/pull/4237#discussion_r228528007
2018-10-31 23:17:05 +01:00
Daniel Hahler
65817dd797 changelog [ci skip] 2018-10-31 23:13:25 +01:00
Andreu Vallbona Plazas
c31abb1176 Update talks.rst
Added the slides of a PyconES 2017 talk about pytest and its plugins ecosystem.
2018-10-31 23:06:44 +01:00
Bruno Oliveira
d4ca634ef6 Fix linting 2018-10-31 18:21:55 -03:00
Anthony Sottile
af00367fed Upgrade pyupgrade for crlf fixes (again) 2018-10-31 13:26:49 -07:00
William Jamir Silva
9b94313b44 Update changelog 2018-10-31 17:12:50 -03:00
William Jamir Silva
5404246e64 Improve the warning message for the implicitly str conversion
Signed-off-by: William Jamir Silva <williamjamir@gmail.com>
2018-10-31 16:19:10 -03:00
Daniel Hahler
e0038b82f7 pdb: improve msg about output capturing with set_trace
Do not display "IO-capturing turned off/on" when ``-s`` is used to avoid
confusion.
2018-10-31 17:09:01 +01:00
Bruno Oliveira
0fea71a4f5 Merge pull request #4164 from RonnyPfannschmidt/nowarn-session-attributes
don`t parse compat properties as fixtures
2018-10-31 12:52:52 -03:00
Bruno Oliveira
7571f079c8 Merge pull request #4276 from pfctdayelise/flaky-docs
Add docs page discussing flaky tests
2018-10-31 11:25:27 -03:00
Bruno Oliveira
b5d62cdb55 Update 2701.bugfix.rst 2018-10-31 11:07:24 -03:00
Bruno Oliveira
cc25256982 Fix linting2 2018-10-31 11:05:58 -03:00
Ronny Pfannschmidt
da04ff52e4 ignore _CompatProperty when parsing fixtures
this avoid triggering the warnings when parsing the session node as session plugin
2018-10-31 15:01:41 +01:00
Bruno Oliveira
d5b5be6fbe Fix linting 2018-10-31 10:44:43 -03:00
Brianna Laugher
3b65d190a4 Add docs page discussing flaky tests 2018-10-31 23:45:09 +11:00
Daniel Hahler
ff04a1fb09 Merge pull request #4267 from nicoddemus/tmpdir-4262
Fix access denied error when deleting a stale temporary directory
2018-10-31 00:25:13 +01:00
Daniel Hahler
1f1d4aaf68 cacheprovider: display cachedir also in non-verbose mode if customized 2018-10-30 23:09:54 +01:00
Anthony Sottile
196a739f58 Merge pull request #4269 from asottile/upgrade_hooks
Upgrade pre-commit hooks
2018-10-30 14:06:19 -07:00
Bruno Oliveira
f20eeebde9 Fix access denied error when deleting a stale temporary directory
Fix #4262
2018-10-30 15:35:53 -03:00
Anthony Sottile
b17e6cea21 Upgrade pre-commit hooks 2018-10-30 11:02:44 -07:00
Bruno Oliveira
233c2a23de Merge pull request #4250 from blueyed/ignore-pyc
collection: _recurse: skip __pycache__
2018-10-30 08:25:57 -03:00
Bruno Oliveira
46ec0ec43a Merge pull request #4264 from scop/spelling2
Spelling and grammar fixes
2018-10-30 08:24:01 -03:00
Ville Skyttä
a035c89ea7 Spelling fix 2018-10-30 09:38:55 +02:00
Daniel Hahler
40228fce5a collection: _recurse: skip __pycache__ 2018-10-30 02:34:32 +01:00
Anthony Sottile
f258b75a24 Merge pull request #4261 from asottile/no_anonymous_source_warning
Swallow warnings during anonymous compilation of source
2018-10-29 18:29:53 -07:00
Ville Skyttä
22ab737243 Spelling and grammar fixes 2018-10-29 23:45:45 +02:00
Anthony Sottile
0d1f142b1c Swallow warnings during anonymous compilation of source 2018-10-29 08:38:10 -07:00
Anthony Sottile
8c475a45bb Unrelated cleanups of source.py 2018-10-28 16:43:17 -07:00
Bruno Oliveira
e6e40db9c7 Merge pull request #4258 from pecey/tmp/issue-4255
Fixes #4255 by adding to the doc that module names are not regex-escaped
2018-10-28 09:44:13 -03:00
Ronny Pfannschmidt
cc531a1ca9 Merge pull request #4253 from nicoddemus/merge-master-into-features
Merge master into features
2018-10-28 10:13:08 +01:00
Palash Chatterjee
c3acf049bd Fixes #4255 by adding to the documentation that module names are not regex-escaped 2018-10-28 10:45:34 +05:30
Bruno Oliveira
bab1ef5d38 Merge pull request #4257 from Bernardoow/changed_address_to_pytest-datadir
changed address to pytest-data-dir
2018-10-27 17:16:32 -03:00
Bernardo Gomes
b0c0911ba3 changed address to pytest-data-dir 2018-10-27 14:31:50 -03:00
Bruno Oliveira
3b7fbcd47f Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2018-10-27 14:29:01 -03:00
Bruno Oliveira
9ef23b686c Merge pull request #4252 from nicoddemus/release-3.9.3
Preparing release version 3.9.3
2018-10-27 13:36:42 -03:00
Bruno Oliveira
96784c2052 Preparing release version 3.9.3 2018-10-27 13:07:54 +00:00
Ronny Pfannschmidt
9fe871016d Merge pull request #4147 from davidszotten/stepwise
Stepwise
2018-10-27 15:05:05 +02:00
Bruno Oliveira
e986d06ade Merge pull request #4251 from blueyed/python-collect
python: collect: revisit
2018-10-27 10:02:23 -03:00
Bruno Oliveira
ebba3ebe67 Merge pull request #4240 from RonnyPfannschmidt/perf-example-collect-files
add script to generate a example folder for collecting many files
2018-10-26 19:19:02 -03:00
Ankit Goel
1d09e1d8ce Merge pull request #4248 from jdufresne/binary-type
Remove use of unnecessary compat shim, six.binary_type
2018-10-27 00:03:16 +05:30
Bruno Oliveira
d59786fcc4 Merge pull request #4222 from RonnyPfannschmidt/pathlib-fixes
handle race condition when creation and deletion of a numbered dir overlap
2018-10-26 14:36:43 -03:00
Ankit Goel
af34164858 Fix changelog file extension 2018-10-26 22:03:57 +05:30
Daniel Hahler
dcdf86ef5b python: collect: revisit 2018-10-26 16:06:37 +02:00
Jon Dufresne
167e9b954a Remove use of unnecessary compat shim, six.binary_type
The type `bytes` is available on all supported Python versions. On
Python 2.7, it is an alias of str, same as six.binary_type.

Makes the code slightly more forward compatible.
2018-10-26 06:27:50 -07:00
Daniel Hahler
9cde67c09c Merge pull request #4224 from blueyed/_getconftestmodules
_getconftestmodules: avoid isfile()/dirpath()
2018-10-26 14:44:46 +02:00
Ronny Pfannschmidt
ae2fc27799 handle test folder cleanup being unable to create a cleanup lock 2018-10-26 14:31:54 +02:00
Bruno Oliveira
56989a8350 Merge pull request #4244 from RonnyPfannschmidt/fix-4243
fix #4243 - support positional argument stacklevel on python2
2018-10-26 08:09:33 -03:00
Bruno Oliveira
8d0e1a99e4 Merge pull request #4241 from blueyed/move-duplicates
Move handling of duplicate files
2018-10-26 08:07:48 -03:00
Ronny Pfannschmidt
ce0b0518c7 fix #4243 - support positional argument stacklevel on python2 2018-10-26 09:01:25 +02:00
Ronny Pfannschmidt
bf19917537 Merge pull request #4242 from pytest-dev/merge-master
merge master into features
2018-10-26 07:21:59 +02:00
Anthony Sottile
777e9e1e17 Merge remote-tracking branch 'origin/master' into merge-master 2018-10-25 18:00:39 -07:00
Ronny Pfannschmidt
bfa1993840 add script to generate a example folder for collecting many files 2018-10-25 22:07:20 +02:00
Daniel Hahler
e041823643 Move handling of duplicate files
This removes the hack added in https://github.com/pytest-dev/pytest/pull/3802.

Adjusts test:

- it appears to not have been changed to 7 intentionally.
- removes XXX comment, likely not relevant anymore since 6dac7743.
2018-10-25 20:48:08 +02:00
Daniel Hahler
63691f5656 _getconftestmodules: avoid isfile()/dirpath()
Ref: https://github.com/pytest-dev/pytest/issues/2206#issuecomment-432623646
2018-10-25 20:25:07 +02:00
Daniel Hahler
6dc575f5ee Merge pull request #4239 from blueyed/lru_cache
Move lru_cache wrapper to compat
2018-10-25 20:09:01 +02:00
Daniel Hahler
0dc6cb298e Move lru_cache wrapper to compat
Ref: https://github.com/pytest-dev/pytest/pull/4227#discussion_r228060373
2018-10-25 18:20:36 +02:00
Bruno Oliveira
041044eef0 Merge pull request #4238 from asottile/cl
Add a changelog for #4235 [ci skip]
2018-10-25 13:14:05 -03:00
Anthony Sottile
1af31a09f4 Add a changelog for #4235 [ci skip] 2018-10-25 09:09:25 -07:00
Daniel Hahler
f466105d66 Merge pull request #2619 from blueyed/pdb-resume-capture
pdb: resume capturing after `continue`
2018-10-25 14:28:47 +02:00
Bruno Oliveira
ccdb248397 Merge pull request #4235 from asottile/reorder_python_imports
Apply reorder-python-imports to all files
2018-10-25 08:37:40 -03:00
Daniel Hahler
ede3a4e850 pytest_{enter,leave}_pdb: pass through pdb instance 2018-10-25 13:28:24 +02:00
Daniel Hahler
a4ea66cb1f pdb: resume capturing after continue
After `pdb.set_trace()` capturing is turned off.
This patch resumes it after using the `continue` (or `c` / `cont`)
command.

Store _pytest_capman on the class, for pdbpp's do_debug hack to keep it.

Without this, `debug …` would fail like this:

    /usr/lib/python3.6/cmd.py:217: in onecmd
        return func(arg)
    .venv/lib/python3.6/site-packages/pdb.py:608: in do_debug
        return orig_do_debug(self, arg)
    /usr/lib/python3.6/pdb.py:1099: in do_debug
        sys.call_tracing(p.run, (arg, globals, locals))
    /usr/lib/python3.6/bdb.py:434: in run
        exec(cmd, globals, locals)
    /usr/lib/python3.6/bdb.py:51: in trace_dispatch
        return self.dispatch_line(frame)
    /usr/lib/python3.6/bdb.py:69: in dispatch_line
        self.user_line(frame)
    /usr/lib/python3.6/pdb.py:261: in user_line
        self.interaction(frame, None)
    .venv/lib/python3.6/site-packages/pdb.py:203: in interaction
        self.setup(frame, traceback)
    E   AttributeError: 'PytestPdb' object has no attribute '_pytest_capman'

- add pytest_leave_pdb hook
- fixes test_pdb_interaction_capturing_twice: would fail on master now,
  but works here
2018-10-25 13:28:24 +02:00
Anthony Sottile
2368fbb63c Apply reorder-python-imports to all files 2018-10-25 00:01:29 -07:00
Ronny Pfannschmidt
f6dfca7182 Merge pull request #4229 from nicoddemus/fix-warning-location
Show node that originated a warning in the warnings summary
2018-10-25 08:26:01 +02:00
Ronny Pfannschmidt
65b97c2f41 Merge pull request #4227 from blueyed/_getconftest_pathlist-lru
Use functools.lru_cache with _getconftest_pathlist
2018-10-25 08:12:51 +02:00
Bruno Oliveira
4a69104af3 Merge pull request #4232 from blueyed/fix-doc-caplog
doc: fix caplog: s/methods/properties/
2018-10-24 19:27:30 -03:00
Bruno Oliveira
1786ad16a7 functools.lru_cache does not exist on Python 2, apply for Python 3 only 2018-10-24 18:59:54 -03:00
Daniel Hahler
2cf4c67e45 doc: fix caplog: s/methods/properties/ 2018-10-24 23:57:11 +02:00
Bruno Oliveira
2ad43ee442 Show node that originated a warning in the warnings summary
Fix #4221
2018-10-24 18:49:53 -03:00
Daniel Hahler
15278aacb9 Merge pull request #4231 from blueyed/fix-master
Fix flake8: os imported, but unused
2018-10-24 23:47:46 +02:00
Daniel Hahler
57caa4e25e Fix flake8: os imported, but unused
Likely due to b6fa4e24.
2018-10-24 23:43:41 +02:00
Daniel Hahler
66ce952da6 Merge pull request #4228 from blueyed/merge-master
Merge master into features
2018-10-24 23:04:52 +02:00
Bruno Oliveira
b6fa4e248f Merge pull request #4028 from asottile/revert_breakpoint_code
Revert patching of breakpointhook as it appears to do nothing
2018-10-24 17:50:19 -03:00
Daniel Hahler
eee8201e4f Merge remote-tracking branch 'origin/master' into merge-master 2018-10-24 22:36:34 +02:00
Daniel Hahler
e690e191fd Merge pull request #4225 from blueyed/collect-performance
TerminalWriter: write "collecting" msg only once every 0.5s
2018-10-24 22:35:53 +02:00
Daniel Hahler
d40cd3ec6b Use functools.lru_cache with _getconftest_pathlist
For pytest's own suite the `cache_info()` looks as follows:

    > session.config._getconftest_pathlist.cache_info()
    CacheInfo(hits=231, misses=19, maxsize=None, currsize=19)

While it does not really make a difference for me this might help with
larger test suites / the case mentioned in
https://github.com/pytest-dev/pytest/issues/2206#issuecomment-432623646.
2018-10-24 18:22:30 +02:00
Daniel Hahler
9df1b037d6 Merge pull request #4217 from nicoddemus/fix-macos-py37-travis
Fix MacOS py37 on Travis
2018-10-24 17:51:49 +02:00
Bruno Oliveira
28dbffdaf2 Attempt to fix macosx build setup
This has been failing as of 2018-10-23 while installing gcc with
this message:

	==> Installing numpy dependency: gcc
	==> Downloading https://homebrew.bintray.com/bottles/gcc-8.2.0.high_sierra.bottl
	######################################################################## 100.0%
	==> Pouring gcc-8.2.0.high_sierra.bottle.1.tar.gz
	Error: The `brew link` step did not complete successfully
	The formula built, but is not symlinked into /usr/local
	Could not symlink include/c++
	Target /usr/local/include/c++
	already exists. You may want to remove it:
	  rm '/usr/local/include/c++'
	To force the link and overwrite all conflicting files:
	  brew link --overwrite gcc
	To list all files that would be deleted:
	  brew link --overwrite --dry-run gcc
	Possible conflicting files are:
	/usr/local/include/c++ -> /usr/local/Caskroom/oclint/0.13.1,17.4.0/oclint-0.13.1/include/c++
2018-10-24 12:46:45 -03:00
Daniel Hahler
f8f4c16020 TerminalWriter: write "collecting" msg only once every 0.1s
Running `pytest -k doesnotmatch` on pytest's own tests takes ~3s with
Kitty terminal for me, but only ~1s with `-q`.
It also is faster with urxvt, but still takes 2.2s there.

This patch only calls `report_collect` every 0.1s, which is good enough
for reporting collection progress, and improves the time with both Kitty
and urxvt to ~1.2s for me.
2018-10-24 16:48:35 +02:00
Bruno Oliveira
8bced7415c Merge pull request #4220 from anpr/doc_raise_on_empty_parameterset
Add `empty_parameter_set_mark` ini option documentation to the parametrize doc
2018-10-23 19:10:44 -03:00
Bruno Oliveira
72d98a7c52 Merge pull request #4214 from blueyed/fix-4174
Fix "Plugin already registered" error with symlinks
2018-10-23 17:10:15 -03:00
Andreas Profous
0dd85157ea Add reference to `empty_parameter_set_mark` parametrize doc 2018-10-23 22:03:05 +02:00
Daniel Hahler
2a45851c9e Merge pull request #4218 from blueyed/remove-_shutil_rmtree_remove_writable
minor: remove unused _shutil_rmtree_remove_writable
2018-10-23 18:34:28 +02:00
Daniel Hahler
b51ee48f78 minor: remove unused _shutil_rmtree_remove_writable 2018-10-23 17:36:22 +02:00
Daniel Hahler
fadac0ffc0 Fix "Plugin already registered" error with symlinks
Fixes https://github.com/pytest-dev/pytest/issues/4174.
2018-10-23 10:15:23 +02:00
Anthony Sottile
799b72cf6f Merge pull request #4213 from asottile/flake8_master_fixes
Fixes for flake8 master
2018-10-22 20:08:38 -07:00
Bruno Oliveira
fc0f89ac14 Merge pull request #4215 from nicoddemus/release-3.9.2
Release version 3.9.2
2018-10-22 22:08:16 -03:00
Bruno Oliveira
771e860011 Preparing release version 3.9.2 2018-10-22 21:47:42 +00:00
Anthony Sottile
cb39bd0651 Fixes for flake8 master 2018-10-22 08:50:00 -07:00
Anthony Sottile
c94b2b227e Merge pull request #4208 from nicoddemus/pytestskip-docs-4206
Remove pytest.config example from skipping at module level docs
2018-10-21 10:28:53 -07:00
Ankit Goel
f30911d3af Merge pull request #4209 from nicoddemus/fixture-named-request
Issue a warning when a fixture named 'request' is collected
2018-10-21 05:49:08 +05:30
Ankit Goel
cd72e23f3f Merge pull request #4207 from nicoddemus/recursive-dep-fixtures
Improve error message when a recursive dependency between fixtures is detected
2018-10-20 22:19:21 +05:30
Bruno Oliveira
7bb51b8ceb Issue a warning when a fixture named 'request' is collected
Fix #611
2018-10-20 12:09:44 -03:00
Bruno Oliveira
b9990f77ff Merge pull request #4204 from vbarbaresi/3340_log_hooks
Fix logging usage in hooks pytest_sessionstart/finish
2018-10-20 11:36:06 -03:00
Bruno Oliveira
6b126997e1 Remove pytest.config example from skipping at module level docs 2018-10-20 11:28:39 -03:00
Bruno Oliveira
02ae7d8531 Improve error message when a recursive dependency between fixtures is detected
Fix #2909
2018-10-20 09:44:42 -03:00
Bruno Oliveira
f947cb2613 Merge remote-tracking branch 'upstream/features' into davidszotten/stepwise 2018-10-20 09:18:02 -03:00
Vincent Barbaresi
db106d6085 Fix logging usage in hooks pytest_sessionstart/finish #3340 2018-10-20 09:55:10 +02:00
Bruno Oliveira
b0eed7b56c Merge pull request #4205 from vbarbaresi/fix_typo
fix typo in tmpdir documentation (trivial)
2018-10-19 17:49:32 -03:00
Vincent Barbaresi
51d358a7a9 fix typo in tmpdir documentation 2018-10-19 19:22:04 +02:00
Bruno Oliveira
c54cdd05b8 Merge pull request #4201 from ykantor/patch-1
Update tmpdir.rst - very trivial
2018-10-19 12:13:35 -03:00
Bruno Oliveira
dde147641e Fix linting 2018-10-19 09:33:51 -03:00
Bruno Oliveira
2abd005cc9 Merge pull request #4195 from nicoddemus/issue-3691
Use safe_str() to format warning message about unicode in Python 2
2018-10-19 07:18:29 -03:00
Ronny Pfannschmidt
366b88388b Merge pull request #4200 from asottile/upgrade_hooks
Upgrade pre-commit/pre-commit-hooks to 2.0.0
2018-10-19 08:33:03 +02:00
ykantor
0fc1801d0d Update tmpdir.rst 2018-10-19 05:54:29 +02:00
Anthony Sottile
11ff14be1f Upgrade pre-commit/pre-commit-hooks to 2.0.0 2018-10-18 20:11:35 -07:00
Anthony Sottile
dc0b4efffa Merge pull request #4196 from nicoddemus/better-signature-error-msg-4026
Improve error message when it is not possible to determine a function's signature
2018-10-18 18:56:55 -07:00
Bruno Oliveira
864d7fef30 Add back some {posargs} placeholders for pytest invocations in tox.ini
Those were removed by accident in a previous commits it seems
2018-10-18 21:57:11 -03:00
Bruno Oliveira
18035211f5 Use safe_str() to format warning message about unicode in Python 2
Fix #3691
2018-10-18 21:56:17 -03:00
Anthony Sottile
61080da89d Merge pull request #4192 from asottile/fix_recwarn_stacklevel
Fix filename reported by `warnings.warn` when using `recwarn` under python2.
2018-10-18 16:22:00 -07:00
Bruno Oliveira
ac5704290f Improve error message when it is not possible to determine a function's signature
Fix #4026
2018-10-18 20:06:43 -03:00
Bruno Oliveira
b432f1207c Merge pull request #4190 from nicoddemus/merge-master-into-features
Merge master into features
2018-10-18 19:23:16 -03:00
Anthony Sottile
cdd0e18ca8 Emulate resetting the warnings registry for python 2.x 2018-10-18 10:43:05 -07:00
Bruno Oliveira
43c3f59660 Merge pull request #4188 from svenstaro/make-it-more-colorful
Make --color more colorful
2018-10-18 14:14:53 -03:00
Bruno Oliveira
e4871f7722 Merge pull request #4183 from RonnyPfannschmidt/bump-setuptools
fix #4177 - pin setuptools>=40.0
2018-10-18 07:49:03 -03:00
Bruno Oliveira
517ee588c6 Merge pull request #4186 from nicoddemus/drop-coveralls
No longer upload code coverage to coveralls
2018-10-18 07:48:40 -03:00
Ankit Goel
1b51497936 [WIP] Update warning stacklevel when wrapping warnings.warn 2018-10-18 02:36:41 +00:00
Sven-Hendrik Haase
f694d8d6ad Make --color more colorful 2018-10-18 03:56:58 +02:00
Bruno Oliveira
a83ee197c6 Merge remote-tracking branch 'upstream/master' into RonnyPfannschmidt/bump-setuptools 2018-10-17 19:05:52 -03:00
Bruno Oliveira
12f94b81c0 No longer upload code coverage to coveralls
We have since moved to codecov and uploading to coveralls is breaking
OS-X builds for py37 [1], so we might as well take this opportunity to drop
it.

[1] https://travis-ci.org/pytest-dev/pytest/jobs/442858038
2018-10-17 18:18:08 -03:00
Bruno Oliveira
e6b01b45f1 Merge pull request #4185 from RonnyPfannschmidt/fix-fail
fix test_cleanup_keep for expecting symlinks
2018-10-17 18:15:37 -03:00
David Szotten
e478f66d8b cache is set by the cacheprovider 2018-10-17 21:17:54 +01:00
Ronny Pfannschmidt
56dd7bc551 TestNumberedDir: ignore that symlinks arent created on windows 2018-10-17 21:39:23 +02:00
Bruno Oliveira
8a768b0db0 Merge pull request #4182 from nicoddemus/fix-deprecations-hook-name
Fix hook name in deprecations.rst
2018-10-17 16:18:52 -03:00
Ronny Pfannschmidt
8dca8f3c9f fix test_cleanup_keep for expecting symlinks 2018-10-17 21:16:44 +02:00
Ronny Pfannschmidt
cc335d44a0 fix #4179 - bring back the current testrun symlink 2018-10-17 20:43:27 +02:00
Ronny Pfannschmidt
4f4c91caf5 fix #4177 - pin setuptools>=40.0 2018-10-17 20:08:07 +02:00
Bruno Oliveira
ba5a295544 Fix hook name in deprecations.rst
As mentioned in https://github.com/pytest-dev/pytest/issues/4128#issuecomment-430690498
2018-10-17 14:53:41 -03:00
Bruno Oliveira
93bdbf7572 Merge pull request #4173 from nicoddemus/warning-docs-update
Update warnings docs
2018-10-17 09:24:32 -03:00
Anthony Sottile
ab8907f6f5 s/comparision/comparison/g [ci skip] 2018-10-16 17:23:29 -07:00
Bruno Oliveira
215a2ed3de Update warnings docs
Some points on the document work different in 3.9, plus changed the order
of the sections a bit to make more sense for users reading it for the first time.
2018-10-16 21:00:57 -03:00
Bruno Oliveira
f7285b6ab2 Merge pull request #4172 from nicoddemus/merge-features-into-master
Merge features into master
2018-10-16 18:59:23 -03:00
Bruno Oliveira
ee0a306ee4 Merge remote-tracking branch 'upstream/features' into merge-features-into-master 2018-10-16 17:41:27 -03:00
Bruno Oliveira
7931b5b489 Merge pull request #4171 from RonnyPfannschmidt/release-3.9.1
Release 3.9.1
2018-10-16 17:40:31 -03:00
Ronny Pfannschmidt
c5bbf8ac73 make note about the unpublished 3.9.0 release 2018-10-16 22:21:15 +02:00
Ronny Pfannschmidt
253c5786af Preparing release version 3.9.1 2018-10-16 22:16:58 +02:00
Ronny Pfannschmidt
c4550bc922 Merge branch 'release-3.9.0' of github.com:nicoddemus/pytest into release-3.9.1 2018-10-16 22:07:38 +02:00
Bruno Oliveira
2c00f8aad1 Merge pull request #4170 from RonnyPfannschmidt/fix-metadata-url-quotes
Fix metadata url quotes
2018-10-16 16:58:36 -03:00
Ronny Pfannschmidt
456715a5c1 fix url quotes in setup.cfg metadata 2018-10-16 21:48:39 +02:00
Ankit Goel
f858177495 Merge pull request #4167 from vbarbaresi/3533_junit_escape_skipped
Fix #3533: properly escape raw XML object
2018-10-16 21:10:42 +05:30
Bruno Oliveira
54b8ad4554 Merge pull request #4159 from thisch/subclassedfile
Increase required verbosity level for debug output
2018-10-16 10:41:27 -03:00
Vincent Barbaresi
d72154acda add changelog for #3533 2018-10-16 15:07:23 +02:00
Vincent Barbaresi
f55ded20a9 fix #3533: properly escape raw XML object
Using string formatting with the raw escaped object lead to string evaluation
"<py._xmlgen.raw object>"
Format the unescaped string first, then use the XML escape method as a last step.
2018-10-16 14:46:39 +02:00
Bruno Oliveira
17655b54f2 Merge pull request #4163 from nicoddemus/travis-passenv-4162
Pass TRAVIS env var to test environments [skip appveyor]
2018-10-15 20:50:43 -03:00
Bruno Oliveira
12edc4e7b8 Pass TRAVIS env var to test environments [skip appveyor]
xdist has an workaround inplace for Travis so "-n auto" works.

Fix #4162
2018-10-15 20:06:59 -03:00
David Szotten
c25310d34f fix cacheprovider test 2018-10-15 21:51:15 +01:00
Bruno Oliveira
2868c31495 Preparing release version 3.9.0 2018-10-15 20:23:30 +00:00
Bruno Oliveira
39a13d7064 Fix tmp_path example in docs 2018-10-15 20:19:15 +00:00
Bruno Oliveira
e4e4fd1e52 Merge pull request #4158 from nicoddemus/merge-master-into-features
Merge master into features (prepare for 3.9, pt2)
2018-10-15 17:12:08 -03:00
David Szotten
d67d189d00 grammar 2018-10-15 20:04:39 +01:00
David Szotten
8187c148d9 now pinned to pytest version 2018-10-15 20:04:39 +01:00
David Szotten
e773c8ceda linting 2018-10-15 20:04:39 +01:00
David Szotten
4f652c9045 we have a pr number now 2018-10-15 20:04:39 +01:00
David Szotten
126bb0760e authors 2018-10-15 20:04:39 +01:00
David Szotten
8c059dbc48 draft changelog 2018-10-15 20:04:39 +01:00
David Szotten
fd66f69c19 draft doc 2018-10-15 20:04:39 +01:00
David Szotten
63c01d1541 update for builtin plugin 2018-10-15 20:04:39 +01:00
David Szotten
c56d7ac40e move files into the pytest file structure 2018-10-15 20:04:39 +01:00
David Szotten
d9c428c1de add compat for pytest 3.7 and tox config for (some of) the versions i could still get working 2018-10-15 20:04:39 +01:00
Niclas Olofsson
bd9495486b pytest 2.7 compatibility. 2018-10-15 20:04:39 +01:00
Niclas Olofsson
33f1ff4e8c Use result.stderr in tests since result.errlines has changed behaviour. 2018-10-15 20:04:39 +01:00
Niclas Olofsson
1d23bef3fb Use a single node ID rather than a set for failed tests. 2018-10-15 20:04:38 +01:00
Niclas Olofsson
661055105c Restructured project. 2018-10-15 20:04:38 +01:00
Thomas Hisch
e8c220b9bd Increase required verbosity level for debug output
To show the subclassed file in legacy test suits in the runtest output
you have to set the verbosity level to at least "-vv" now.

Closes #3211
2018-10-15 20:38:32 +02:00
Bruno Oliveira
9646a1cd7a Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2018-10-15 12:55:28 -03:00
Bruno Oliveira
9087ac4010 Merge pull request #4157 from nicoddemus/fix-pr-template-link
Use full link to changelog's README in PR template
2018-10-15 12:50:16 -03:00
Anthony Sottile
093e19a7d9 Merge pull request #4153 from asottile/syntax_warning_filename
Display the filename when encountering `SyntaxWarning`.
2018-10-15 08:40:51 -07:00
Bruno Oliveira
9e867ce864 Use full link to changelog's README in PR template
Fix #4156
2018-10-15 12:19:52 -03:00
Bruno Oliveira
8abf30ad71 Merge pull request #4155 from Tadaboody/Add_a_simple_example_on_how_to_use_pytester_to_the_CONTRIBUTING_guide_4151
Add testdir examples to CONTRIBUTING guide
2018-10-15 08:48:57 -03:00
Bruno Oliveira
ea25eb1ecc Fix linting 2018-10-15 08:15:40 -03:00
Bruno Oliveira
58b6e8616c Merge pull request #4149 from RonnyPfannschmidt/modern-build
modernize packaging for setuptools>30.3
2018-10-15 08:13:47 -03:00
Bruno Oliveira
f129ba617f Improve docs a bit 2018-10-15 08:00:16 -03:00
Tomer Keren
99d957bd3d Check off PR requirements 2018-10-15 11:36:31 +03:00
Tomer Keren
661013c3e9 Add testdir examples to CONTRIBUTING guide
Hopefully Closes: #4151
2018-10-15 11:13:24 +03:00
Ankit Goel
141c51f0cb Merge pull request #4145 from labcodes/4098
Add returncode argument to pytest.exit
2018-10-15 11:04:11 +05:30
Ronny Pfannschmidt
d65c7658d5 changelog 2018-10-15 07:32:38 +02:00
Ronny Pfannschmidt
7855284ef7 move most setuptools parameters over to setup.cfg 2018-10-15 07:30:07 +02:00
Ronny Pfannschmidt
5b0f88712b Merge pull request #4148 from RonnyPfannschmidt/pathlib-cleanup-symlink-is-fine
fix #4135 - handle symlinks in tmp path cleanup
2018-10-15 07:02:13 +02:00
Anthony Sottile
2e42d937dc Display the filename when encountering SyntaxWarning.
```console
$ cd t && rm -rf __pycache__ && pytest t.py -q -c /dev/null; cd ..
.                                                                        [100%]
=============================== warnings summary ===============================
<unknown>:2: DeprecationWarning: invalid escape sequence \.

-- Docs: https://docs.pytest.org/en/latest/warnings.html
1 passed, 1 warnings in 0.01 seconds

```

```console
$ cd t && rm -rf __pycache__ && pytest t.py -q -c /dev/null; cd ..
.                                                                        [100%]
=============================== warnings summary ===============================
/tmp/pytest/t/t.py:2: DeprecationWarning: invalid escape sequence \.
  '\.wat'

-- Docs: https://docs.pytest.org/en/latest/warnings.html
1 passed, 1 warnings in 0.01 seconds
```
2018-10-14 16:11:47 -07:00
Jose Carlos Menezes
27d932e882 Fix order of parameters when raising Exit exception 2018-10-14 18:48:32 -03:00
Jose Carlos Menezes
40091ec2c7 Update pytest.exit docstring 2018-10-14 18:44:53 -03:00
Jose Carlos Menezes
76fb9970c8 Check if returncode is not None before assigning test return code 2018-10-14 18:43:48 -03:00
Jose Carlos Menezes
d32f2c5c14 Change Exit.__init__ params order to keep backward compatibility 2018-10-14 18:42:55 -03:00
Bruno Oliveira
49defa2890 Merge pull request #4144 from nicoddemus/fix-flaky-durations-test
Fix flaky durations test
2018-10-14 18:40:14 -03:00
Bruno Oliveira
fe2dae4885 Merge pull request #4140 from blueyed/ci
Faster CI
2018-10-14 18:39:13 -03:00
Bruno Oliveira
ced62f30ba Attempt to create symlinks even on Windows, skipping when not possible 2018-10-14 18:21:04 -03:00
Jose Carlos Menezes
bbd1cbb0b3 Update changelog to better reading 2018-10-14 18:03:37 -03:00
Jose Carlos Menezes
d4dfd526c1 Update pytest.exit docstring 2018-10-14 18:01:47 -03:00
Ronny Pfannschmidt
d4351ac5a2 modernize packaging for setuptools>30.3 2018-10-14 21:44:32 +02:00
Jose Carlos Menezes
766d2daa06 Update returncode exit test to check exitstatus returrned from test session 2018-10-14 16:41:16 -03:00
Jose Carlos Menezes
836c9f82f1 Set test session exitstatus value from Exit excetion return code 2018-10-14 16:39:43 -03:00
Jose Carlos Menezes
46d6a3fc27 Pass returncode to Error exception when creating instance 2018-10-14 16:36:53 -03:00
Ronny Pfannschmidt
1dfa303b1e fix #4135 - handle symlinks in tmp path cleanup 2018-10-14 21:20:34 +02:00
Bruno Oliveira
6258248865 Merge pull request #4138 from blueyed/cov-pexpect
tox.ini: clean up changedir
2018-10-14 15:41:54 -03:00
Bruno Oliveira
4808145846 test_request_garbage is flaky when running with xdist
Example failure:

https://travis-ci.org/pytest-dev/pytest/jobs/441305926#L545
2018-10-14 15:17:08 -03:00
Jose Carlos Menezes
a0666354dd Update changelog 2018-10-14 12:29:19 -03:00
Jose Carlos Menezes
ce55dcf64c Add test for calling pytest.exit with statuscode
It checks that a SystemError was raised and the SystemError code
is the same as the returncode argument.
2018-10-14 12:29:19 -03:00
Jose Carlos Menezes
d7be039f1b Add returncode argument to pytest.exit
If the argument is not None, it'll raise a SystemExit exception to
cleanly exit pytest.
2018-10-14 12:26:31 -03:00
Bruno Oliveira
7e1fac5f91 Merge pull request #4139 from blueyed/passenv
tox.ini: passenv: COVERAGE_*
2018-10-14 12:24:28 -03:00
Bruno Oliveira
486ded3fca Fix flaky durations test
Unfortunately due to fluctuations in runtime "test_something"
might still appear in the final message.

Example failure:

https://ci.appveyor.com/project/pytestbot/pytest/builds/19494829/job/8lx847u0c78m63wf
2018-10-14 12:22:56 -03:00
Daniel Hahler
0be84cd68b Merge pull request #4141 from blueyed/testpaths-fix
tox.ini: fix testpaths
2018-10-14 17:21:10 +02:00
Daniel Hahler
323c846ce6 tox.ini: fix testpaths
Broken recently in 307fa7a4 (features branch).

[ci skip] (since it apparently is not tested/used there)
2018-10-14 17:05:28 +02:00
Daniel Hahler
3bd9f981a2 tox.ini: clean up changedir 2018-10-14 14:33:28 +02:00
Daniel Hahler
7ded937e19 AppVeyor: use fast_finish
This runs py27, py37 and linting first - simulating the baseline stage
used on Travis.
2018-10-14 14:27:34 +02:00
Daniel Hahler
6d0667f1db CI: run specialized factors in a single job
Given the setup time for jobs, it makes sense to run
*-pexpect,*-trial,*-numpy in a single build job.
2018-10-14 14:27:34 +02:00
Daniel Hahler
7c380b19f3 tox.ini: passenv: COVERAGE_*
This is required to pass through COVERAGE_PROCESS_START etc.
2018-10-14 12:34:17 +02:00
Daniel Hahler
5322f422e3 Merge pull request #4108 from blueyed/realpath
Resolve symlinks for args
2018-10-14 11:30:18 +02:00
Daniel Hahler
c6c326f076 Merge pull request #4137 from blueyed/toxini
tox.ini: pexpect: use posargs; cleanup posargs
2018-10-14 11:29:34 +02:00
Daniel Hahler
d6832a8b56 Merge pull request #4133 from blueyed/pdb-quit
pdb: handle quitting in post_mortem
2018-10-14 11:29:09 +02:00
Daniel Hahler
3bfaa8ab84 Merge pull request #4132 from blueyed/pdb-internal-dupe
Do not print (duplicate) INTERNALERROR with --pdb.
2018-10-14 11:25:35 +02:00
Bruno Oliveira
9fb305b17b Merge pull request #4086 from jeffreyrack/4063-exclude-0-durations
Exclude durations that are 0.00 seconds long.
2018-10-13 22:16:04 -03:00
Bruno Oliveira
e3bf9cede4 Fix linting 2018-10-13 22:13:25 -03:00
Daniel Hahler
4a49715614 tox.ini: pexpect: use posargs; cleanup posargs
- no need for {posargs:testing} really
- remove `-ra`, used with addopts already
2018-10-14 00:08:46 +02:00
Daniel Hahler
86c7dcff68 pdb: handle quitting in post_mortem
`help quit` in pdb says:

> Quit from the debugger. The program being executed is aborted.

But pytest would continue with the next tests, often making it necessary
to kill the pytest process when using `--pdb` and trying to cancel the
tests using `KeyboardInterrupt` / `Ctrl-C`.
2018-10-14 00:05:45 +02:00
Daniel Hahler
7268462b33 Resolve symlinks for args
This fixes running `pytest tests/test_foo.py::test_bar`, where `tests`
is a symlink to `project/app/tests`: previously
`project/app/conftest.py` would be ignored for fixtures then.
2018-10-13 23:59:05 +02:00
Daniel Hahler
448830e656 Do not print INTERNALERROR with --pdb
This gets printed by the terminal reporter already, and currently
results in the same error being displayed twice, e.g. when raising an
`Exception` manually from `pytest.debugging.pytest_exception_interact`.
2018-10-13 23:56:34 +02:00
Bruno Oliveira
3683d92c53 Adjust the 'durations hidden' message 2018-10-13 18:40:32 -03:00
Daniel Hahler
d3d8d53e41 tests: test_pdb: fix print statements 2018-10-13 23:33:52 +02:00
Jeffrey Rackauckas
7a271a91b0 Fix rounding error when displaying durations in non-verbose mode. 2018-10-13 12:55:17 -07:00
Jeffrey Rackauckas
47f5c29002 Update messaging for --durations when not in verbose mode. 2018-10-13 12:51:04 -07:00
Bruno Oliveira
27d2683a02 Merge pull request #4134 from blueyed/minor
Minor: code style / constant
2018-10-13 16:13:02 -03:00
Bruno Oliveira
792f365c14 Merge pull request #4136 from luziferius/patch-1
docs: deprecation.rst: Add missing arguments to example code
2018-10-13 16:12:49 -03:00
Thomas Hess
91b2797498 docs: deprecation.rst: Add missing arguments to code example
In the proposed new style using `@pytest.mark.parametrize`,
the example function signature missed the actual arguments.
Add the missing arguments
2018-10-13 20:33:31 +02:00
Daniel Hahler
c27c8f41a8 Merge pull request #4123 from blueyed/clarify
tests: clarify/document/harden acceptance tests
2018-10-13 18:26:10 +02:00
Daniel Hahler
ee54fb9a6b pytester: use EXIT_INTERRUPTED 2018-10-13 17:06:40 +02:00
Daniel Hahler
10ddc466bf minor: typo and code style 2018-10-13 17:06:40 +02:00
Bruno Oliveira
24c83d725a Merge pull request #4129 from nicoddemus/merge-master-into-features
Merge master into features (prepare for 3.9)
2018-10-13 12:05:54 -03:00
Daniel Hahler
6bf4692c7d acceptance_test: clarify/document/fix tests
Ref: e2e6e31711 (r30863971)
2018-10-13 14:41:17 +02:00
Daniel Hahler
81426c3d19 tests: harden test_cmdline_python_package_symlink 2018-10-13 14:41:12 +02:00
Bruno Oliveira
ed42ada373 Merge pull request #4124 from nicoddemus/traceback-import-error-3332
Improve tracebacks for ImportErrors in conftest
2018-10-13 09:25:10 -03:00
Daniel Hahler
e2667106a2 Merge pull request #4126 from blueyed/testpaths
tox.ini: use testpaths, cleanup other pytest options
2018-10-13 14:10:44 +02:00
Bruno Oliveira
29d5849519 Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2018-10-13 08:50:32 -03:00
Bruno Oliveira
eabf15b626 Merge pull request #4125 from nicoddemus/docs-baseline
Run docs, doctesting and linting in the same job to save some CI time
2018-10-12 21:01:59 -03:00
Bruno Oliveira
2dc619cbf4 Run docs, doctesting and linting in the same environment to save some CI time 2018-10-12 13:35:27 -03:00
Daniel Hahler
307fa7a42a tox.ini: use testpaths, cleanup other pytest options 2018-10-12 17:07:45 +02:00
Bruno Oliveira
ef97121d42 Removed unused ConftestImportFailure.__str__ method 2018-10-12 10:57:13 -03:00
Ankit Goel
d46b6b2bc3 Merge pull request #4121 from labcodes/3713
Update usefixtures documentation
2018-10-12 19:08:40 +05:30
Bruno Oliveira
2cb3534679 Move filter_traceback to _pytest._code 2018-10-12 10:19:50 -03:00
Bruno Oliveira
8e11fe5304 Improve tracebacks for ImportErrors in conftest.py files
Fix #3332
2018-10-12 10:10:55 -03:00
Bruno Oliveira
36dc671843 New ExceptionInfo.getrepr 'chain' parameter to be able to suppress chained exceptions 2018-10-12 10:08:55 -03:00
Jose Carlos Menezes
dbaa9464ba Update usefixtures documentation
Clarifying that it can't be used with fixture functions
2018-10-12 09:45:49 -03:00
Bruno Oliveira
933de16fe4 Merge pull request #3988 from RonnyPfannschmidt/tmpdir-port-pathlib
Tmpdir port pathlib
2018-10-12 08:33:47 -03:00
Bruno Oliveira
e8348a1d12 Merge pull request #4077 from nicoddemus/short-usage-errors
Improve internal error messages
2018-10-12 08:18:07 -03:00
Bruno Oliveira
0f5263cdc3 Merge pull request #4109 from njonesu/master
Fix multiple string literals on a line #4093
2018-10-11 15:50:08 -03:00
Ronny Pfannschmidt
4736b2bdfb address review comments 2018-10-11 20:48:30 +02:00
Anthony Sottile
8ecdd4e9ff Merge pull request #4104 from asottile/deprecated_call_match
Implement pytest.deprecated_call with pytest.warns
2018-10-11 08:20:13 -07:00
Daniel Hahler
b3940666a7 Merge pull request #4103 from blueyed/conftest
conftest: optimize _getconftestmodules
2018-10-11 13:52:48 +02:00
Bruno Oliveira
e20987ce82 Merge pull request #4110 from blueyed/pdb
tests: fixes for pdbpp
2018-10-11 08:43:24 -03:00
Ronny Pfannschmidt
584051aa90 extend docs with basics about tmp_path and tmp_path_facotry 2018-10-11 10:33:59 +02:00
Ronny Pfannschmidt
16e2737da3 implement tmp_path_factory and deprecate pytest.ensuretemp as intended 2018-10-11 09:41:37 +02:00
Ronny Pfannschmidt
36c2a101cb add missing docstring 2018-10-11 07:15:09 +02:00
Ronny Pfannschmidt
ebd597b2fd use the constant for lock timeouts 2018-10-11 07:15:09 +02:00
Ronny Pfannschmidt
94829c391b make tmpdir env cleanup idempotent 2018-10-11 07:15:09 +02:00
Ronny Pfannschmidt
b82d6f7a0b pytester: use per test tmproot 2018-10-11 07:15:09 +02:00
Ronny Pfannschmidt
4a436b5470 resolve in code review commments 2018-10-11 07:15:09 +02:00
Ronny Pfannschmidt
ad6f63edda add changelog 2018-10-11 07:15:09 +02:00
Ronny Pfannschmidt
3036914097 sort out rmtree expectations 2018-10-11 07:15:09 +02:00
Ronny Pfannschmidt
2831cb9ab5 unify paths.py and pathlib.py 2018-10-11 07:15:09 +02:00
Ronny Pfannschmidt
00716177b4 fix missed Path import 2018-10-11 07:15:09 +02:00
Ronny Pfannschmidt
85cc9b8f12 move all the things into _pytest.pathlib 2018-10-11 07:15:08 +02:00
Ronny Pfannschmidt
fed4f73a61 ignore rmtree errors 2018-10-11 07:15:08 +02:00
Ronny Pfannschmidt
d76fa59b35 fix lock timeouts for good this time 2018-10-11 07:15:08 +02:00
Ronny Pfannschmidt
2532dc1dbb fix up lock consideration argument 2018-10-11 07:15:08 +02:00
Ronny Pfannschmidt
642cd86dd1 shape up removal and lock destruction 2018-10-11 07:15:08 +02:00
Ronny Pfannschmidt
b3a5b0ebe1 remove path from exposure 2018-10-11 07:15:08 +02:00
Ronny Pfannschmidt
8b4a29357e fix typo 2018-10-11 07:15:08 +02:00
Ronny Pfannschmidt
ab3637d486 implement cleanup for unlocked folders 2018-10-11 07:15:08 +02:00
Ronny Pfannschmidt
66a690928c bring in purepath and fix an assertion 2018-10-11 07:15:08 +02:00
Ronny Pfannschmidt
8e00280fc1 fix linting 2018-10-11 07:15:08 +02:00
Ronny Pfannschmidt
d053cdfbbb factor out max and iterate on locks and cleanups 2018-10-11 07:15:08 +02:00
Ronny Pfannschmidt
2e39fd89d1 add python27 support by using reduce instead of max 2018-10-11 07:15:08 +02:00
Ronny Pfannschmidt
b48e23d54c port interals of tmpdir to a basic pathlib implementation
this is still lacking locking and cleanup of the folders
2018-10-11 07:15:08 +02:00
Bruno Oliveira
c9a85b0e78 Fix linting 2018-10-10 19:54:39 -03:00
Bruno Oliveira
bf265a424d Minor adjustments found during code review 2018-10-10 19:35:49 -03:00
Bruno Oliveira
5436e42990 Use pytest.fail(..., pytrace=False) when treating user errors
This prevents an enormous and often useless stack trace from showing
to end users.

Fix #3867
Fix #2293
2018-10-10 19:16:53 -03:00
Bruno Oliveira
67f40e18a7 Use attr.s(repr=False) because we customize MarkInfo's repr 2018-10-10 19:13:34 -03:00
Daniel Hahler
52ff1eaf37 _getconftestmodules: optimize 2018-10-10 21:30:33 +02:00
Daniel Hahler
602e74c2a7 Merge pull request #4107 from blueyed/__tracebackhide__
pytester: fix __tracebackhide__ for {re_,fn}match_lines
2018-10-10 20:55:32 +02:00
Daniel Hahler
be511c1a05 tests: add missing expect before sendeof for pdbpp
With pdb++ this additional `expect` is required, otherwise `sendeof()`
will block forever.
2018-10-10 20:50:49 +02:00
Daniel Hahler
f36f9d2698 tests: fix/clarify expect for Pdb
`expect()` expects an regular expression, so "Pdb" is equivalent to
"(Pdb)".

But instead of escaping the parenthesis this patch removes them, to
allow for matching "(Pdb++)", too.
2018-10-10 20:50:49 +02:00
Anthony Sottile
dbfb3ccc42 Add changelog entry 2018-10-10 10:46:09 -07:00
Niklas JQ
d1322570dd Fix issue 4093 2018-10-10 19:45:07 +02:00
Daniel Hahler
4c9015c3b1 Merge pull request #4105 from blueyed/repr
Fix trailing whitespace in FixtureDef.__repr__
2018-10-10 19:28:32 +02:00
Niklas JQ
c14a23d4e4 Fix #4093: multiple string literals on a line 2018-10-10 19:28:31 +02:00
Daniel Hahler
b8fc3e569a pytester: fix __tracebackhide__ for {re_,fn}match_lines 2018-10-10 19:27:43 +02:00
Anthony Sottile
e0f6fce9e9 In python2, display previously warned warnings 2018-10-10 09:37:21 -07:00
Daniel Hahler
d93de6cc67 Fix trailing whitespace in FixtureDef.__repr__ 2018-10-10 18:14:56 +02:00
Anthony Sottile
aeb92accb2 Implement pytest.deprecated_call with pytest.warns 2018-10-10 08:03:23 -07:00
Anthony Sottile
943bbdd8ce Merge pull request #4100 from nicoddemus/merge-master-into-features
Merge master into features
2018-10-10 07:35:09 -07:00
Bruno Oliveira
9a3836a0cf Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2018-10-09 19:34:04 -03:00
Anthony Sottile
4b164d947d Merge pull request #4099 from asottile/re-enable_linting_windows
re-enable linting tox env on windows
2018-10-09 15:16:08 -07:00
Anthony Sottile
11a07211b6 re-enable linting tox env on windows 2018-10-09 13:01:51 -07:00
Anthony Sottile
28a3f0fcb9 Revert "Merge pull request #4094 from pytest-dev/asottile/asottile-patch-1"
This reverts commit c55d641963, reversing
changes made to 8393fdd51d.
2018-10-09 12:50:03 -07:00
Anthony Sottile
b8c30aab2b Merge pull request #4097 from asottile/improve_doc_plugin_load
Fix formatting for plugin loading in conftest
2018-10-09 10:23:04 -07:00
Daniel Hahler
b8958168f5 Merge pull request #4092 from altendky/4073-altendky-subprocessing_timeout-take_2
Correct timing in test_pytester.test_testdir_run_with_timeout()
2018-10-09 18:46:58 +02:00
Anthony Sottile
aaaae0b232 Fix formatting for plugin loading in conftest 2018-10-09 09:30:56 -07:00
Anthony Sottile
c55d641963 Merge pull request #4094 from pytest-dev/asottile/asottile-patch-1
Temporarily disable `linting` env in appveyor
2018-10-08 22:55:34 -07:00
Anthony Sottile
4ec85f934c Temporarily disable linting env in appveyor 2018-10-08 22:54:32 -07:00
Ronny Pfannschmidt
8393fdd51d Merge pull request #4089 from asottile/upgrade_hooks
Upgrade pre-commit hooks
2018-10-09 07:43:28 +02:00
Kyle Altendorf
4071c8a4a8 Correct timing in test_pytester.test_testdir_run_with_timeout() 2018-10-08 21:03:42 -04:00
Anthony Sottile
e8c10d4a98 Merge pull request #4090 from asottile/faster_tests
Improve performance of ~3 of the slowest tests
2018-10-08 17:07:10 -07:00
Anthony Sottile
a86035625c Increase recursion limit (broke xdist tests) 2018-10-08 12:57:45 -07:00
Anthony Sottile
4f631440be Use RuntimeError for py27 + py34 compat 2018-10-08 11:47:06 -07:00
Anthony Sottile
3901569f26 Improve performance of ~3 of the slowest tests 2018-10-08 11:12:55 -07:00
Anthony Sottile
689b856cb7 Merge pull request #4088 from Sup3rGeo/bugfix/announcements-name-victor-maryama
Renamed Victor to full name.
2018-10-08 10:16:20 -07:00
Anthony Sottile
65545d8fb2 Manual fixups of black formatting 2018-10-08 10:12:42 -07:00
Anthony Sottile
1caf6d5907 Upgrade pre-commit hooks 2018-10-08 10:10:46 -07:00
Victor Maryama
55871c68a4 Renamed Victor to full name. 2018-10-08 18:43:50 +02:00
Jeffrey Rackauckas
fc11b81005 Exclude durations that are 0.00 seconds long. 2018-10-07 19:19:48 -07:00
Kyle Altendorf
a6fb4c8268 Merge pull request #4078 from altendky/4073-altendky-subprocessing_timeout
Add timeout for Testdir.runpytest_subprocess() and Testdir.run()
2018-10-07 18:07:06 -04:00
Kyle Altendorf
48dcc67274 Increase timeout in test_testdir_run_with_timeout to decrease false failures 2018-10-06 22:02:33 -04:00
Kyle Altendorf
ccaec8d360 __tracebackhide__ = True 2018-10-06 21:57:03 -04:00
Ronny Pfannschmidt
66609665f2 Merge pull request #4076 from nicoddemus/unittest-param-fixture-msg
Improve error message when TestCase functions use a parametrized fixture
2018-10-06 07:43:57 +02:00
Kyle Altendorf
4b36f9aa64 Tidy timeout checking 2018-10-05 16:46:24 -04:00
Kyle Altendorf
5ecbb0acba Correct new changelog to have newline at end 2018-10-05 10:22:07 -04:00
Kyle Altendorf
20902deb75 Add Kyle Altendorf to AUTHORS 2018-10-05 10:02:59 -04:00
Kyle Altendorf
ed5556bdac Add to docstrings 2018-10-05 10:02:59 -04:00
Kyle Altendorf
ee64f1fb9f Add changelog file for 4073 2018-10-05 10:02:59 -04:00
Kyle Altendorf
8e0e862c84 Stretch out the time assertion for slow AppVeyor 2018-10-05 01:38:01 -04:00
Kyle Altendorf
42422a7f62 Throw away arbitrary args to runpytest_subprocess() 2018-10-05 00:30:25 -04:00
Kyle Altendorf
f3a173b736 Revert "Use signal.alarm() for py2 timeout"
This reverts commit 900cef6397.
2018-10-05 00:05:46 -04:00
Kyle Altendorf
5c38a5160d Slight diff tidy 2018-10-04 23:33:38 -04:00
Kyle Altendorf
dcf9eb0104 Raise an exception on unexpected kwargs 2018-10-04 23:27:01 -04:00
Kyle Altendorf
dd225e1b9d Tidy getting of timeout from kwargs 2018-10-04 23:15:30 -04:00
Kyle Altendorf
900cef6397 Use signal.alarm() for py2 timeout 2018-10-04 23:11:26 -04:00
Kyle Altendorf
0d095fc978 Up timeout to 1 second for test 2018-10-04 23:09:07 -04:00
Kyle Altendorf
dcd635ba0c Correct timeout to check every so often 2018-10-04 23:08:57 -04:00
Kyle Altendorf
33f0338eeb kill and wait for subprocess before raising TimeoutExpired 2018-10-04 22:52:51 -04:00
Kyle Altendorf
d5e5433553 Add descriptive message for timeout 2018-10-04 21:43:41 -04:00
Kyle Altendorf
d2906950ce monotonic.monotonic() -> time.time() 2018-10-04 21:26:08 -04:00
Bruno Oliveira
fe7050ba00 Fix lint 2018-10-04 18:45:30 -03:00
Bruno Oliveira
a1208f5631 Merge pull request #4075 from nicoddemus/dynamic-fixturenames
Fix request.fixturenames to return fixtures created dynamically
2018-10-04 09:21:23 -03:00
Kyle Altendorf
870a93c37b Actually construct TimeoutExpired 2018-10-04 01:02:58 -04:00
Kyle Altendorf
96b2ae6654 Initial pass at timeout for subprocessing pytest
pytest-dev/pytest#4073
2018-10-03 23:56:57 -04:00
Anthony Sottile
b098292352 Merge pull request #4069 from asottile/deindent_4066
Fix source reindenting by using `textwrap.dedent` directly.
2018-10-03 16:11:51 -07:00
Bruno Oliveira
212937eb3e Improve error message when TestCase functions use a parametrized fixture
Fix #2535
2018-10-03 19:43:46 -03:00
Bruno Oliveira
70c7273640 Fix request.fixturenames to return fixtures created dynamically
Fix #3057
2018-10-03 18:50:14 -03:00
Anthony Sottile
e5ab62b1b6 Remove (unused) offset= parameter from deindent() 2018-10-03 13:33:10 -07:00
Anthony Sottile
b8b9e8d41c Remove duplicate test (tested above) 2018-10-03 10:01:06 -07:00
Bruno Oliveira
e712adc226 Merge pull request #4072 from pecey/tmp/issue-4064
Fixes #4064 by correcting the documentation for unit-tests
2018-10-03 12:26:35 -03:00
Palash Chatterjee
f9ac60807c Fixes #4064 by correcting the documentation for unit-tests 2018-10-03 18:11:09 +05:30
Bruno Oliveira
3f03625a5d Merge pull request #4070 from jeffreyrack/4058-update-fixture-docs
Update documentation to indicate a fixture can be invoked more than once in it's scope.
2018-10-03 08:39:41 -03:00
Ronny Pfannschmidt
29d3faed66 Merge pull request #4068 from nicoddemus/merge-master-into-features
Merge master into features
2018-10-03 08:30:39 +02:00
Jeffrey Rackauckas
c5dec6056f Fix wording in fixtures doc. 2018-10-02 21:17:53 -07:00
Jeffrey Rackauckas
642847c079 Update documentation on fixture being invoked more than once in a scope. 2018-10-02 20:53:15 -07:00
Anthony Sottile
f102ccc8f0 Fix source reindenting by using textwrap.dedent directly. 2018-10-02 16:13:35 -07:00
Bruno Oliveira
20f93ae8fa Merge pull request #4067 from beneyal/master
Add pytest.freeze_includes() to reference
2018-10-02 20:02:37 -03:00
Bruno Oliveira
1101a20408 Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2018-10-02 18:13:54 -03:00
Anthony Sottile
df435fa8bd Merge pull request #4065 from asottile/release-3.8.2
Preparing release version 3.8.2
2018-10-02 13:53:52 -07:00
Ben Eyal
a5269b26e0 Add anchor for "Freezing pytest" 2018-10-02 17:54:59 +03:00
Anthony Sottile
d3673c7429 Preparing release version 3.8.2 2018-10-02 07:46:02 -07:00
Ben Eyal
5010e02eda Add pytest.freeze_includes to reference 2018-10-02 17:39:08 +03:00
Bruno Oliveira
25fe3706a4 Merge pull request #4056 from nicoddemus/unicode-vars
Ensure Monkeypatch setenv and delenv use bytes keys in Python 2
2018-10-02 07:56:32 -03:00
Bruno Oliveira
1a323fbd3c Show a warning when non-str is given to Monkeypatch.setenv 2018-10-01 20:07:07 -03:00
Bruno Oliveira
9d971d33be Hide internal pytest.warns traceback 2018-10-01 18:45:08 -03:00
Bruno Oliveira
bc009a8582 Fix test to comply with pypy 6.0 2018-10-01 18:37:27 -03:00
Bruno Oliveira
5e7d427df1 Merge pull request #4060 from nicoddemus/4051-changelog
Improve changelog for #4051
2018-10-01 18:12:52 -03:00
Bruno Oliveira
dd59ed3b18 Merge pull request #4059 from labcodes/documenting-scopes
Add possible values for fixture scope to docs
2018-10-01 17:25:42 -03:00
Bruno Oliveira
20d0f0e56b Improve changelog for #4051 2018-10-01 17:12:05 -03:00
Bruno Oliveira
d24a7e6c5a Issue warning if Monkeypatch.setenv/delenv receive non-strings in Python 2
Fixes the bug described in:

	https://github.com/tox-dev/tox/pull/1025#discussion_r221273830

Which is more evident when using `unicode_literals`.
2018-10-01 17:05:30 -03:00
Jose Carlos Menezes
4dc73bda45 Update changelog 2018-10-01 14:41:30 -03:00
Jose Carlos Menezes
732cc2687d Add possible values for fixture scope to docs 2018-10-01 14:31:28 -03:00
Ronny Pfannschmidt
5d2d64c190 Merge pull request #4057 from jeffreyrack/4051-improve-error-messaging
Improve error messaging when invalid syntax is passed to the -m option
2018-10-01 07:16:59 +02:00
Jeffrey Rackauckas
7a6d16c1eb Adding .rst to end of changelog fragment filename. 2018-09-30 18:45:49 -07:00
Jeffrey Rackauckas
c2179c3127 Improve error messaging when invalid syntax is passed to the -m option 2018-09-30 18:34:56 -07:00
Bruno Oliveira
d8d7f73e1c Merge pull request #4045 from nicoddemus/root-conftest-warning-workaround-4039
Do not issue non-top-level conftest warning when --pyargs is used
2018-09-27 09:26:11 -03:00
Ronny Pfannschmidt
3c23b5b010 Merge pull request #4037 from nicoddemus/deprecate-item-warnings-captured-hook
Document that item parameter of pytest_warning_captured hook is deprecated
2018-09-27 13:20:26 +02:00
Bruno Oliveira
783019a8e6 Rename 4040.trivial.rst to 4040.bugfix.rst 2018-09-27 08:08:03 -03:00
Bruno Oliveira
d2fc7ca6e0 Merge pull request #4041 from Zac-HD/user-properties-type
Ensure user_properties is a list
2018-09-27 08:04:30 -03:00
Bruno Oliveira
2d06927a06 Merge pull request #4040 from ods/summary_passes_less_noisy
Exclude empty reports for passed tests
2018-09-27 08:01:58 -03:00
Denis Otkidach
44d29d887e Changelog entry on excluding empty reports for passed tests 2018-09-26 19:02:35 +03:00
Bruno Oliveira
32c5a113e2 Do not issue non-top-level conftest warning when --pyargs is used
Fix #4039
2018-09-26 12:02:08 -03:00
Bruno Oliveira
ba5630e0f8 Simplify test_pytest_plugins_in_non_top_level_conftest_deprecated 2018-09-26 10:49:14 -03:00
Denis Otkidach
808df48ee8 Test for excluding empty reports for passed tests 2018-09-26 16:44:00 +03:00
Zac-HD
a089a9577e Succinct definition of user_properties 2018-09-26 22:40:11 +10:00
Zac-HD
6be2136f20 Ensure user_properties is a list 2018-09-26 22:04:50 +10:00
Denis Otkidach
f9ab81a493 Exclude empty reports for passed tests 2018-09-26 11:55:39 +03:00
Bruno Oliveira
1636522563 Document that item parameter of pytest_warning_captured hook is deprecated
Our policy is to not deprecate features during bugfix releases, but in this
case I believe it makes sense as we are only documenting it as deprecated,
without issuing warnings which might potentially break test suites.

This will get the word out that hook implementers should not use this parameter
at all.

Fix #4036
2018-09-25 17:38:22 -03:00
Bruno Oliveira
b1fbb2ab92 Merge pull request #4032 from hjwp/patch-1
add documentation of register_assert_rewrite
2018-09-25 08:43:29 -03:00
Daniel Hahler
e85edf5212 Merge pull request #4029 from nicoddemus/warnings-example-deprecation-docs
Add an example on how to update config.warn calls
2018-09-25 13:25:21 +02:00
Bruno Oliveira
b03bad5dbb Fix linting 2018-09-25 08:12:55 -03:00
Harry Percival
19ec300b2a fix rst syntax again 2018-09-25 06:58:47 +01:00
Harry Percival
11442f2ad7 fix rst syntax thing 2018-09-25 06:57:33 +01:00
Harry Percival
97748b6605 mention conftest.py as a good place to do it. 2018-09-25 06:55:28 +01:00
Harry Percival
2b762337bd add documentation of register_assert_rewrite
wip
2018-09-25 06:49:50 +01:00
Bruno Oliveira
9899b8f1fb Add an example on how to update config.warn calls
As commented in https://github.com/pytest-dev/pytest-cov/pull/230#pullrequestreview-157958838
2018-09-23 22:42:09 -03:00
Anthony Sottile
956b3aca97 Revert patching of breakpointhook as it appears to do nothing 2018-09-23 18:39:50 -07:00
Anthony Sottile
4474beeb82 Typo fix [ci skip] 2018-09-23 18:07:28 -07:00
Ronny Pfannschmidt
5d8467bedc Merge pull request #4023 from nicoddemus/deprecated-3.9
Add 3.9 deprecated features to deprecations.rst
2018-09-23 18:21:32 +02:00
Ronny Pfannschmidt
eca3e781b6 Merge pull request #4022 from iwanb/fix_reload
Fix #3539: reload module with assertion rewrite import hook
2018-09-23 18:17:56 +02:00
Bruno Oliveira
0d04aa7c59 Add 3.9 deprecated features to deprecations.rst 2018-09-23 09:26:12 -03:00
iwanb
c61ff31ffa Fix #3539: reload module with assertion rewrite import hook 2018-09-23 13:05:55 +02:00
Ronny Pfannschmidt
e03a19f88d Merge pull request #4021 from nicoddemus/merge-master-into-features
Merge master into features
2018-09-23 11:57:05 +02:00
Bruno Oliveira
fcc5b6d604 Add "deprecation" to possible changelog entries in pre-commit 2018-09-22 18:43:22 -03:00
Bruno Oliveira
42afce27b3 Merge pull request #4019 from nicoddemus/deprecation-warnings-4013
Show deprecation warnings even if filters are customized
2018-09-22 18:17:07 -03:00
Bruno Oliveira
56d0b5a7e2 Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2018-09-22 18:14:36 -03:00
Ankit Goel
ec57cbf82d Merge pull request #4020 from crazymerlyn/release-3.8.1
Preparing release version 3.8.1
2018-09-23 00:56:27 +05:30
Bruno Oliveira
c30184709d Show deprecation warnings even if filters are customized
Fix #4013
2018-09-22 10:25:57 -03:00
Thomas Hisch
83802d1494 Merge pull request #3986 from thisch/fb3964
Add support for logging in collection-phase
2018-09-19 20:47:19 +02:00
Thomas Hisch
18cc74b8d0 Remove useless comment 2018-09-19 15:18:37 +02:00
Thomas Hisch
048342817b Add testcase for logging to file 2018-09-18 21:47:42 +02:00
Thomas Hisch
d1a3aa7b2b Update 3964.rst 2018-09-18 21:31:20 +02:00
Thomas Hisch
e967d4587a Add support for logging in collection-phase
The logging plugin does not output log messages generated during the
collection-phase when live-logging is enabled. This fixes this.

Fixes #3964
2018-09-18 20:18:24 +02:00
Bruno Oliveira
a79dc12f1e Merge pull request #3970 from sambarluc/raise_on_empty_parameterset
Raise exception if parametrize collects an empty parameter set
2018-09-18 08:11:34 -03:00
Andrea Cimatoribus
913c07e414 Add changelog file and new author 2018-09-15 09:18:03 +02:00
Andrea Cimatoribus
4a9f468aac Update documentation 2018-09-15 09:18:03 +02:00
Andrea Cimatoribus
05155e4db0 Fail at parametrize option for empty parameter set
Optionally raise an exception when parametrize collects no arguments.
Provide the name of the test causing the failure in the exception
message.

See: #3849
2018-09-15 09:18:03 +02:00
Ronny Pfannschmidt
bceaede198 Merge pull request #3978 from nicoddemus/warn-yield-and-compat-properties
Actually deprecate long standing features
2018-09-15 07:19:59 +02:00
Bruno Oliveira
ae8f3695b5 Move UnformattedWarning to _pytest.warning_types 2018-09-14 15:31:20 -03:00
Bruno Oliveira
da6830f19b Introduce UnformattedWarning to keep warning types and messages in _pytest.deprecated 2018-09-14 14:49:05 -03:00
Bruno Oliveira
32ee0b9c88 Move warning messages to _pytest.deprecated 2018-09-13 15:56:50 -03:00
Bruno Oliveira
feb8240410 Use self.Function again during collection 2018-09-13 15:44:02 -03:00
Bruno Oliveira
b7dd9154c3 Deprecate custom node types during collection by using special names 2018-09-13 14:55:28 -03:00
Bruno Oliveira
482bd5efd2 Show deprecation warning for cached_setup 2018-09-13 14:25:46 -03:00
Bruno Oliveira
bf074b37a3 Show deprecation warnings for compat properties
Fix #3616
2018-09-13 14:10:30 -03:00
Bruno Oliveira
495a55725b Separate deprecations and removals in the CHANGELOG 2018-09-13 14:02:01 -03:00
Bruno Oliveira
53c9124fc9 Merge pull request #3947 from nicoddemus/warnings-filter-precedence
-W now takes precedence over filters in ini files
2018-09-13 13:23:00 -03:00
Bruno Oliveira
ab40696007 -W now takes precedence over filters in ini files
Fix #3946
2018-09-11 19:00:42 +02:00
Ronny Pfannschmidt
d12f46caef Merge pull request #3949 from nicoddemus/merge-master-into-features
Merge master into features
2018-09-07 07:58:36 +02:00
177 changed files with 5492 additions and 1927 deletions

View File

@@ -3,7 +3,7 @@ Thanks for submitting a PR, your contribution is really appreciated!
Here's a quick checklist that should be present in PRs (you can delete this text from the final description, this is
just a guideline):
- [ ] Create a new changelog file in the `changelog` folder, with a name like `<ISSUE NUMBER>.<TYPE>.rst`. See [changelog/README.rst](/changelog/README.rst) for details.
- [ ] 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.
- [ ] Target the `master` branch for bug fixes, documentation updates and trivial changes.
- [ ] Target the `features` branch for new features and removals/deprecations.
- [ ] Include documentation when adding new features.

View File

@@ -7,26 +7,34 @@ repos:
args: [--safe, --quiet]
language_version: python3
- repo: https://github.com/asottile/blacken-docs
rev: v0.2.0
rev: v0.3.0
hooks:
- id: blacken-docs
additional_dependencies: [black==18.6b4]
additional_dependencies: [black==18.9b0]
language_version: python3
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v1.3.0
rev: v2.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: debug-statements
exclude: _pytest/debugging.py
language_version: python3
- id: flake8
- repo: https://github.com/asottile/pyupgrade
rev: v1.2.0
language_version: python3
- repo: https://github.com/asottile/reorder_python_imports
rev: v1.3.3
hooks:
- id: pyupgrade
- id: reorder-python-imports
args: ['--application-directories=.:src']
- repo: https://github.com/asottile/pyupgrade
rev: v1.10.1
hooks:
- id: pyupgrade
args: [--keep-percent-format]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.0.0
rev: v1.1.0
hooks:
- id: rst-backticks
- repo: local
@@ -40,6 +48,6 @@ repos:
- id: changelogs-rst
name: changelog filenames
language: fail
entry: 'changelog files must be named ####.(feature|bugfix|doc|removal|vendor|trivial).rst'
exclude: changelog/(\d+\.(feature|bugfix|doc|removal|vendor|trivial).rst|README.rst|_template.rst)
entry: 'changelog files must be named ####.(feature|bugfix|doc|deprecation|removal|vendor|trivial).rst'
exclude: changelog/(\d+\.(feature|bugfix|doc|deprecation|removal|vendor|trivial).rst|README.rst|_template.rst)
files: ^changelog/

View File

@@ -1,5 +1,6 @@
sudo: false
language: python
dist: xenial
stages:
- baseline
- name: test
@@ -7,40 +8,34 @@ stages:
- name: deploy
if: repo = pytest-dev/pytest AND tag IS present
python:
- '3.6'
- '3.7'
install:
- pip install --upgrade --pre tox
env:
matrix:
# note: please use "tox --listenvs" to populate the build matrix below
# please remove the linting env in all cases
- TOXENV=py27-pexpect
- TOXENV=py27-xdist
- TOXENV=py27-trial
- TOXENV=py27-numpy
- TOXENV=py27-pluggymaster PYTEST_NO_COVERAGE=1
- TOXENV=py36-pexpect
- TOXENV=py36-xdist
- TOXENV=py36-trial
- TOXENV=py36-numpy
- TOXENV=py36-pluggymaster PYTEST_NO_COVERAGE=1
- TOXENV=py27
# Specialized factors for py27.
- TOXENV=py27-nobyte
- TOXENV=doctesting
- TOXENV=docs PYTEST_NO_COVERAGE=1
- TOXENV=py27-xdist
- TOXENV=py27-pluggymaster PYTEST_NO_COVERAGE=1
# Specialized factors for py37.
- TOXENV=py37-pexpect,py37-trial,py37-numpy
- TOXENV=py37-pluggymaster PYTEST_NO_COVERAGE=1
- TOXENV=py37-freeze PYTEST_NO_COVERAGE=1
jobs:
include:
# Coverage tracking is slow with pypy, skip it.
- env: TOXENV=pypy PYTEST_NO_COVERAGE=1
python: 'pypy-5.4'
dist: trusty
- env: TOXENV=py34
python: '3.4'
- env: TOXENV=py35
python: '3.5'
- env: TOXENV=py36-freeze PYTEST_NO_COVERAGE=1
- env: TOXENV=py36
python: '3.6'
- env: TOXENV=py37
python: '3.7'
sudo: required
dist: xenial
- &test-macos
language: generic
os: osx
@@ -58,10 +53,10 @@ jobs:
- brew link python
- stage: baseline
env: TOXENV=py27
- env: TOXENV=py34
- env: TOXENV=py36
- env: TOXENV=linting PYTEST_NO_COVERAGE=1
env: TOXENV=py27-pexpect,py27-trial,py27-numpy
- env: TOXENV=py37-xdist
- env: TOXENV=linting,docs,doctesting
python: '3.7'
- stage: deploy
python: '3.6'
@@ -94,17 +89,12 @@ after_success:
- |
if [[ "$PYTEST_NO_COVERAGE" != 1 ]]; then
set -e
pip install coverage
# Add last TOXENV to $PATH.
PATH="$PWD/.tox/${TOXENV##*,}/bin:$PATH"
coverage combine
coverage xml --ignore-errors
coverage report -m --ignore-errors
bash <(curl -s https://codecov.io/bash) -Z -X gcov -X coveragepy -X search -X xcode -X gcovout -X fix -f coverage.xml -F "${TOXENV//-/,},linux"
# Coveralls does not support merged reports.
if [[ "$TOXENV" = py37 ]]; then
pip install coveralls
coveralls
fi
fi
notifications:

13
AUTHORS
View File

@@ -10,9 +10,11 @@ Ahn Ki-Wook
Alan Velasco
Alexander Johnson
Alexei Kozlenok
Allan Feldman
Anatoly Bubenkoff
Anders Hovmöller
Andras Tim
Andrea Cimatoribus
Andreas Zeidler
Andrzej Ostrowski
Andy Freeland
@@ -57,6 +59,7 @@ Danielle Jenkins
Dave Hunt
David Díaz-Barquero
David Mohr
David Szotten
David Vierra
Daw-Ran Liou
Denis Kirisov
@@ -73,6 +76,7 @@ Endre Galaczi
Eric Hunsberger
Eric Siegerman
Erik M. Bray
Fabien Zarifian
Fabio Zadrozny
Feng Ma
Florian Bruhin
@@ -93,6 +97,7 @@ Hui Wang (coldnight)
Ian Bicking
Ian Lesperance
Ionuț Turturică
Iwan Briquemont
Jaap Broekhuizen
Jan Balster
Janne Vanhala
@@ -118,6 +123,7 @@ Katerina Koukiou
Kevin Cox
Kodi B. Arfer
Kostis Anagnostopoulos
Kyle Altendorf
Lawrence Mitchell
Lee Kamentsky
Lev Maximov
@@ -157,6 +163,7 @@ Miro Hrončok
Nathaniel Waisbrot
Ned Batchelder
Neven Mundar
Niclas Olofsson
Nicolas Delaby
Oleg Pidsadnyi
Oleg Sushchenko
@@ -178,6 +185,7 @@ Raphael Pierzina
Raquel Alegre
Ravi Chandra
Roberto Polli
Roland Puntaier
Romain Dorgueil
Roman Bolshakov
Ronny Pfannschmidt
@@ -197,6 +205,7 @@ Stefan Zimmermann
Stefano Taschini
Steffen Allner
Stephan Obermann
Sven-Hendrik Haase
Tadek Teleżyński
Tarcisio Fischer
Tareq Alayan
@@ -206,6 +215,7 @@ Thomas Hisch
Tim Strazny
Tom Dalton
Tom Viner
Tomer Keren
Trevor Bekolay
Tyler Goodlet
Tzu-ping Chung
@@ -222,6 +232,5 @@ Wim Glenn
Wouter van Ackooy
Xuan Luong
Xuecong Liao
Zac Hatfield-Dodds
Zoltán Máté
Roland Puntaier
Allan Feldman

View File

@@ -18,6 +18,453 @@ with advance notice in the **Deprecations** section of releases.
.. towncrier release notes start
pytest 4.0.0 (2018-11-13)
=========================
Removals
--------
- `#3737 <https://github.com/pytest-dev/pytest/issues/3737>`_: **RemovedInPytest4Warnings are now errors by default.**
Following our plan to remove deprecated features with as little disruption as
possible, all warnings of type ``RemovedInPytest4Warnings`` now generate errors
instead of warning messages.
**The affected features will be effectively removed in pytest 4.1**, so please consult the
`Deprecations and Removals <https://docs.pytest.org/en/latest/deprecations.html>`__
section in the docs for directions on how to update existing code.
In the pytest ``4.0.X`` series, it is possible to change the errors back into warnings as a stop
gap measure by adding this to your ``pytest.ini`` file:
.. code-block:: ini
[pytest]
filterwarnings =
ignore::pytest.RemovedInPytest4Warning
But this will stop working when pytest ``4.1`` is released.
**If you have concerns** about the removal of a specific feature, please add a
comment to `#4348 <https://github.com/pytest-dev/pytest/issues/4348>`__.
- `#4358 <https://github.com/pytest-dev/pytest/issues/4358>`_: Remove the ``::()`` notation to denote a test class instance in node ids.
Previously, node ids that contain test instances would use ``::()`` to denote the instance like this::
test_foo.py::Test::()::test_bar
The extra ``::()`` was puzzling to most users and has been removed, so that the test id becomes now::
test_foo.py::Test::test_bar
This change could not accompany a deprecation period as is usual when user-facing functionality changes because
it was not really possible to detect when the functionality was being used explicitly.
The extra ``::()`` might have been removed in some places internally already,
which then led to confusion in places where it was expected, e.g. with
``--deselect`` (`#4127 <https://github.com/pytest-dev/pytest/issues/4127>`_).
Test class instances are also not listed with ``--collect-only`` anymore.
Features
--------
- `#4270 <https://github.com/pytest-dev/pytest/issues/4270>`_: The ``cache_dir`` option uses ``$TOX_ENV_DIR`` as prefix (if set in the environment).
This uses a different cache per tox environment by default.
Bug Fixes
---------
- `#3554 <https://github.com/pytest-dev/pytest/issues/3554>`_: Fix ``CallInfo.__repr__`` for when the call is not finished yet.
pytest 3.10.1 (2018-11-11)
==========================
Bug Fixes
---------
- `#4287 <https://github.com/pytest-dev/pytest/issues/4287>`_: Fix nested usage of debugging plugin (pdb), e.g. with pytester's ``testdir.runpytest``.
- `#4304 <https://github.com/pytest-dev/pytest/issues/4304>`_: Block the ``stepwise`` plugin if ``cacheprovider`` is also blocked, as one depends on the other.
- `#4306 <https://github.com/pytest-dev/pytest/issues/4306>`_: Parse ``minversion`` as an actual version and not as dot-separated strings.
- `#4310 <https://github.com/pytest-dev/pytest/issues/4310>`_: Fix duplicate collection due to multiple args matching the same packages.
- `#4321 <https://github.com/pytest-dev/pytest/issues/4321>`_: Fix ``item.nodeid`` with resolved symlinks.
- `#4325 <https://github.com/pytest-dev/pytest/issues/4325>`_: Fix collection of direct symlinked files, where the target does not match ``python_files``.
- `#4329 <https://github.com/pytest-dev/pytest/issues/4329>`_: Fix TypeError in report_collect with _collect_report_last_write.
Trivial/Internal Changes
------------------------
- `#4305 <https://github.com/pytest-dev/pytest/issues/4305>`_: Replace byte/unicode helpers in test_capture with python level syntax.
pytest 3.10.0 (2018-11-03)
==========================
Features
--------
- `#2619 <https://github.com/pytest-dev/pytest/issues/2619>`_: Resume capturing output after ``continue`` with ``__import__("pdb").set_trace()``.
This also adds a new ``pytest_leave_pdb`` hook, and passes in ``pdb`` to the
existing ``pytest_enter_pdb`` hook.
- `#4147 <https://github.com/pytest-dev/pytest/issues/4147>`_: Add ``--sw``, ``--stepwise`` as an alternative to ``--lf -x`` for stopping at the first failure, but starting the next test invocation from that test. See `the documentation <https://docs.pytest.org/en/latest/cache.html#stepwise>`__ for more info.
- `#4188 <https://github.com/pytest-dev/pytest/issues/4188>`_: Make ``--color`` emit colorful dots when not running in verbose mode. Earlier, it would only colorize the test-by-test output if ``--verbose`` was also passed.
- `#4225 <https://github.com/pytest-dev/pytest/issues/4225>`_: Improve performance with collection reporting in non-quiet mode with terminals.
The "collecting …" message is only printed/updated every 0.5s.
Bug Fixes
---------
- `#2701 <https://github.com/pytest-dev/pytest/issues/2701>`_: Fix false ``RemovedInPytest4Warning: usage of Session... is deprecated, please use pytest`` warnings.
- `#4046 <https://github.com/pytest-dev/pytest/issues/4046>`_: Fix problems with running tests in package ``__init__.py`` files.
- `#4260 <https://github.com/pytest-dev/pytest/issues/4260>`_: Swallow warnings during anonymous compilation of source.
- `#4262 <https://github.com/pytest-dev/pytest/issues/4262>`_: Fix access denied error when deleting stale directories created by ``tmpdir`` / ``tmp_path``.
- `#611 <https://github.com/pytest-dev/pytest/issues/611>`_: Naming a fixture ``request`` will now raise a warning: the ``request`` fixture is internal and
should not be overwritten as it will lead to internal errors.
- `#4266 <https://github.com/pytest-dev/pytest/issues/4266>`_: Handle (ignore) exceptions raised during collection, e.g. with Django's LazySettings proxy class.
Improved Documentation
----------------------
- `#4255 <https://github.com/pytest-dev/pytest/issues/4255>`_: Added missing documentation about the fact that module names passed to filter warnings are not regex-escaped.
Trivial/Internal Changes
------------------------
- `#4272 <https://github.com/pytest-dev/pytest/issues/4272>`_: Display cachedir also in non-verbose mode if non-default.
- `#4277 <https://github.com/pytest-dev/pytest/issues/4277>`_: pdb: improve message about output capturing with ``set_trace``.
Do not display "IO-capturing turned off/on" when ``-s`` is used to avoid
confusion.
- `#4279 <https://github.com/pytest-dev/pytest/issues/4279>`_: Improve message and stack level of warnings issued by ``monkeypatch.setenv`` when the value of the environment variable is not a ``str``.
pytest 3.9.3 (2018-10-27)
=========================
Bug Fixes
---------
- `#4174 <https://github.com/pytest-dev/pytest/issues/4174>`_: Fix "ValueError: Plugin already registered" with conftest plugins via symlink.
- `#4181 <https://github.com/pytest-dev/pytest/issues/4181>`_: Handle race condition between creation and deletion of temporary folders.
- `#4221 <https://github.com/pytest-dev/pytest/issues/4221>`_: Fix bug where the warning summary at the end of the test session was not showing the test where the warning was originated.
- `#4243 <https://github.com/pytest-dev/pytest/issues/4243>`_: Fix regression when ``stacklevel`` for warnings was passed as positional argument on python2.
Improved Documentation
----------------------
- `#3851 <https://github.com/pytest-dev/pytest/issues/3851>`_: Add reference to ``empty_parameter_set_mark`` ini option in documentation of ``@pytest.mark.parametrize``
Trivial/Internal Changes
------------------------
- `#4028 <https://github.com/pytest-dev/pytest/issues/4028>`_: Revert patching of ``sys.breakpointhook`` since it appears to do nothing.
- `#4233 <https://github.com/pytest-dev/pytest/issues/4233>`_: Apply an import sorter (``reorder-python-imports``) to the codebase.
- `#4248 <https://github.com/pytest-dev/pytest/issues/4248>`_: Remove use of unnecessary compat shim, six.binary_type
pytest 3.9.2 (2018-10-22)
=========================
Bug Fixes
---------
- `#2909 <https://github.com/pytest-dev/pytest/issues/2909>`_: Improve error message when a recursive dependency between fixtures is detected.
- `#3340 <https://github.com/pytest-dev/pytest/issues/3340>`_: Fix logging messages not shown in hooks ``pytest_sessionstart()`` and ``pytest_sessionfinish()``.
- `#3533 <https://github.com/pytest-dev/pytest/issues/3533>`_: Fix unescaped XML raw objects in JUnit report for skipped tests
- `#3691 <https://github.com/pytest-dev/pytest/issues/3691>`_: Python 2: safely format warning message about passing unicode strings to ``warnings.warn``, which may cause
surprising ``MemoryError`` exception when monkey patching ``warnings.warn`` itself.
- `#4026 <https://github.com/pytest-dev/pytest/issues/4026>`_: Improve error message when it is not possible to determine a function's signature.
- `#4177 <https://github.com/pytest-dev/pytest/issues/4177>`_: Pin ``setuptools>=40.0`` to support ``py_modules`` in ``setup.cfg``
- `#4179 <https://github.com/pytest-dev/pytest/issues/4179>`_: Restore the tmpdir behaviour of symlinking the current test run.
- `#4192 <https://github.com/pytest-dev/pytest/issues/4192>`_: Fix filename reported by ``warnings.warn`` when using ``recwarn`` under python2.
pytest 3.9.1 (2018-10-16)
=========================
Features
--------
- `#4159 <https://github.com/pytest-dev/pytest/issues/4159>`_: For test-suites containing test classes, the information about the subclassed
module is now output only if a higher verbosity level is specified (at least
"-vv").
pytest 3.9.0 (2018-10-15 - not published due to a release automation bug)
=========================================================================
Deprecations
------------
- `#3616 <https://github.com/pytest-dev/pytest/issues/3616>`_: The following accesses have been documented as deprecated for years, but are now actually emitting deprecation warnings.
* Access of ``Module``, ``Function``, ``Class``, ``Instance``, ``File`` and ``Item`` through ``Node`` instances. Now
users will this warning::
usage of Function.Module is deprecated, please use pytest.Module instead
Users should just ``import pytest`` and access those objects using the ``pytest`` module.
* ``request.cached_setup``, this was the precursor of the setup/teardown mechanism available to fixtures. You can
consult `funcarg comparison section in the docs <https://docs.pytest.org/en/latest/funcarg_compare.html>`_.
* Using objects named ``"Class"`` as a way to customize the type of nodes that are collected in ``Collector``
subclasses has been deprecated. Users instead should use ``pytest_collect_make_item`` to customize node types during
collection.
This issue should affect only advanced plugins who create new collection types, so if you see this warning
message please contact the authors so they can change the code.
* The warning that produces the message below has changed to ``RemovedInPytest4Warning``::
getfuncargvalue is deprecated, use getfixturevalue
- `#3988 <https://github.com/pytest-dev/pytest/issues/3988>`_: Add a Deprecation warning for pytest.ensuretemp as it was deprecated since a while.
Features
--------
- `#2293 <https://github.com/pytest-dev/pytest/issues/2293>`_: Improve usage errors messages by hiding internal details which can be distracting and noisy.
This has the side effect that some error conditions that previously raised generic errors (such as
``ValueError`` for unregistered marks) are now raising ``Failed`` exceptions.
- `#3332 <https://github.com/pytest-dev/pytest/issues/3332>`_: Improve the error displayed when a ``conftest.py`` file could not be imported.
In order to implement this, a new ``chain`` parameter was added to ``ExceptionInfo.getrepr``
to show or hide chained tracebacks in Python 3 (defaults to ``True``).
- `#3849 <https://github.com/pytest-dev/pytest/issues/3849>`_: Add ``empty_parameter_set_mark=fail_at_collect`` ini option for raising an exception when parametrize collects an empty set.
- `#3964 <https://github.com/pytest-dev/pytest/issues/3964>`_: Log messages generated in the collection phase are shown when
live-logging is enabled and/or when they are logged to a file.
- `#3985 <https://github.com/pytest-dev/pytest/issues/3985>`_: Introduce ``tmp_path`` as a fixture providing a Path object.
- `#4013 <https://github.com/pytest-dev/pytest/issues/4013>`_: Deprecation warnings are now shown even if you customize the warnings filters yourself. In the previous version
any customization would override pytest's filters and deprecation warnings would fall back to being hidden by default.
- `#4073 <https://github.com/pytest-dev/pytest/issues/4073>`_: Allow specification of timeout for ``Testdir.runpytest_subprocess()`` and ``Testdir.run()``.
- `#4098 <https://github.com/pytest-dev/pytest/issues/4098>`_: Add returncode argument to pytest.exit() to exit pytest with a specific return code.
- `#4102 <https://github.com/pytest-dev/pytest/issues/4102>`_: Reimplement ``pytest.deprecated_call`` using ``pytest.warns`` so it supports the ``match='...'`` keyword argument.
This has the side effect that ``pytest.deprecated_call`` now raises ``pytest.fail.Exception`` instead
of ``AssertionError``.
- `#4149 <https://github.com/pytest-dev/pytest/issues/4149>`_: Require setuptools>=30.3 and move most of the metadata to ``setup.cfg``.
Bug Fixes
---------
- `#2535 <https://github.com/pytest-dev/pytest/issues/2535>`_: Improve error message when test functions of ``unittest.TestCase`` subclasses use a parametrized fixture.
- `#3057 <https://github.com/pytest-dev/pytest/issues/3057>`_: ``request.fixturenames`` now correctly returns the name of fixtures created by ``request.getfixturevalue()``.
- `#3946 <https://github.com/pytest-dev/pytest/issues/3946>`_: Warning filters passed as command line options using ``-W`` now take precedence over filters defined in ``ini``
configuration files.
- `#4066 <https://github.com/pytest-dev/pytest/issues/4066>`_: Fix source reindenting by using ``textwrap.dedent`` directly.
- `#4102 <https://github.com/pytest-dev/pytest/issues/4102>`_: ``pytest.warn`` will capture previously-warned warnings in Python 2. Previously they were never raised.
- `#4108 <https://github.com/pytest-dev/pytest/issues/4108>`_: Resolve symbolic links for args.
This fixes running ``pytest tests/test_foo.py::test_bar``, where ``tests``
is a symlink to ``project/app/tests``:
previously ``project/app/conftest.py`` would be ignored for fixtures then.
- `#4132 <https://github.com/pytest-dev/pytest/issues/4132>`_: Fix duplicate printing of internal errors when using ``--pdb``.
- `#4135 <https://github.com/pytest-dev/pytest/issues/4135>`_: pathlib based tmpdir cleanup now correctly handles symlinks in the folder.
- `#4152 <https://github.com/pytest-dev/pytest/issues/4152>`_: Display the filename when encountering ``SyntaxWarning``.
Improved Documentation
----------------------
- `#3713 <https://github.com/pytest-dev/pytest/issues/3713>`_: Update usefixtures documentation to clarify that it can't be used with fixture functions.
- `#4058 <https://github.com/pytest-dev/pytest/issues/4058>`_: Update fixture documentation to specify that a fixture can be invoked twice in the scope it's defined for.
- `#4064 <https://github.com/pytest-dev/pytest/issues/4064>`_: According to unittest.rst, setUpModule and tearDownModule were not implemented, but it turns out they are. So updated the documentation for unittest.
- `#4151 <https://github.com/pytest-dev/pytest/issues/4151>`_: Add tempir testing example to CONTRIBUTING.rst guide
Trivial/Internal Changes
------------------------
- `#2293 <https://github.com/pytest-dev/pytest/issues/2293>`_: The internal ``MarkerError`` exception has been removed.
- `#3988 <https://github.com/pytest-dev/pytest/issues/3988>`_: Port the implementation of tmpdir to pathlib.
- `#4063 <https://github.com/pytest-dev/pytest/issues/4063>`_: Exclude 0.00 second entries from ``--duration`` output unless ``-vv`` is passed on the command-line.
- `#4093 <https://github.com/pytest-dev/pytest/issues/4093>`_: Fixed formatting of string literals in internal tests.
pytest 3.8.2 (2018-10-02)
=========================
Deprecations and Removals
-------------------------
- `#4036 <https://github.com/pytest-dev/pytest/issues/4036>`_: The ``item`` parameter of ``pytest_warning_captured`` hook is now documented as deprecated. We realized only after
the ``3.8`` release that this parameter is incompatible with ``pytest-xdist``.
Our policy is to not deprecate features during bugfix releases, but in this case we believe it makes sense as we are
only documenting it as deprecated, without issuing warnings which might potentially break test suites. This will get
the word out that hook implementers should not use this parameter at all.
In a future release ``item`` will always be ``None`` and will emit a proper warning when a hook implementation
makes use of it.
Bug Fixes
---------
- `#3539 <https://github.com/pytest-dev/pytest/issues/3539>`_: Fix reload on assertion rewritten modules.
- `#4034 <https://github.com/pytest-dev/pytest/issues/4034>`_: The ``.user_properties`` attribute of ``TestReport`` objects is a list
of (name, value) tuples, but could sometimes be instantiated as a tuple
of tuples. It is now always a list.
- `#4039 <https://github.com/pytest-dev/pytest/issues/4039>`_: No longer issue warnings about using ``pytest_plugins`` in non-top-level directories when using ``--pyargs``: the
current ``--pyargs`` mechanism is not reliable and might give false negatives.
- `#4040 <https://github.com/pytest-dev/pytest/issues/4040>`_: Exclude empty reports for passed tests when ``-rP`` option is used.
- `#4051 <https://github.com/pytest-dev/pytest/issues/4051>`_: Improve error message when an invalid Python expression is passed to the ``-m`` option.
- `#4056 <https://github.com/pytest-dev/pytest/issues/4056>`_: ``MonkeyPatch.setenv`` and ``MonkeyPatch.delenv`` issue a warning if the environment variable name is not ``str`` on Python 2.
In Python 2, adding ``unicode`` keys to ``os.environ`` causes problems with ``subprocess`` (and possible other modules),
making this a subtle bug specially susceptible when used with ``from __future__ import unicode_literals``.
Improved Documentation
----------------------
- `#3928 <https://github.com/pytest-dev/pytest/issues/3928>`_: Add possible values for fixture scope to docs.
pytest 3.8.1 (2018-09-22)
=========================
@@ -88,7 +535,7 @@ Features
the standard warnings filters to manage those warnings. This introduces ``PytestWarning``,
``PytestDeprecationWarning`` and ``RemovedInPytest4Warning`` warning types as part of the public API.
Consult `the documentation <https://docs.pytest.org/en/latest/warnings.html#internal-pytest-warnings>`_ for more info.
Consult `the documentation <https://docs.pytest.org/en/latest/warnings.html#internal-pytest-warnings>`__ for more info.
- `#2908 <https://github.com/pytest-dev/pytest/issues/2908>`_: ``DeprecationWarning`` and ``PendingDeprecationWarning`` are now shown by default if no other warning filter is
@@ -263,7 +710,7 @@ Bug Fixes
- `#3473 <https://github.com/pytest-dev/pytest/issues/3473>`_: Raise immediately if ``approx()`` is given an expected value of a type it doesn't understand (e.g. strings, nested dicts, etc.).
- `#3712 <https://github.com/pytest-dev/pytest/issues/3712>`_: Correctly represent the dimensions of an numpy array when calling ``repr()`` on ``approx()``.
- `#3712 <https://github.com/pytest-dev/pytest/issues/3712>`_: Correctly represent the dimensions of a numpy array when calling ``repr()`` on ``approx()``.
- `#3742 <https://github.com/pytest-dev/pytest/issues/3742>`_: Fix incompatibility with third party plugins during collection, which produced the error ``object has no attribute '_collectfile'``.

View File

@@ -169,7 +169,7 @@ Short version
#. Follow **PEP-8** for naming and `black <https://github.com/ambv/black>`_ for formatting.
#. Tests are run using ``tox``::
tox -e linting,py27,py36
tox -e linting,py27,py37
The test environments above are usually enough to cover most cases locally.
@@ -237,12 +237,12 @@ Here is a simple overview, with pytest-specific bits:
#. Run all the tests
You need to have Python 2.7 and 3.6 available in your system. Now
You need to have Python 2.7 and 3.7 available in your system. Now
running tests is as simple as issuing this command::
$ tox -e linting,py27,py36
$ tox -e linting,py27,py37
This command will run tests via the "tox" tool against Python 2.7 and 3.6
This command will run tests via the "tox" tool against Python 2.7 and 3.7
and also perform "lint" coding-style checks.
#. You can now edit your local working copy and run the tests again as necessary. Please follow PEP-8 for naming.
@@ -252,9 +252,9 @@ Here is a simple overview, with pytest-specific bits:
$ tox -e py27 -- --pdb
Or to only run tests in a particular test module on Python 3.6::
Or to only run tests in a particular test module on Python 3.7::
$ tox -e py36 -- testing/test_config.py
$ tox -e py37 -- testing/test_config.py
When committing, ``pre-commit`` will re-format the files if necessary.
@@ -280,6 +280,47 @@ Here is a simple overview, with pytest-specific bits:
base: features # if it's a feature
Writing Tests
----------------------------
Writing tests for plugins or for pytest itself is often done using the `testdir fixture <https://docs.pytest.org/en/latest/reference.html#testdir>`_, as a "black-box" test.
For example, to ensure a simple test passes you can write:
.. code-block:: python
def test_true_assertion(testdir):
testdir.makepyfile(
"""
def test_foo():
assert True
"""
)
result = testdir.runpytest()
result.assert_outcomes(failed=0, passed=1)
Alternatively, it is possible to make checks based on the actual output of the termal using
*glob-like* expressions:
.. code-block:: python
def test_true_assertion(testdir):
testdir.makepyfile(
"""
def test_foo():
assert False
"""
)
result = testdir.runpytest()
result.stdout.fnmatch_lines(["*assert False*", "*1 failed*"])
When choosing a file where to write a new test, take a look at the existing files and see if there's
one file which looks like a good fit. For example, a regression test about a bug in the ``--lf`` option
should go into ``test_cacheprovider.py``, given that this option is implemented in ``cacheprovider.py``.
If in doubt, go ahead and open a PR with your best guess and we can discuss this over the code.
Joining the Development Team
----------------------------

View File

@@ -46,5 +46,3 @@ taking a lot of time to make a new one.
* testing-in-python@lists.idyll.org (only major/minor releases)
And announce it on `Twitter <https://twitter.com/>`_ with the ``#pytest`` hashtag.
#. After a minor/major release, merge ``release-X.Y.Z`` into ``master`` and push (or open a PR).

View File

@@ -1,31 +1,29 @@
environment:
matrix:
- TOXENV: "linting"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py37-xdist"
- TOXENV: "py27-xdist"
- TOXENV: "py27"
- TOXENV: "py34"
- TOXENV: "py35"
- TOXENV: "py36"
- TOXENV: "py37"
- TOXENV: "linting,docs,doctesting"
- TOXENV: "py36"
- TOXENV: "py35"
- TOXENV: "py34"
- TOXENV: "pypy"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py27-xdist"
- TOXENV: "py27-trial"
- TOXENV: "py27-numpy"
# Specialized factors for py27.
- TOXENV: "py27-trial,py27-numpy,py27-nobyte"
- TOXENV: "py27-pluggymaster"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py36-xdist"
- TOXENV: "py36-trial"
- TOXENV: "py36-numpy"
- TOXENV: "py36-pluggymaster"
# Specialized factors for py37.
- TOXENV: "py37-trial,py37-numpy"
- TOXENV: "py37-pluggymaster"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py27-nobyte"
- TOXENV: "doctesting"
- TOXENV: "py36-freeze"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "docs"
- TOXENV: "py37-freeze"
PYTEST_NO_COVERAGE: "1"
matrix:
fast_finish: true
install:
- echo Installed Pythons
- dir c:\Python*

View File

@@ -1,10 +1,7 @@
# 10000 iterations, just for relative comparison
# 2.7.5 3.3.2
# FilesCompleter 75.1109 69.2116
# FastFilesCompleter 0.7383 1.0760
import timeit
imports = [

View File

@@ -1,4 +1,3 @@
import pytest

View File

@@ -1,4 +1,5 @@
from six.moves import range
import pytest

View File

@@ -14,7 +14,8 @@ Each file should be named like ``<ISSUE>.<TYPE>.rst``, where
* ``feature``: new user facing features, like new command-line options and new behavior.
* ``bugfix``: fixes a reported bug.
* ``doc``: documentation improvement, like rewording an entire session or adding missing docs.
* ``removal``: feature deprecation or removal.
* ``deprecation``: feature deprecation.
* ``removal``: feature removal.
* ``vendor``: changes in packages vendored in pytest.
* ``trivial``: fixing a small typo or internal change that might be noteworthy.

View File

@@ -1,19 +1,17 @@
# flasky extensions. flasky pygments style based on tango style
from pygments.style import Style
from pygments.token import (
Keyword,
Name,
Comment,
String,
Error,
Number,
Operator,
Generic,
Whitespace,
Punctuation,
Other,
Literal,
)
from pygments.token import Comment
from pygments.token import Error
from pygments.token import Generic
from pygments.token import Keyword
from pygments.token import Literal
from pygments.token import Name
from pygments.token import Number
from pygments.token import Operator
from pygments.token import Other
from pygments.token import Punctuation
from pygments.token import String
from pygments.token import Whitespace
class FlaskyStyle(Style):

View File

@@ -6,6 +6,14 @@ Release announcements
:maxdepth: 2
release-4.0.0
release-3.10.1
release-3.10.0
release-3.9.3
release-3.9.2
release-3.9.1
release-3.9.0
release-3.8.2
release-3.8.1
release-3.8.0
release-3.7.4

View File

@@ -0,0 +1,43 @@
pytest-3.10.0
=======================================
The pytest team is proud to announce the 3.10.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged
to take a look at the CHANGELOG:
https://docs.pytest.org/en/latest/changelog.html
For complete documentation, please visit:
https://docs.pytest.org/en/latest/
As usual, you can upgrade from pypi via:
pip install -U pytest
Thanks to all who contributed to this release, among them:
* Anders Hovmöller
* Andreu Vallbona Plazas
* Ankit Goel
* Anthony Sottile
* Bernardo Gomes
* Brianna Laugher
* Bruno Oliveira
* Daniel Hahler
* David Szotten
* Mick Koch
* Niclas Olofsson
* Palash Chatterjee
* Ronny Pfannschmidt
* Sven-Hendrik Haase
* Ville Skyttä
* William Jamir Silva
Happy testing,
The Pytest Development Team

View File

@@ -0,0 +1,24 @@
pytest-3.10.1
=======================================
pytest 3.10.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
* Boris Feld
* Bruno Oliveira
* Daniel Hahler
* Fabien ZARIFIAN
* Jon Dufresne
* Ronny Pfannschmidt
Happy testing,
The pytest Development Team

View File

@@ -20,8 +20,7 @@ Thanks to all who contributed to this release, among them:
* Ondřej Súkup
* Ronny Pfannschmidt
* T.E.A de Souza
* Victor
* victor
* Victor Maryama
Happy testing,

View File

@@ -22,10 +22,9 @@ Thanks to all who contributed to this release, among them:
* Ronny Pfannschmidt
* Sankt Petersbug
* Tyler Richard
* Victor
* Victor Maryama
* Vlad Shcherbina
* turturica
* victor
* wim glenn

View File

@@ -0,0 +1,28 @@
pytest-3.8.2
=======================================
pytest 3.8.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:
* Ankit Goel
* Anthony Sottile
* Bruno Oliveira
* Daniel Hahler
* Denis Otkidach
* Harry Percival
* Jeffrey Rackauckas
* Jose Carlos Menezes
* Ronny Pfannschmidt
* Zac-HD
* iwanb
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,43 @@
pytest-3.9.0
=======================================
The pytest team is proud to announce the 3.9.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged
to take a look at the CHANGELOG:
https://docs.pytest.org/en/latest/changelog.html
For complete documentation, please visit:
https://docs.pytest.org/en/latest/
As usual, you can upgrade from pypi via:
pip install -U pytest
Thanks to all who contributed to this release, among them:
* Andrea Cimatoribus
* Ankit Goel
* Anthony Sottile
* Ben Eyal
* Bruno Oliveira
* Daniel Hahler
* Jeffrey Rackauckas
* Jose Carlos Menezes
* Kyle Altendorf
* Niklas JQ
* Palash Chatterjee
* Ronny Pfannschmidt
* Thomas Hess
* Thomas Hisch
* Tomer Keren
* Victor Maryama
Happy testing,
The Pytest Development Team

View File

@@ -0,0 +1,20 @@
pytest-3.9.1
=======================================
pytest 3.9.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:
* Bruno Oliveira
* Ronny Pfannschmidt
* Thomas Hisch
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,23 @@
pytest-3.9.2
=======================================
pytest 3.9.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:
* Ankit Goel
* Anthony Sottile
* Bruno Oliveira
* Ronny Pfannschmidt
* Vincent Barbaresi
* ykantor
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,24 @@
pytest-3.9.3
=======================================
pytest 3.9.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:
* Andreas Profous
* Ankit Goel
* Anthony Sottile
* Bruno Oliveira
* Daniel Hahler
* Jon Dufresne
* Ronny Pfannschmidt
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,30 @@
pytest-4.0.0
=======================================
The pytest team is proud to announce the 4.0.0 release!
pytest is a mature Python testing tool with more than a 2000 tests
against itself, passing on many different interpreters and platforms.
This release contains a number of bugs fixes and improvements, so users are encouraged
to take a look at the CHANGELOG:
https://docs.pytest.org/en/latest/changelog.html
For complete documentation, please visit:
https://docs.pytest.org/en/latest/
As usual, you can upgrade from pypi via:
pip install -U pytest
Thanks to all who contributed to this release, among them:
* Bruno Oliveira
* Daniel Hahler
* Ronny Pfannschmidt
Happy testing,
The Pytest Development Team

View File

@@ -264,8 +264,12 @@ Advanced assertion introspection
Reporting details about a failing assertion is achieved by rewriting assert
statements before they are run. Rewritten assert statements put introspection
information into the assertion failure message. ``pytest`` only rewrites test
modules directly discovered by its test collection process, so asserts in
supporting modules which are not themselves test modules will not be rewritten.
modules directly discovered by its test collection process, so **asserts in
supporting modules which are not themselves test modules will not be rewritten**.
You can manually enable assertion rewriting for an imported module by calling
`register_assert_rewrite <https://docs.pytest.org/en/latest/writing_plugins.html#assertion-rewriting>`_
before you import it (a good place to do that is in ``conftest.py``).
.. note::

View File

@@ -75,7 +75,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
caplog
Access and control log capturing.
Captured logs are available through the following methods::
Captured logs are available through the following properties/methods::
* caplog.text -> string containing formatted log output
* caplog.records -> list of logging.LogRecord instances
@@ -104,7 +104,9 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
See http://docs.python.org/library/warnings.html for information
on warning categories.
tmpdir_factory
Return a TempdirFactory instance for the test session.
Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.
tmp_path_factory
Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.
tmpdir
Return a temporary directory path object
which is unique to each test function invocation,
@@ -113,6 +115,16 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
path object.
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
tmp_path
Return a temporary directory path object
which is unique to each test function invocation,
created as a sub directory of the base temporary
directory. The returned object is a :class:`pathlib.Path`
object.
.. note::
in python < 3.6 this is a pathlib2.Path
no tests ran in 0.12 seconds

View File

@@ -244,6 +244,8 @@ You can always peek at the content of the cache using the
{'test_caching.py::test_function': True}
cache/nodeids contains:
['test_caching.py::test_function']
cache/stepwise contains:
[]
example/value contains:
42
@@ -260,3 +262,9 @@ by adding the ``--cache-clear`` option like this::
This is recommended for invocations from Continuous Integration
servers where isolation and correctness is more important
than speed.
Stepwise
--------
As an alternative to ``--lf -x``, especially for cases where you expect a large part of the test suite will fail, ``--sw``, ``--stepwise`` allows you to fix them one at a time. The test suite will run until the first failure and then stop. At the next invocation, tests will continue from the last failing test and then run until the next failing test. You may use the ``--stepwise-skip`` option to ignore one failing test and stop the test execution on the second failing test instead. This is useful if you get stuck on a failing test and just want to ignore it until later.

View File

@@ -10,17 +10,15 @@
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The full version, including alpha/beta/rc tags.
# The short X.Y version.
import datetime
import os
import sys
import datetime
from _pytest import __version__ as version

View File

@@ -33,6 +33,7 @@ Full pytest documentation
reference
goodpractices
flaky
pythonpath
customize
example/index

View File

@@ -14,6 +14,67 @@ Below is a complete list of all pytest features which are considered deprecated.
:class:`_pytest.warning_types.PytestWarning` or subclasses, which can be filtered using
:ref:`standard warning filters <warnings>`.
Internal classes accessed through ``Node``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.9
Access of ``Module``, ``Function``, ``Class``, ``Instance``, ``File`` and ``Item`` through ``Node`` instances now issue
this warning::
usage of Function.Module is deprecated, please use pytest.Module instead
Users should just ``import pytest`` and access those objects using the ``pytest`` module.
This has been documented as deprecated for years, but only now we are actually emitting deprecation warnings.
``cached_setup``
~~~~~~~~~~~~~~~~
.. deprecated:: 3.9
``request.cached_setup`` was the precursor of the setup/teardown mechanism available to fixtures.
Example:
.. code-block:: python
@pytest.fixture
def db_session():
return request.cached_setup(
setup=Session.create, teardown=lambda session: session.close(), scope="module"
)
This should be updated to make use of standard fixture mechanisms:
.. code-block:: python
@pytest.fixture(scope="module")
def db_session():
session = Session.create()
yield session
session.close()
You can consult `funcarg comparison section in the docs <https://docs.pytest.org/en/latest/funcarg_compare.html>`_ for
more information.
This has been documented as deprecated for years, but only now we are actually emitting deprecation warnings.
Using ``Class`` in custom Collectors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.9
Using objects named ``"Class"`` as a way to customize the type of nodes that are collected in ``Collector``
subclasses has been deprecated. Users instead should use ``pytest_pycollect_makeitem`` to customize node types during
collection.
This issue should affect only advanced plugins who create new collection types, so if you see this warning
message please contact the authors so they can change the code.
``Config.warn`` and ``Node.warn``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -22,14 +83,24 @@ Below is a complete list of all pytest features which are considered deprecated.
Those methods were part of the internal pytest warnings system, but since ``3.8`` pytest is using the builtin warning
system for its own warnings, so those two functions are now deprecated.
``Config.warn`` should be replaced by calls to the standard ``warnings.warn``.
``Config.warn`` should be replaced by calls to the standard ``warnings.warn``, example:
.. code-block:: python
config.warn("C1", "some warning")
Becomes:
.. code-block:: python
warnings.warn(pytest.PytestWarning("some warning"))
``Node.warn`` now supports two signatures:
* ``node.warn(PytestWarning("some message"))``: is now the recommended way to call this function.
* ``node.warn(PytestWarning("some message"))``: is now the **recommended** way to call this function.
The warning instance must be a PytestWarning or subclass.
* ``node.warn("CI", "some message")``: this code/message form is now deprecated and should be converted to the warning instance form above.
* ``node.warn("CI", "some message")``: this code/message form is now **deprecated** and should be converted to the warning instance form above.
``pytest_namespace``
@@ -233,7 +304,7 @@ This form of test function doesn't support fixtures properly, and users should s
.. code-block:: python
@pytest.mark.parametrize("x, y", [(2, 4), (3, 9)])
def test_squared():
def test_squared(x, y):
assert x ** x == y

View File

@@ -1,7 +1,9 @@
from pytest import raises
import _pytest._code
import six
import _pytest._code
import pytest
from pytest import raises
def otherfunc(a, b):
assert a == b
@@ -15,15 +17,11 @@ def otherfunc_multi(a, b):
assert a == b
@pytest.mark.parametrize("param1, param2", [(3, 6)])
def test_generative(param1, param2):
assert param1 * 2 < param2
def pytest_generate_tests(metafunc):
if "param1" in metafunc.fixturenames:
metafunc.addcall(funcargs=dict(param1=3, param2=6))
class TestFailing(object):
def test_simple(self):
def f():
@@ -247,7 +245,7 @@ class TestCustomAssertMsg(object):
b = 2
assert (
A.a == b
), "A.a appears not to be b\n" "or does not appear to be b\none of those"
), "A.a appears not to be b\nor does not appear to be b\none of those"
def test_custom_repr(self):
class JSON(object):

View File

@@ -1,6 +1,7 @@
import pytest
import py
import pytest
mydir = py.path.local(__file__).dirpath()

View File

@@ -1,4 +1,3 @@
hello = "world"

View File

@@ -1,4 +1,3 @@
import py
failure_demo = py.path.local(__file__).dirpath("failure_demo.py")

View File

@@ -1,4 +1,3 @@
import pytest

View File

@@ -5,6 +5,7 @@ serialization via the pickle module.
import textwrap
import py
import pytest
pythonlist = ["python2.7", "python3.4", "python3.5"]
@@ -32,7 +33,7 @@ class Python(object):
dumpfile = self.picklefile.dirpath("dump.py")
dumpfile.write(
textwrap.dedent(
"""\
r"""
import pickle
f = open({!r}, 'wb')
s = pickle.dump({!r}, f, protocol=2)
@@ -48,7 +49,7 @@ class Python(object):
loadfile = self.picklefile.dirpath("load.py")
loadfile.write(
textwrap.dedent(
"""\
r"""
import pickle
f = open({!r}, 'rb')
obj = pickle.load(f)

View File

@@ -1,5 +1,4 @@
# content of conftest.py
import pytest

View File

@@ -213,7 +213,6 @@ If you just collect tests you'll also nicely see 'advanced' and 'basic' as varia
collected 4 items
<Module 'test_scenarios.py'>
<Class 'TestSampleWithScenarios'>
<Instance '()'>
<Function 'test_demo1[basic]'>
<Function 'test_demo2[basic]'>
<Function 'test_demo1[advanced]'>
@@ -411,11 +410,10 @@ is to be run with different sets of arguments for its three arguments:
Running it results in some skips if we don't have all the python interpreters installed and otherwise runs all combinations (5 interpreters times 5 interpreters times 3 objects to serialize/deserialize)::
. $ pytest -rs -q multipython.py
...ssssssssssssssssssssssss [100%]
...sss...sssssssss...sss... [100%]
========================= short test summary info ==========================
SKIP [12] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.4' not found
SKIP [12] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.5' not found
3 passed, 24 skipped in 0.12 seconds
SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:30: 'python3.4' not found
12 passed, 15 skipped in 0.12 seconds
Indirect parametrization of optional implementations/imports
--------------------------------------------------------------------

View File

@@ -1,4 +1,5 @@
import sys
import pytest
py3 = sys.version_info[0] >= 3

View File

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

View File

@@ -2,4 +2,4 @@ def test_exception_syntax():
try:
0 / 0
except ZeroDivisionError as e:
pass
assert e

View File

@@ -132,7 +132,6 @@ The test collection would look like this::
collected 2 items
<Module 'check_myapp.py'>
<Class 'CheckMyApp'>
<Instance '()'>
<Function 'simple_check'>
<Function 'complex_check'>
@@ -187,7 +186,6 @@ You can always peek at the collection tree without running tests like this::
<Module 'CWD/pythoncollection.py'>
<Function 'test_function'>
<Class 'TestClass'>
<Instance '()'>
<Function 'test_method'>
<Function 'test_anothermethod'>

View File

@@ -18,15 +18,16 @@ get on the terminal - we are working on that)::
failure_demo.py FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF [100%]
================================= FAILURES =================================
____________________________ test_generative[0] ____________________________
___________________________ test_generative[3-6] ___________________________
param1 = 3, param2 = 6
@pytest.mark.parametrize("param1, param2", [(3, 6)])
def test_generative(param1, param2):
> assert param1 * 2 < param2
E assert (3 * 2) < 6
failure_demo.py:19: AssertionError
failure_demo.py:22: AssertionError
_________________________ TestFailing.test_simple __________________________
self = <failure_demo.TestFailing object at 0xdeadbeef>
@@ -43,7 +44,7 @@ get on the terminal - we are working on that)::
E + where 42 = <function TestFailing.test_simple.<locals>.f at 0xdeadbeef>()
E + and 43 = <function TestFailing.test_simple.<locals>.g at 0xdeadbeef>()
failure_demo.py:35: AssertionError
failure_demo.py:33: AssertionError
____________________ TestFailing.test_simple_multiline _____________________
self = <failure_demo.TestFailing object at 0xdeadbeef>
@@ -51,7 +52,7 @@ get on the terminal - we are working on that)::
def test_simple_multiline(self):
> otherfunc_multi(42, 6 * 9)
failure_demo.py:38:
failure_demo.py:36:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
a = 42, b = 54
@@ -60,7 +61,7 @@ get on the terminal - we are working on that)::
> assert a == b
E assert 42 == 54
failure_demo.py:15: AssertionError
failure_demo.py:17: AssertionError
___________________________ TestFailing.test_not ___________________________
self = <failure_demo.TestFailing object at 0xdeadbeef>
@@ -73,7 +74,7 @@ get on the terminal - we are working on that)::
E assert not 42
E + where 42 = <function TestFailing.test_not.<locals>.f at 0xdeadbeef>()
failure_demo.py:44: AssertionError
failure_demo.py:42: AssertionError
_________________ TestSpecialisedExplanations.test_eq_text _________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -84,7 +85,7 @@ get on the terminal - we are working on that)::
E - spam
E + eggs
failure_demo.py:49: AssertionError
failure_demo.py:47: AssertionError
_____________ TestSpecialisedExplanations.test_eq_similar_text _____________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -97,7 +98,7 @@ get on the terminal - we are working on that)::
E + foo 2 bar
E ? ^
failure_demo.py:52: AssertionError
failure_demo.py:50: AssertionError
____________ TestSpecialisedExplanations.test_eq_multiline_text ____________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -110,7 +111,7 @@ get on the terminal - we are working on that)::
E + eggs
E bar
failure_demo.py:55: AssertionError
failure_demo.py:53: AssertionError
______________ TestSpecialisedExplanations.test_eq_long_text _______________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -127,7 +128,7 @@ get on the terminal - we are working on that)::
E + 1111111111b222222222
E ? ^
failure_demo.py:60: AssertionError
failure_demo.py:58: AssertionError
_________ TestSpecialisedExplanations.test_eq_long_text_multiline __________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -147,7 +148,7 @@ get on the terminal - we are working on that)::
E
E ...Full output truncated (7 lines hidden), use '-vv' to show
failure_demo.py:65: AssertionError
failure_demo.py:63: AssertionError
_________________ TestSpecialisedExplanations.test_eq_list _________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -158,7 +159,7 @@ get on the terminal - we are working on that)::
E At index 2 diff: 2 != 3
E Use -v to get the full diff
failure_demo.py:68: AssertionError
failure_demo.py:66: AssertionError
______________ TestSpecialisedExplanations.test_eq_list_long _______________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -171,7 +172,7 @@ get on the terminal - we are working on that)::
E At index 100 diff: 1 != 2
E Use -v to get the full diff
failure_demo.py:73: AssertionError
failure_demo.py:71: AssertionError
_________________ TestSpecialisedExplanations.test_eq_dict _________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -189,7 +190,7 @@ get on the terminal - we are working on that)::
E
E ...Full output truncated (2 lines hidden), use '-vv' to show
failure_demo.py:76: AssertionError
failure_demo.py:74: AssertionError
_________________ TestSpecialisedExplanations.test_eq_set __________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -207,7 +208,7 @@ get on the terminal - we are working on that)::
E
E ...Full output truncated (2 lines hidden), use '-vv' to show
failure_demo.py:79: AssertionError
failure_demo.py:77: AssertionError
_____________ TestSpecialisedExplanations.test_eq_longer_list ______________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -218,7 +219,7 @@ get on the terminal - we are working on that)::
E Right contains more items, first extra item: 3
E Use -v to get the full diff
failure_demo.py:82: AssertionError
failure_demo.py:80: AssertionError
_________________ TestSpecialisedExplanations.test_in_list _________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -227,7 +228,7 @@ get on the terminal - we are working on that)::
> assert 1 in [0, 2, 3, 4, 5]
E assert 1 in [0, 2, 3, 4, 5]
failure_demo.py:85: AssertionError
failure_demo.py:83: AssertionError
__________ TestSpecialisedExplanations.test_not_in_text_multiline __________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -246,7 +247,7 @@ get on the terminal - we are working on that)::
E
E ...Full output truncated (2 lines hidden), use '-vv' to show
failure_demo.py:89: AssertionError
failure_demo.py:87: AssertionError
___________ TestSpecialisedExplanations.test_not_in_text_single ____________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -259,7 +260,7 @@ get on the terminal - we are working on that)::
E single foo line
E ? +++
failure_demo.py:93: AssertionError
failure_demo.py:91: AssertionError
_________ TestSpecialisedExplanations.test_not_in_text_single_long _________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -272,7 +273,7 @@ get on the terminal - we are working on that)::
E head head foo tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail
E ? +++
failure_demo.py:97: AssertionError
failure_demo.py:95: AssertionError
______ TestSpecialisedExplanations.test_not_in_text_single_long_term _______
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -285,7 +286,7 @@ get on the terminal - we are working on that)::
E head head fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffftail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail tail
E ? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
failure_demo.py:101: AssertionError
failure_demo.py:99: AssertionError
______________________________ test_attribute ______________________________
def test_attribute():
@@ -297,7 +298,7 @@ get on the terminal - we are working on that)::
E assert 1 == 2
E + where 1 = <failure_demo.test_attribute.<locals>.Foo object at 0xdeadbeef>.b
failure_demo.py:109: AssertionError
failure_demo.py:107: AssertionError
_________________________ test_attribute_instance __________________________
def test_attribute_instance():
@@ -309,7 +310,7 @@ get on the terminal - we are working on that)::
E + where 1 = <failure_demo.test_attribute_instance.<locals>.Foo object at 0xdeadbeef>.b
E + where <failure_demo.test_attribute_instance.<locals>.Foo object at 0xdeadbeef> = <class 'failure_demo.test_attribute_instance.<locals>.Foo'>()
failure_demo.py:116: AssertionError
failure_demo.py:114: AssertionError
__________________________ test_attribute_failure __________________________
def test_attribute_failure():
@@ -322,7 +323,7 @@ get on the terminal - we are working on that)::
i = Foo()
> assert i.b == 2
failure_demo.py:127:
failure_demo.py:125:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <failure_demo.test_attribute_failure.<locals>.Foo object at 0xdeadbeef>
@@ -331,7 +332,7 @@ get on the terminal - we are working on that)::
> raise Exception("Failed to get attrib")
E Exception: Failed to get attrib
failure_demo.py:122: Exception
failure_demo.py:120: Exception
_________________________ test_attribute_multiple __________________________
def test_attribute_multiple():
@@ -348,7 +349,7 @@ get on the terminal - we are working on that)::
E + and 2 = <failure_demo.test_attribute_multiple.<locals>.Bar object at 0xdeadbeef>.b
E + where <failure_demo.test_attribute_multiple.<locals>.Bar object at 0xdeadbeef> = <class 'failure_demo.test_attribute_multiple.<locals>.Bar'>()
failure_demo.py:137: AssertionError
failure_demo.py:135: AssertionError
__________________________ TestRaises.test_raises __________________________
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -357,7 +358,7 @@ get on the terminal - we are working on that)::
s = "qwe" # NOQA
> raises(TypeError, "int(s)")
failure_demo.py:147:
failure_demo.py:145:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> int(s)
@@ -372,7 +373,7 @@ get on the terminal - we are working on that)::
> raises(IOError, "int('3')")
E Failed: DID NOT RAISE <class 'OSError'>
failure_demo.py:150: Failed
failure_demo.py:148: Failed
__________________________ TestRaises.test_raise ___________________________
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -381,7 +382,7 @@ get on the terminal - we are working on that)::
> raise ValueError("demo error")
E ValueError: demo error
failure_demo.py:153: ValueError
failure_demo.py:151: ValueError
________________________ TestRaises.test_tupleerror ________________________
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -390,7 +391,7 @@ get on the terminal - we are working on that)::
> a, b = [1] # NOQA
E ValueError: not enough values to unpack (expected 2, got 1)
failure_demo.py:156: ValueError
failure_demo.py:154: ValueError
______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -401,7 +402,7 @@ get on the terminal - we are working on that)::
> a, b = items.pop()
E TypeError: 'int' object is not iterable
failure_demo.py:161: TypeError
failure_demo.py:159: TypeError
--------------------------- Captured stdout call ---------------------------
items is [1, 2, 3]
________________________ TestRaises.test_some_error ________________________
@@ -412,7 +413,7 @@ get on the terminal - we are working on that)::
> if namenotexi: # NOQA
E NameError: name 'namenotexi' is not defined
failure_demo.py:164: NameError
failure_demo.py:162: NameError
____________________ test_dynamic_compile_shows_nicely _____________________
def test_dynamic_compile_shows_nicely():
@@ -427,14 +428,14 @@ get on the terminal - we are working on that)::
sys.modules[name] = module
> module.foo()
failure_demo.py:182:
failure_demo.py:180:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def foo():
> assert 1 == 0
E AssertionError
<2-codegen 'abc-123' $REGENDOC_TMPDIR/assertion/failure_demo.py:179>:2: AssertionError
<2-codegen 'abc-123' $REGENDOC_TMPDIR/assertion/failure_demo.py:177>:2: AssertionError
____________________ TestMoreErrors.test_complex_error _____________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -448,9 +449,9 @@ get on the terminal - we are working on that)::
> somefunc(f(), g())
failure_demo.py:193:
failure_demo.py:191:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
failure_demo.py:11: in somefunc
failure_demo.py:13: in somefunc
otherfunc(x, y)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
@@ -460,7 +461,7 @@ get on the terminal - we are working on that)::
> assert a == b
E assert 44 == 43
failure_demo.py:7: AssertionError
failure_demo.py:9: AssertionError
___________________ TestMoreErrors.test_z1_unpack_error ____________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -470,7 +471,7 @@ get on the terminal - we are working on that)::
> a, b = items
E ValueError: not enough values to unpack (expected 2, got 0)
failure_demo.py:197: ValueError
failure_demo.py:195: ValueError
____________________ TestMoreErrors.test_z2_type_error _____________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -480,7 +481,7 @@ get on the terminal - we are working on that)::
> a, b = items
E TypeError: 'int' object is not iterable
failure_demo.py:201: TypeError
failure_demo.py:199: TypeError
______________________ TestMoreErrors.test_startswith ______________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -493,7 +494,7 @@ get on the terminal - we are working on that)::
E + where False = <built-in method startswith of str object at 0xdeadbeef>('456')
E + where <built-in method startswith of str object at 0xdeadbeef> = '123'.startswith
failure_demo.py:206: AssertionError
failure_demo.py:204: AssertionError
__________________ TestMoreErrors.test_startswith_nested ___________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -512,7 +513,7 @@ get on the terminal - we are working on that)::
E + where '123' = <function TestMoreErrors.test_startswith_nested.<locals>.f at 0xdeadbeef>()
E + and '456' = <function TestMoreErrors.test_startswith_nested.<locals>.g at 0xdeadbeef>()
failure_demo.py:215: AssertionError
failure_demo.py:213: AssertionError
_____________________ TestMoreErrors.test_global_func ______________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -523,7 +524,7 @@ get on the terminal - we are working on that)::
E + where False = isinstance(43, float)
E + where 43 = globf(42)
failure_demo.py:218: AssertionError
failure_demo.py:216: AssertionError
_______________________ TestMoreErrors.test_instance _______________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -534,7 +535,7 @@ get on the terminal - we are working on that)::
E assert 42 != 42
E + where 42 = <failure_demo.TestMoreErrors object at 0xdeadbeef>.x
failure_demo.py:222: AssertionError
failure_demo.py:220: AssertionError
_______________________ TestMoreErrors.test_compare ________________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -544,7 +545,7 @@ get on the terminal - we are working on that)::
E assert 11 < 5
E + where 11 = globf(10)
failure_demo.py:225: AssertionError
failure_demo.py:223: AssertionError
_____________________ TestMoreErrors.test_try_finally ______________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -555,7 +556,7 @@ get on the terminal - we are working on that)::
> assert x == 0
E assert 1 == 0
failure_demo.py:230: AssertionError
failure_demo.py:228: AssertionError
___________________ TestCustomAssertMsg.test_single_line ___________________
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
@@ -570,7 +571,7 @@ get on the terminal - we are working on that)::
E assert 1 == 2
E + where 1 = <class 'failure_demo.TestCustomAssertMsg.test_single_line.<locals>.A'>.a
failure_demo.py:241: AssertionError
failure_demo.py:239: AssertionError
____________________ TestCustomAssertMsg.test_multiline ____________________
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
@@ -582,14 +583,14 @@ get on the terminal - we are working on that)::
b = 2
> assert (
A.a == b
), "A.a appears not to be b\n" "or does not appear to be b\none of those"
), "A.a appears not to be b\nor does not appear to be b\none of those"
E AssertionError: A.a appears not to be b
E or does not appear to be b
E one of those
E assert 1 == 2
E + where 1 = <class 'failure_demo.TestCustomAssertMsg.test_multiline.<locals>.A'>.a
failure_demo.py:248: AssertionError
failure_demo.py:246: AssertionError
___________________ TestCustomAssertMsg.test_custom_repr ___________________
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
@@ -611,11 +612,5 @@ get on the terminal - we are working on that)::
E assert 1 == 2
E + where 1 = This is JSON\n{\n 'foo': 'bar'\n}.a
failure_demo.py:261: AssertionError
============================= warnings summary =============================
$REGENDOC_TMPDIR/assertion/failure_demo.py:24: RemovedInPytest4Warning: Metafunc.addcall is deprecated and scheduled to be removed in pytest 4.0.
Please use Metafunc.parametrize instead.
metafunc.addcall(funcargs=dict(param1=3, param2=6))
-- Docs: https://docs.pytest.org/en/latest/warnings.html
================== 42 failed, 1 warnings in 0.12 seconds ===================
failure_demo.py:259: AssertionError
======================== 42 failed in 0.12 seconds =========================

View File

@@ -496,7 +496,7 @@ If we run this::
test_step.py:11: AssertionError
========================= short test summary info ==========================
XFAIL test_step.py::TestUserHandling::()::test_deletion
XFAIL test_step.py::TestUserHandling::test_deletion
reason: previous test failed (test_modification)
============== 1 failed, 2 passed, 1 xfailed in 0.12 seconds ===============
@@ -574,7 +574,7 @@ We can run this::
file $REGENDOC_TMPDIR/b/test_error.py, line 1
def test_root(db): # no db here, will error out
E fixture 'db' not found
> available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_property, record_xml_attribute, record_xml_property, recwarn, tmpdir, tmpdir_factory
> available fixtures: cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_property, record_xml_attribute, record_xml_property, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
> use 'pytest --fixtures [testpath]' for help on them.
$REGENDOC_TMPDIR/b/test_error.py:1
@@ -852,6 +852,8 @@ In that order.
can be changed between releases (even bug fixes) so it shouldn't be relied on for scripting
or automation.
.. _freezing-pytest:
Freezing pytest
---------------

View File

@@ -153,7 +153,7 @@ This makes use of the automatic caching mechanisms of pytest.
Another good approach is by adding the data files in the ``tests`` folder.
There are also community plugins available to help managing this aspect of
testing, e.g. `pytest-datadir <https://github.com/gabrielcnr/pytest-datadir>`__
testing, e.g. `pytest-datadir <https://pypi.org/project/pytest-datadir/>`__
and `pytest-datafiles <https://pypi.org/project/pytest-datafiles/>`__.
.. _smtpshared:
@@ -171,6 +171,7 @@ to cause the decorated ``smtp_connection`` fixture function to only be invoked
once per test *module* (the default is to invoke once per test *function*).
Multiple test functions in a test module will thus
each receive the same ``smtp_connection`` fixture instance, thus saving time.
Possible values for ``scope`` are: ``function``, ``class``, ``module``, ``package`` or ``session``.
The next example puts the fixture function into a separate ``conftest.py`` file
so that tests from multiple test modules in the directory can
@@ -258,6 +259,11 @@ instance, you can simply declare it:
Finally, the ``class`` scope will invoke the fixture once per test *class*.
.. note::
Pytest will only cache one instance of a fixture at a time.
This means that when using a parametrized fixture, pytest may invoke a fixture more than once in the given scope.
``package`` scope (experimental)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

125
doc/en/flaky.rst Normal file
View File

@@ -0,0 +1,125 @@
Flaky tests
-----------
A "flaky" test is one that exhibits intermittent or sporadic failure, that seems to have non-deterministic behaviour. Sometimes it passes, sometimes it fails, and it's not clear why. This page discusses pytest features that can help and other general strategies for identifying, fixing or mitigating them.
Why flaky tests are a problem
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Flaky tests are particularly troublesome when a continuous integration (CI) server is being used, so that all tests must pass before a new code change can be merged. If the test result is not a reliable signal -- that a test failure means the code change broke the test -- developers can become mistrustful of the test results, which can lead to overlooking genuine failures. It is also a source of wasted time as developers must re-run test suites and investigate spurious failures.
Potential root causes
^^^^^^^^^^^^^^^^^^^^^
System state
~~~~~~~~~~~~
Broadly speaking, a flaky test indicates that the test relies on some system state that is not being appropriately controlled - the test environment is not sufficiently isolated. Higher level tests are more likely to be flaky as they rely on more state.
Flaky tests sometimes appear when a test suite is run in parallel (such as use of pytest-xdist). This can indicate a test is reliant on test ordering.
- Perhaps a different test is failing to clean up after itself and leaving behind data which causes the flaky test to fail.
- The flaky test is reliant on data from a previous test that doesn't clean up after itself, and in parallel runs that previous test is not always present
- Tests that modify global state typically cannot be run in parallel.
Overly strict assertion
~~~~~~~~~~~~~~~~~~~~~~~
Overly strict assertions can cause problems with floating point comparison as well as timing issues. `pytest.approx <https://docs.pytest.org/en/latest/reference.html#pytest-approx>`_ is useful here.
Pytest features
^^^^^^^^^^^^^^^
Xfail strict
~~~~~~~~~~~~
:ref:`pytest.mark.xfail ref` with ``strict=False`` can be used to mark a test so that its failure does not cause the whole build to break. This could be considered like a manual quarantine, and is rather dangerous to use permanently.
PYTEST_CURRENT_TEST
~~~~~~~~~~~~~~~~~~~
:ref:`pytest current test env` may be useful for figuring out "which test got stuck".
Plugins
~~~~~~~
Rerunning any failed tests can mitigate the negative effects of flaky tests by giving them additional chances to pass, so that the overall build does not fail. Several pytest plugins support this:
* `flaky <https://github.com/box/flaky>`_
* `pytest-flakefinder <https://github.com/dropbox/pytest-flakefinder>`_ - `blog post <https://blogs.dropbox.com/tech/2016/03/open-sourcing-pytest-tools/>`_
* `pytest-rerunfailures <https://github.com/pytest-dev/pytest-rerunfailures>`_
* `pytest-replay <https://github.com/ESSS/pytest-replay>`_: This plugin helps to reproduce locally crashes or flaky tests observed during CI runs.
Plugins to deliberately randomize tests can help expose tests with state problems:
* `pytest-random-order <https://github.com/jbasko/pytest-random-order>`_
* `pytest-randomly <https://github.com/pytest-dev/pytest-randomly>`_
Other general strategies
^^^^^^^^^^^^^^^^^^^^^^^^
Split up test suites
~~~~~~~~~~~~~~~~~~~~
It can be common to split a single test suite into two, such as unit vs integration, and only use the unit test suite as a CI gate. This also helps keep build times manageable as high level tests tend to be slower. However, it means it does become possible for code that breaks the build to be merged, so extra vigilance is needed for monitoring the integration test results.
Video/screenshot on failure
~~~~~~~~~~~~~~~~~~~~~~~~~~~
For UI tests these are important for understanding what the state of the UI was when the test failed. pytest-splinter can be used with plugins like pytest-bdd and can `save a screenshot on test failure <https://pytest-splinter.readthedocs.io/en/latest/#automatic-screenshots-on-test-failure>`_, which can help to isolate the cause.
Delete or rewrite the test
~~~~~~~~~~~~~~~~~~~~~~~~~~
If the functionality is covered by other tests, perhaps the test can be removed. If not, perhaps it can be rewritten at a lower level which will remove the flakiness or make its source more apparent.
Quarantine
~~~~~~~~~~
Mark Lapierre discusses the `Pros and Cons of Quarantined Tests <https://dev.to/mlapierre/pros-and-cons-of-quarantined-tests-2emj>`_ in a post from 2018.
CI tools that rerun on failure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Azure Pipelines (the Azure cloud CI/CD tool, formerly Visual Studio Team Services or VSTS) has a feature to `identify flaky tests <https://docs.microsoft.com/en-us/azure/devops/release-notes/2017/dec-11-vsts#identify-flaky-tests>`_ and rerun failed tests.
Research
^^^^^^^^
This is a limited list, please submit an issue or pull request to expand it!
* Gao, Zebao, Yalan Liang, Myra B. Cohen, Atif M. Memon, and Zhen Wang. "Making system user interactive tests repeatable: When and what should we control?." In *Software Engineering (ICSE), 2015 IEEE/ACM 37th IEEE International Conference on*, vol. 1, pp. 55-65. IEEE, 2015. `PDF <http://www.cs.umd.edu/~atif/pubs/gao-icse15.pdf>`__
* Palomba, Fabio, and Andy Zaidman. "Does refactoring of test smells induce fixing flaky tests?." In *Software Maintenance and Evolution (ICSME), 2017 IEEE International Conference on*, pp. 1-12. IEEE, 2017. `PDF in Google Drive <https://drive.google.com/file/d/10HdcCQiuQVgW3yYUJD-TSTq1NbYEprl0/view>`__
* Bell, Jonathan, Owolabi Legunsen, Michael Hilton, Lamyaa Eloussi, Tifany Yung, and Darko Marinov. "DeFlaker: Automatically detecting flaky tests." In *Proceedings of the 2018 International Conference on Software Engineering*. 2018. `PDF <https://www.jonbell.net/icse18-deflaker.pdf>`__
Resources
^^^^^^^^^
* `Eradicating Non-Determinism in Tests <https://martinfowler.com/articles/nonDeterminism.html>`_ by Martin Fowler, 2011
* `No more flaky tests on the Go team <https://www.thoughtworks.com/insights/blog/no-more-flaky-tests-go-team>`_ by Pavan Sudarshan, 2012
* `The Build That Cried Broken: Building Trust in your Continuous Integration Tests <https://www.youtube.com/embed/VotJqV4n8ig>`_ talk (video) by `Angie Jones <http://angiejones.tech/>`_ at SeleniumConf Austin 2017
* `Test and Code Podcast: Flaky Tests and How to Deal with Them <https://testandcode.com/50>`_ by Brian Okken and Anthony Shaw, 2018
* Microsoft:
* `How we approach testing VSTS to enable continuous delivery <https://blogs.msdn.microsoft.com/bharry/2017/06/28/testing-in-a-cloud-delivery-cadence/>`_ by Brian Harry MS, 2017
* `Eliminating Flaky Tests <https://docs.microsoft.com/en-us/azure/devops/learn/devops-at-microsoft/eliminating-flaky-tests>`_ blog and talk (video) by Munil Shah, 2017
* Google:
* `Flaky Tests at Google and How We Mitigate Them <https://testing.googleblog.com/2016/05/flaky-tests-at-google-and-how-we.html>`_ by John Micco, 2016
* `Where do Google's flaky tests come from? <https://docs.google.com/document/d/1mZ0-Kc97DI_F3tf_GBW_NB_aqka-P1jVOsFfufxqUUM/edit#heading=h.ec0r4fypsleh>`_ by Jeff Listfield, 2017

View File

@@ -175,3 +175,13 @@ Previous to version 2.4 to set a break point in code one needed to use ``pytest.
This is no longer needed and one can use the native ``import pdb;pdb.set_trace()`` call directly.
For more details see :ref:`breakpoints`.
"compat" properties
-------------------
.. deprecated:: 3.9
Access of ``Module``, ``Function``, ``Class``, ``Instance``, ``File`` and ``Item`` through ``Node`` instances have long
been documented as deprecated, but started to emit warnings from pytest ``3.9`` and onward.
Users should just ``import pytest`` and access those objects using the ``pytest`` module.

View File

@@ -114,6 +114,10 @@ Let's run this::
The one parameter set which caused a failure previously now
shows up as an "xfailed (expected to fail)" test.
In case the values provided to ``parametrize`` result in an empty list - for
example, if they're dynamically generated by some function - the behaviour of
pytest is defined by the :confval:`empty_parameter_set_mark` option.
To get all combinations of multiple parametrized arguments you can stack
``parametrize`` decorators::

View File

@@ -59,9 +59,9 @@ To see a complete list of all plugins with their latest testing
status against different pytest and Python versions, please visit
`plugincompat <http://plugincompat.herokuapp.com/>`_.
You may also discover more plugins through a `pytest- pypi.python.org search`_.
You may also discover more plugins through a `pytest- pypi.org search`_.
.. _`pytest- pypi.python.org search`: https://pypi.org/search/?q=pytest-
.. _`pytest- pypi.org search`: https://pypi.org/search/?q=pytest-
.. _`available installable plugins`:
@@ -69,17 +69,15 @@ You may also discover more plugins through a `pytest- pypi.python.org search`_.
Requiring/Loading plugins in a test module or conftest file
-----------------------------------------------------------
You can require plugins in a test module or a conftest file like this::
You can require plugins in a test module or a conftest file like this:
pytest_plugins = "myapp.testsupport.myplugin",
.. code-block:: python
pytest_plugins = ("myapp.testsupport.myplugin",)
When the test module or conftest plugin is loaded the specified plugins
will be loaded as well.
pytest_plugins = "myapp.testsupport.myplugin"
which will import the specified module as a ``pytest`` plugin.
.. note::
Requiring plugins using a ``pytest_plugins`` variable in non-root
``conftest.py`` files is deprecated. See

View File

@@ -75,7 +75,7 @@ Issues
------
* By using ``request.getfuncargvalue()`` we rely on actual fixture function
execution to know what fixtures are involved, due to it's dynamic nature
execution to know what fixtures are involved, due to its dynamic nature
* More importantly, ``request.getfuncargvalue()`` cannot be combined with
parametrized fixtures, such as ``extra_context``
* This is very inconvenient if you wish to extend an existing test suite by

View File

@@ -84,6 +84,12 @@ pytest.warns
.. autofunction:: pytest.warns(expected_warning: Exception, [match])
:with:
pytest.freeze_includes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**Tutorial**: :ref:`freezing-pytest`.
.. autofunction:: pytest.freeze_includes
.. _`marks ref`:
@@ -111,6 +117,7 @@ Add warning filters to marked test items.
A *warning specification string*, which is composed of contents of the tuple ``(action, message, category, module, lineno)``
as specified in `The Warnings filter <https://docs.python.org/3/library/warnings.html#warning-filter>`_ section of
the Python documentation, separated by ``":"``. Optional fields can be omitted.
Module names passed for filtering are not regex-escaped.
For example:
@@ -172,7 +179,7 @@ Mark a test function as using the given fixture names.
.. warning::
This mark can be used with *test functions* only, having no affect when applied
This mark has no effect when applied
to a **fixture** function.
.. py:function:: pytest.mark.usefixtures(*names)
@@ -976,6 +983,7 @@ passed multiple times. The expected format is ``name=value``. For example::
* ``skip`` skips tests with an empty parameterset (default)
* ``xfail`` marks tests with an empty parameterset as xfail(run=False)
* ``fail_at_collect`` raises an exception if parametrize collects an empty parameter set
.. code-block:: ini

View File

@@ -58,18 +58,20 @@ by calling the ``pytest.skip(reason)`` function:
if not valid_config():
pytest.skip("unsupported configuration")
The imperative method is useful when it is not possible to evaluate the skip condition
during import time.
It is also possible to skip the whole module using
``pytest.skip(reason, allow_module_level=True)`` at the module level:
.. code-block:: python
import sys
import pytest
if not pytest.config.getoption("--custom-flag"):
pytest.skip("--custom-flag is missing, skipping tests", allow_module_level=True)
if not sys.platform.startswith("win"):
pytest.skip("skipping windows-only tests", allow_module_level=True)
The imperative method is useful when it is not possible to evaluate the skip condition
during import time.
**Reference**: :ref:`pytest.mark.skip ref`

View File

@@ -23,6 +23,8 @@ Books
Talks and blog postings
---------------------------------------------
- pytest: recommendations, basic packages for testing in Python and Django, Andreu Vallbona, PyconES 2017 (`slides in english <http://talks.apsl.io/testing-pycones-2017/>`_, `video in spanish <https://www.youtube.com/watch?v=K20GeR-lXDk>`_)
- `Pythonic testing, Igor Starikov (Russian, PyNsk, November 2016)
<https://www.youtube.com/watch?v=_92nfdd5nK8>`_.

View File

@@ -5,6 +5,76 @@
Temporary directories and files
================================================
The ``tmp_path`` fixture
------------------------
.. versionadded:: 3.9
You can use the ``tmp_path`` fixture which will
provide a temporary directory unique to the test invocation,
created in the `base temporary directory`_.
``tmp_path`` is a ``pathlib/pathlib2.Path`` object. Here is an example test usage:
.. code-block:: python
# content of test_tmp_path.py
import os
CONTENT = u"content"
def test_create_file(tmp_path):
d = tmp_path / "sub"
d.mkdir()
p = d / "hello.txt"
p.write_text(CONTENT)
assert p.read_text() == CONTENT
assert len(list(tmp_path.iterdir())) == 1
assert 0
Running this would result in a passed test except for the last
``assert 0`` line which we use to look at values::
$ pytest test_tmp_path.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 1 item
test_tmp_path.py F [100%]
================================= FAILURES =================================
_____________________________ test_create_file _____________________________
tmp_path = PosixPath('PYTEST_TMPDIR/test_create_file0')
def test_create_file(tmp_path):
d = tmp_path / "sub"
d.mkdir()
p = d / "hello.txt"
p.write_text(CONTENT)
assert p.read_text() == CONTENT
assert len(list(tmp_path.iterdir())) == 1
> assert 0
E assert 0
test_tmp_path.py:13: AssertionError
========================= 1 failed in 0.12 seconds =========================
The ``tmp_path_factory`` fixture
--------------------------------
.. versionadded:: 3.9
The ``tmp_path_factory`` is a session-scoped fixture which can be used
to create arbitrary temporary directories from any other fixture or test.
It is intended to replace ``tmpdir_factory``, and returns :class:`pathlib.Path` instances.
The 'tmpdir' fixture
--------------------

View File

@@ -22,16 +22,15 @@ Almost all ``unittest`` features are supported:
* ``@unittest.skip`` style decorators;
* ``setUp/tearDown``;
* ``setUpClass/tearDownClass()``;
* ``setUpClass/tearDownClass``;
* ``setUpModule/tearDownModule``;
.. _`load_tests protocol`: https://docs.python.org/3/library/unittest.html#load-tests-protocol
.. _`setUpModule/tearDownModule`: https://docs.python.org/3/library/unittest.html#setupmodule-and-teardownmodule
.. _`subtests`: https://docs.python.org/3/library/unittest.html#distinguishing-test-iterations-using-subtests
Up to this point pytest does not have support for the following features:
* `load_tests protocol`_;
* `setUpModule/tearDownModule`_;
* `subtests`_;
Benefits out of the box

View File

@@ -255,8 +255,8 @@ Pytest supports the use of ``breakpoint()`` with the following behaviours:
- When ``breakpoint()`` is called and ``PYTHONBREAKPOINT`` is set to the default value, pytest will use the custom internal PDB trace UI instead of the system default ``Pdb``.
- When tests are complete, the system will default back to the system ``Pdb`` trace UI.
- If ``--pdb`` is called on execution of pytest, the custom internal Pdb trace UI is used on ``bothbreakpoint()`` and failed tests/unhandled exceptions.
- If ``--pdbcls`` is used, the custom class debugger will be executed when a test fails (as expected within existing behaviour), but also when ``breakpoint()`` is called from within a test, the custom class debugger will be instantiated.
- With ``--pdb`` passed to pytest, the custom internal Pdb trace UI is used with both ``breakpoint()`` and failed tests/unhandled exceptions.
- ``--pdbcls`` can be used to specify a custom debugger class.
.. _durations:
@@ -269,6 +269,7 @@ To get a list of the slowest 10 test durations::
pytest --durations=10
By default, pytest will not show test durations that are too small (<0.01s) unless ``-vv`` is passed on the command-line.
Creating JUnitXML format files
----------------------------------------------------

View File

@@ -29,8 +29,9 @@ Running pytest now produces this output::
test_show_warnings.py . [100%]
============================= warnings summary =============================
$REGENDOC_TMPDIR/test_show_warnings.py:4: UserWarning: api v1, should use functions from v2
warnings.warn(UserWarning("api v1, should use functions from v2"))
test_show_warnings.py::test_one
$REGENDOC_TMPDIR/test_show_warnings.py:4: UserWarning: api v1, should use functions from v2
warnings.warn(UserWarning("api v1, should use functions from v2"))
-- Docs: https://docs.pytest.org/en/latest/warnings.html
=================== 1 passed, 1 warnings in 0.12 seconds ===================
@@ -75,54 +76,6 @@ Both ``-W`` command-line option and ``filterwarnings`` ini option are based on P
`-W option`_ and `warnings.simplefilter`_, so please refer to those sections in the Python
documentation for other examples and advanced usage.
Disabling warning summary
-------------------------
Although not recommended, you can use the ``--disable-warnings`` command-line option to suppress the
warning summary entirely from the test run output.
Disabling warning capture entirely
----------------------------------
This plugin is enabled by default but can be disabled entirely in your ``pytest.ini`` file with:
.. code-block:: ini
[pytest]
addopts = -p no:warnings
Or passing ``-p no:warnings`` in the command-line. This might be useful if your test suites handles warnings
using an external system.
.. _`deprecation-warnings`:
DeprecationWarning and PendingDeprecationWarning
------------------------------------------------
.. versionadded:: 3.8
By default pytest will display ``DeprecationWarning`` and ``PendingDeprecationWarning`` if no other warning filters
are configured.
To disable showing ``DeprecationWarning`` and ``PendingDeprecationWarning`` warnings, you might define any warnings
filter either in the command-line or in the ini file, or you can use:
.. code-block:: ini
[pytest]
filterwarnings =
ignore::DeprecationWarning
ignore::PendingDeprecationWarning
.. note::
This makes pytest more compliant with `PEP-0506 <https://www.python.org/dev/peps/pep-0565/#recommended-filter-settings-for-test-runners>`_ which suggests that those warnings should
be shown by default by test runners, but pytest doesn't follow ``PEP-0506`` completely because resetting all
warning filters like suggested in the PEP will break existing test suites that configure warning filters themselves
by calling ``warnings.simplefilter`` (see issue `#2430 <https://github.com/pytest-dev/pytest/issues/2430>`_
for an example of that).
.. _`filterwarnings`:
``@pytest.mark.filterwarnings``
@@ -161,24 +114,6 @@ decorator or to all tests in a module by setting the ``pytestmark`` variable:
pytestmark = pytest.mark.filterwarnings("error")
.. note::
Except for these features, pytest does not change the python warning filter; it only captures
and displays the warnings which are issued with respect to the currently configured filter,
including changes to the filter made by test functions or by the system under test.
.. note::
``DeprecationWarning`` and ``PendingDeprecationWarning`` are hidden by the standard library
by default so you have to explicitly configure them to be displayed in your ``pytest.ini``:
.. code-block:: ini
[pytest]
filterwarnings =
once::DeprecationWarning
once::PendingDeprecationWarning
*Credits go to Florian Schulze for the reference implementation in the* `pytest-warnings`_
*plugin.*
@@ -187,6 +122,102 @@ decorator or to all tests in a module by setting the ``pytestmark`` variable:
.. _warnings.simplefilter: https://docs.python.org/3/library/warnings.html#warnings.simplefilter
.. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings
Disabling warnings summary
--------------------------
Although not recommended, you can use the ``--disable-warnings`` command-line option to suppress the
warning summary entirely from the test run output.
Disabling warning capture entirely
----------------------------------
This plugin is enabled by default but can be disabled entirely in your ``pytest.ini`` file with:
.. code-block:: ini
[pytest]
addopts = -p no:warnings
Or passing ``-p no:warnings`` in the command-line. This might be useful if your test suites handles warnings
using an external system.
.. _`deprecation-warnings`:
DeprecationWarning and PendingDeprecationWarning
------------------------------------------------
.. versionadded:: 3.8
.. versionchanged:: 3.9
By default pytest will display ``DeprecationWarning`` and ``PendingDeprecationWarning`` warnings from
user code and third-party libraries, as recommended by `PEP-0506 <https://www.python.org/dev/peps/pep-0565>`_.
This helps users keep their code modern and avoid breakages when deprecated warnings are effectively removed.
Sometimes it is useful to hide some specific deprecation warnings that happen in code that you have no control over
(such as third-party libraries), in which case you might use the warning filters options (ini or marks) to ignore
those warnings.
For example:
.. code-block:: ini
[pytest]
filterwarnings =
ignore:.*U.*mode is deprecated:DeprecationWarning
This will ignore all warnings of type ``DeprecationWarning`` where the start of the message matches
the regular expression ``".*U.*mode is deprecated"``.
.. note::
If warnings are configured at the interpreter level, using
the `PYTHONWARNINGS <https://docs.python.org/3/using/cmdline.html#envvar-PYTHONWARNINGS>`_ environment variable or the
``-W`` command-line option, pytest will not configure any filters by default.
Also pytest doesn't follow ``PEP-0506`` suggestion of resetting all warning filters because
it might break test suites that configure warning filters themselves
by calling ``warnings.simplefilter`` (see issue `#2430 <https://github.com/pytest-dev/pytest/issues/2430>`_
for an example of that).
.. _`ensuring a function triggers a deprecation warning`:
.. _ensuring_function_triggers:
Ensuring code triggers a deprecation warning
--------------------------------------------
You can also call a global helper for checking
that a certain function call triggers a ``DeprecationWarning`` or
``PendingDeprecationWarning``::
import pytest
def test_global():
pytest.deprecated_call(myfunction, 17)
By default, ``DeprecationWarning`` and ``PendingDeprecationWarning`` will not be
caught when using ``pytest.warns`` or ``recwarn`` because default Python warnings filters hide
them. If you wish to record them in your own code, use the
command ``warnings.simplefilter('always')``::
import warnings
import pytest
def test_deprecation(recwarn):
warnings.simplefilter('always')
warnings.warn("deprecated", DeprecationWarning)
assert len(recwarn) == 1
assert recwarn.pop(DeprecationWarning)
You can also use it as a contextmanager::
def test_global():
with pytest.deprecated_call():
myobject.deprecated_method()
.. _`asserting warnings`:
@@ -293,43 +324,6 @@ warnings, or index into it to get a particular recorded warning.
Full API: :class:`WarningsRecorder`.
.. _`ensuring a function triggers a deprecation warning`:
.. _ensuring_function_triggers:
Ensuring a function triggers a deprecation warning
-------------------------------------------------------
You can also call a global helper for checking
that a certain function call triggers a ``DeprecationWarning`` or
``PendingDeprecationWarning``::
import pytest
def test_global():
pytest.deprecated_call(myfunction, 17)
By default, ``DeprecationWarning`` and ``PendingDeprecationWarning`` will not be
caught when using ``pytest.warns`` or ``recwarn`` because default Python warnings filters hide
them. If you wish to record them in your own code, use the
command ``warnings.simplefilter('always')``::
import warnings
import pytest
def test_deprecation(recwarn):
warnings.simplefilter('always')
warnings.warn("deprecated", DeprecationWarning)
assert len(recwarn) == 1
assert recwarn.pop(DeprecationWarning)
You can also use it as a contextmanager::
def test_global():
with pytest.deprecated_call():
myobject.deprecated_method()
.. _internal-warnings:
@@ -358,8 +352,9 @@ defines an ``__init__`` constructor, as this prevents the class from being insta
$ pytest test_pytest_warnings.py -q
============================= warnings summary =============================
$REGENDOC_TMPDIR/test_pytest_warnings.py:1: PytestWarning: cannot collect test class 'Test' because it has a __init__ constructor
class Test:
test_pytest_warnings.py:1
$REGENDOC_TMPDIR/test_pytest_warnings.py:1: PytestWarning: cannot collect test class 'Test' because it has a __init__ constructor
class Test:
-- Docs: https://docs.pytest.org/en/latest/warnings.html
1 warnings in 0.12 seconds

View File

@@ -386,7 +386,7 @@ return a result object, with which we can assert the tests' outcomes.
result.assert_outcomes(passed=4)
additionally it is possible to copy examples for a example folder before running pytest on it
additionally it is possible to copy examples for an example folder before running pytest on it
.. code:: ini
@@ -418,8 +418,9 @@ additionally it is possible to copy examples for a example folder before running
test_example.py .. [100%]
============================= warnings summary =============================
$REGENDOC_TMPDIR/test_example.py:4: PytestExperimentalApiWarning: testdir.copy_example is an experimental api that may change over time
testdir.copy_example("test_example.py")
test_example.py::test_plugin
$REGENDOC_TMPDIR/test_example.py:4: PytestExperimentalApiWarning: testdir.copy_example is an experimental api that may change over time
testdir.copy_example("test_example.py")
-- Docs: https://docs.pytest.org/en/latest/warnings.html
=================== 2 passed, 1 warnings in 0.12 seconds ===================

View File

@@ -1,4 +1,5 @@
import json
import py
import requests

View File

@@ -1,6 +1,7 @@
[build-system]
requires = [
"setuptools",
# sync with setup.py until we discard non-pep-517/518
"setuptools>=40.0",
"setuptools-scm",
"wheel",
]
@@ -15,7 +16,12 @@ template = "changelog/_template.rst"
[[tool.towncrier.type]]
directory = "removal"
name = "Deprecations and Removals"
name = "Removals"
showcontent = true
[[tool.towncrier.type]]
directory = "deprecation"
name = "Deprecations"
showcontent = true
[[tool.towncrier.type]]

View File

@@ -2,9 +2,13 @@
Invoke development tasks.
"""
import argparse
from colorama import init, Fore
from pathlib import Path
from subprocess import check_output, check_call, call
from subprocess import call
from subprocess import check_call
from subprocess import check_output
from colorama import Fore
from colorama import init
def announce(version):

View File

@@ -1,3 +1,55 @@
[metadata]
name = pytest
description = pytest: simple powerful testing with Python
long_description = file: README.rst
url = https://docs.pytest.org/en/latest/
project_urls =
Source=https://github.com/pytest-dev/pytest
Tracker=https://github.com/pytest-dev/pytest/issues
author = Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others
license = MIT license
license_file = LICENSE
keywords = test, unittest
classifiers =
Development Status :: 6 - Mature
Intended Audience :: Developers
License :: OSI Approved :: MIT License
Operating System :: POSIX
Operating System :: Microsoft :: Windows
Operating System :: MacOS :: MacOS X
Topic :: Software Development :: Testing
Topic :: Software Development :: Libraries
Topic :: Utilities
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
Programming Language :: Python :: 3
Programming Language :: Python :: 3.4
Programming Language :: Python :: 3.5
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
platforms = unix, linux, osx, cygwin, win32
[options]
zip_safe = no
packages =
_pytest
_pytest.assertion
_pytest._code
_pytest.mark
_pytest.config
py_modules = pytest
python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
[options.entry_points]
console_scripts =
pytest=pytest:main
py.test=pytest:main
[build_sphinx]
source-dir = doc/en/
build-dir = doc/build
@@ -13,8 +65,6 @@ universal = 1
ignore =
_pytest/_version.py
[metadata]
license_file = LICENSE
[devpi:upload]
formats = sdist.tgz,bdist_wheel

131
setup.py
View File

@@ -1,126 +1,35 @@
import os
import sys
import setuptools
import pkg_resources
from setuptools import setup
classifiers = [
"Development Status :: 6 - Mature",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Operating System :: POSIX",
"Operating System :: Microsoft :: Windows",
"Operating System :: MacOS :: MacOS X",
"Topic :: Software Development :: Testing",
"Topic :: Software Development :: Libraries",
"Topic :: Utilities",
] + [
("Programming Language :: Python :: %s" % x)
for x in "2 2.7 3 3.4 3.5 3.6 3.7".split()
# TODO: if py gets upgrade to >=1.6,
# remove _width_of_current_line in terminal.py
INSTALL_REQUIRES = [
"py>=1.5.0",
"six>=1.10.0",
"setuptools",
"attrs>=17.4.0",
"more-itertools>=4.0.0",
"atomicwrites>=1.0",
'funcsigs;python_version<"3.0"',
'pathlib2>=2.2.0;python_version<"3.6"',
'colorama;sys_platform=="win32"',
]
with open("README.rst") as fd:
long_description = fd.read()
def get_environment_marker_support_level():
"""
Tests how well setuptools supports PEP-426 environment marker.
The first known release to support it is 0.7 (and the earliest on PyPI seems to be 0.7.2
so we're using that), see: https://setuptools.readthedocs.io/en/latest/history.html#id350
The support is later enhanced to allow direct conditional inclusions inside install_requires,
which is now recommended by setuptools. It first appeared in 36.2.0, went broken with 36.2.1, and
again worked since 36.2.2, so we're using that. See:
https://setuptools.readthedocs.io/en/latest/history.html#v36-2-2
https://github.com/pypa/setuptools/issues/1099
References:
* https://wheel.readthedocs.io/en/latest/index.html#defining-conditional-dependencies
* https://www.python.org/dev/peps/pep-0426/#environment-markers
* https://setuptools.readthedocs.io/en/latest/setuptools.html#declaring-platform-specific-dependencies
"""
try:
version = pkg_resources.parse_version(setuptools.__version__)
if version >= pkg_resources.parse_version("36.2.2"):
return 2
if version >= pkg_resources.parse_version("0.7.2"):
return 1
except Exception as exc:
sys.stderr.write("Could not test setuptool's version: %s\n" % exc)
# as of testing on 2018-05-26 fedora was on version 37* and debian was on version 33+
# we should consider erroring on those
return 0
# if _PYTEST_SETUP_SKIP_PLUGGY_DEP is set, skip installing pluggy;
# used by tox.ini to test with pluggy master
if "_PYTEST_SETUP_SKIP_PLUGGY_DEP" not in os.environ:
INSTALL_REQUIRES.append("pluggy>=0.7")
def main():
extras_require = {}
install_requires = [
"py>=1.5.0", # if py gets upgrade to >=1.6, remove _width_of_current_line in terminal.py
"six>=1.10.0",
"setuptools",
"attrs>=17.4.0",
"more-itertools>=4.0.0",
"atomicwrites>=1.0",
]
# if _PYTEST_SETUP_SKIP_PLUGGY_DEP is set, skip installing pluggy;
# used by tox.ini to test with pluggy master
if "_PYTEST_SETUP_SKIP_PLUGGY_DEP" not in os.environ:
install_requires.append("pluggy>=0.7")
environment_marker_support_level = get_environment_marker_support_level()
if environment_marker_support_level >= 2:
install_requires.append('funcsigs;python_version<"3.0"')
install_requires.append('pathlib2>=2.2.0;python_version<"3.6"')
install_requires.append('colorama;sys_platform=="win32"')
elif environment_marker_support_level == 1:
extras_require[':python_version<"3.0"'] = ["funcsigs"]
extras_require[':python_version<"3.6"'] = ["pathlib2>=2.2.0"]
extras_require[':sys_platform=="win32"'] = ["colorama"]
else:
if sys.platform == "win32":
install_requires.append("colorama")
if sys.version_info < (3, 0):
install_requires.append("funcsigs")
if sys.version_info < (3, 6):
install_requires.append("pathlib2>=2.2.0")
setup(
name="pytest",
description="pytest: simple powerful testing with Python",
long_description=long_description,
use_scm_version={"write_to": "src/_pytest/_version.py"},
url="https://docs.pytest.org/en/latest/",
project_urls={
"Source": "https://github.com/pytest-dev/pytest",
"Tracker": "https://github.com/pytest-dev/pytest/issues",
},
license="MIT license",
platforms=["unix", "linux", "osx", "cygwin", "win32"],
author=(
"Holger Krekel, Bruno Oliveira, Ronny Pfannschmidt, "
"Floris Bruynooghe, Brianna Laugher, Florian Bruhin and others"
),
entry_points={"console_scripts": ["pytest=pytest:main", "py.test=pytest:main"]},
classifiers=classifiers,
keywords="test unittest",
# the following should be enabled for release
setup_requires=["setuptools-scm"],
setup_requires=["setuptools-scm", "setuptools>=40.0"],
package_dir={"": "src"},
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
install_requires=install_requires,
extras_require=extras_require,
packages=[
"_pytest",
"_pytest.assertion",
"_pytest._code",
"_pytest.mark",
"_pytest.config",
],
py_modules=["pytest"],
zip_safe=False,
install_requires=INSTALL_REQUIRES,
)

View File

@@ -1,4 +1,3 @@
"""allow bash-completion for argparse with argcomplete if installed
needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail
to find the magic string, so _ARGCOMPLETE env. var is never set, and
@@ -54,9 +53,12 @@ If things do not work right away:
which should throw a KeyError: 'COMPLINE' (which is properly set by the
global argcomplete script).
"""
from __future__ import absolute_import, division, print_function
import sys
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import sys
from glob import glob

View File

@@ -1,10 +1,14 @@
""" python inspection/code generation API """
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from .code import Code # noqa
from .code import ExceptionInfo # noqa
from .code import filter_traceback # noqa
from .code import Frame # noqa
from .code import Traceback # noqa
from .code import getrawcode # noqa
from .source import Source # noqa
from .code import Traceback # noqa
from .source import compile_ as compile # noqa
from .source import getfslineno # noqa
from .source import Source # noqa

View File

@@ -2,8 +2,13 @@
# CHANGES:
# - some_str is replaced, trying to create unicode strings
#
from __future__ import absolute_import, division, print_function, unicode_literals
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import types
from six import text_type

View File

@@ -1,17 +1,27 @@
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import inspect
import pprint
import re
import sys
import traceback
from inspect import CO_VARARGS, CO_VARKEYWORDS
from inspect import CO_VARARGS
from inspect import CO_VARKEYWORDS
from weakref import ref
import attr
import re
from weakref import ref
from _pytest.compat import _PY2, _PY3, PY35, safe_str
from six import text_type
import pluggy
import py
import six
from six import text_type
import _pytest
from _pytest.compat import _PY2
from _pytest.compat import _PY3
from _pytest.compat import PY35
from _pytest.compat import safe_str
builtin_repr = repr
@@ -451,13 +461,35 @@ class ExceptionInfo(object):
tbfilter=True,
funcargs=False,
truncate_locals=True,
chain=True,
):
""" return str()able representation of this exception info.
showlocals: show locals per traceback entry
style: long|short|no|native traceback style
tbfilter: hide entries (where __tracebackhide__ is true)
"""
Return str()able representation of this exception info.
in case of style==native, tbfilter and showlocals is ignored.
:param bool showlocals:
Show locals per traceback entry.
Ignored if ``style=="native"``.
:param str style: long|short|no|native traceback style
:param bool abspath:
If paths should be changed to absolute or left unchanged.
:param bool tbfilter:
Hide entries that contain a local variable ``__tracebackhide__==True``.
Ignored if ``style=="native"``.
:param bool funcargs:
Show fixtures ("funcargs" for legacy purposes) per traceback entry.
:param bool truncate_locals:
With ``showlocals==True``, make sure locals can be safely represented as strings.
:param bool chain: if chained exceptions in Python 3 should be shown.
.. versionchanged:: 3.9
Added the ``chain`` parameter.
"""
if style == "native":
return ReprExceptionInfo(
@@ -476,6 +508,7 @@ class ExceptionInfo(object):
tbfilter=tbfilter,
funcargs=funcargs,
truncate_locals=truncate_locals,
chain=chain,
)
return fmt.repr_excinfo(self)
@@ -516,6 +549,7 @@ class FormattedExcinfo(object):
tbfilter = attr.ib(default=True)
funcargs = attr.ib(default=False)
truncate_locals = attr.ib(default=True)
chain = attr.ib(default=True)
astcache = attr.ib(default=attr.Factory(dict), init=False, repr=False)
def _getindent(self, source):
@@ -735,7 +769,7 @@ class FormattedExcinfo(object):
reprcrash = None
repr_chain += [(reprtraceback, reprcrash, descr)]
if e.__cause__ is not None:
if e.__cause__ is not None and self.chain:
e = e.__cause__
excinfo = (
ExceptionInfo((type(e), e, e.__traceback__))
@@ -743,7 +777,11 @@ class FormattedExcinfo(object):
else None
)
descr = "The above exception was the direct cause of the following exception:"
elif e.__context__ is not None and not e.__suppress_context__:
elif (
e.__context__ is not None
and not e.__suppress_context__
and self.chain
):
e = e.__context__
excinfo = (
ExceptionInfo((type(e), e, e.__traceback__))
@@ -979,3 +1017,36 @@ else:
return "maximum recursion depth exceeded" in str(excinfo.value)
except UnicodeError:
return False
# relative paths that we use to filter traceback entries from appearing to the user;
# see filter_traceback
# note: if we need to add more paths than what we have now we should probably use a list
# for better maintenance
_PLUGGY_DIR = py.path.local(pluggy.__file__.rstrip("oc"))
# pluggy is either a package or a single module depending on the version
if _PLUGGY_DIR.basename == "__init__.py":
_PLUGGY_DIR = _PLUGGY_DIR.dirpath()
_PYTEST_DIR = py.path.local(_pytest.__file__).dirpath()
_PY_DIR = py.path.local(py.__file__).dirpath()
def filter_traceback(entry):
"""Return True if a TracebackEntry instance should be removed from tracebacks:
* dynamically generated code (no code to show up for it);
* internal traceback from pytest or its internal libraries, py and pluggy.
"""
# entry.path might sometimes return a str object when the entry
# points to dynamically generated code
# see https://bitbucket.org/pytest-dev/py/issues/71
raw_filename = entry.frame.code.raw.co_filename
is_generated = "<" in raw_filename and ">" in raw_filename
if is_generated:
return False
# entry.path might point to a non-existing file, in which case it will
# also return a str object. see #1133
p = py.path.local(entry.path)
return (
not p.relto(_PLUGGY_DIR) and not p.relto(_PYTEST_DIR) and not p.relto(_PY_DIR)
)

View File

@@ -1,16 +1,19 @@
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import ast
from ast import PyCF_ONLY_AST as _AST_FLAG
from bisect import bisect_right
import inspect
import linecache
import sys
import six
import inspect
import textwrap
import tokenize
import py
import warnings
from ast import PyCF_ONLY_AST as _AST_FLAG
from bisect import bisect_right
cpy_compile = compile
import py
import six
class Source(object):
@@ -23,7 +26,6 @@ class Source(object):
def __init__(self, *parts, **kwargs):
self.lines = lines = []
de = kwargs.get("deindent", True)
rstrip = kwargs.get("rstrip", True)
for part in parts:
if not part:
partlines = []
@@ -33,11 +35,6 @@ class Source(object):
partlines = [x.rstrip("\n") for x in part]
elif isinstance(part, six.string_types):
partlines = part.split("\n")
if rstrip:
while partlines:
if partlines[-1].strip():
break
partlines.pop()
else:
partlines = getsource(part, deindent=de).lines
if de:
@@ -115,17 +112,10 @@ class Source(object):
ast, start, end = getstatementrange_ast(lineno, self)
return start, end
def deindent(self, offset=None):
""" return a new source object deindented by offset.
If offset is None then guess an indentation offset from
the first non-blank line. Subsequent lines which have a
lower indentation offset will be copied verbatim as
they are assumed to be part of multilines.
"""
# XXX maybe use the tokenizer to properly handle multiline
# strings etc.pp?
def deindent(self):
"""return a new source object deindented."""
newsource = Source()
newsource.lines[:] = deindent(self.lines, offset)
newsource.lines[:] = deindent(self.lines)
return newsource
def isparseable(self, deindent=True):
@@ -170,7 +160,7 @@ class Source(object):
filename = base + "%r %s:%d>" % (filename, fn, lineno)
source = "\n".join(self.lines) + "\n"
try:
co = cpy_compile(source, filename, mode, flag)
co = compile(source, filename, mode, flag)
except SyntaxError:
ex = sys.exc_info()[1]
# re-represent syntax errors from parsing python strings
@@ -204,7 +194,7 @@ def compile_(source, filename=None, mode="exec", flags=0, dont_inherit=0):
"""
if isinstance(source, ast.AST):
# XXX should Source support having AST?
return cpy_compile(source, filename, mode, flags, dont_inherit)
return compile(source, filename, mode, flags, dont_inherit)
_genframe = sys._getframe(1) # the caller
s = Source(source)
co = s.compile(filename, mode, flags, _genframe=_genframe)
@@ -268,47 +258,8 @@ def getsource(obj, **kwargs):
return Source(strsrc, **kwargs)
def deindent(lines, offset=None):
if offset is None:
for line in lines:
line = line.expandtabs()
s = line.lstrip()
if s:
offset = len(line) - len(s)
break
else:
offset = 0
if offset == 0:
return list(lines)
newlines = []
def readline_generator(lines):
for line in lines:
yield line + "\n"
it = readline_generator(lines)
try:
for _, _, (sline, _), (eline, _), _ in tokenize.generate_tokens(
lambda: next(it)
):
if sline > len(lines):
break # End of input reached
if sline > len(newlines):
line = lines[sline - 1].expandtabs()
if line.lstrip() and line[:offset].isspace():
line = line[offset:] # Deindent
newlines.append(line)
for i in range(sline, eline):
# Don't deindent continuing lines of
# multiline tokens (i.e. multiline strings)
newlines.append(lines[i])
except (IndentationError, tokenize.TokenError):
pass
# Add any lines we didn't see. E.g. if an exception was raised.
newlines.extend(lines[len(newlines) :])
return newlines
def deindent(lines):
return textwrap.dedent("\n".join(lines)).splitlines()
def get_statement_startend2(lineno, node):
@@ -338,7 +289,11 @@ def get_statement_startend2(lineno, node):
def getstatementrange_ast(lineno, source, assertion=False, astnode=None):
if astnode is None:
content = str(source)
astnode = compile(content, "source", "exec", 1024) # 1024 for AST
# See #4260:
# don't produce duplicate warnings when compiling source to find ast
with warnings.catch_warnings():
warnings.simplefilter("ignore")
astnode = compile(content, "source", "exec", _AST_FLAG)
start, end = get_statement_startend2(lineno, astnode)
# we need to correct the end:

View File

@@ -1,13 +1,17 @@
"""
support for presenting detailed information in failing assertions.
"""
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import sys
import six
from _pytest.assertion import util
from _pytest.assertion import rewrite
from _pytest.assertion import truncate
from _pytest.assertion import util
def pytest_addoption(parser):

View File

@@ -1,13 +1,15 @@
"""Rewrite assertion AST to produce nice error messages"""
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import ast
import errno
import itertools
import imp
import itertools
import marshal
import os
import re
import six
import string
import struct
import sys
@@ -15,10 +17,12 @@ import types
import atomicwrites
import py
import six
from _pytest.assertion import util
from _pytest.compat import PurePath, spec_from_file_location
from _pytest.paths import fnmatch_ex
from _pytest.compat import spec_from_file_location
from _pytest.pathlib import fnmatch_ex
from _pytest.pathlib import PurePath
# pytest caches rewritten pycs in __pycache__.
if hasattr(imp, "get_tag"):
@@ -269,17 +273,17 @@ class AssertionRewritingHook(object):
)
def load_module(self, name):
# If there is an existing module object named 'fullname' in
# sys.modules, the loader must use that existing module. (Otherwise,
# the reload() builtin will not work correctly.)
if name in sys.modules:
return sys.modules[name]
co, pyc = self.modules.pop(name)
# I wish I could just call imp.load_compiled here, but __file__ has to
# be set properly. In Python 3.2+, this all would be handled correctly
# by load_compiled.
mod = sys.modules[name] = imp.new_module(name)
if name in sys.modules:
# If there is an existing module object named 'fullname' in
# sys.modules, the loader must use that existing module. (Otherwise,
# the reload() builtin will not work correctly.)
mod = sys.modules[name]
else:
# I wish I could just call imp.load_compiled here, but __file__ has to
# be set properly. In Python 3.2+, this all would be handled correctly
# by load_compiled.
mod = sys.modules[name] = imp.new_module(name)
try:
mod.__file__ = co.co_filename
# Normally, this attribute is 3.2+.
@@ -398,7 +402,7 @@ def _rewrite_test(config, fn):
finally:
del state._indecode
try:
tree = ast.parse(source)
tree = ast.parse(source, filename=fn.strpath)
except SyntaxError:
# Let this pop up again in the real import.
state.trace("failed to parse: %r" % (fn,))
@@ -705,10 +709,9 @@ class AssertionRewriter(ast.NodeVisitor):
setattr(node, name, new)
elif (
isinstance(field, ast.AST)
and
# Don't recurse into expressions as they can't contain
# asserts.
not isinstance(field, ast.expr)
and not isinstance(field, ast.expr)
):
nodes.append(field)

View File

@@ -4,7 +4,10 @@ Utilities for truncating assertion output.
Current default behaviour is to truncate assertion explanations at
~8 terminal lines, unless running in "-vv" mode or running on CI.
"""
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import six

View File

@@ -1,13 +1,15 @@
"""Utilities for assertion debugging"""
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import pprint
import _pytest._code
import py
import six
from ..compat import Sequence
u = six.text_type
import _pytest._code
from ..compat import Sequence
# The _reprcompare attribute on the util module is used by the new assertion
# interpretation code and assertion rewriter to detect this plugin was
@@ -19,9 +21,9 @@ _reprcompare = None
# the re-encoding is needed for python2 repr
# with non-ascii characters (see issue 877 and 1379)
def ecu(s):
try:
return u(s, "utf-8", "replace")
except TypeError:
if isinstance(s, bytes):
return s.decode("UTF-8", "replace")
else:
return s
@@ -38,7 +40,7 @@ def format_explanation(explanation):
explanation = ecu(explanation)
lines = _split_explanation(explanation)
result = _format_lines(lines)
return u("\n").join(result)
return u"\n".join(result)
def _split_explanation(explanation):
@@ -48,7 +50,7 @@ def _split_explanation(explanation):
Any other newlines will be escaped and appear in the line as the
literal '\n' characters.
"""
raw_lines = (explanation or u("")).split("\n")
raw_lines = (explanation or u"").split("\n")
lines = [raw_lines[0]]
for values in raw_lines[1:]:
if values and values[0] in ["{", "}", "~", ">"]:
@@ -73,13 +75,13 @@ def _format_lines(lines):
for line in lines[1:]:
if line.startswith("{"):
if stackcnt[-1]:
s = u("and ")
s = u"and "
else:
s = u("where ")
s = u"where "
stack.append(len(result))
stackcnt[-1] += 1
stackcnt.append(0)
result.append(u(" +") + u(" ") * (len(stack) - 1) + s + line[1:])
result.append(u" +" + u" " * (len(stack) - 1) + s + line[1:])
elif line.startswith("}"):
stack.pop()
stackcnt.pop()
@@ -88,7 +90,7 @@ def _format_lines(lines):
assert line[0] in ["~", ">"]
stack[-1] += 1
indent = len(stack) if line.startswith("~") else len(stack) - 1
result.append(u(" ") * indent + line[1:])
result.append(u" " * indent + line[1:])
assert len(stack) == 1
return result
@@ -106,7 +108,7 @@ def assertrepr_compare(config, op, left, right):
left_repr = py.io.saferepr(left, maxsize=int(width // 2))
right_repr = py.io.saferepr(right, maxsize=width - len(left_repr))
summary = u("%s %s %s") % (ecu(left_repr), op, ecu(right_repr))
summary = u"%s %s %s" % (ecu(left_repr), op, ecu(right_repr))
def issequence(x):
return isinstance(x, Sequence) and not isinstance(x, basestring)
@@ -151,11 +153,9 @@ def assertrepr_compare(config, op, left, right):
explanation = _notin_text(left, right, verbose)
except Exception:
explanation = [
u(
"(pytest_assertion plugin: representation of details failed. "
"Probably an object has a faulty __repr__.)"
),
u(_pytest._code.ExceptionInfo()),
u"(pytest_assertion plugin: representation of details failed. "
u"Probably an object has a faulty __repr__.)",
six.text_type(_pytest._code.ExceptionInfo()),
]
if not explanation:
@@ -199,8 +199,7 @@ def _diff_text(left, right, verbose=False):
if i > 42:
i -= 10 # Provide some context
explanation = [
u("Skipping %s identical leading " "characters in diff, use -v to show")
% i
u"Skipping %s identical leading characters in diff, use -v to show" % i
]
left = left[i:]
right = right[i:]
@@ -211,11 +210,8 @@ def _diff_text(left, right, verbose=False):
if i > 42:
i -= 10 # Provide some context
explanation += [
u(
"Skipping %s identical trailing "
"characters in diff, use -v to show"
)
% i
u"Skipping {} identical trailing "
u"characters in diff, use -v to show".format(i)
]
left = left[:-i]
right = right[:-i]
@@ -233,21 +229,21 @@ def _diff_text(left, right, verbose=False):
def _compare_eq_iterable(left, right, verbose=False):
if not verbose:
return [u("Use -v to get the full diff")]
return [u"Use -v to get the full diff"]
# dynamic import to speedup pytest
import difflib
try:
left_formatting = pprint.pformat(left).splitlines()
right_formatting = pprint.pformat(right).splitlines()
explanation = [u("Full diff:")]
explanation = [u"Full diff:"]
except Exception:
# hack: PrettyPrinter.pformat() in python 2 fails when formatting items that can't be sorted(), ie, calling
# sorted() on a list would raise. See issue #718.
# As a workaround, the full diff is generated by using the repr() string of each item of each container.
left_formatting = sorted(repr(x) for x in left)
right_formatting = sorted(repr(x) for x in right)
explanation = [u("Full diff (fallback to calling repr on each item):")]
explanation = [u"Full diff (fallback to calling repr on each item):"]
explanation.extend(
line.strip() for line in difflib.ndiff(left_formatting, right_formatting)
)
@@ -258,16 +254,16 @@ def _compare_eq_sequence(left, right, verbose=False):
explanation = []
for i in range(min(len(left), len(right))):
if left[i] != right[i]:
explanation += [u("At index %s diff: %r != %r") % (i, left[i], right[i])]
explanation += [u"At index %s diff: %r != %r" % (i, left[i], right[i])]
break
if len(left) > len(right):
explanation += [
u("Left contains more items, first extra item: %s")
u"Left contains more items, first extra item: %s"
% py.io.saferepr(left[len(right)])
]
elif len(left) < len(right):
explanation += [
u("Right contains more items, first extra item: %s")
u"Right contains more items, first extra item: %s"
% py.io.saferepr(right[len(left)])
]
return explanation
@@ -278,11 +274,11 @@ def _compare_eq_set(left, right, verbose=False):
diff_left = left - right
diff_right = right - left
if diff_left:
explanation.append(u("Extra items in the left set:"))
explanation.append(u"Extra items in the left set:")
for item in diff_left:
explanation.append(py.io.saferepr(item))
if diff_right:
explanation.append(u("Extra items in the right set:"))
explanation.append(u"Extra items in the right set:")
for item in diff_right:
explanation.append(py.io.saferepr(item))
return explanation
@@ -293,26 +289,26 @@ def _compare_eq_dict(left, right, verbose=False):
common = set(left).intersection(set(right))
same = {k: left[k] for k in common if left[k] == right[k]}
if same and verbose < 2:
explanation += [u("Omitting %s identical items, use -vv to show") % len(same)]
explanation += [u"Omitting %s identical items, use -vv to show" % len(same)]
elif same:
explanation += [u("Common items:")]
explanation += [u"Common items:"]
explanation += pprint.pformat(same).splitlines()
diff = {k for k in common if left[k] != right[k]}
if diff:
explanation += [u("Differing items:")]
explanation += [u"Differing items:"]
for k in diff:
explanation += [
py.io.saferepr({k: left[k]}) + " != " + py.io.saferepr({k: right[k]})
]
extra_left = set(left) - set(right)
if extra_left:
explanation.append(u("Left contains more items:"))
explanation.append(u"Left contains more items:")
explanation.extend(
pprint.pformat({k: left[k] for k in extra_left}).splitlines()
)
extra_right = set(right) - set(left)
if extra_right:
explanation.append(u("Right contains more items:"))
explanation.append(u"Right contains more items:")
explanation.extend(
pprint.pformat({k: right[k] for k in extra_right}).splitlines()
)
@@ -325,14 +321,14 @@ def _notin_text(term, text, verbose=False):
tail = text[index + len(term) :]
correct_text = head + tail
diff = _diff_text(correct_text, text, verbose)
newdiff = [u("%s is contained here:") % py.io.saferepr(term, maxsize=42)]
newdiff = [u"%s is contained here:" % py.io.saferepr(term, maxsize=42)]
for line in diff:
if line.startswith(u("Skipping")):
if line.startswith(u"Skipping"):
continue
if line.startswith(u("- ")):
if line.startswith(u"- "):
continue
if line.startswith(u("+ ")):
newdiff.append(u(" ") + line[2:])
if line.startswith(u"+ "):
newdiff.append(u" " + line[2:])
else:
newdiff.append(line)
return newdiff

View File

@@ -4,19 +4,23 @@ merged implementation of the cache provider
the name cache was not chosen to ensure pluggy automatically
ignores the external pytest-cache
"""
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import json
import os
from collections import OrderedDict
import attr
import py
import six
import attr
import pytest
import json
import shutil
from . import paths
from .compat import _PY2 as PY2, Path
from .compat import _PY2 as PY2
from .pathlib import Path
from .pathlib import resolve_from_str
from .pathlib import rmtree
README_CONTENT = u"""\
# pytest cache directory #
@@ -39,13 +43,13 @@ class Cache(object):
def for_config(cls, config):
cachedir = cls.cache_dir_from_config(config)
if config.getoption("cacheclear") and cachedir.exists():
shutil.rmtree(str(cachedir))
rmtree(cachedir, force=True)
cachedir.mkdir()
return cls(cachedir, config)
@staticmethod
def cache_dir_from_config(config):
return paths.resolve_from_str(config.getini("cache_dir"), config.rootdir)
return resolve_from_str(config.getini("cache_dir"), config.rootdir)
def warn(self, fmt, **args):
from _pytest.warnings import _issue_config_warning
@@ -272,7 +276,10 @@ def pytest_addoption(parser):
dest="cacheclear",
help="remove all cache contents at start of test run.",
)
parser.addini("cache_dir", default=".pytest_cache", help="cache directory path.")
cache_dir_default = ".pytest_cache"
if "TOX_ENV_DIR" in os.environ:
cache_dir_default = os.path.join(os.environ["TOX_ENV_DIR"], cache_dir_default)
parser.addini("cache_dir", default=cache_dir_default, help="cache directory path.")
group.addoption(
"--lfnf",
"--last-failed-no-failures",
@@ -316,7 +323,8 @@ def cache(request):
def pytest_report_header(config):
if config.option.verbose:
"""Display cachedir with --cache-show and if non-default."""
if config.option.verbose or config.getini("cache_dir") != ".pytest_cache":
cachedir = config.cache._cachedir
# TODO: evaluate generating upward relative paths
# starting with .., ../.. if sensible
@@ -344,7 +352,7 @@ def cacheshow(config, session):
key = valpath.relative_to(vdir)
val = config.cache.get(key, dummy)
if val is dummy:
tw.line("%s contains unreadable content, " "will be ignored" % key)
tw.line("%s contains unreadable content, will be ignored" % key)
else:
tw.line("%s contains:" % key)
for line in pformat(val).splitlines():

View File

@@ -2,17 +2,20 @@
per-test stdout/stderr capturing mechanism.
"""
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import collections
import contextlib
import sys
import os
import io
import os
import sys
from io import UnsupportedOperation
from tempfile import TemporaryFile
import six
import pytest
from _pytest.compat import CaptureIO
@@ -99,6 +102,9 @@ class CaptureManager(object):
# Global capturing control
def is_globally_capturing(self):
return self._method != "no"
def start_global_capturing(self):
assert self._global_capturing is None
self._global_capturing = self._getcapture(self._method)
@@ -121,7 +127,7 @@ class CaptureManager(object):
def read_global_capture(self):
return self._global_capturing.readouterr()
# Fixture Control (its just forwarding, think about removing this later)
# Fixture Control (it's just forwarding, think about removing this later)
def activate_fixture(self, item):
"""If the current item is using ``capsys`` or ``capfd``, activate them so they take precedence over
@@ -498,7 +504,7 @@ class FDCaptureBinary(object):
snap() produces `bytes`
"""
EMPTY_BUFFER = bytes()
EMPTY_BUFFER = b""
def __init__(self, targetfd, tmpfile=None):
self.targetfd = targetfd
@@ -624,7 +630,7 @@ class SysCapture(object):
class SysCaptureBinary(SysCapture):
EMPTY_BUFFER = bytes()
EMPTY_BUFFER = b""
def snap(self):
res = self.tmpfile.buffer.getvalue()
@@ -654,7 +660,7 @@ class DontReadFromInput(six.Iterator):
return self
def fileno(self):
raise UnsupportedOperation("redirected stdin is pseudofile, " "has no fileno()")
raise UnsupportedOperation("redirected stdin is pseudofile, has no fileno()")
def isatty(self):
return False

View File

@@ -1,7 +1,9 @@
"""
python version compatibility code
"""
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import codecs
import functools
@@ -11,11 +13,12 @@ import sys
from contextlib import contextmanager
import py
import six
from six import text_type
import _pytest
from _pytest.outcomes import fail
from _pytest.outcomes import TEST_OUTCOME
from six import text_type
import six
try:
import enum
@@ -23,8 +26,6 @@ except ImportError: # pragma: no cover
# Only available in Python 3.4+ or as a backport
enum = None
__all__ = ["Path", "PurePath"]
_PY3 = sys.version_info > (3, 0)
_PY2 = not _PY3
@@ -41,11 +42,6 @@ PY35 = sys.version_info[:2] >= (3, 5)
PY36 = sys.version_info[:2] >= (3, 6)
MODULE_NOT_FOUND_ERROR = "ModuleNotFoundError" if PY36 else "ImportError"
if PY36:
from pathlib import Path, PurePath
else:
from pathlib2 import Path, PurePath
if _PY3:
from collections.abc import MutableMapping as MappingMixin
@@ -138,9 +134,17 @@ def getfuncargnames(function, is_method=False, cls=None):
# ordered mapping of parameter names to Parameter instances. This
# creates a tuple of the names of the parameters that don't have
# defaults.
try:
parameters = signature(function).parameters
except (ValueError, TypeError) as e:
fail(
"Could not determine arguments of {!r}: {}".format(function, e),
pytrace=False,
)
arg_names = tuple(
p.name
for p in signature(function).parameters.values()
for p in parameters.values()
if (
p.kind is Parameter.POSITIONAL_OR_KEYWORD
or p.kind is Parameter.KEYWORD_ONLY
@@ -275,7 +279,7 @@ def get_real_func(obj):
obj = new_obj
else:
raise ValueError(
("could not find real function of {start}" "\nstopped at {current}").format(
("could not find real function of {start}\nstopped at {current}").format(
start=py.io.saferepr(start_obj), current=py.io.saferepr(obj)
)
)
@@ -330,6 +334,14 @@ def safe_getattr(object, name, default):
return default
def safe_isclass(obj):
"""Ignore any exception via isinstance on Python 3."""
try:
return isclass(obj)
except Exception:
return False
def _is_unittest_unexpected_success_a_failure():
"""Return if the test suite should fail if an @expectedFailure unittest test PASSES.
@@ -416,3 +428,16 @@ class FuncargnamesCompatAttr(object):
def funcargnames(self):
""" alias attribute for ``fixturenames`` for pre-2.3 compatibility"""
return self.fixturenames
if six.PY2:
def lru_cache(*_, **__):
def dec(fn):
return fn
return dec
else:
from functools import lru_cache # noqa: F401

View File

@@ -1,34 +1,40 @@
""" command line options, ini-file and conftest.py processing. """
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import copy
import inspect
import os
import shlex
import traceback
import sys
import types
import warnings
import copy
import six
import py
from distutils.version import LooseVersion
# DON't import pytest here because it causes import cycle troubles
import sys
import os
from _pytest.outcomes import Skipped
import py
import six
from pluggy import HookimplMarker
from pluggy import HookspecMarker
from pluggy import PluginManager
import _pytest._code
import _pytest.hookspec # the extension point definitions
import _pytest.assertion
from pluggy import PluginManager, HookimplMarker, HookspecMarker
import _pytest.hookspec # the extension point definitions
from .exceptions import PrintHelp
from .exceptions import UsageError
from .findpaths import determine_setup
from .findpaths import exists
from _pytest._code import ExceptionInfo
from _pytest._code import filter_traceback
from _pytest.compat import lru_cache
from _pytest.compat import safe_str
from .exceptions import UsageError, PrintHelp
from .findpaths import determine_setup, exists
from _pytest.outcomes import Skipped
hookimpl = HookimplMarker("pytest")
hookspec = HookspecMarker("pytest")
# pytest startup
#
class ConftestImportFailure(Exception):
def __init__(self, path, excinfo):
@@ -36,12 +42,6 @@ class ConftestImportFailure(Exception):
self.path = path
self.excinfo = excinfo
def __str__(self):
etype, evalue, etb = self.excinfo
formatted = traceback.format_tb(etb)
# The level of the tracebacks we want to print is hand crafted :(
return repr(evalue) + "\n" + "".join(formatted[2:])
def main(args=None, plugins=None):
""" return exit code, after performing an in-process test run.
@@ -57,10 +57,20 @@ def main(args=None, plugins=None):
try:
config = _prepareconfig(args, plugins)
except ConftestImportFailure as e:
exc_info = ExceptionInfo(e.excinfo)
tw = py.io.TerminalWriter(sys.stderr)
for line in traceback.format_exception(*e.excinfo):
tw.line(
"ImportError while loading conftest '{e.path}'.".format(e=e), red=True
)
exc_info.traceback = exc_info.traceback.filter(filter_traceback)
exc_repr = (
exc_info.getrepr(style="short", chain=False)
if exc_info.traceback
else exc_info.exconly()
)
formatted_tb = safe_str(exc_repr)
for line in formatted_tb.splitlines():
tw.line(line.rstrip(), red=True)
tw.line("ERROR: could not load %s\n" % (e.path,), red=True)
return 4
else:
try:
@@ -125,6 +135,7 @@ default_plugins = (
"freeze_support",
"setuponly",
"setupplan",
"stepwise",
"warnings",
"logging",
)
@@ -204,7 +215,7 @@ class PytestPluginManager(PluginManager):
self._conftest_plugins = set()
# state related to local conftest plugins
self._path2confmods = {}
self._dirpath2confmods = {}
self._conftestpath2mod = {}
self._confcutdir = None
self._noconftest = False
@@ -351,6 +362,7 @@ class PytestPluginManager(PluginManager):
else None
)
self._noconftest = namespace.noconftest
self._using_pyargs = namespace.pyargs
testpaths = namespace.file_or_dir
foundanchor = False
for path in testpaths:
@@ -374,29 +386,35 @@ class PytestPluginManager(PluginManager):
if x.check(dir=1):
self._getconftestmodules(x)
@lru_cache(maxsize=128)
def _getconftestmodules(self, path):
if self._noconftest:
return []
try:
return self._path2confmods[path]
except KeyError:
if path.isfile():
clist = self._getconftestmodules(path.dirpath())
else:
# XXX these days we may rather want to use config.rootdir
# and allow users to opt into looking into the rootdir parent
# directories instead of requiring to specify confcutdir
clist = []
for parent in path.parts():
if self._confcutdir and self._confcutdir.relto(parent):
continue
conftestpath = parent.join("conftest.py")
if conftestpath.isfile():
mod = self._importconftest(conftestpath)
clist.append(mod)
self._path2confmods[path] = clist
return clist
if path.isfile():
directory = path.dirpath()
else:
directory = path
if six.PY2: # py2 is not using lru_cache.
try:
return self._dirpath2confmods[directory]
except KeyError:
pass
# XXX these days we may rather want to use config.rootdir
# and allow users to opt into looking into the rootdir parent
# directories instead of requiring to specify confcutdir
clist = []
for parent in directory.realpath().parts():
if self._confcutdir and self._confcutdir.relto(parent):
continue
conftestpath = parent.join("conftest.py")
if conftestpath.isfile():
mod = self._importconftest(conftestpath)
clist.append(mod)
self._dirpath2confmods[directory] = clist
return clist
def _rget_with_confmod(self, name, path):
modules = self._getconftestmodules(path)
@@ -416,7 +434,11 @@ class PytestPluginManager(PluginManager):
_ensure_removed_sysmodule(conftestpath.purebasename)
try:
mod = conftestpath.pyimport()
if hasattr(mod, "pytest_plugins") and self._configured:
if (
hasattr(mod, "pytest_plugins")
and self._configured
and not self._using_pyargs
):
from _pytest.deprecated import (
PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
)
@@ -433,8 +455,8 @@ class PytestPluginManager(PluginManager):
self._conftest_plugins.add(mod)
self._conftestpath2mod[conftestpath] = mod
dirpath = conftestpath.dirpath()
if dirpath in self._path2confmods:
for path, mods in self._path2confmods.items():
if dirpath in self._dirpath2confmods:
for path, mods in self._dirpath2confmods.items():
if path and path.relto(dirpath) or path == dirpath:
assert mod not in mods
mods.append(mod)
@@ -455,6 +477,11 @@ class PytestPluginManager(PluginManager):
def consider_pluginarg(self, arg):
if arg.startswith("no:"):
name = arg[3:]
# PR #4304 : remove stepwise if cacheprovider is blocked
if name == "cacheprovider":
self.set_blocked("stepwise")
self.set_blocked("pytest_stepwise")
self.set_blocked(name)
if not name.startswith("pytest_"):
self.set_blocked("pytest_" + name)
@@ -795,9 +822,7 @@ class Config(object):
minver = self.inicfg.get("minversion", None)
if minver:
ver = minver.split(".")
myver = pytest.__version__.split(".")
if myver < ver:
if LooseVersion(minver) > LooseVersion(pytest.__version__):
raise pytest.UsageError(
"%s:%d: requires pytest-%s, actual pytest-%s'"
% (
@@ -826,11 +851,13 @@ class Config(object):
args, self.option, namespace=self.option
)
if not args:
cwd = os.getcwd()
if cwd == self.rootdir:
args = self.getini("testpaths")
if self.invocation_dir == self.rootdir:
args = [
str(self.invocation_dir.join(x, abs=True))
for x in self.getini("testpaths")
]
if not args:
args = [cwd]
args = [str(self.invocation_dir)]
self.args = args
except PrintHelp:
pass

View File

@@ -1,11 +1,10 @@
import six
import warnings
import argparse
from gettext import gettext as _
import sys as _sys
import warnings
from gettext import gettext as _
import py
import six
from ..main import EXIT_USAGEERROR
@@ -153,7 +152,7 @@ class ArgumentError(Exception):
class Argument(object):
"""class that mimics the necessary behaviour of optparse.Option
its currently a least effort implementation
it's currently a least effort implementation
and ignoring choices and integer prefixes
https://docs.python.org/3/library/optparse.html#optparse-standard-option-types
"""

View File

@@ -1,5 +1,7 @@
import py
import os
import py
from .exceptions import UsageError
@@ -103,21 +105,18 @@ def determine_setup(inifile, args, rootdir_cmd_arg=None, config=None):
if inifile:
iniconfig = py.iniconfig.IniConfig(inifile)
is_cfg_file = str(inifile).endswith(".cfg")
# TODO: [pytest] section in *.cfg files is depricated. Need refactoring.
sections = ["tool:pytest", "pytest"] if is_cfg_file else ["pytest"]
for section in sections:
try:
inicfg = iniconfig[section]
if is_cfg_file and section == "pytest" and config is not None:
from _pytest.deprecated import CFG_PYTEST_SECTION
from _pytest.warning_types import RemovedInPytest4Warning
from _pytest.warnings import _issue_config_warning
# TODO: [pytest] section in *.cfg files is deprecated. Need refactoring once
# the deprecation expires.
_issue_config_warning(
RemovedInPytest4Warning(
CFG_PYTEST_SECTION.format(filename=str(inifile))
),
config,
CFG_PYTEST_SECTION.format(filename=str(inifile)), config
)
break
except KeyError:

View File

@@ -1,19 +1,15 @@
""" interactive debugging with PDB, the Python Debugger. """
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import pdb
import sys
import os
from doctest import UnexpectedException
from _pytest import outcomes
from _pytest.config import hookimpl
try:
from builtins import breakpoint # noqa
SUPPORTS_BREAKPOINT_BUILTIN = True
except ImportError:
SUPPORTS_BREAKPOINT_BUILTIN = False
def pytest_addoption(parser):
group = parser.getgroup("general")
@@ -51,25 +47,24 @@ def pytest_configure(config):
if config.getvalue("usepdb"):
config.pluginmanager.register(PdbInvoke(), "pdbinvoke")
# Use custom Pdb class set_trace instead of default Pdb on breakpoint() call
if SUPPORTS_BREAKPOINT_BUILTIN:
_environ_pythonbreakpoint = os.environ.get("PYTHONBREAKPOINT", "")
if _environ_pythonbreakpoint == "":
sys.breakpointhook = pytestPDB.set_trace
old = (pdb.set_trace, pytestPDB._pluginmanager)
def fin():
pdb.set_trace, pytestPDB._pluginmanager = old
pytestPDB._config = None
pytestPDB._pdb_cls = pdb.Pdb
if SUPPORTS_BREAKPOINT_BUILTIN:
sys.breakpointhook = sys.__breakpointhook__
pytestPDB._saved.append(
(pdb.set_trace, pytestPDB._pluginmanager, pytestPDB._config, pytestPDB._pdb_cls)
)
pdb.set_trace = pytestPDB.set_trace
pytestPDB._pluginmanager = config.pluginmanager
pytestPDB._config = config
pytestPDB._pdb_cls = pdb_cls
# NOTE: not using pytest_unconfigure, since it might get called although
# pytest_configure was not (if another plugin raises UsageError).
def fin():
(
pdb.set_trace,
pytestPDB._pluginmanager,
pytestPDB._config,
pytestPDB._pdb_cls,
) = pytestPDB._saved.pop()
config._cleanup.append(fin)
@@ -79,6 +74,7 @@ class pytestPDB(object):
_pluginmanager = None
_config = None
_pdb_cls = pdb.Pdb
_saved = []
@classmethod
def set_trace(cls, set_break=True):
@@ -92,10 +88,54 @@ class pytestPDB(object):
capman.suspend_global_capture(in_=True)
tw = _pytest.config.create_terminal_writer(cls._config)
tw.line()
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config)
if capman and capman.is_globally_capturing():
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
else:
tw.sep(">", "PDB set_trace")
class _PdbWrapper(cls._pdb_cls, object):
_pytest_capman = capman
_continued = False
def do_continue(self, arg):
ret = super(_PdbWrapper, self).do_continue(arg)
if self._pytest_capman:
tw = _pytest.config.create_terminal_writer(cls._config)
tw.line()
if self._pytest_capman.is_globally_capturing():
tw.sep(">", "PDB continue (IO-capturing resumed)")
else:
tw.sep(">", "PDB continue")
self._pytest_capman.resume_global_capture()
cls._pluginmanager.hook.pytest_leave_pdb(
config=cls._config, pdb=self
)
self._continued = True
return ret
do_c = do_cont = do_continue
def setup(self, f, tb):
"""Suspend on setup().
Needed after do_continue resumed, and entering another
breakpoint again.
"""
ret = super(_PdbWrapper, self).setup(f, tb)
if not ret and self._continued:
# pdb.setup() returns True if the command wants to exit
# from the interaction: do not suspend capturing then.
if self._pytest_capman:
self._pytest_capman.suspend_global_capture(in_=True)
return ret
_pdb = _PdbWrapper()
cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config, pdb=_pdb)
else:
_pdb = cls._pdb_cls()
if set_break:
cls._pdb_cls().set_trace(frame)
_pdb.set_trace(frame)
class PdbInvoke(object):
@@ -109,9 +149,6 @@ class PdbInvoke(object):
_enter_pdb(node, call.excinfo, report)
def pytest_internalerror(self, excrepr, excinfo):
for line in str(excrepr).split("\n"):
sys.stderr.write("INTERNALERROR> %s\n" % line)
sys.stderr.flush()
tb = _postmortem_traceback(excinfo)
post_mortem(tb)
@@ -164,8 +201,9 @@ def _enter_pdb(node, excinfo, rep):
rep.toterminal(tw)
tw.sep(">", "entering PDB")
tb = _postmortem_traceback(excinfo)
post_mortem(tb)
rep._pdbshown = True
if post_mortem(tb):
outcomes.exit("Quitting debugger")
return rep
@@ -196,3 +234,4 @@ def post_mortem(t):
p = Pdb()
p.reset()
p.interaction(None, t)
return p.quitting

View File

@@ -4,10 +4,18 @@ that is planned to be removed in the next pytest release.
Keeping it in a central location makes it easy to track what is deprecated and should
be removed when the time comes.
"""
from __future__ import absolute_import, division, print_function
All constants defined in this module should be either PytestWarning instances or UnformattedWarning
in case of warnings which need to format their messages.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from _pytest.warning_types import PytestDeprecationWarning
from _pytest.warning_types import RemovedInPytest4Warning
from _pytest.warning_types import UnformattedWarning
MAIN_STR_ARGS = RemovedInPytest4Warning(
"passing a string to pytest.main() is deprecated, "
@@ -18,25 +26,52 @@ YIELD_TESTS = RemovedInPytest4Warning(
"yield tests are deprecated, and scheduled to be removed in pytest 4.0"
)
FUNCARG_PREFIX = (
CACHED_SETUP = RemovedInPytest4Warning(
"cached_setup is deprecated and will be removed in a future release. "
"Use standard fixture functions instead."
)
COMPAT_PROPERTY = UnformattedWarning(
RemovedInPytest4Warning,
"usage of {owner}.{name} is deprecated, please use pytest.{name} instead",
)
CUSTOM_CLASS = UnformattedWarning(
RemovedInPytest4Warning,
'use of special named "{name}" objects in collectors of type "{type_name}" to '
"customize the created nodes is deprecated. "
"Use pytest_pycollect_makeitem(...) to create custom "
"collection nodes instead.",
)
FUNCARG_PREFIX = UnformattedWarning(
RemovedInPytest4Warning,
'{name}: declaring fixtures using "pytest_funcarg__" prefix is deprecated '
"and scheduled to be removed in pytest 4.0. "
"Please remove the prefix and use the @pytest.fixture decorator instead."
"Please remove the prefix and use the @pytest.fixture decorator instead.",
)
FIXTURE_FUNCTION_CALL = (
FIXTURE_FUNCTION_CALL = UnformattedWarning(
RemovedInPytest4Warning,
'Fixture "{name}" called directly. Fixtures are not meant to be called directly, '
"are created automatically when test functions request them as parameters. "
"See https://docs.pytest.org/en/latest/fixture.html for more information."
"See https://docs.pytest.org/en/latest/fixture.html for more information.",
)
CFG_PYTEST_SECTION = (
"[pytest] section in {filename} files is deprecated, use [tool:pytest] instead."
FIXTURE_NAMED_REQUEST = PytestDeprecationWarning(
"'request' is a reserved name for fixtures and will raise an error in future versions"
)
GETFUNCARGVALUE = "getfuncargvalue is deprecated, use getfixturevalue"
CFG_PYTEST_SECTION = UnformattedWarning(
RemovedInPytest4Warning,
"[pytest] section in {filename} files is deprecated, use [tool:pytest] instead.",
)
RESULT_LOG = (
GETFUNCARGVALUE = RemovedInPytest4Warning(
"getfuncargvalue is deprecated, use getfixturevalue"
)
RESULT_LOG = RemovedInPytest4Warning(
"--result-log is deprecated and scheduled for removal in pytest 4.0.\n"
"See https://docs.pytest.org/en/latest/usage.html#creating-resultlog-format-files for more information."
)
@@ -64,7 +99,7 @@ RECORD_XML_PROPERTY = RemovedInPytest4Warning(
)
COLLECTOR_MAKEITEM = RemovedInPytest4Warning(
"pycollector makeitem was removed " "as it is an accidentially leaked internal api"
"pycollector makeitem was removed as it is an accidentially leaked internal api"
)
METAFUNC_ADD_CALL = RemovedInPytest4Warning(
@@ -81,3 +116,8 @@ PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST = RemovedInPytest4Warning(
PYTEST_NAMESPACE = RemovedInPytest4Warning(
"pytest_namespace is deprecated and will be removed soon"
)
PYTEST_ENSURETEMP = RemovedInPytest4Warning(
"pytest/tmpdir_factory.ensuretemp is deprecated, \n"
"please use the tmp_path fixture or tmp_path_factory.mktemp"
)

View File

@@ -1,12 +1,16 @@
""" discover and run doctests in modules and test files."""
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import traceback
import sys
import platform
import sys
import traceback
import pytest
from _pytest._code.code import ExceptionInfo, ReprFileLocation, TerminalRepr
from _pytest._code.code import ExceptionInfo
from _pytest._code.code import ReprFileLocation
from _pytest._code.code import TerminalRepr
from _pytest.fixtures import FixtureRequest

View File

@@ -1,39 +1,42 @@
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import functools
import inspect
import sys
import warnings
from collections import OrderedDict, deque, defaultdict
import six
from more_itertools import flatten
from collections import defaultdict
from collections import deque
from collections import OrderedDict
import attr
import py
import six
from more_itertools import flatten
from py._code.code import FormattedExcinfo
import _pytest
from _pytest import nodes
from _pytest._code.code import TerminalRepr
from _pytest.compat import (
NOTSET,
exc_clear,
_format_args,
getfslineno,
get_real_func,
is_generator,
isclass,
getimfunc,
getlocation,
getfuncargnames,
safe_getattr,
FuncargnamesCompatAttr,
get_real_method,
_PytestWrapper,
)
from _pytest.deprecated import FIXTURE_FUNCTION_CALL, RemovedInPytest4Warning
from _pytest.outcomes import fail, TEST_OUTCOME
from _pytest.compat import _format_args
from _pytest.compat import _PytestWrapper
from _pytest.compat import exc_clear
from _pytest.compat import FuncargnamesCompatAttr
from _pytest.compat import get_real_func
from _pytest.compat import get_real_method
from _pytest.compat import getfslineno
from _pytest.compat import getfuncargnames
from _pytest.compat import getimfunc
from _pytest.compat import getlocation
from _pytest.compat import is_generator
from _pytest.compat import isclass
from _pytest.compat import NOTSET
from _pytest.compat import safe_getattr
from _pytest.deprecated import FIXTURE_FUNCTION_CALL
from _pytest.deprecated import FIXTURE_NAMED_REQUEST
from _pytest.outcomes import fail
from _pytest.outcomes import TEST_OUTCOME
FIXTURE_MSG = 'fixtures cannot have "pytest_funcarg__" prefix and be decorated with @pytest.fixture:\n{}'
@@ -359,8 +362,10 @@ class FixtureRequest(FuncargnamesCompatAttr):
@property
def fixturenames(self):
# backward incompatible note: now a readonly property
return list(self._pyfuncitem._fixtureinfo.names_closure)
"""names of all active fixtures in this request"""
result = list(self._pyfuncitem._fixtureinfo.names_closure)
result.extend(set(self._fixture_defs).difference(result))
return result
@property
def node(self):
@@ -479,6 +484,9 @@ class FixtureRequest(FuncargnamesCompatAttr):
or ``session`` indicating the caching lifecycle of the resource.
:arg extrakey: added to internal caching key of (funcargname, scope).
"""
from _pytest.deprecated import CACHED_SETUP
warnings.warn(CACHED_SETUP, stacklevel=2)
if not hasattr(self.config, "_setupcache"):
self.config._setupcache = {} # XXX weakref?
cachekey = (self.fixturename, self._getscopeitem(scope), extrakey)
@@ -512,7 +520,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
""" Deprecated, use getfixturevalue. """
from _pytest import deprecated
warnings.warn(deprecated.GETFUNCARGVALUE, DeprecationWarning, stacklevel=2)
warnings.warn(deprecated.GETFUNCARGVALUE, stacklevel=2)
return self.getfixturevalue(argname)
def _get_active_fixturedef(self, argname):
@@ -562,7 +570,20 @@ class FixtureRequest(FuncargnamesCompatAttr):
except (AttributeError, ValueError):
param = NOTSET
param_index = 0
if fixturedef.params is not None:
has_params = fixturedef.params is not None
fixtures_not_supported = getattr(funcitem, "nofuncargs", False)
if has_params and fixtures_not_supported:
msg = (
"{name} does not support fixtures, maybe unittest.TestCase subclass?\n"
"Node id: {nodeid}\n"
"Function type: {typename}"
).format(
name=funcitem.name,
nodeid=funcitem.nodeid,
typename=type(funcitem).__name__,
)
fail(msg, pytrace=False)
if has_params:
frame = inspect.stack()[3]
frameinfo = inspect.getframeinfo(frame[0])
source_path = frameinfo.filename
@@ -571,16 +592,18 @@ class FixtureRequest(FuncargnamesCompatAttr):
if source_path.relto(funcitem.config.rootdir):
source_path = source_path.relto(funcitem.config.rootdir)
msg = (
"The requested fixture has no parameter defined for the "
"current test.\n\nRequested fixture '{}' defined in:\n{}"
"The requested fixture has no parameter defined for test:\n"
" {}\n\n"
"Requested fixture '{}' defined in:\n{}"
"\n\nRequested here:\n{}:{}".format(
funcitem.nodeid,
fixturedef.argname,
getlocation(fixturedef.func, funcitem.config.rootdir),
source_path,
source_lineno,
)
)
fail(msg)
fail(msg, pytrace=False)
else:
# indices might not be set if old-style metafunc.addcall() was used
param_index = funcitem.callspec.indices.get(argname, 0)
@@ -596,7 +619,7 @@ class FixtureRequest(FuncargnamesCompatAttr):
subrequest._check_scope(argname, self.scope, scope)
# clear sys.exc_info before invoking the fixture (python bug?)
# if its not explicitly cleared it will leak into the call
# if it's not explicitly cleared it will leak into the call
exc_clear()
try:
# call the fixture function
@@ -698,10 +721,11 @@ def scope2index(scope, descr, where=None):
try:
return scopes.index(scope)
except ValueError:
raise ValueError(
"{} {}has an unsupported scope value '{}'".format(
fail(
"{} {}got an unexpected scope value '{}'".format(
descr, "from {} ".format(where) if where else "", scope
)
),
pytrace=False,
)
@@ -741,14 +765,19 @@ class FixtureLookupError(LookupError):
if msg is None:
fm = self.request._fixturemanager
available = []
available = set()
parentid = self.request._pyfuncitem.parent.nodeid
for name, fixturedefs in fm._arg2fixturedefs.items():
faclist = list(fm._matchfactories(fixturedefs, parentid))
if faclist and name not in available:
available.append(name)
msg = "fixture %r not found" % (self.argname,)
msg += "\n available fixtures: %s" % (", ".join(sorted(available)),)
if faclist:
available.add(name)
if self.argname in available:
msg = " recursive dependency involving fixture '{}' detected".format(
self.argname
)
else:
msg = "fixture '{}' not found".format(self.argname)
msg += "\n available fixtures: {}".format(", ".join(sorted(available)))
msg += "\n use 'pytest --fixtures [testpath]' for help on them."
return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname)
@@ -834,7 +863,9 @@ class FixtureDef(object):
self.argname = argname
self.scope = scope
self.scopenum = scope2index(
scope or "function", descr="fixture {}".format(func.__name__), where=baseid
scope or "function",
descr="Fixture '{}'".format(func.__name__),
where=baseid,
)
self.params = params
self.argnames = getfuncargnames(func, is_method=unittest)
@@ -896,7 +927,7 @@ class FixtureDef(object):
return hook.pytest_fixture_setup(fixturedef=self, request=request)
def __repr__(self):
return "<FixtureDef name=%r scope=%r baseid=%r >" % (
return "<FixtureDef argname=%r scope=%r baseid=%r>" % (
self.argname,
self.scope,
self.baseid,
@@ -956,8 +987,9 @@ def wrap_function_to_warning_if_called_directly(function, fixture_marker):
used as an argument in a test function.
"""
is_yield_function = is_generator(function)
msg = FIXTURE_FUNCTION_CALL.format(name=fixture_marker.name or function.__name__)
warning = RemovedInPytest4Warning(msg)
warning = FIXTURE_FUNCTION_CALL.format(
name=fixture_marker.name or function.__name__
)
if is_yield_function:
@@ -996,7 +1028,7 @@ class FixtureFunctionMarker(object):
def __call__(self, function):
if isclass(function):
raise ValueError("class fixtures not supported (may be in the future)")
raise ValueError("class fixtures not supported (maybe in the future)")
if getattr(function, "_pytestfixturefunction", False):
raise ValueError(
@@ -1005,6 +1037,9 @@ class FixtureFunctionMarker(object):
function = wrap_function_to_warning_if_called_directly(function, self)
name = self.name or function.__name__
if name == "request":
warnings.warn(FIXTURE_NAMED_REQUEST)
function._pytestfixturefunction = self
return function
@@ -1151,7 +1186,7 @@ class FixtureManager(object):
def pytest_plugin_registered(self, plugin):
nodeid = None
try:
p = py.path.local(plugin.__file__)
p = py.path.local(plugin.__file__).realpath()
except AttributeError:
pass
else:
@@ -1162,6 +1197,7 @@ class FixtureManager(object):
nodeid = p.dirpath().relto(self.config.rootdir)
if p.sep != nodes.SEP:
nodeid = nodeid.replace(p.sep, nodes.SEP)
self.parsefactories(plugin, nodeid)
def _getautousenames(self, nodeid):
@@ -1266,11 +1302,18 @@ class FixtureManager(object):
nodeid = node_or_obj.nodeid
if holderobj in self._holderobjseen:
return
from _pytest.nodes import _CompatProperty
self._holderobjseen.add(holderobj)
autousenames = []
for name in dir(holderobj):
# The attribute can be an arbitrary descriptor, so the attribute
# access below can raise. safe_getatt() ignores such exceptions.
maybe_property = safe_getattr(type(holderobj), name, None)
if isinstance(maybe_property, _CompatProperty):
# deprecated
continue
obj = safe_getattr(holderobj, name, None)
marker = getfixturemarker(obj)
# fixture functions have a pytest_funcarg__ prefix (pre-2.3 style)
@@ -1284,9 +1327,7 @@ class FixtureManager(object):
filename, lineno = getfslineno(obj)
warnings.warn_explicit(
RemovedInPytest4Warning(
deprecated.FUNCARG_PREFIX.format(name=name)
),
deprecated.FUNCARG_PREFIX.format(name=name),
category=None,
filename=str(filename),
lineno=lineno + 1,
@@ -1349,8 +1390,7 @@ class FixtureManager(object):
fixturedefs = self._arg2fixturedefs[argname]
except KeyError:
return None
else:
return tuple(self._matchfactories(fixturedefs, nodeid))
return tuple(self._matchfactories(fixturedefs, nodeid))
def _matchfactories(self, fixturedefs, nodeid):
for fixturedef in fixturedefs:

View File

@@ -2,7 +2,9 @@
Provides a function to report all internal modules for using freezing tools
pytest
"""
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
def freeze_includes():

View File

@@ -1,13 +1,17 @@
""" version info, help messages, tracing configuration. """
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import py
import pytest
from _pytest.config import PrintHelp
import os
import sys
from argparse import Action
import py
import pytest
from _pytest.config import PrintHelp
class HelpAction(Action):
"""This is an argparse Action that will raise an exception in
@@ -139,7 +143,7 @@ def showhelp(config):
tw.line()
tw.line()
tw.line(
"[pytest] ini-options in the first " "pytest.ini|tox.ini|setup.cfg file found:"
"[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:"
)
tw.line()

View File

@@ -1,6 +1,6 @@
""" hook specifications for pytest plugins, invoked from main.py and builtin plugins. """
from pluggy import HookspecMarker
from .deprecated import PYTEST_NAMESPACE
@@ -41,10 +41,10 @@ def pytest_namespace():
Plugins whose users depend on the current namespace functionality should prepare to migrate to a
namespace they actually own.
To support the migration its suggested to trigger ``DeprecationWarnings`` for objects they put into the
To support the migration it's suggested to trigger ``DeprecationWarnings`` for objects they put into the
pytest namespace.
An stopgap measure to avoid the warning is to monkeypatch the ``pytest`` module, but just as the
A stopgap measure to avoid the warning is to monkeypatch the ``pytest`` module, but just as the
``pytest_namespace`` hook this should be seen as a temporary measure to be removed in future versions after
an appropriate transition period.
"""
@@ -562,6 +562,9 @@ def pytest_warning_captured(warning_message, when, item):
* ``"runtest"``: during test execution.
:param pytest.Item|None item:
**DEPRECATED**: This parameter is incompatible with ``pytest-xdist``, and will always receive ``None``
in a future release.
The item being executed if ``when`` is ``"runtest"``, otherwise ``None``.
"""
@@ -600,9 +603,21 @@ def pytest_exception_interact(node, call, report):
"""
def pytest_enter_pdb(config):
def pytest_enter_pdb(config, pdb):
""" called upon pdb.set_trace(), can be used by plugins to take special
action just before the python debugger enters in interactive mode.
:param _pytest.config.Config config: pytest config object
:param pdb.Pdb pdb: Pdb instance
"""
def pytest_leave_pdb(config, pdb):
""" called when leaving pdb (e.g. with continue after pdb.set_trace()).
Can be used by plugins to take special action just after the python
debugger leaves interactive mode.
:param _pytest.config.Config config: pytest config object
:param pdb.Pdb pdb: Pdb instance
"""

View File

@@ -8,14 +8,18 @@ Based on initial code from Ross Lawley.
Output conforms to https://github.com/jenkinsci/xunit-plugin/blob/master/
src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd
"""
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import functools
import py
import os
import re
import sys
import time
import py
import pytest
from _pytest import nodes
from _pytest.config import filename_arg
@@ -38,7 +42,7 @@ class Junit(py.xml.Namespace):
# this dynamically instead of hardcoding it. The spec range of valid
# chars is: Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
# | [#x10000-#x10FFFF]
_legal_chars = (0x09, 0x0A, 0x0d)
_legal_chars = (0x09, 0x0A, 0x0D)
_legal_ranges = ((0x20, 0x7E), (0x80, 0xD7FF), (0xE000, 0xFFFD), (0x10000, 0x10FFFF))
_legal_xml_re = [
unicode("%s-%s") % (unichr(low), unichr(high))
@@ -221,12 +225,14 @@ class _NodeReporter(object):
else:
filename, lineno, skipreason = report.longrepr
if skipreason.startswith("Skipped: "):
skipreason = bin_xml_escape(skipreason[9:])
skipreason = skipreason[9:]
details = "%s:%s: %s" % (filename, lineno, skipreason)
self.append(
Junit.skipped(
"%s:%s: %s" % (filename, lineno, skipreason),
bin_xml_escape(details),
type="pytest.skip",
message=skipreason,
message=bin_xml_escape(skipreason),
)
)
self.write_captured_output(report)

View File

@@ -1,15 +1,18 @@
""" Access and control log capturing. """
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import logging
from contextlib import closing, contextmanager
import re
from contextlib import contextmanager
import py
import six
import pytest
from _pytest.compat import dummy_context_manager
from _pytest.config import create_terminal_writer
import pytest
import py
DEFAULT_LOG_FORMAT = "%(filename)-25s %(lineno)4d %(levelname)-8s %(message)s"
@@ -213,7 +216,8 @@ class LogCaptureFixture(object):
def __init__(self, item):
"""Creates a new funcarg."""
self._item = item
self._initial_log_levels = {} # type: Dict[str, int] # dict of log name -> log level
# dict of log name -> log level
self._initial_log_levels = {} # type: Dict[str, int]
def _finalize(self):
"""Finalizes the fixture.
@@ -262,7 +266,7 @@ class LogCaptureFixture(object):
@property
def record_tuples(self):
"""Returns a list of a striped down version of log records intended
"""Returns a list of a stripped down version of log records intended
for use in assertion comparison.
The format of the tuple is:
@@ -278,7 +282,7 @@ class LogCaptureFixture(object):
Unlike 'records', which contains the format string and parameters for interpolation, log messages in this list
are all interpolated.
Unlike 'text', which contains the output from the handler, log messages in this list are unadorned with
levels, timestamps, etc, making exact comparisions more reliable.
levels, timestamps, etc, making exact comparisons more reliable.
Note that traceback or stack info (from :func:`logging.exception` or the `exc_info` or `stack_info` arguments
to the logging functions) is not included, as this is added by the formatter in the handler.
@@ -329,7 +333,7 @@ class LogCaptureFixture(object):
def caplog(request):
"""Access and control log capturing.
Captured logs are available through the following methods::
Captured logs are available through the following properties/methods::
* caplog.text -> string containing formatted log output
* caplog.records -> list of logging.LogRecord instances
@@ -414,7 +418,6 @@ class LoggingPlugin(object):
else:
self.log_file_handler = None
# initialized during pytest_runtestloop
self.log_cli_handler = None
def _log_cli_enabled(self):
@@ -425,6 +428,22 @@ class LoggingPlugin(object):
"--log-cli-level"
) is not None or self._config.getini("log_cli")
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_collection(self):
# This has to be called before the first log message is logged,
# so we can access the terminal reporter plugin.
self._setup_cli_logging()
with self.live_logs_context():
if self.log_cli_handler:
self.log_cli_handler.set_when("collection")
if self.log_file_handler is not None:
with catching_logs(self.log_file_handler, level=self.log_file_level):
yield
else:
yield
@contextmanager
def _runtest_for(self, item, when):
"""Implements the internals of pytest_runtest_xxx() hook."""
@@ -481,25 +500,41 @@ class LoggingPlugin(object):
with self._runtest_for(None, "finish"):
yield
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_sessionfinish(self):
with self.live_logs_context():
if self.log_cli_handler:
self.log_cli_handler.set_when("sessionfinish")
if self.log_file_handler is not None:
with catching_logs(self.log_file_handler, level=self.log_file_level):
yield
else:
yield
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_sessionstart(self):
self._setup_cli_logging()
with self.live_logs_context():
if self.log_cli_handler:
self.log_cli_handler.set_when("sessionstart")
if self.log_file_handler is not None:
with catching_logs(self.log_file_handler, level=self.log_file_level):
yield
else:
yield
@pytest.hookimpl(hookwrapper=True)
def pytest_runtestloop(self, session):
"""Runs all collected test items."""
self._setup_cli_logging()
with self.live_logs_context:
with self.live_logs_context():
if self.log_file_handler is not None:
with closing(self.log_file_handler):
with catching_logs(
self.log_file_handler, level=self.log_file_level
):
yield # run all the tests
with catching_logs(self.log_file_handler, level=self.log_file_level):
yield # run all the tests
else:
yield # run all the tests
def _setup_cli_logging(self):
"""Sets up the handler and logger for the Live Logs feature, if enabled.
This must be done right before starting the loop so we can access the terminal reporter plugin.
"""
"""Sets up the handler and logger for the Live Logs feature, if enabled."""
terminal_reporter = self._config.pluginmanager.get_plugin("terminalreporter")
if self._log_cli_enabled() and terminal_reporter is not None:
capture_manager = self._config.pluginmanager.get_plugin("capturemanager")
@@ -529,11 +564,14 @@ class LoggingPlugin(object):
self._config, "log_cli_level", "log_level"
)
self.log_cli_handler = log_cli_handler
self.live_logs_context = catching_logs(
self.live_logs_context = lambda: catching_logs(
log_cli_handler, formatter=log_cli_formatter, level=log_cli_level
)
else:
self.live_logs_context = dummy_context_manager()
self.live_logs_context = lambda: dummy_context_manager()
# Note that the lambda for the live_logs_context is needed because
# live_logs_context can otherwise not be entered multiple times due
# to limitations of contextlib.contextmanager
class _LiveLoggingStreamHandler(logging.StreamHandler):

View File

@@ -1,19 +1,23 @@
""" core implementation of testing process: init, session, runtest loop. """
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import contextlib
import functools
import os
import pkgutil
import six
import sys
import _pytest
from _pytest import nodes
import _pytest._code
import attr
import py
import six
from _pytest.config import directory_arg, UsageError, hookimpl
import _pytest._code
from _pytest import nodes
from _pytest.config import directory_arg
from _pytest.config import hookimpl
from _pytest.config import UsageError
from _pytest.outcomes import exit
from _pytest.runner import collect_one_node
@@ -156,7 +160,10 @@ def pytest_addoption(parser):
dest="basetemp",
default=None,
metavar="dir",
help="base temporary directory for this test run.",
help=(
"base temporary directory for this test run."
"(warning: this directory is removed if it exists)"
),
)
@@ -182,10 +189,13 @@ def wrap_session(config, doit):
session.exitstatus = EXIT_TESTSFAILED
except KeyboardInterrupt:
excinfo = _pytest._code.ExceptionInfo()
if initstate < 2 and isinstance(excinfo.value, exit.Exception):
exitstatus = EXIT_INTERRUPTED
if initstate <= 2 and isinstance(excinfo.value, exit.Exception):
sys.stderr.write("{}: {}\n".format(excinfo.typename, excinfo.value.msg))
if excinfo.value.returncode is not None:
exitstatus = excinfo.value.returncode
config.hook.pytest_keyboard_interrupt(excinfo=excinfo)
session.exitstatus = EXIT_INTERRUPTED
session.exitstatus = exitstatus
except: # noqa
excinfo = _pytest._code.ExceptionInfo()
config.notify_exception(excinfo, config.option)
@@ -269,18 +279,9 @@ def pytest_ignore_collect(path, config):
return True
allow_in_venv = config.getoption("collect_in_virtualenv")
if _in_venv(path) and not allow_in_venv:
if not allow_in_venv and _in_venv(path):
return True
# Skip duplicate paths.
keepduplicates = config.getoption("keepduplicates")
duplicate_paths = config.pluginmanager._duplicatepaths
if not keepduplicates:
if path in duplicate_paths:
return True
else:
duplicate_paths.add(path)
return False
@@ -368,6 +369,16 @@ class Failed(Exception):
""" signals a stop as failed test run. """
@attr.s
class _bestrelpath_cache(dict):
path = attr.ib()
def __missing__(self, path):
r = self.path.bestrelpath(path)
self[path] = r
return r
class Session(nodes.FSCollector):
Interrupted = Interrupted
Failed = Failed
@@ -386,9 +397,16 @@ class Session(nodes.FSCollector):
self._initialpaths = frozenset()
# Keep track of any collected nodes in here, so we don't duplicate fixtures
self._node_cache = {}
self._bestrelpathcache = _bestrelpath_cache(config.rootdir)
# Dirnames of pkgs with dunder-init files.
self._pkg_roots = {}
self.config.pluginmanager.register(self, name="session")
def _node_location_to_relpath(self, node_path):
# bestrelpath is a quite slow function
return self._bestrelpathcache[node_path]
@hookimpl(tryfirst=True)
def pytest_collectstart(self):
if self.shouldfail:
@@ -469,8 +487,8 @@ class Session(nodes.FSCollector):
return items
def collect(self):
for parts in self._initialparts:
arg = "::".join(map(str, parts))
for initialpart in self._initialparts:
arg = "::".join(map(str, initialpart))
self.trace("processing argument", arg)
self.trace.root.indent += 1
try:
@@ -488,85 +506,120 @@ class Session(nodes.FSCollector):
names = self._parsearg(arg)
argpath = names.pop(0)
paths = []
root = self
# Start with a Session root, and delve to argpath item (dir or file)
# and stack all Packages found on the way.
# No point in finding packages when collecting doctests
if not self.config.option.doctestmodules:
for parent in argpath.parts():
pm = self.config.pluginmanager
pm = self.config.pluginmanager
for parent in reversed(argpath.parts()):
if pm._confcutdir and pm._confcutdir.relto(parent):
continue
break
if parent.isdir():
pkginit = parent.join("__init__.py")
if pkginit.isfile():
if pkginit in self._node_cache:
root = self._node_cache[pkginit][0]
else:
col = root._collectfile(pkginit)
if pkginit not in self._node_cache:
col = self._collectfile(pkginit, handle_dupes=False)
if col:
if isinstance(col[0], Package):
root = col[0]
self._pkg_roots[parent] = col[0]
# always store a list in the cache, matchnodes expects it
self._node_cache[root.fspath] = [root]
self._node_cache[col[0].fspath] = [col[0]]
# If it's a directory argument, recurse and look for any Subpackages.
# Let the Package collector deal with subnodes, don't collect here.
if argpath.check(dir=1):
assert not names, "invalid arg %r" % (arg,)
for path in argpath.visit(
fil=lambda x: x.check(file=1), rec=self._recurse, bf=True, sort=True
):
pkginit = path.dirpath().join("__init__.py")
if pkginit.exists() and not any(x in pkginit.parts() for x in paths):
for x in root._collectfile(pkginit):
yield x
paths.append(x.fspath.dirpath())
if not any(x in path.parts() for x in paths):
for x in root._collectfile(path):
if (type(x), x.fspath) in self._node_cache:
yield self._node_cache[(type(x), x.fspath)]
else:
self._node_cache[(type(x), x.fspath)] = x
if six.PY2:
def filter_(f):
return f.check(file=1) and not f.strpath.endswith("*.pyc")
else:
def filter_(f):
return f.check(file=1)
seen_dirs = set()
for path in argpath.visit(
fil=filter_, rec=self._recurse, bf=True, sort=True
):
dirpath = path.dirpath()
if dirpath not in seen_dirs:
# Collect packages first.
seen_dirs.add(dirpath)
pkginit = dirpath.join("__init__.py")
if pkginit.exists():
for x in self._collectfile(pkginit):
yield x
if isinstance(x, Package):
self._pkg_roots[dirpath] = x
if dirpath in self._pkg_roots:
# Do not collect packages here.
continue
for x in self._collectfile(path):
key = (type(x), x.fspath)
if key in self._node_cache:
yield self._node_cache[key]
else:
self._node_cache[key] = x
yield x
else:
assert argpath.check(file=1)
if argpath in self._node_cache:
col = self._node_cache[argpath]
else:
col = root._collectfile(argpath)
collect_root = self._pkg_roots.get(argpath.dirname, self)
col = collect_root._collectfile(argpath)
if col:
self._node_cache[argpath] = col
for y in self.matchnodes(col, names):
m = self.matchnodes(col, names)
# If __init__.py was the only file requested, then the matched node will be
# the corresponding Package, and the first yielded item will be the __init__
# Module itself, so just use that. If this special case isn't taken, then all
# the files in the package will be yielded.
if argpath.basename == "__init__.py":
yield next(m[0].collect())
return
for y in m:
yield y
def _collectfile(self, path):
def _collectfile(self, path, handle_dupes=True):
ihook = self.gethookproxy(path)
if not self.isinitpath(path):
if ihook.pytest_ignore_collect(path=path, config=self.config):
return ()
if handle_dupes:
keepduplicates = self.config.getoption("keepduplicates")
if not keepduplicates:
duplicate_paths = self.config.pluginmanager._duplicatepaths
if path in duplicate_paths:
return ()
else:
duplicate_paths.add(path)
return ihook.pytest_collect_file(path=path, parent=self)
def _recurse(self, path):
ihook = self.gethookproxy(path.dirpath())
if ihook.pytest_ignore_collect(path=path, config=self.config):
return
def _recurse(self, dirpath):
if dirpath.basename == "__pycache__":
return False
ihook = self.gethookproxy(dirpath.dirpath())
if ihook.pytest_ignore_collect(path=dirpath, config=self.config):
return False
for pat in self._norecursepatterns:
if path.check(fnmatch=pat):
if dirpath.check(fnmatch=pat):
return False
ihook = self.gethookproxy(path)
ihook.pytest_collect_directory(path=path, parent=self)
ihook = self.gethookproxy(dirpath)
ihook.pytest_collect_directory(path=dirpath, parent=self)
return True
def _tryconvertpyarg(self, x):
"""Convert a dotted module name to path.
"""
"""Convert a dotted module name to path."""
try:
with _patched_find_module():
loader = pkgutil.find_loader(x)
@@ -598,9 +651,8 @@ class Session(nodes.FSCollector):
raise UsageError(
"file or package not found: " + arg + " (missing __init__.py?)"
)
else:
raise UsageError("file not found: " + arg)
parts[0] = path
raise UsageError("file not found: " + arg)
parts[0] = path.realpath()
return parts
def matchnodes(self, matching, names):

View File

@@ -1,18 +1,20 @@
""" generic mechanism for marking and selecting python functions. """
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from .legacy import matchkeyword
from .legacy import matchmark
from .structures import EMPTY_PARAMETERSET_OPTION
from .structures import get_empty_parameterset_mark
from .structures import Mark
from .structures import MARK_GEN
from .structures import MarkDecorator
from .structures import MarkGenerator
from .structures import MarkInfo
from .structures import ParameterSet
from .structures import transfer_markers
from _pytest.config import UsageError
from .structures import (
ParameterSet,
EMPTY_PARAMETERSET_OPTION,
MARK_GEN,
Mark,
MarkInfo,
MarkDecorator,
MarkGenerator,
transfer_markers,
get_empty_parameterset_mark,
)
from .legacy import matchkeyword, matchmark
__all__ = [
"Mark",
@@ -24,11 +26,6 @@ __all__ = [
]
class MarkerError(Exception):
"""Error in use of a pytest marker/attribute."""
def param(*values, **kw):
"""Specify a parameter in `pytest.mark.parametrize`_ calls or
:ref:`parametrized fixtures <fixture-parametrize-marks>`.
@@ -163,9 +160,9 @@ def pytest_configure(config):
empty_parameterset = config.getini(EMPTY_PARAMETERSET_OPTION)
if empty_parameterset not in ("skip", "xfail", None, ""):
if empty_parameterset not in ("skip", "xfail", "fail_at_collect", None, ""):
raise UsageError(
"{!s} must be one of skip and xfail,"
"{!s} must be one of skip, xfail or fail_at_collect"
" but it is {!r}".format(EMPTY_PARAMETERSET_OPTION, empty_parameterset)
)

View File

@@ -1,10 +1,12 @@
import os
import six
import sys
import platform
import sys
import traceback
from ..outcomes import fail, TEST_OUTCOME
import six
from ..outcomes import fail
from ..outcomes import TEST_OUTCOME
def cached_eval(config, expr, d):
@@ -90,7 +92,10 @@ class MarkEvaluator(object):
else:
if "reason" not in mark.kwargs:
# XXX better be checked at collection time
msg = "you need to specify reason=STRING " "when using booleans as conditions."
msg = (
"you need to specify reason=STRING "
"when using booleans as conditions."
)
fail(msg)
result = bool(expr)
if result:

View File

@@ -2,9 +2,10 @@
this is a place where we put datastructures used by legacy apis
we hope ot remove
"""
import attr
import keyword
import attr
from _pytest.config import UsageError
@@ -66,7 +67,10 @@ python_keywords_allowed_list = ["or", "and", "not"]
def matchmark(colitem, markexpr):
"""Tries to match on any marker names, attached to the given colitem."""
return eval(markexpr, {}, MarkMapping.from_item(colitem))
try:
return eval(markexpr, {}, MarkMapping.from_item(colitem))
except SyntaxError as e:
raise SyntaxError(str(e) + "\nMarker expression must be valid Python!")
def matchkeyword(colitem, keywordexpr):

View File

@@ -5,11 +5,15 @@ from functools import reduce
from operator import attrgetter
import attr
from ..deprecated import MARK_PARAMETERSET_UNPACKING, MARK_INFO_ATTRIBUTE
from ..compat import NOTSET, getfslineno, MappingMixin
from six.moves import map
from ..compat import getfslineno
from ..compat import MappingMixin
from ..compat import NOTSET
from ..deprecated import MARK_INFO_ATTRIBUTE
from ..deprecated import MARK_PARAMETERSET_UNPACKING
from _pytest.outcomes import fail
EMPTY_PARAMETERSET_OPTION = "empty_parameter_set_mark"
@@ -32,11 +36,19 @@ def istestfunc(func):
def get_empty_parameterset_mark(config, argnames, func):
from ..nodes import Collector
requested_mark = config.getini(EMPTY_PARAMETERSET_OPTION)
if requested_mark in ("", None, "skip"):
mark = MARK_GEN.skip
elif requested_mark == "xfail":
mark = MARK_GEN.xfail(run=False)
elif requested_mark == "fail_at_collect":
f_name = func.__name__
_, lineno = getfslineno(func)
raise Collector.CollectError(
"Empty parameter set in '%s' at line %d" % (f_name, lineno)
)
else:
raise LookupError(requested_mark)
fs, lineno = getfslineno(func)
@@ -307,7 +319,7 @@ def _marked(func, mark):
return any(mark == info.combined for info in func_mark)
@attr.s
@attr.s(repr=False)
class MarkInfo(object):
""" Marking object created by :class:`MarkDecorator` instances. """
@@ -385,7 +397,7 @@ class MarkGenerator(object):
x = marker.split("(", 1)[0]
values.add(x)
if name not in self._markers:
raise AttributeError("%r not a registered marker" % (name,))
fail("{!r} not a registered marker".format(name), pytrace=False)
MARK_GEN = MarkGenerator()
@@ -431,7 +443,7 @@ class NodeKeywords(MappingMixin):
@attr.s(cmp=False, hash=False)
class NodeMarkers(object):
"""
internal strucutre for storing marks belongong to a node
internal structure for storing marks belonging to a node
..warning::

View File

@@ -1,12 +1,17 @@
""" monkeypatching and mocking functionality. """
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import sys
import re
import sys
import warnings
from contextlib import contextmanager
import six
import pytest
from _pytest.fixtures import fixture
RE_IMPORT_ERROR_NAME = re.compile("^No module named (.*)$")
@@ -209,13 +214,33 @@ class MonkeyPatch(object):
self._setitem.append((dic, name, dic.get(name, notset)))
del dic[name]
def _warn_if_env_name_is_not_str(self, name):
"""On Python 2, warn if the given environment variable name is not a native str (#4056)"""
if six.PY2 and not isinstance(name, str):
warnings.warn(
pytest.PytestWarning(
"Environment variable name {!r} should be str".format(name)
)
)
def setenv(self, name, value, prepend=None):
""" Set environment variable ``name`` to ``value``. If ``prepend``
is a character, read the current environment variable value
and prepend the ``value`` adjoined with the ``prepend`` character."""
value = str(value)
if not isinstance(value, str):
warnings.warn(
pytest.PytestWarning(
"Value of environment variable {name} type should be str, but got "
"{value!r} (type: {type}); converted to str implicitly".format(
name=name, value=value, type=type(value).__name__
)
),
stacklevel=2,
)
value = str(value)
if prepend and name in os.environ:
value = value + prepend + os.environ[name]
self._warn_if_env_name_is_not_str(name)
self.setitem(os.environ, name, value)
def delenv(self, name, raising=True):
@@ -225,6 +250,7 @@ class MonkeyPatch(object):
If ``raising`` is set to False, no exception will be raised if the
environment variable is missing.
"""
self._warn_if_env_name_is_not_str(name)
self.delitem(os.environ, name, raising=raising)
def syspath_prepend(self, path):

View File

@@ -1,16 +1,19 @@
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import warnings
import six
import py
import attr
import py
import six
import _pytest
import _pytest._code
from _pytest.compat import getfslineno
from _pytest.mark.structures import NodeKeywords, MarkInfo
from _pytest.mark.structures import MarkInfo
from _pytest.mark.structures import NodeKeywords
from _pytest.outcomes import fail
SEP = "/"
@@ -24,7 +27,7 @@ def _splitnode(nodeid):
''
'testing/code'
'testing/code/test_excinfo.py'
'testing/code/test_excinfo.py::TestFormattedExcinfo::()'
'testing/code/test_excinfo.py::TestFormattedExcinfo'
Return values are lists e.g.
[]
@@ -36,7 +39,7 @@ def _splitnode(nodeid):
# If there is no root node at all, return an empty list so the caller's logic can remain sane
return []
parts = nodeid.split(SEP)
# Replace single last element 'test_foo.py::Bar::()' with multiple elements 'test_foo.py', 'Bar', '()'
# Replace single last element 'test_foo.py::Bar' with multiple elements 'test_foo.py', 'Bar'
parts[-1:] = parts[-1].split("::")
return parts
@@ -44,7 +47,7 @@ def _splitnode(nodeid):
def ischildnode(baseid, nodeid):
"""Return True if the nodeid is a child node of the baseid.
E.g. 'foo/bar::Baz::()' is a child of 'foo', 'foo/bar' and 'foo/bar::Baz', but not of 'foo/blorp'
E.g. 'foo/bar::Baz' is a child of 'foo', 'foo/bar' and 'foo/bar::Baz', but not of 'foo/blorp'
"""
base_parts = _splitnode(baseid)
node_parts = _splitnode(nodeid)
@@ -61,11 +64,11 @@ class _CompatProperty(object):
if obj is None:
return self
# TODO: reenable in the features branch
# warnings.warn(
# "usage of {owner!r}.{name} is deprecated, please use pytest.{name} instead".format(
# name=self.name, owner=type(owner).__name__),
# PendingDeprecationWarning, stacklevel=2)
from _pytest.deprecated import COMPAT_PROPERTY
warnings.warn(
COMPAT_PROPERTY.format(name=self.name, owner=owner.__name__), stacklevel=2
)
return getattr(__import__("pytest"), self.name)
@@ -104,10 +107,12 @@ class Node(object):
self._name2pseudofixturedef = {}
if nodeid is not None:
assert "::()" not in nodeid
self._nodeid = nodeid
else:
assert parent is not None
self._nodeid = self.parent.nodeid + "::" + self.name
self._nodeid = self.parent.nodeid
if self.name != "()":
self._nodeid += "::" + self.name
@property
def ihook(self):
@@ -126,11 +131,10 @@ class Node(object):
if isinstance(maybe_compatprop, _CompatProperty):
return getattr(__import__("pytest"), name)
else:
from _pytest.deprecated import CUSTOM_CLASS
cls = getattr(self, name)
# TODO: reenable in the features branch
# warnings.warn("use of node.%s is deprecated, "
# "use pytest_pycollect_makeitem(...) to create custom "
# "collection nodes" % name, category=DeprecationWarning)
self.warn(CUSTOM_CLASS.format(name=name, type_name=type(self).__name__))
return cls
def __repr__(self):
@@ -347,6 +351,9 @@ class Node(object):
pass
def _repr_failure_py(self, excinfo, style=None):
if excinfo.errisinstance(fail.Exception):
if not excinfo.value.pytrace:
return six.text_type(excinfo.value)
fm = self.session._fixturemanager
if excinfo.errisinstance(fm.FixtureLookupError):
return excinfo.value.formatrepr()
@@ -442,7 +449,7 @@ class Collector(Node):
def _check_initialpaths_for_relpath(session, fspath):
for initial_path in session._initialpaths:
if fspath.common(initial_path) == initial_path:
return fspath.relto(initial_path.dirname)
return fspath.relto(initial_path)
class FSCollector(Collector):
@@ -518,13 +525,7 @@ class Item(Node):
return self._location
except AttributeError:
location = self.reportinfo()
# bestrelpath is a quite slow function
cache = self.config.__dict__.setdefault("_bestrelpathcache", {})
try:
fspath = cache[location[0]]
except KeyError:
fspath = self.session.fspath.bestrelpath(location[0])
cache[location[0]] = fspath
fspath = self.session._node_location_to_relpath(location[0])
location = (fspath, location[1], str(location[2]))
self._location = location
return location

View File

@@ -1,9 +1,13 @@
""" run test suites written for nose. """
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import sys
from _pytest import unittest, runner, python
from _pytest import python
from _pytest import runner
from _pytest import unittest
from _pytest.config import hookimpl

View File

@@ -2,7 +2,10 @@
exception classes and constants handling test outcomes
as well as functions creating them
"""
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import sys
@@ -49,18 +52,24 @@ class Failed(OutcomeException):
class Exit(KeyboardInterrupt):
""" raised for immediate program exits (no tracebacks/summaries)"""
def __init__(self, msg="unknown reason"):
def __init__(self, msg="unknown reason", returncode=None):
self.msg = msg
self.returncode = returncode
KeyboardInterrupt.__init__(self, msg)
# exposed helper methods
def exit(msg):
""" exit testing process as if KeyboardInterrupt was triggered. """
def exit(msg, returncode=None):
"""
Exit testing process as if KeyboardInterrupt was triggered.
:param str msg: message to display upon exit.
:param int returncode: return code to be used when exiting pytest.
"""
__tracebackhide__ = True
raise Exit(msg)
raise Exit(msg, returncode)
exit.Exception = Exit

View File

@@ -1,11 +1,15 @@
""" submit failure or test session information to a pastebin service. """
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import pytest
import six
import sys
import tempfile
import six
import pytest
def pytest_addoption(parser):
group = parser.getgroup("terminal reporting")

320
src/_pytest/pathlib.py Normal file
View File

@@ -0,0 +1,320 @@
import atexit
import errno
import fnmatch
import itertools
import operator
import os
import shutil
import sys
import uuid
from functools import reduce
from os.path import expanduser
from os.path import expandvars
from os.path import isabs
from os.path import sep
from posixpath import sep as posix_sep
import six
from six.moves import map
from .compat import PY36
if PY36:
from pathlib import Path, PurePath
else:
from pathlib2 import Path, PurePath
__all__ = ["Path", "PurePath"]
LOCK_TIMEOUT = 60 * 60 * 3
get_lock_path = operator.methodcaller("joinpath", ".lock")
def ensure_reset_dir(path):
"""
ensures the given path is an empty directory
"""
if path.exists():
rmtree(path, force=True)
path.mkdir()
def rmtree(path, force=False):
if force:
# NOTE: ignore_errors might leave dead folders around.
# Python needs a rm -rf as a followup.
shutil.rmtree(str(path), ignore_errors=True)
else:
shutil.rmtree(str(path))
def find_prefixed(root, prefix):
"""finds all elements in root that begin with the prefix, case insensitive"""
l_prefix = prefix.lower()
for x in root.iterdir():
if x.name.lower().startswith(l_prefix):
yield x
def extract_suffixes(iter, prefix):
"""
:param iter: iterator over path names
:param prefix: expected prefix of the path names
:returns: the parts of the paths following the prefix
"""
p_len = len(prefix)
for p in iter:
yield p.name[p_len:]
def find_suffixes(root, prefix):
"""combines find_prefixes and extract_suffixes
"""
return extract_suffixes(find_prefixed(root, prefix), prefix)
def parse_num(maybe_num):
"""parses number path suffixes, returns -1 on error"""
try:
return int(maybe_num)
except ValueError:
return -1
if six.PY2:
def _max(iterable, default):
"""needed due to python2.7 lacking the default argument for max"""
return reduce(max, iterable, default)
else:
_max = max
def _force_symlink(root, target, link_to):
"""helper to create the current symlink
it's full of race conditions that are reasonably ok to ignore
for the context of best effort linking to the latest testrun
the presumption being thatin case of much parallelism
the inaccuracy is going to be acceptable
"""
current_symlink = root.joinpath(target)
try:
current_symlink.unlink()
except OSError:
pass
try:
current_symlink.symlink_to(link_to)
except Exception:
pass
def make_numbered_dir(root, prefix):
"""create a directory with an increased number as suffix for the given prefix"""
for i in range(10):
# try up to 10 times to create the folder
max_existing = _max(map(parse_num, find_suffixes(root, prefix)), default=-1)
new_number = max_existing + 1
new_path = root.joinpath("{}{}".format(prefix, new_number))
try:
new_path.mkdir()
except Exception:
pass
else:
_force_symlink(root, prefix + "current", new_path)
return new_path
else:
raise EnvironmentError(
"could not create numbered dir with prefix "
"{prefix} in {root} after 10 tries".format(prefix=prefix, root=root)
)
def create_cleanup_lock(p):
"""crates a lock to prevent premature folder cleanup"""
lock_path = get_lock_path(p)
try:
fd = os.open(str(lock_path), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
except OSError as e:
if e.errno == errno.EEXIST:
six.raise_from(
EnvironmentError("cannot create lockfile in {path}".format(path=p)), e
)
else:
raise
else:
pid = os.getpid()
spid = str(pid)
if not isinstance(spid, bytes):
spid = spid.encode("ascii")
os.write(fd, spid)
os.close(fd)
if not lock_path.is_file():
raise EnvironmentError("lock path got renamed after successful creation")
return lock_path
def register_cleanup_lock_removal(lock_path, register=atexit.register):
"""registers a cleanup function for removing a lock, by default on atexit"""
pid = os.getpid()
def cleanup_on_exit(lock_path=lock_path, original_pid=pid):
current_pid = os.getpid()
if current_pid != original_pid:
# fork
return
try:
lock_path.unlink()
except (OSError, IOError):
pass
return register(cleanup_on_exit)
def maybe_delete_a_numbered_dir(path):
"""removes a numbered directory if its lock can be obtained and it does not seem to be in use"""
lock_path = None
try:
lock_path = create_cleanup_lock(path)
parent = path.parent
garbage = parent.joinpath("garbage-{}".format(uuid.uuid4()))
path.rename(garbage)
rmtree(garbage, force=True)
except (OSError, EnvironmentError):
# known races:
# * other process did a cleanup at the same time
# * deletable folder was found
# * process cwd (Windows)
return
finally:
# if we created the lock, ensure we remove it even if we failed
# to properly remove the numbered dir
if lock_path is not None:
try:
lock_path.unlink()
except (OSError, IOError):
pass
def ensure_deletable(path, consider_lock_dead_if_created_before):
"""checks if a lock exists and breaks it if its considered dead"""
if path.is_symlink():
return False
lock = get_lock_path(path)
if not lock.exists():
return True
try:
lock_time = lock.stat().st_mtime
except Exception:
return False
else:
if lock_time < consider_lock_dead_if_created_before:
lock.unlink()
return True
else:
return False
def try_cleanup(path, consider_lock_dead_if_created_before):
"""tries to cleanup a folder if we can ensure it's deletable"""
if ensure_deletable(path, consider_lock_dead_if_created_before):
maybe_delete_a_numbered_dir(path)
def cleanup_candidates(root, prefix, keep):
"""lists candidates for numbered directories to be removed - follows py.path"""
max_existing = _max(map(parse_num, find_suffixes(root, prefix)), default=-1)
max_delete = max_existing - keep
paths = find_prefixed(root, prefix)
paths, paths2 = itertools.tee(paths)
numbers = map(parse_num, extract_suffixes(paths2, prefix))
for path, number in zip(paths, numbers):
if number <= max_delete:
yield path
def cleanup_numbered_dir(root, prefix, keep, consider_lock_dead_if_created_before):
"""cleanup for lock driven numbered directories"""
for path in cleanup_candidates(root, prefix, keep):
try_cleanup(path, consider_lock_dead_if_created_before)
for path in root.glob("garbage-*"):
try_cleanup(path, consider_lock_dead_if_created_before)
def make_numbered_dir_with_cleanup(root, prefix, keep, lock_timeout):
"""creates a numbered dir with a cleanup lock and removes old ones"""
e = None
for i in range(10):
try:
p = make_numbered_dir(root, prefix)
lock_path = create_cleanup_lock(p)
register_cleanup_lock_removal(lock_path)
except Exception as exc:
e = exc
else:
consider_lock_dead_if_created_before = p.stat().st_mtime - lock_timeout
cleanup_numbered_dir(
root=root,
prefix=prefix,
keep=keep,
consider_lock_dead_if_created_before=consider_lock_dead_if_created_before,
)
return p
assert e is not None
raise e
def resolve_from_str(input, root):
assert not isinstance(input, Path), "would break on py2"
root = Path(root)
input = expanduser(input)
input = expandvars(input)
if isabs(input):
return Path(input)
else:
return root.joinpath(input)
def fnmatch_ex(pattern, path):
"""FNMatcher port from py.path.common which works with PurePath() instances.
The difference between this algorithm and PurePath.match() is that the latter matches "**" glob expressions
for each part of the path, while this algorithm uses the whole path instead.
For example:
"tests/foo/bar/doc/test_foo.py" matches pattern "tests/**/doc/test*.py" with this algorithm, but not with
PurePath.match().
This algorithm was ported to keep backward-compatibility with existing settings which assume paths match according
this logic.
References:
* https://bugs.python.org/issue29249
* https://bugs.python.org/issue34731
"""
path = PurePath(path)
iswin32 = sys.platform.startswith("win")
if iswin32 and sep not in pattern and posix_sep in pattern:
# Running on Windows, the pattern has no Windows path separators,
# and the pattern has one or more Posix path separators. Replace
# the Posix path separators with the Windows path separator.
pattern = pattern.replace(posix_sep, sep)
if sep not in pattern:
name = path.name
else:
name = six.text_type(path)
return fnmatch.fnmatch(name, pattern)
def parts(s):
parts = s.split(sep)
return {sep.join(parts[: i + 1]) or sep for i in range(len(parts))}

View File

@@ -1,52 +0,0 @@
from os.path import expanduser, expandvars, isabs, sep
from posixpath import sep as posix_sep
import fnmatch
import sys
import six
from .compat import Path, PurePath
def resolve_from_str(input, root):
assert not isinstance(input, Path), "would break on py2"
root = Path(root)
input = expanduser(input)
input = expandvars(input)
if isabs(input):
return Path(input)
else:
return root.joinpath(input)
def fnmatch_ex(pattern, path):
"""FNMatcher port from py.path.common which works with PurePath() instances.
The difference between this algorithm and PurePath.match() is that the latter matches "**" glob expressions
for each part of the path, while this algorithm uses the whole path instead.
For example:
"tests/foo/bar/doc/test_foo.py" matches pattern "tests/**/doc/test*.py" with this algorithm, but not with
PurePath.match().
This algorithm was ported to keep backward-compatibility with existing settings which assume paths match according
this logic.
References:
* https://bugs.python.org/issue29249
* https://bugs.python.org/issue34731
"""
path = PurePath(path)
iswin32 = sys.platform.startswith("win")
if iswin32 and sep not in pattern and posix_sep in pattern:
# Running on Windows, the pattern has no Windows path separators,
# and the pattern has one or more Posix path separators. Replace
# the Posix path separators with the Windows path separator.
pattern = pattern.replace(posix_sep, sep)
if sep not in pattern:
name = path.name
else:
name = six.text_type(path)
return fnmatch.fnmatch(name, pattern)

View File

@@ -1,5 +1,7 @@
"""(disabled by default) support for testing pytest and pytest plugins."""
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import codecs
import gc
@@ -7,22 +9,25 @@ import os
import platform
import re
import subprocess
import six
import sys
import time
import traceback
from fnmatch import fnmatch
from weakref import WeakKeyDictionary
from _pytest.capture import MultiCapture, SysCapture
from _pytest._code import Source
import py
import six
import pytest
from _pytest.main import Session, EXIT_OK
from _pytest._code import Source
from _pytest.assertion.rewrite import AssertionRewritingHook
from _pytest.compat import Path
from _pytest.capture import MultiCapture
from _pytest.capture import SysCapture
from _pytest.compat import safe_str
from _pytest.main import EXIT_INTERRUPTED
from _pytest.main import EXIT_OK
from _pytest.main import Session
from _pytest.pathlib import Path
IGNORE_PAM = [ # filenames added when obtaining details about the current user
u"/var/lib/sss/mc/passwd"
@@ -61,6 +66,11 @@ def pytest_configure(config):
config.pluginmanager.register(checker)
def raise_on_kwargs(kwargs):
if kwargs:
raise TypeError("Unexpected arguments: {}".format(", ".join(sorted(kwargs))))
class LsofFdLeakChecker(object):
def get_open_files(self):
out = self._exec_lsof()
@@ -482,11 +492,17 @@ class Testdir(object):
"""
class TimeoutExpired(Exception):
pass
def __init__(self, request, tmpdir_factory):
self.request = request
self._mod_collections = WeakKeyDictionary()
name = request.function.__name__
self.tmpdir = tmpdir_factory.mktemp(name, numbered=True)
self.test_tmproot = tmpdir_factory.mktemp("tmp-" + name, numbered=True)
os.environ["PYTEST_DEBUG_TEMPROOT"] = str(self.test_tmproot)
os.environ.pop("TOX_ENV_DIR", None) # Ensure that it is not used for caching.
self.plugins = []
self._cwd_snapshot = CwdSnapshot()
self._sys_path_snapshot = SysPathsSnapshot()
@@ -513,6 +529,7 @@ class Testdir(object):
self._sys_modules_snapshot.restore()
self._sys_path_snapshot.restore()
self._cwd_snapshot.restore()
os.environ.pop("PYTEST_DEBUG_TEMPROOT", None)
def __take_sys_modules_snapshot(self):
# some zope modules used by twisted-related tests keep internal state
@@ -845,7 +862,7 @@ class Testdir(object):
# typically we reraise keyboard interrupts from the child run
# because it's our user requesting interruption of the testing
if ret == 2 and not kwargs.get("no_reraise_ctrlc"):
if ret == EXIT_INTERRUPTED and not kwargs.get("no_reraise_ctrlc"):
calls = reprec.getcalls("pytest_keyboard_interrupt")
if calls and calls[-1].excinfo.type == KeyboardInterrupt:
raise KeyboardInterrupt()
@@ -1039,14 +1056,23 @@ class Testdir(object):
return popen
def run(self, *cmdargs):
def run(self, *cmdargs, **kwargs):
"""Run a command with arguments.
Run a process using subprocess.Popen saving the stdout and stderr.
:param args: the sequence of arguments to pass to `subprocess.Popen()`
:param timeout: the period in seconds after which to timeout and raise
:py:class:`Testdir.TimeoutExpired`
Returns a :py:class:`RunResult`.
"""
__tracebackhide__ = True
timeout = kwargs.pop("timeout", None)
raise_on_kwargs(kwargs)
cmdargs = [
str(arg) if isinstance(arg, py.path.local) else arg for arg in cmdargs
]
@@ -1061,7 +1087,40 @@ class Testdir(object):
popen = self.popen(
cmdargs, stdout=f1, stderr=f2, close_fds=(sys.platform != "win32")
)
ret = popen.wait()
def handle_timeout():
__tracebackhide__ = True
timeout_message = (
"{seconds} second timeout expired running:"
" {command}".format(seconds=timeout, command=cmdargs)
)
popen.kill()
popen.wait()
raise self.TimeoutExpired(timeout_message)
if timeout is None:
ret = popen.wait()
elif six.PY3:
try:
ret = popen.wait(timeout)
except subprocess.TimeoutExpired:
handle_timeout()
else:
end = time.time() + timeout
resolution = min(0.1, timeout / 10)
while True:
ret = popen.poll()
if ret is not None:
break
if time.time() > end:
handle_timeout()
time.sleep(resolution)
finally:
f1.close()
f2.close()
@@ -1102,15 +1161,21 @@ class Testdir(object):
def runpytest_subprocess(self, *args, **kwargs):
"""Run pytest as a subprocess with given arguments.
Any plugins added to the :py:attr:`plugins` list will added using the
``-p`` command line option. Additionally ``--basetemp`` is used put
Any plugins added to the :py:attr:`plugins` list will be added using the
``-p`` command line option. Additionally ``--basetemp`` is used to put
any temporary files and directories in a numbered directory prefixed
with "runpytest-" so they do not conflict with the normal numbered
pytest location for temporary files and directories.
with "runpytest-" to not conflict with the normal numbered pytest
location for temporary files and directories.
:param args: the sequence of arguments to pass to the pytest subprocess
:param timeout: the period in seconds after which to timeout and raise
:py:class:`Testdir.TimeoutExpired`
Returns a :py:class:`RunResult`.
"""
__tracebackhide__ = True
p = py.path.local.make_numbered_dir(
prefix="runpytest-", keep=None, rootdir=self.tmpdir
)
@@ -1119,7 +1184,7 @@ class Testdir(object):
if plugins:
args = ("-p", plugins[0]) + args
args = self._getpytestargs() + args
return self.run(*args)
return self.run(*args, timeout=kwargs.get("timeout"))
def spawn_pytest(self, string, expect_timeout=10.0):
"""Run pytest using pexpect.
@@ -1267,6 +1332,7 @@ class LineMatcher(object):
matches and non-matches are also printed on stdout.
"""
__tracebackhide__ = True
self._match_lines(lines2, fnmatch, "fnmatch")
def re_match_lines(self, lines2):
@@ -1278,6 +1344,7 @@ class LineMatcher(object):
The matches and non-matches are also printed on stdout.
"""
__tracebackhide__ = True
self._match_lines(lines2, lambda name, pat: re.match(pat, name), "re.match")
def _match_lines(self, lines2, match_func, match_nickname):

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