Compare commits

...

139 Commits

Author SHA1 Message Date
Bruno Oliveira
3d88d1827b Fixed linting 2018-11-03 19:50:19 -03: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
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
Anthony Sottile
cb39bd0651 Fixes for flake8 master 2018-10-22 08:50:00 -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
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
f947cb2613 Merge remote-tracking branch 'upstream/features' into davidszotten/stepwise 2018-10-20 09:18:02 -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
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
Sven-Hendrik Haase
f694d8d6ad Make --color more colorful 2018-10-18 03:56:58 +02:00
David Szotten
e478f66d8b cache is set by the cacheprovider 2018-10-17 21:17:54 +01:00
David Szotten
c25310d34f fix cacheprovider test 2018-10-15 21:51:15 +01: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
Anthony Sottile
dbfb3ccc42 Add changelog entry 2018-10-10 10:46:09 -07:00
Anthony Sottile
956b3aca97 Revert patching of breakpointhook as it appears to do nothing 2018-09-23 18:39:50 -07:00
139 changed files with 1934 additions and 703 deletions

View File

@@ -23,8 +23,13 @@ repos:
language_version: python3
- id: flake8
language_version: python3
- repo: https://github.com/asottile/reorder_python_imports
rev: v1.3.3
hooks:
- id: reorder-python-imports
args: ['--application-directories=.:src']
- repo: https://github.com/asottile/pyupgrade
rev: v1.8.0
rev: v1.10.1
hooks:
- id: pyupgrade
args: [--keep-percent-format]

View File

@@ -47,6 +47,11 @@ jobs:
env: TOXENV=py37
before_install:
- brew update
# remove c++ include files because upgrading python as of 2018-10-23, also
# attempts to upgrade gcc, and it fails because the include files already
# exist. removing the include files is one of the solutions recommended by brew
# this workaround might not be necessary in the future
- rm '/usr/local/include/c++'
- brew upgrade python
- brew unlink python
- brew link python

View File

@@ -59,6 +59,7 @@ Danielle Jenkins
Dave Hunt
David Díaz-Barquero
David Mohr
David Szotten
David Vierra
Daw-Ran Liou
Denis Kirisov
@@ -161,6 +162,7 @@ Miro Hrončok
Nathaniel Waisbrot
Ned Batchelder
Neven Mundar
Niclas Olofsson
Nicolas Delaby
Oleg Pidsadnyi
Oleg Sushchenko
@@ -202,6 +204,7 @@ Stefan Zimmermann
Stefano Taschini
Steffen Allner
Stephan Obermann
Sven-Hendrik Haase
Tadek Teleżyński
Tarcisio Fischer
Tareq Alayan

View File

@@ -18,6 +18,110 @@ with advance notice in the **Deprecations** section of releases.
.. towncrier release notes start
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.
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)
=========================
@@ -328,7 +432,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
@@ -503,7 +607,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

@@ -2,7 +2,6 @@
# 2.7.5 3.3.2
# FilesCompleter 75.1109 69.2116
# FastFilesCompleter 0.7383 1.0760
import timeit
imports = [

View File

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

1
doc/4266.bugfix.rst Normal file
View File

@@ -0,0 +1 @@
Handle (ignore) exceptions raised during collection, e.g. with Django's LazySettings proxy class.

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,8 @@ Release announcements
:maxdepth: 2
release-3.10.0
release-3.9.3
release-3.9.2
release-3.9.1
release-3.9.0

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.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

@@ -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

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

@@ -1,7 +1,8 @@
from pytest import raises
import _pytest._code
import six
import _pytest._code
from pytest import raises
def otherfunc(a, b):
assert a == b

View File

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

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

@@ -85,8 +85,9 @@ interesting to just look at the collection tree::
rootdir: $REGENDOC_TMPDIR/nonpython, inifile:
collected 2 items
<Package '$REGENDOC_TMPDIR/nonpython'>
<YamlFile 'test_simple.yml'>
<YamlItem 'hello'>
<YamlItem 'ok'>
<Package '$REGENDOC_TMPDIR/nonpython'>
<YamlFile 'test_simple.yml'>
<YamlItem 'hello'>
<YamlItem 'ok'>
======================= no tests ran in 0.12 seconds =======================

View File

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

View File

@@ -413,7 +413,7 @@ Running it results in some skips if we don't have all the python interpreters in
. $ pytest -rs -q multipython.py
...sss...sssssssss...sss... [100%]
========================= short test summary info ==========================
SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.4' not found
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

@@ -26,7 +26,7 @@ get on the terminal - we are working on that)::
> assert param1 * 2 < param2
E assert (3 * 2) < 6
failure_demo.py:19: AssertionError
failure_demo.py:20: AssertionError
_________________________ TestFailing.test_simple __________________________
self = <failure_demo.TestFailing object at 0xdeadbeef>
@@ -43,7 +43,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:36: AssertionError
____________________ TestFailing.test_simple_multiline _____________________
self = <failure_demo.TestFailing object at 0xdeadbeef>
@@ -51,7 +51,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:39:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
a = 42, b = 54
@@ -60,7 +60,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:16: AssertionError
___________________________ TestFailing.test_not ___________________________
self = <failure_demo.TestFailing object at 0xdeadbeef>
@@ -73,7 +73,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:45: AssertionError
_________________ TestSpecialisedExplanations.test_eq_text _________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -84,7 +84,7 @@ get on the terminal - we are working on that)::
E - spam
E + eggs
failure_demo.py:49: AssertionError
failure_demo.py:50: AssertionError
_____________ TestSpecialisedExplanations.test_eq_similar_text _____________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -97,7 +97,7 @@ get on the terminal - we are working on that)::
E + foo 2 bar
E ? ^
failure_demo.py:52: AssertionError
failure_demo.py:53: AssertionError
____________ TestSpecialisedExplanations.test_eq_multiline_text ____________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -110,7 +110,7 @@ get on the terminal - we are working on that)::
E + eggs
E bar
failure_demo.py:55: AssertionError
failure_demo.py:56: AssertionError
______________ TestSpecialisedExplanations.test_eq_long_text _______________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -127,7 +127,7 @@ get on the terminal - we are working on that)::
E + 1111111111b222222222
E ? ^
failure_demo.py:60: AssertionError
failure_demo.py:61: AssertionError
_________ TestSpecialisedExplanations.test_eq_long_text_multiline __________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -147,7 +147,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:66: AssertionError
_________________ TestSpecialisedExplanations.test_eq_list _________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -158,7 +158,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:69: AssertionError
______________ TestSpecialisedExplanations.test_eq_list_long _______________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -171,7 +171,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:74: AssertionError
_________________ TestSpecialisedExplanations.test_eq_dict _________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -189,7 +189,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:77: AssertionError
_________________ TestSpecialisedExplanations.test_eq_set __________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -207,7 +207,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:80: AssertionError
_____________ TestSpecialisedExplanations.test_eq_longer_list ______________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -218,7 +218,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:83: AssertionError
_________________ TestSpecialisedExplanations.test_in_list _________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -227,7 +227,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:86: AssertionError
__________ TestSpecialisedExplanations.test_not_in_text_multiline __________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -246,7 +246,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:90: AssertionError
___________ TestSpecialisedExplanations.test_not_in_text_single ____________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -259,7 +259,7 @@ get on the terminal - we are working on that)::
E single foo line
E ? +++
failure_demo.py:93: AssertionError
failure_demo.py:94: AssertionError
_________ TestSpecialisedExplanations.test_not_in_text_single_long _________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -272,7 +272,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:98: AssertionError
______ TestSpecialisedExplanations.test_not_in_text_single_long_term _______
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -285,7 +285,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:102: AssertionError
______________________________ test_attribute ______________________________
def test_attribute():
@@ -297,7 +297,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:110: AssertionError
_________________________ test_attribute_instance __________________________
def test_attribute_instance():
@@ -309,7 +309,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:117: AssertionError
__________________________ test_attribute_failure __________________________
def test_attribute_failure():
@@ -322,7 +322,7 @@ get on the terminal - we are working on that)::
i = Foo()
> assert i.b == 2
failure_demo.py:127:
failure_demo.py:128:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <failure_demo.test_attribute_failure.<locals>.Foo object at 0xdeadbeef>
@@ -331,7 +331,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:123: Exception
_________________________ test_attribute_multiple __________________________
def test_attribute_multiple():
@@ -348,7 +348,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:138: AssertionError
__________________________ TestRaises.test_raises __________________________
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -357,7 +357,7 @@ get on the terminal - we are working on that)::
s = "qwe" # NOQA
> raises(TypeError, "int(s)")
failure_demo.py:147:
failure_demo.py:148:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> int(s)
@@ -372,7 +372,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:151: Failed
__________________________ TestRaises.test_raise ___________________________
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -381,7 +381,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:154: ValueError
________________________ TestRaises.test_tupleerror ________________________
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -390,7 +390,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:157: ValueError
______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -401,7 +401,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:162: TypeError
--------------------------- Captured stdout call ---------------------------
items is [1, 2, 3]
________________________ TestRaises.test_some_error ________________________
@@ -412,7 +412,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:165: NameError
____________________ test_dynamic_compile_shows_nicely _____________________
def test_dynamic_compile_shows_nicely():
@@ -427,14 +427,14 @@ get on the terminal - we are working on that)::
sys.modules[name] = module
> module.foo()
failure_demo.py:182:
failure_demo.py:183:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
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:180>:2: AssertionError
____________________ TestMoreErrors.test_complex_error _____________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -448,9 +448,9 @@ get on the terminal - we are working on that)::
> somefunc(f(), g())
failure_demo.py:193:
failure_demo.py:194:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
failure_demo.py:11: in somefunc
failure_demo.py:12: in somefunc
otherfunc(x, y)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
@@ -460,7 +460,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:8: AssertionError
___________________ TestMoreErrors.test_z1_unpack_error ____________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -470,7 +470,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:198: ValueError
____________________ TestMoreErrors.test_z2_type_error _____________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -480,7 +480,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:202: TypeError
______________________ TestMoreErrors.test_startswith ______________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -493,7 +493,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:207: AssertionError
__________________ TestMoreErrors.test_startswith_nested ___________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -512,7 +512,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:216: AssertionError
_____________________ TestMoreErrors.test_global_func ______________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -523,7 +523,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:219: AssertionError
_______________________ TestMoreErrors.test_instance _______________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -534,7 +534,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:223: AssertionError
_______________________ TestMoreErrors.test_compare ________________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -544,7 +544,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:226: AssertionError
_____________________ TestMoreErrors.test_try_finally ______________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -555,7 +555,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:231: AssertionError
___________________ TestCustomAssertMsg.test_single_line ___________________
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
@@ -570,7 +570,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:242: AssertionError
____________________ TestCustomAssertMsg.test_multiline ____________________
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
@@ -589,7 +589,7 @@ get on the terminal - we are working on that)::
E assert 1 == 2
E + where 1 = <class 'failure_demo.TestCustomAssertMsg.test_multiline.<locals>.A'>.a
failure_demo.py:248: AssertionError
failure_demo.py:249: AssertionError
___________________ TestCustomAssertMsg.test_custom_repr ___________________
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
@@ -611,11 +611,12 @@ 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
failure_demo.py:262: 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))
failure_demo.py:25
$REGENDOC_TMPDIR/assertion/failure_demo.py:25: 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 ===================

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:

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

@@ -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

@@ -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

@@ -117,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:

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

@@ -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 ===================
@@ -351,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,23 +418,12 @@ 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")
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:329: RemovedInPytest4Warning: usage of Session.Class is deprecated, please use pytest.Class instead
return getattr(object, name, default)
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:329: RemovedInPytest4Warning: usage of Session.File is deprecated, please use pytest.File instead
return getattr(object, name, default)
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:329: RemovedInPytest4Warning: usage of Session.Function is deprecated, please use pytest.Function instead
return getattr(object, name, default)
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:329: RemovedInPytest4Warning: usage of Session.Instance is deprecated, please use pytest.Instance instead
return getattr(object, name, default)
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:329: RemovedInPytest4Warning: usage of Session.Item is deprecated, please use pytest.Item instead
return getattr(object, name, default)
$PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/compat.py:329: RemovedInPytest4Warning: usage of Session.Module is deprecated, please use pytest.Module instead
return getattr(object, name, default)
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, 7 warnings in 0.12 seconds ===================
=================== 2 passed, 1 warnings in 0.12 seconds ===================
For more information about the result object that ``runpytest()`` returns, and
the methods that it provides please check out the :py:class:`RunResult

View File

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

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,4 +1,5 @@
import os
from setuptools import setup

View File

@@ -53,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,11 +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 Frame # noqa
from .code import Traceback # noqa
from .code import filter_traceback # noqa
from .code import Frame # 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,19 +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 pluggy
import re
from weakref import ref
import _pytest
from _pytest.compat import _PY2, _PY3, PY35, safe_str
from six import text_type
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

View File

@@ -1,17 +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):
@@ -158,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
@@ -192,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)
@@ -287,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,11 +17,12 @@ import types
import atomicwrites
import py
import six
from _pytest.assertion import util
from _pytest.pathlib import PurePath
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"):
@@ -706,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,10 +1,14 @@
"""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
import _pytest._code
from ..compat import Sequence
u = six.text_type

View File

@@ -4,18 +4,22 @@ 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
from collections import OrderedDict
import attr
import py
import six
import attr
import pytest
import json
from .compat import _PY2 as PY2
from .pathlib import Path, resolve_from_str, rmtree
from .pathlib import Path
from .pathlib import resolve_from_str
from .pathlib import rmtree
README_CONTENT = u"""\
# pytest cache directory #
@@ -315,7 +319,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

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

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 TEST_OUTCOME, fail
from six import text_type
import six
from _pytest.outcomes import fail
from _pytest.outcomes import TEST_OUTCOME
try:
import enum
@@ -331,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.
@@ -417,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,27 +1,35 @@
""" 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 sys
import types
import warnings
import copy
import six
import py
# 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
from _pytest._code import ExceptionInfo, filter_traceback
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")
@@ -126,6 +134,7 @@ default_plugins = (
"freeze_support",
"setuponly",
"setupplan",
"stepwise",
"warnings",
"logging",
)
@@ -205,7 +214,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
@@ -376,6 +385,7 @@ class PytestPluginManager(PluginManager):
if x.check(dir=1):
self._getconftestmodules(x)
@lru_cache(maxsize=128)
def _getconftestmodules(self, path):
if self._noconftest:
return []
@@ -384,23 +394,26 @@ class PytestPluginManager(PluginManager):
directory = path.dirpath()
else:
directory = path
try:
return self._path2confmods[directory]
except KeyError:
# 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.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[directory] = clist
return clist
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)
@@ -441,8 +454,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)

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

View File

@@ -1,7 +1,8 @@
""" 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 os
import pdb
import sys
from doctest import UnexpectedException
@@ -9,13 +10,6 @@ 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")
@@ -53,20 +47,12 @@ 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__
pdb.set_trace = pytestPDB.set_trace
pytestPDB._pluginmanager = config.pluginmanager
@@ -94,10 +80,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):

View File

@@ -8,10 +8,13 @@ be removed when the time comes.
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, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from _pytest.warning_types import UnformattedWarning, RemovedInPytest4Warning
from _pytest.warning_types import PytestDeprecationWarning
from _pytest.warning_types import RemovedInPytest4Warning
from _pytest.warning_types import UnformattedWarning
MAIN_STR_ARGS = RemovedInPytest4Warning(
@@ -55,6 +58,10 @@ FIXTURE_FUNCTION_CALL = UnformattedWarning(
"See https://docs.pytest.org/en/latest/fixture.html for more information.",
)
FIXTURE_NAMED_REQUEST = PytestDeprecationWarning(
"'request' is a reserved name for fixtures and will raise an error in future versions"
)
CFG_PYTEST_SECTION = UnformattedWarning(
RemovedInPytest4Warning,
"[pytest] section in {filename} files is deprecated, use [tool:pytest] instead.",

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.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.outcomes import fail, TEST_OUTCOME
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{}'
@@ -616,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
@@ -1034,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
@@ -1191,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):
@@ -1295,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)

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

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.
"""
@@ -603,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

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 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"
@@ -263,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:
@@ -330,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

View File

@@ -1,20 +1,24 @@
""" 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 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.pathlib import parts
from _pytest.runner import collect_one_node
@@ -278,15 +282,6 @@ def pytest_ignore_collect(path, config):
if _in_venv(path) and not allow_in_venv:
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
@@ -475,8 +470,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:
@@ -494,7 +489,7 @@ class Session(nodes.FSCollector):
names = self._parsearg(arg)
argpath = names.pop(0).realpath()
paths = []
paths = set()
root = self
# Start with a Session root, and delve to argpath item (dir or file)
@@ -523,21 +518,37 @@ class Session(nodes.FSCollector):
# 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):
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:
seen_dirs.add(dirpath)
pkginit = dirpath.join("__init__.py")
if pkginit.exists() and parts(pkginit.strpath).isdisjoint(paths):
for x in root._collectfile(pkginit):
yield x
paths.add(x.fspath.dirpath())
if parts(path.strpath).isdisjoint(paths):
for x in root._collectfile(path):
if (type(x), x.fspath) in self._node_cache:
yield self._node_cache[(type(x), x.fspath)]
key = (type(x), x.fspath)
if key in self._node_cache:
yield self._node_cache[key]
else:
self._node_cache[(type(x), x.fspath)] = x
self._node_cache[key] = x
yield x
else:
assert argpath.check(file=1)
@@ -548,7 +559,15 @@ class Session(nodes.FSCollector):
col = 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):
@@ -556,17 +575,29 @@ class Session(nodes.FSCollector):
if not self.isinitpath(path):
if ihook.pytest_ignore_collect(path=path, config=self.config):
return ()
# Skip duplicate paths.
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):

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",

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):

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

View File

@@ -5,12 +5,15 @@ from functools import reduce
from operator import attrgetter
import attr
from _pytest.outcomes import fail
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"
@@ -440,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,9 +1,11 @@
""" 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
@@ -228,10 +230,12 @@ class MonkeyPatch(object):
if not isinstance(value, str):
warnings.warn(
pytest.PytestWarning(
"Environment variable value {!r} should be str, converted to str implicitly".format(
value
"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:

View File

@@ -1,18 +1,20 @@
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 MarkInfo
from _pytest.mark.structures import NodeKeywords
from _pytest.outcomes import fail
from _pytest.mark.structures import NodeKeywords, MarkInfo
SEP = "/"
tracebackcutdir = py.path.local(_pytest.__file__).dirpath()

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

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")

View File

@@ -1,19 +1,21 @@
import os
import errno
import atexit
import operator
import six
import sys
from functools import reduce
import uuid
from six.moves import map
import itertools
import shutil
from os.path import expanduser, expandvars, isabs, sep
from posixpath import sep as posix_sep
import errno
import fnmatch
import stat
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
@@ -33,24 +35,17 @@ get_lock_path = operator.methodcaller("joinpath", ".lock")
def ensure_reset_dir(path):
"""
ensures the given path is a empty directory
ensures the given path is an empty directory
"""
if path.exists():
rmtree(path, force=True)
path.mkdir()
def _shutil_rmtree_remove_writable(func, fspath, _):
"Clear the readonly bit and reattempt the removal"
os.chmod(fspath, stat.S_IWRITE)
func(fspath)
def rmtree(path, force=False):
if force:
# ignore_errors leaves dead folders around
# python needs a rm -rf as a followup
# the trick with _shutil_rmtree_remove_writable is unreliable
# 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))
@@ -103,8 +98,8 @@ else:
def _force_symlink(root, target, link_to):
"""helper to create the current symlink
its full of race conditions that are reasonably ok to ignore
for the contex of best effort linking to the latest testrun
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
@@ -121,7 +116,7 @@ def _force_symlink(root, target, link_to):
def make_numbered_dir(root, prefix):
"""create a directory with a increased number as suffix for the given 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)
@@ -156,12 +151,12 @@ def create_cleanup_lock(p):
else:
pid = os.getpid()
spid = str(pid)
if not isinstance(spid, six.binary_type):
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 sucessfull creation")
raise EnvironmentError("lock path got renamed after successful creation")
return lock_path
@@ -182,14 +177,30 @@ def register_cleanup_lock_removal(lock_path, register=atexit.register):
return register(cleanup_on_exit)
def delete_a_numbered_dir(path):
"""removes a numbered directory"""
create_cleanup_lock(path)
parent = path.parent
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)
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):
@@ -212,9 +223,9 @@ def ensure_deletable(path, consider_lock_dead_if_created_before):
def try_cleanup(path, consider_lock_dead_if_created_before):
"""tries to cleanup a folder if we can ensure its deletable"""
"""tries to cleanup a folder if we can ensure it's deletable"""
if ensure_deletable(path, consider_lock_dead_if_created_before):
delete_a_numbered_dir(path)
maybe_delete_a_numbered_dir(path)
def cleanup_candidates(root, prefix, keep):
@@ -245,8 +256,8 @@ def make_numbered_dir_with_cleanup(root, prefix, keep, lock_timeout):
p = make_numbered_dir(root, prefix)
lock_path = create_cleanup_lock(p)
register_cleanup_lock_removal(lock_path)
except Exception as e:
pass
except Exception as exc:
e = exc
else:
consider_lock_dead_if_created_before = p.stat().st_mtime - lock_timeout
cleanup_numbered_dir(
@@ -302,3 +313,8 @@ def fnmatch_ex(pattern, path):
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,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,23 +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
from _pytest.main import Session, EXIT_INTERRUPTED, EXIT_OK
from _pytest.assertion.rewrite import AssertionRewritingHook
from _pytest.pathlib import Path
from _pytest.compat import safe_str
import py
import six
import pytest
from _pytest._code import Source
from _pytest.assertion.rewrite import AssertionRewritingHook
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"

View File

@@ -1,50 +1,50 @@
""" Python test discovery, setup and run of test functions. """
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 fnmatch
import inspect
import sys
import os
import collections
import sys
import warnings
from textwrap import dedent
import py
import six
from _pytest.main import FSHookProxy
from _pytest.config import hookimpl
import _pytest
from _pytest._code import filter_traceback
from _pytest import deprecated
from _pytest import fixtures
from _pytest import nodes
from _pytest import deprecated
from _pytest.compat import (
isclass,
isfunction,
is_generator,
ascii_escaped,
REGEX_TYPE,
STRING_TYPES,
NoneType,
NOTSET,
get_real_func,
getfslineno,
safe_getattr,
safe_str,
getlocation,
enum,
get_default_arg_names,
getimfunc,
)
from _pytest._code import filter_traceback
from _pytest.compat import ascii_escaped
from _pytest.compat import enum
from _pytest.compat import get_default_arg_names
from _pytest.compat import get_real_func
from _pytest.compat import getfslineno
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 isfunction
from _pytest.compat import NoneType
from _pytest.compat import NOTSET
from _pytest.compat import REGEX_TYPE
from _pytest.compat import safe_getattr
from _pytest.compat import safe_isclass
from _pytest.compat import safe_str
from _pytest.compat import STRING_TYPES
from _pytest.config import hookimpl
from _pytest.main import FSHookProxy
from _pytest.mark.structures import get_unpacked_marks
from _pytest.mark.structures import normalize_mark_list
from _pytest.mark.structures import transfer_markers
from _pytest.outcomes import fail
from _pytest.mark.structures import (
transfer_markers,
get_unpacked_marks,
normalize_mark_list,
)
from _pytest.warning_types import RemovedInPytest4Warning, PytestWarning
from _pytest.pathlib import parts
from _pytest.warning_types import PytestWarning
from _pytest.warning_types import RemovedInPytest4Warning
def pyobj_property(name):
@@ -197,7 +197,7 @@ def pytest_pycollect_makeitem(collector, name, obj):
if res is not None:
return
# nothing was collected elsewhere, let's do it here
if isclass(obj):
if safe_isclass(obj):
if collector.istestclass(obj, name):
Class = collector._getcustomclass("Class")
outcome.force_result(Class(name, parent=collector))
@@ -518,15 +518,17 @@ class Package(Module):
self._norecursepatterns = session._norecursepatterns
self.fspath = fspath
def _recurse(self, path):
ihook = self.gethookproxy(path.dirpath())
if ihook.pytest_ignore_collect(path=path, config=self.config):
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
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 gethookproxy(self, fspath):
@@ -554,15 +556,6 @@ class Package(Module):
return path in self.session._initialpaths
def collect(self):
# XXX: HACK!
# Before starting to collect any files from this package we need
# to cleanup the duplicate paths added by the session's collect().
# Proper fix is to not track these as duplicates in the first place.
for path in list(self.session.config.pluginmanager._duplicatepaths):
# if path.parts()[:len(self.fspath.dirpath().parts())] == self.fspath.dirpath().parts():
if path.dirname.startswith(self.name):
self.session.config.pluginmanager._duplicatepaths.remove(path)
this_path = self.fspath.dirpath()
init_module = this_path.join("__init__.py")
if init_module.check(file=1) and path_matches_patterns(
@@ -571,19 +564,16 @@ class Package(Module):
yield Module(init_module, self)
pkg_prefixes = set()
for path in this_path.visit(rec=self._recurse, bf=True, sort=True):
# we will visit our own __init__.py file, in which case we skip it
skip = False
if path.basename == "__init__.py" and path.dirpath() == this_path:
continue
# We will visit our own __init__.py file, in which case we skip it.
if path.isfile():
if path.basename == "__init__.py" and path.dirpath() == this_path:
continue
for pkg_prefix in pkg_prefixes:
if (
pkg_prefix in path.parts()
and pkg_prefix.join("__init__.py") != path
):
skip = True
if skip:
parts_ = parts(path.strpath)
if any(
pkg_prefix in parts_ and pkg_prefix.join("__init__.py") != path
for pkg_prefix in pkg_prefixes
):
continue
if path.isdir() and path.join("__init__.py").check(file=1):
@@ -663,7 +653,7 @@ class Instance(PyCollector):
_ALLOW_MARKERS = False # hack, destroy later
# instances share the object with their parents in a way
# that duplicates markers instances if not taken out
# can be removed at node strucutre reorganization time
# can be removed at node structure reorganization time
def _getobj(self):
return self.parent.obj()
@@ -1345,7 +1335,7 @@ class Function(FunctionMixin, nodes.Item, fixtures.FuncargnamesCompatAttr):
"""
_genid = None
# disable since functions handle it themselfes
# disable since functions handle it themselves
_ALLOW_MARKERS = False
def __init__(

View File

@@ -1,20 +1,20 @@
import math
import pprint
import sys
from numbers import Number
from decimal import Decimal
from numbers import Number
import six
from six.moves import zip, filterfalse
from more_itertools.more import always_iterable
from six.moves import filterfalse
from six.moves import zip
from _pytest.compat import isclass
from _pytest.compat import Mapping, Sequence
from _pytest.compat import STRING_TYPES
from _pytest.outcomes import fail
import _pytest._code
from _pytest.compat import isclass
from _pytest.compat import Mapping
from _pytest.compat import Sequence
from _pytest.compat import STRING_TYPES
from _pytest.outcomes import fail
BASE_TYPE = (type, STRING_TYPES)

View File

@@ -1,15 +1,16 @@
""" recording warnings during test function execution. """
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 _pytest._code
import re
import sys
import warnings
import six
import _pytest._code
from _pytest.fixtures import yield_fixture
from _pytest.outcomes import fail
@@ -155,21 +156,27 @@ class WarningsRecorder(warnings.catch_warnings):
# trivial patching of `warnings.warn` seems to be enough somehow?
if six.PY2:
def warn(*args, **kwargs):
kwargs.setdefault("stacklevel", 1)
kwargs["stacklevel"] += 1
def warn(message, category=None, stacklevel=1):
# duplicate the stdlib logic due to
# bad handing in the c version of warnings
if isinstance(message, Warning):
category = message.__class__
# Check category argument
if category is None:
category = UserWarning
assert issubclass(category, Warning)
# emulate resetting the warn registry
f_globals = sys._getframe(kwargs["stacklevel"] - 1).f_globals
f_globals = sys._getframe(stacklevel).f_globals
if "__warningregistry__" in f_globals:
orig = f_globals["__warningregistry__"]
f_globals["__warningregistry__"] = None
try:
return self._saved_warn(*args, **kwargs)
return self._saved_warn(message, category, stacklevel + 1)
finally:
f_globals["__warningregistry__"] = orig
else:
return self._saved_warn(*args, **kwargs)
return self._saved_warn(message, category, stacklevel + 1)
warnings.warn, self._saved_warn = warn, warnings.warn
return self

View File

@@ -1,4 +1,5 @@
import py
from _pytest._code.code import TerminalRepr

View File

@@ -1,10 +1,13 @@
""" log machine-parseable test session result information in a plain
text file.
"""
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 py
import os
def pytest_addoption(parser):

View File

@@ -1,5 +1,7 @@
""" basic collect and runtest protocol implementations """
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import bdb
import os
@@ -7,10 +9,14 @@ import sys
from time import time
import six
from _pytest._code.code import ExceptionInfo
from _pytest.outcomes import skip, Skipped, TEST_OUTCOME
from .reports import TestReport, CollectReport, CollectErrorRepr
from .reports import CollectErrorRepr
from .reports import CollectReport
from .reports import TestReport
from _pytest._code.code import ExceptionInfo
from _pytest.outcomes import skip
from _pytest.outcomes import Skipped
from _pytest.outcomes import TEST_OUTCOME
#
# pytest plugin hooks

View File

@@ -1,7 +1,10 @@
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 pytest
import sys
def pytest_addoption(parser):

View File

@@ -1,4 +1,6 @@
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import pytest

View File

@@ -1,9 +1,13 @@
""" support for skip/xfail functions and markers. """
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from _pytest.config import hookimpl
from _pytest.mark.evaluate import MarkEvaluator
from _pytest.outcomes import fail, skip, xfail
from _pytest.outcomes import fail
from _pytest.outcomes import skip
from _pytest.outcomes import xfail
def pytest_addoption(parser):

102
src/_pytest/stepwise.py Normal file
View File

@@ -0,0 +1,102 @@
import pytest
def pytest_addoption(parser):
group = parser.getgroup("general")
group.addoption(
"--sw",
"--stepwise",
action="store_true",
dest="stepwise",
help="exit on test fail and continue from last failing test next time",
)
group.addoption(
"--stepwise-skip",
action="store_true",
dest="stepwise_skip",
help="ignore the first failing test but stop on the next failing test",
)
@pytest.hookimpl
def pytest_configure(config):
config.pluginmanager.register(StepwisePlugin(config), "stepwiseplugin")
class StepwisePlugin:
def __init__(self, config):
self.config = config
self.active = config.getvalue("stepwise")
self.session = None
if self.active:
self.lastfailed = config.cache.get("cache/stepwise", None)
self.skip = config.getvalue("stepwise_skip")
def pytest_sessionstart(self, session):
self.session = session
def pytest_collection_modifyitems(self, session, config, items):
if not self.active or not self.lastfailed:
return
already_passed = []
found = False
# Make a list of all tests that have been run before the last failing one.
for item in items:
if item.nodeid == self.lastfailed:
found = True
break
else:
already_passed.append(item)
# If the previously failed test was not found among the test items,
# do not skip any tests.
if not found:
already_passed = []
for item in already_passed:
items.remove(item)
config.hook.pytest_deselected(items=already_passed)
def pytest_collectreport(self, report):
if self.active and report.failed:
self.session.shouldstop = (
"Error when collecting test, stopping test execution."
)
def pytest_runtest_logreport(self, report):
# Skip this hook if plugin is not active or the test is xfailed.
if not self.active or "xfail" in report.keywords:
return
if report.failed:
if self.skip:
# Remove test from the failed ones (if it exists) and unset the skip option
# to make sure the following tests will not be skipped.
if report.nodeid == self.lastfailed:
self.lastfailed = None
self.skip = False
else:
# Mark test as the last failing and interrupt the test session.
self.lastfailed = report.nodeid
self.session.shouldstop = (
"Test failed, continuing from this test next run."
)
else:
# If the test was actually run and did pass.
if report.when == "call":
# Remove test from the failed ones, if exists.
if report.nodeid == self.lastfailed:
self.lastfailed = None
def pytest_sessionfinish(self, session):
if self.active:
self.config.cache.set("cache/stepwise", self.lastfailed)
else:
# Clear the list of failing tests if the plugin is not active.
self.config.cache.set("cache/stepwise", [])

View File

@@ -2,8 +2,11 @@
This is a good source for looking at the various reporting hooks.
"""
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 itertools
import platform
import sys
@@ -17,16 +20,11 @@ from more_itertools import collapse
import pytest
from _pytest import nodes
from _pytest.main import (
EXIT_OK,
EXIT_TESTSFAILED,
EXIT_INTERRUPTED,
EXIT_USAGEERROR,
EXIT_NOTESTSCOLLECTED,
)
import argparse
from _pytest.main import EXIT_INTERRUPTED
from _pytest.main import EXIT_NOTESTSCOLLECTED
from _pytest.main import EXIT_OK
from _pytest.main import EXIT_TESTSFAILED
from _pytest.main import EXIT_USAGEERROR
class MoreQuietAction(argparse.Action):
@@ -248,6 +246,7 @@ class TerminalReporter(object):
self.isatty = file.isatty()
self._progress_nodeids_reported = set()
self._show_progress_info = self._determine_show_progress_info()
self._collect_report_last_write = None
def _determine_show_progress_info(self):
"""Return True if we should display progress information based on the current config"""
@@ -263,7 +262,7 @@ class TerminalReporter(object):
char = {"xfailed": "x", "skipped": "s"}.get(char, char)
return char in self.reportchars
def write_fspath_result(self, nodeid, res):
def write_fspath_result(self, nodeid, res, **markup):
fspath = self.config.rootdir.join(nodeid.split("::")[0])
if fspath != self.currentfspath:
if self.currentfspath is not None and self._show_progress_info:
@@ -272,7 +271,7 @@ class TerminalReporter(object):
fspath = self.startdir.bestrelpath(fspath)
self._tw.line()
self._tw.write(fspath + " ")
self._tw.write(res)
self._tw.write(res, **markup)
def write_ensure_prefix(self, prefix, extra="", **kwargs):
if self.currentfspath != prefix:
@@ -386,22 +385,22 @@ class TerminalReporter(object):
# probably passed setup/teardown
return
running_xdist = hasattr(rep, "node")
if markup is None:
if rep.passed:
markup = {"green": True}
elif rep.failed:
markup = {"red": True}
elif rep.skipped:
markup = {"yellow": True}
else:
markup = {}
if self.verbosity <= 0:
if not running_xdist and self.showfspath:
self.write_fspath_result(rep.nodeid, letter)
self.write_fspath_result(rep.nodeid, letter, **markup)
else:
self._tw.write(letter)
self._tw.write(letter, **markup)
else:
self._progress_nodeids_reported.add(rep.nodeid)
if markup is None:
if rep.passed:
markup = {"green": True}
elif rep.failed:
markup = {"red": True}
elif rep.skipped:
markup = {"yellow": True}
else:
markup = {}
line = self._locationline(rep.nodeid, *rep.location)
if not running_xdist:
self.write_ensure_prefix(line, word, **markup)
@@ -474,7 +473,11 @@ class TerminalReporter(object):
return self._tw.chars_on_current_line
def pytest_collection(self):
if not self.isatty and self.config.option.verbose >= 1:
if self.isatty:
if self.config.option.verbose >= 0:
self.write("collecting ... ", bold=True)
self._collect_report_last_write = time.time()
elif self.config.option.verbose >= 1:
self.write("collecting ... ", bold=True)
def pytest_collectreport(self, report):
@@ -485,13 +488,19 @@ class TerminalReporter(object):
items = [x for x in report.result if isinstance(x, pytest.Item)]
self._numcollected += len(items)
if self.isatty:
# self.write_fspath_result(report.nodeid, 'E')
self.report_collect()
def report_collect(self, final=False):
if self.config.option.verbose < 0:
return
if not final:
# Only write "collecting" report every 0.5s.
t = time.time()
if self._collect_report_last_write > t - 0.5:
return
self._collect_report_last_write = t
errors = len(self.stats.get("error", []))
skipped = len(self.stats.get("skipped", []))
deselected = len(self.stats.get("deselected", []))
@@ -725,11 +734,10 @@ class TerminalReporter(object):
# legacy warnings show their location explicitly, while standard warnings look better without
# it because the location is already formatted into the message
warning_records = list(warning_records)
is_legacy = warning_records[0].legacy
if location and is_legacy:
if location:
self._tw.line(str(location))
for w in warning_records:
if is_legacy:
if location:
lines = w.message.splitlines()
indented = "\n".join(" " + x for x in lines)
message = indented.rstrip()

View File

@@ -1,22 +1,23 @@
""" support for providing temporary directories to test functions. """
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 re
import pytest
import py
from _pytest.monkeypatch import MonkeyPatch
import attr
import tempfile
import warnings
from .pathlib import (
Path,
make_numbered_dir,
make_numbered_dir_with_cleanup,
ensure_reset_dir,
LOCK_TIMEOUT,
)
import attr
import py
import pytest
from .pathlib import ensure_reset_dir
from .pathlib import LOCK_TIMEOUT
from .pathlib import make_numbered_dir
from .pathlib import make_numbered_dir_with_cleanup
from .pathlib import Path
from _pytest.monkeypatch import MonkeyPatch
@attr.s

View File

@@ -1,15 +1,21 @@
""" discovery and running of std-library "unittest" style tests. """
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 traceback
# for transferring markers
import _pytest._code
from _pytest.config import hookimpl
from _pytest.outcomes import fail, skip, xfail
from _pytest.python import transfer_markers, Class, Module, Function
from _pytest.compat import getimfunc
from _pytest.config import hookimpl
from _pytest.outcomes import fail
from _pytest.outcomes import skip
from _pytest.outcomes import xfail
from _pytest.python import Class
from _pytest.python import Function
from _pytest.python import Module
from _pytest.python import transfer_markers
def pytest_pycollect_makeitem(collector, name, obj):

View File

@@ -1,11 +1,12 @@
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 warnings
from contextlib import contextmanager
import pytest
from _pytest import compat

View File

@@ -2,30 +2,44 @@
"""
pytest: unit and functional testing with Python.
"""
# else we are imported
from _pytest.config import main, UsageError, cmdline, hookspec, hookimpl
from _pytest.fixtures import fixture, yield_fixture
from _pytest.assertion import register_assert_rewrite
from _pytest.freeze_support import freeze_includes
from _pytest import __version__
from _pytest.assertion import register_assert_rewrite
from _pytest.config import cmdline
from _pytest.config import hookimpl
from _pytest.config import hookspec
from _pytest.config import main
from _pytest.config import UsageError
from _pytest.debugging import pytestPDB as __pytestPDB
from _pytest.recwarn import warns, deprecated_call
from _pytest.outcomes import fail, skip, importorskip, exit, xfail
from _pytest.mark import MARK_GEN as mark, param
from _pytest.main import Session
from _pytest.nodes import Item, Collector, File
from _pytest.fixtures import fillfixtures as _fillfuncargs
from _pytest.python import Package, Module, Class, Instance, Function, Generator
from _pytest.python_api import approx, raises
from _pytest.warning_types import (
PytestWarning,
PytestDeprecationWarning,
RemovedInPytest4Warning,
PytestExperimentalApiWarning,
)
from _pytest.fixtures import fixture
from _pytest.fixtures import yield_fixture
from _pytest.freeze_support import freeze_includes
from _pytest.main import Session
from _pytest.mark import MARK_GEN as mark
from _pytest.mark import param
from _pytest.nodes import Collector
from _pytest.nodes import File
from _pytest.nodes import Item
from _pytest.outcomes import exit
from _pytest.outcomes import fail
from _pytest.outcomes import importorskip
from _pytest.outcomes import skip
from _pytest.outcomes import xfail
from _pytest.python import Class
from _pytest.python import Function
from _pytest.python import Generator
from _pytest.python import Instance
from _pytest.python import Module
from _pytest.python import Package
from _pytest.python_api import approx
from _pytest.python_api import raises
from _pytest.recwarn import deprecated_call
from _pytest.recwarn import warns
from _pytest.warning_types import PytestDeprecationWarning
from _pytest.warning_types import PytestExperimentalApiWarning
from _pytest.warning_types import PytestWarning
from _pytest.warning_types import RemovedInPytest4Warning
set_trace = __pytestPDB.set_trace

View File

@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
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 textwrap
import types
import py
import six
import py
import pytest
from _pytest.main import EXIT_NOTESTSCOLLECTED, EXIT_USAGEERROR
from _pytest.main import EXIT_NOTESTSCOLLECTED
from _pytest.main import EXIT_USAGEERROR
def prepend_pythonpath(*dirs):

View File

@@ -1,13 +1,15 @@
# coding: utf-8
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 six import text_type
from test_excinfo import TWMock
import _pytest._code
import pytest
from six import text_type
from test_excinfo import TWMock
try:
import mock

View File

@@ -1,24 +1,25 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import operator
import os
import sys
import textwrap
import _pytest
import py
import pytest
import six
from _pytest._code.code import (
ExceptionInfo,
FormattedExcinfo,
ReprExceptionInfo,
ExceptionChainRepr,
)
from six.moves import queue
import py
import six
from six.moves import queue
from test_source import astonly
import _pytest
import pytest
from _pytest._code.code import ExceptionChainRepr
from _pytest._code.code import ExceptionInfo
from _pytest._code.code import FormattedExcinfo
from _pytest._code.code import ReprExceptionInfo
try:
import importlib
except ImportError:

View File

@@ -2,13 +2,17 @@
# flake8: noqa
# disable flake check on this file because some constructs are strange
# or redundant on purpose and can't be disable on a line-by-line basis
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 sys
import six
import _pytest._code
import pytest
import six
from _pytest._code import Source
from _pytest._code.source import ast

View File

@@ -1,9 +1,13 @@
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 pytest
pytestmark = pytest.mark.pytester_example_path("deprecated")
@pytest.mark.filterwarnings("default")
def test_yield_tests_deprecation(testdir):
@@ -392,3 +396,13 @@ def test_pycollector_makeitem_is_deprecated():
with pytest.warns(RemovedInPytest4Warning):
collector.makeitem("foo", "bar")
assert collector.called
def test_fixture_named_request(testdir):
testdir.copy_example()
result = testdir.runpytest()
result.stdout.fnmatch_lines(
[
"*'request' is a reserved name for fixtures and will raise an error in future versions"
]
)

View File

@@ -0,0 +1,10 @@
import pytest
@pytest.fixture
def request():
pass
def test():
pass

View File

@@ -1,6 +1,7 @@
import pytest
import pprint
import pytest
def pytest_generate_tests(metafunc):
if "arg1" in metafunc.fixturenames:

View File

@@ -0,0 +1 @@
foo_*

View File

@@ -0,0 +1,28 @@
import argparse
import pathlib
HERE = pathlib.Path(__file__).parent
TEST_CONTENT = (HERE / "template_test.py").read_bytes()
parser = argparse.ArgumentParser()
parser.add_argument("numbers", nargs="*", type=int)
def generate_folders(root, elements, *more_numbers):
fill_len = len(str(elements))
if more_numbers:
for i in range(elements):
new_folder = root.joinpath(f"foo_{i:0>{fill_len}}")
new_folder.mkdir()
new_folder.joinpath("__init__.py").write_bytes(TEST_CONTENT)
generate_folders(new_folder, *more_numbers)
else:
for i in range(elements):
new_test = root.joinpath(f"test_{i:0<{fill_len}}.py")
new_test.write_bytes(TEST_CONTENT)
if __name__ == "__main__":
args = parser.parse_args()
generate_folders(HERE, *(args.numbers or (10, 100)))

View File

@@ -0,0 +1,2 @@
def test_x():
pass

View File

@@ -1,6 +1,7 @@
import pytest
import unittest
import pytest
@pytest.fixture(params=[1, 2])
def two(request):

View File

@@ -1,6 +1,7 @@
import logging
import py.io
from _pytest.logging import ColoredLevelFormatter

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
import re
import os
import re
from io import open
import six

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