Compare commits

..

677 Commits
3.6.2 ... 3.8.2

Author SHA1 Message Date
Anthony Sottile
d3673c7429 Preparing release version 3.8.2 2018-10-02 07:46:02 -07:00
Bruno Oliveira
25fe3706a4 Merge pull request #4056 from nicoddemus/unicode-vars
Ensure Monkeypatch setenv and delenv use bytes keys in Python 2
2018-10-02 07:56:32 -03:00
Bruno Oliveira
1a323fbd3c Show a warning when non-str is given to Monkeypatch.setenv 2018-10-01 20:07:07 -03:00
Bruno Oliveira
9d971d33be Hide internal pytest.warns traceback 2018-10-01 18:45:08 -03:00
Bruno Oliveira
bc009a8582 Fix test to comply with pypy 6.0 2018-10-01 18:37:27 -03:00
Bruno Oliveira
5e7d427df1 Merge pull request #4060 from nicoddemus/4051-changelog
Improve changelog for #4051
2018-10-01 18:12:52 -03:00
Bruno Oliveira
dd59ed3b18 Merge pull request #4059 from labcodes/documenting-scopes
Add possible values for fixture scope to docs
2018-10-01 17:25:42 -03:00
Bruno Oliveira
20d0f0e56b Improve changelog for #4051 2018-10-01 17:12:05 -03:00
Bruno Oliveira
d24a7e6c5a Issue warning if Monkeypatch.setenv/delenv receive non-strings in Python 2
Fixes the bug described in:

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

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

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

Fix #4036
2018-09-25 17:38:22 -03:00
Bruno Oliveira
b1fbb2ab92 Merge pull request #4032 from hjwp/patch-1
add documentation of register_assert_rewrite
2018-09-25 08:43:29 -03:00
Daniel Hahler
e85edf5212 Merge pull request #4029 from nicoddemus/warnings-example-deprecation-docs
Add an example on how to update config.warn calls
2018-09-25 13:25:21 +02:00
Bruno Oliveira
b03bad5dbb Fix linting 2018-09-25 08:12:55 -03:00
Harry Percival
19ec300b2a fix rst syntax again 2018-09-25 06:58:47 +01:00
Harry Percival
11442f2ad7 fix rst syntax thing 2018-09-25 06:57:33 +01:00
Harry Percival
97748b6605 mention conftest.py as a good place to do it. 2018-09-25 06:55:28 +01:00
Harry Percival
2b762337bd add documentation of register_assert_rewrite
wip
2018-09-25 06:49:50 +01:00
Bruno Oliveira
9899b8f1fb Add an example on how to update config.warn calls
As commented in https://github.com/pytest-dev/pytest-cov/pull/230#pullrequestreview-157958838
2018-09-23 22:42:09 -03:00
Anthony Sottile
4474beeb82 Typo fix [ci skip] 2018-09-23 18:07:28 -07:00
Ronny Pfannschmidt
eca3e781b6 Merge pull request #4022 from iwanb/fix_reload
Fix #3539: reload module with assertion rewrite import hook
2018-09-23 18:17:56 +02:00
iwanb
c61ff31ffa Fix #3539: reload module with assertion rewrite import hook 2018-09-23 13:05:55 +02:00
Ankit Goel
ec57cbf82d Merge pull request #4020 from crazymerlyn/release-3.8.1
Preparing release version 3.8.1
2018-09-23 00:56:27 +05:30
CrazyMerlyn
3f6a46c2a4 Preparing release version 3.8.1 2018-09-22 16:34:06 +00:00
Bruno Oliveira
4ba3cb25b0 Merge pull request #4016 from williamjamir/patch-1
Include Python 3.7 on getting started doc
2018-09-21 20:02:25 -03:00
William Jamir Silva
650c458df9 Include Python 3.7 on getting started doc
Close #3932
2018-09-21 19:18:51 -03:00
Ankit Goel
58aa4f91f5 Merge pull request #4012 from maxalbert/fix-docstring-typo
Fix typo in docstring
2018-09-21 22:07:57 +05:30
Maximilian Albert
9b382ed16c Fix typo in docstring 2018-09-21 17:11:15 +01:00
Ronny Pfannschmidt
f02dbaf97f Merge pull request #4010 from nicoddemus/package-len-error-3749
Fix 'Package has no len()' error during collection
2018-09-21 07:40:20 +02:00
Bruno Oliveira
41f6ea13ce Fix 'Package has no len()' error during collection
Fix #3749
2018-09-20 17:53:21 -03:00
Ronny Pfannschmidt
f6eb39df33 Merge pull request #4001 from asottile/fix_bytes_repr_text_mix_python_2
Fix UnicodeDecodeError in assertion with mixed non-ascii bytes repr + text
2018-09-20 22:16:37 +02:00
Bruno Oliveira
7a5e11bbcf Merge pull request #3997 from nicoddemus/deprecation-docs
Introduce deprecations page
2018-09-20 08:22:51 -03:00
Anthony Sottile
7122fa5613 Fix UnicodeDecodeError in assertion with mixed non-ascii bytes repr + text 2018-09-19 20:24:00 -07:00
Bruno Oliveira
7aff81739e Merge pull request #3998 from blueyed/logging-del
logging: del item.catch_log_handler only in teardown
2018-09-19 20:07:19 -03:00
Bruno Oliveira
27772f67c0 Merge pull request #3987 from nicoddemus/fix-find-scope-3941
Fix scope determination with indirect parameters
2018-09-19 20:06:45 -03:00
Bruno Oliveira
10b3b2dc68 Merge pull request #3990 from blueyed/coverage-source
coverage: use modules
2018-09-19 19:55:11 -03:00
Bruno Oliveira
c2841542af Introduce deprecations page
fix #3996
2018-09-19 19:51:29 -03:00
wim glenn
1f28096587 Merge pull request #4003 from pytest-dev/wimglenn-patch-1
seems this subdir is now .pytest_cache not .cache
2018-09-19 14:49:38 -05:00
wim glenn
e86b01e831 Update customize.rst 2018-09-19 14:06:36 -05:00
Bruno Oliveira
d1fa8ae08e Improve CHANGELOG entry 2018-09-19 12:52:10 -03:00
Ronny Pfannschmidt
29dac03314 Merge pull request #3980 from nicoddemus/rewrite-cwd-changed
Fix assertion rewriter crash if cwd changes mid-testing
2018-09-19 17:45:26 +02:00
Daniel Hahler
e7eb7e799b logging: del item.catch_log_handler only in teardown
Without this caplog.record_tuples etc is not available anymore when using
`--pdb`.
2018-09-19 17:17:47 +02:00
Bruno Oliveira
7f48f552c1 Fix linting 2018-09-19 10:18:05 -03:00
Bruno Oliveira
1e2e65f0fa Add references to the relevant Python issues 2018-09-19 08:20:23 -03:00
Daniel Hahler
28c9cc7321 coverage: use modules for source
This should increase coverage for subprocesses, where previously
`source` paths were used only from the config file, but not the initial
`--source` argument.
2018-09-19 07:46:19 +02:00
Bruno Oliveira
ccb90b5c46 [WIP] Introduce deprecations page
fix #3996
2018-09-18 20:56:40 -03:00
Bruno Oliveira
37d2469266 Use a PurePath instance to do matching against patterns in assertion rewrite
This way we don't need to have real file system path, which prevents the
original #3973 bug.
2018-09-17 20:29:09 -03:00
Bruno Oliveira
1df6d28080 Fix assertion rewriter crash if cwd changes mid-testing
Unfortunately we need to get a `py.path.local` object to perform the fnmatch
operation, it is different from the standard `fnmatch` module because it
implements its own custom logic. So we need to use `py.path` to perform
the fnmatch for backward compatibility reasons.

Ideally we should be able to use a "pure path" in `pathlib` terms (a path
not bound to the file system), but we don't have those in pylib.

Fix #3973
2018-09-17 20:04:44 -03:00
Daniel Hahler
03eaad376b tox: coverage factor: combine and report 2018-09-17 14:44:47 +02:00
Daniel Hahler
739f9a4a4b Travis: use codecov-bash
Faster to install and will retry uploads on connection errors.
2018-09-17 14:44:47 +02:00
Daniel Hahler
93224f8cf9 tox: remove obsolete whitelist_externals 2018-09-17 14:44:47 +02:00
Ronny Pfannschmidt
bb57186dd4 Merge pull request #3983 from nicoddemus/update-backward-policy
Review backward compatibility policy
2018-09-16 20:43:55 +02:00
Bruno Oliveira
2803eb9fbb Merge pull request #3984 from nicoddemus/fix-docs-formatting
Fix rendering of the ini example for python_files
2018-09-15 12:05:59 -03:00
Ronny Pfannschmidt
f53eff93db Merge pull request #3982 from nicoddemus/ignore-pytest-cache
Ignore pytest cache
2018-09-15 07:21:45 +02:00
Bruno Oliveira
86a14d007d Fix scope determination with indirect parameters
Fix #3941
2018-09-14 21:33:59 -03:00
Bruno Oliveira
a4dd6ee3ce Fix linting 2018-09-14 17:31:01 -03:00
Bruno Oliveira
130cf7e0db Fix rendering of the ini example for python_files
Also added an example using one pattern per line
2018-09-14 17:27:25 -03:00
Bruno Oliveira
cbb41f1ae2 Ignore Sphinx's .doctrees folder 2018-09-14 16:00:35 -03:00
Bruno Oliveira
fa78da3c03 Update backward compatibility policy with new practices 2018-09-14 15:58:22 -03:00
Bruno Oliveira
87ddb2dbd5 Change flaky test_request_garbage to provide more debug information
This test fails *very* rarely when running in xdist.
2018-09-14 15:25:45 -03:00
Bruno Oliveira
9aa6b0903b .pytest_cache is now automatically ignored by Git 2018-09-14 15:16:40 -03:00
Bruno Oliveira
49800ea134 Merge pull request #3977 from RonnyPfannschmidt/remove-im-func
Remove im_func
2018-09-13 15:46:33 -03:00
Ronny Pfannschmidt
8fe55b1d18 add changelog for fix #3975 2018-09-13 15:40:45 +02:00
Ronny Pfannschmidt
a0ce9a4441 remove the legacy code about im_func and generalize using fix and compat.getimfunc 2018-09-13 15:38:36 +02:00
Daniel Hahler
2cf2dc3d95 Merge pull request #3967 from blueyed/optional-mock
tests: use unittest.mock with py34+
2018-09-13 07:36:42 +02:00
Daniel Hahler
7537e94ddf tests: use unittest.mock with py34+
Fixes https://github.com/pytest-dev/pytest/issues/3965.

Has to work around https://github.com/tox-dev/tox/issues/706.

No coverage for pluggymaster builds is OK though anyway.
2018-09-12 23:21:47 +02:00
Anthony Sottile
2c90b3db9e Merge pull request #3957 from asottile/changelog_files
Improve pre-commit detection for changelog filenames
2018-09-08 10:58:50 -07:00
Anthony Sottile
826adafe2e Improve pre-commit detection for changelog filenames 2018-09-07 09:36:09 -07:00
Anthony Sottile
3dd2933dbd Merge pull request #3948 from nicoddemus/fix-changelog
Amend CHANGELOG with missing #3251
2018-09-07 09:15:09 -07:00
Bruno Oliveira
b55351274e Amend CHANGELOG with missing #3251 2018-09-06 18:56:08 -03:00
Bruno Oliveira
c00d934b21 Merge pull request #3933 from nicoddemus/idval-hypothesis-flaky-3707
Use -n auto now that xdist behaves well in Travis and AppVeyor
2018-09-06 15:15:55 -03:00
Bruno Oliveira
6b526cbe6a Merge pull request #3943 from nicoddemus/no-coverage-on-deploy
Disable coverage during deployment stage
2018-09-06 15:15:32 -03:00
Bruno Oliveira
e0539e6ede Merge pull request #3942 from nicoddemus/merge-features-into-master
Merge features into master
2018-09-06 09:35:28 -03:00
Bruno Oliveira
5eb85efa14 Use -n auto now that xdist behaves well in Travis and AppVeyor
This hopefully fixes the flaky test_idval_hypothesis on AppVeyor

Fix #3707
2018-09-06 09:22:13 -03:00
Bruno Oliveira
9ee8d72fd2 Disable coverage during deployment stage
Otherwise it will fail as there's no coverage data to combine/publish
2018-09-06 09:18:47 -03:00
Bruno Oliveira
8c4ca383ca Merge remote-tracking branch 'upstream/features' into merge-features-into-master 2018-09-06 09:15:56 -03:00
Bruno Oliveira
f2a427da25 Merge pull request #3940 from nicoddemus/release-3.8.0
Release 3.8.0
2018-09-06 09:15:00 -03:00
Bruno Oliveira
e0466d0ad8 Merge pull request #3923 from nicoddemus/codecov
Add support for codecov in AppVeyor
2018-09-06 07:02:56 -03:00
Bruno Oliveira
418a66a09f Replace coveralls' badge by codecov's 2018-09-05 22:37:32 -03:00
Bruno Oliveira
5e2bd17d18 White list external "env" used by Travis for coverage 2018-09-05 22:37:32 -03:00
Bruno Oliveira
ec6fca4aa7 Add codecov support to AppVeyor and remove coveralls 2018-09-05 19:50:06 -03:00
Bruno Oliveira
1f20626618 Preparing release version 3.8.0 2018-09-05 21:06:32 +00:00
Bruno Oliveira
69b34f7658 Merge remote-tracking branch 'upstream/master' into release-3.8.0 2018-09-05 18:02:02 -03:00
Bruno Oliveira
531b76a513 Merge pull request #3931 from nicoddemus/internal-warnings
Use standard warnings for internal pytest warnings
2018-09-05 14:05:52 -03:00
Bruno Oliveira
f63c683faa No longer escape regex in pytest.mark.filterwarnings
Fix #3936
2018-09-05 10:20:25 -03:00
Ronny Pfannschmidt
410d5762c0 Merge pull request #3919 from fabioz/master
Improve import performance of assertion rewrite. Fixes #3918.
2018-09-05 14:33:40 +02:00
Bruno Oliveira
ddb308455a Make sure warn is called in test_parameterset_extractfrom 2018-09-05 09:01:29 -03:00
Bruno Oliveira
f42b5019ec Make code_or_warning parameter private for backward-compatibility 2018-09-04 18:53:58 -03:00
Bruno Oliveira
adc9ed85bc Fix test_idval_hypothesis 2018-09-04 18:49:20 -03:00
Bruno Oliveira
4592def14d Improve test_rewarn_functional 2018-09-04 17:02:56 -03:00
Bruno Oliveira
2e0a7cf78d Revert to having just "runtest" as "when" parameter of the pytest_warning_captured hook 2018-09-04 17:01:23 -03:00
Bruno Oliveira
5a52acaa92 Make config no longer optional in parametrize id functions 2018-09-04 16:55:52 -03:00
Bruno Oliveira
6d497f2c77 Fix stacklevel for warning about Metafunc.addcall 2018-09-04 16:50:24 -03:00
Bruno Oliveira
b7560a8808 Keep backward compatibility for code as kw in Node.warn 2018-09-04 16:48:21 -03:00
Bruno Oliveira
d3ca739c00 Use explicit instances when calling warnings.warn_explicit 2018-09-04 16:29:48 -03:00
Bruno Oliveira
3db76ccf3d Fix Cache.warn function to issue a "config" warning 2018-09-04 15:53:17 -03:00
Bruno Oliveira
438f7a1254 Add "setup", "call" and "teardown" values to "when" parameter of pytest_warning_captured hook 2018-09-04 15:53:17 -03:00
Bruno Oliveira
47bf58d69e Make Node.warn support two forms, new and deprecated
As suggested during review, it now accepts two forms:

Node.warn(warning_instance)  (recommended)

Node.warn(code, message)  (deprecated)
2018-09-04 15:53:17 -03:00
Bruno Oliveira
5ef51262f7 Fix reference to PytestWarning in warningsfilter mark 2018-09-04 15:06:14 -03:00
Bruno Oliveira
a054aa4797 Issue assert rewrite warning if tuple >=1 as suggested in review 2018-09-04 14:45:48 -03:00
Bruno Oliveira
f1cfd10c94 Handle cache warnings in tests 2018-09-04 14:44:02 -03:00
Bruno Oliveira
d3f72ca202 Fix linting for warnings.rst 2018-09-04 14:33:41 -03:00
Bruno Oliveira
022c58bf64 Revert pytest_terminal_summary(tryfirst) in warnings module as this breaks tests 2018-09-04 14:26:34 -03:00
Bruno Oliveira
b42518acd5 Change std_warn to receive a single warning instance, addressed review suggestions 2018-09-04 14:20:42 -03:00
Bruno Oliveira
284a2d110f Move warnings import to top level 2018-09-04 13:46:33 -03:00
Bruno Oliveira
9ae0a3cd85 Do not trigger warning about tuples being always True if the tuple has size != 2 2018-09-04 13:41:11 -03:00
Bruno Oliveira
615c671434 Connect string literals 2018-09-04 13:34:05 -03:00
Bruno Oliveira
29bfa5efa4 Merge pull request #3925 from crazymerlyn/fix-exit-code
Fix exit code for command line errors
2018-09-04 11:53:00 -03:00
Bruno Oliveira
016f8f1536 Improve get_fslocation_from_item's docstring 2018-09-04 11:48:11 -03:00
Bruno Oliveira
e9417be9df Add comment about deprecation warnings being shown by default 2018-09-04 11:35:35 -03:00
Bruno Oliveira
c304998ed7 Remove commented out code 2018-09-04 11:35:35 -03:00
Bruno Oliveira
415a62e373 Fix typo in PytestExperimentalApiWarning 2018-09-04 11:35:35 -03:00
Bruno Oliveira
8ce3aeadbf Move PytestExerimentalApiWarning to warning_types 2018-09-04 11:35:35 -03:00
Bruno Oliveira
b818314045 Improve docs for warnings capture and PEP-0506 remarks 2018-09-04 11:35:34 -03:00
Bruno Oliveira
56d414177a Remove nodeid from messages for warnings generated by standard warnings
Standard warnings already contain the proper location, so we don't need
to also print the node id
2018-09-04 11:35:34 -03:00
Bruno Oliveira
0fffa6ba2f Implement hack to issue warnings during config
Once we can capture warnings during the config stage, we can
then get rid of this function

Related to #2891
2018-09-04 11:35:34 -03:00
Bruno Oliveira
60499d221e Add test to ensure that users can suppress internal warnings 2018-09-04 11:35:34 -03:00
Bruno Oliveira
9965ed84da Show deprecation warnings by default if no other filters are configured
Fix #2908
2018-09-04 11:35:34 -03:00
Bruno Oliveira
7e13593452 Add CHANGELOG entries for #2452
Fix #2452
Fix #2684
2018-09-04 11:35:34 -03:00
Bruno Oliveira
208dd3aad1 Add docs for internal warnings and introduce PytestDeprecationWarning
Fix #2477
2018-09-04 11:35:34 -03:00
Bruno Oliveira
19a01c9849 Make PytestWarning and RemovedInPytest4Warning part of the public API 2018-09-04 11:35:34 -03:00
Bruno Oliveira
78ac7d99f5 Deprecate Config.warn and Node.warn, replaced by standard warnings 2018-09-04 11:35:34 -03:00
Bruno Oliveira
0c8dbdcd92 Fix existing tests now that we are using standard warnings 2018-09-04 11:35:34 -03:00
Bruno Oliveira
8e4501ee29 Use std_warn for warning about applying marks directly to parameters 2018-09-04 11:35:34 -03:00
Bruno Oliveira
0100f61b62 Start the laywork to capture standard warnings 2018-09-04 11:35:15 -03:00
Bruno Oliveira
1a9d913ee1 Capture and display warnings during collection
Fix #3251
2018-09-04 11:35:06 -03:00
Bruno Oliveira
51e32cf7cc Remove Python 2.6 specific warning 2018-09-04 11:35:06 -03:00
Bruno Oliveira
3fcc4cdbd5 Make terminal capture pytest_warning_capture
pytest_logwarning is no longer emitted by the warnings plugin,
only ever emitted from .warn() functions in config and item
2018-09-04 11:35:06 -03:00
Bruno Oliveira
ffd47ceefc Implement new pytest_warning_captured hook 2018-09-04 11:35:00 -03:00
Bruno Oliveira
10f21b423a Remove assert for "reprec" because this is no longer set on the pluginmanager
It seems this has no effect since `pluggy` was developed as a separate
library.
2018-09-04 11:35:00 -03:00
Bruno Oliveira
eec7081b8d Make AssertionRewritingrHook use imp_find_module 2018-09-03 10:18:25 -03:00
CrazyMerlyn
b01704cce1 Fix exit code for command line errors
Fixes #3913
2018-09-03 04:16:35 +00:00
Ronny Pfannschmidt
15ede8aab8 Merge pull request #3924 from nicoddemus/enable-pypy
Reenable pypy now that scandir can be installed without a compiler
2018-09-02 17:34:21 +02:00
Bruno Oliveira
f7dc9b9fef Merge pull request #3922 from nicoddemus/skip-xfail-docs-3219
Mention explicitly when pytest.skip and pytest.xfail can be called
2018-09-02 11:40:34 -03:00
Bruno Oliveira
dc13f0b469 Reenable pypy now that scandir can be installed without a compiler
Ref: benhoyt/scandir#105
Ref: #3111
2018-09-02 11:17:06 -03:00
Bruno Oliveira
a13c6a84df Mention explicitly when pytest.skip and pytest.xfail can be called
Fix #3219
2018-09-02 10:42:05 -03:00
Bruno Oliveira
dfa713163a Merge pull request #3921 from nicoddemus/use-constant
Use EXIT_USAGEERROR instead of magic number
2018-09-01 20:09:39 -03:00
Bruno Oliveira
90c00dfd54 Use EXIT_USAGEERROR instead of magic number 2018-09-01 12:03:28 -03:00
Daniel Hahler
f3b9b21996 Merge pull request #3920 from blueyed/branch
tests/CI: enable branch coverage
2018-09-01 16:52:12 +02:00
Bruno Oliveira
885b8a3b4c Fix linting 2018-09-01 11:13:40 -03:00
Bruno Oliveira
4675912d89 Add tests for early rewrite bailout code and handle patterns with subdirectories 2018-09-01 10:59:21 -03:00
Bruno Oliveira
495b44198f Merge pull request #3917 from dhirensr/docs_for_detailed_info
T3566,T3546: added a blurb in usage.rst for usage of flag -r
2018-09-01 10:09:29 -03:00
Bruno Oliveira
8d8e68cf90 Merge pull request #3911 from wimglenn/i18n_width
improve line width estimate
2018-09-01 08:57:44 -03:00
Bruno Oliveira
f3b0caf299 Improve docs for summary report and move it further up in the doc 2018-09-01 08:54:00 -03:00
Bruno Oliveira
75d29acc06 Fix reference to inter-sphinx objects database 2018-09-01 08:48:47 -03:00
Daniel Hahler
cbbb36fc9b tests/CI: enable branch coverage 2018-08-31 19:26:47 +02:00
Fabio Zadrozny
d53e449296 Improve performance of assertion rewriting. Fixes #3918 2018-08-31 12:27:08 -03:00
Ronny Pfannschmidt
01df368d93 Merge pull request #3914 from nicoddemus/merge-master-into-features
Merge master into features
2018-08-31 15:31:00 +02:00
Bruno Oliveira
2256f2f04d Remove test which is no longer required and improve test_lf_and_ff_prints_no_needless_message
* test_lf_and_ff_obey_verbosity is no longer necessary because
  test_lf_and_ff_prints_no_needless_message already checks if the proper messages
  are displayed when -q is used.

* Improve test_lf_and_ff_prints_no_needless_message so we also check that
  the correct message is displayed when there are failures to run
2018-08-31 08:01:55 -03:00
dhirensr
95881c870e T3566,T3546: added a blurb in usage.rst for usage of flag -r 2018-08-31 11:20:15 +05:30
Ronny Pfannschmidt
019e33ee3f Merge pull request #3915 from nicoddemus/quickstart-book-docs
Add pytest Quick Start Guide to the books section in the docs
2018-08-31 07:40:13 +02:00
Bruno Oliveira
19fa01b91d Tweak changelog 2018-08-30 21:17:14 -03:00
Bruno Oliveira
96aad2983b Move code to get width of current line to a function 2018-08-30 21:16:35 -03:00
wim glenn
c18a5b5179 try to be backwards compat 2018-08-30 19:06:20 -05:00
wim glenn
ed4b94a180 add changelog entry 2018-08-30 18:59:58 -05:00
wim glenn
29c5ac71bc improve line width estimate 2018-08-30 18:59:58 -05:00
Bruno Oliveira
84a9f7a263 Add pytest Quick Start Guide to the books section in the docs 2018-08-30 20:18:51 -03:00
Bruno Oliveira
11e591e442 Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2018-08-30 19:55:23 -03:00
Bruno Oliveira
64f00683f2 Merge pull request #3912 from dhirensr/needless_message
Needless message printed with --failed-first and no failed tests #3853
2018-08-30 19:51:49 -03:00
Bruno Oliveira
84a033fd97 Remove extra newline 2018-08-30 19:48:47 -03:00
Bruno Oliveira
0183d46275 Improve CHANGELOG a bit 2018-08-30 19:44:04 -03:00
Bruno Oliveira
9bd4b0a05e Merge pull request #3910 from hoefling/docfix
doc fix: raises accepts tuples instead of lists
2018-08-30 19:41:44 -03:00
Bruno Oliveira
f0e852b4db Merge pull request #2800 from blueyed/coverage
Travis: report coverage with all builds
2018-08-30 19:41:22 -03:00
dhirensr
ade01b1f5b T3853:Added changelog file 2018-08-30 16:03:18 +05:30
dhirensr
3035b2724d T3853:removed needless message printed with --failed-first,--last-failed and no failed tests 2018-08-30 16:01:42 +05:30
hoefling
8c96eea583 doc fix: raises accepts tuples instead of lists (fixes #3907) 2018-08-30 00:19:59 +02:00
Bruno Oliveira
338953a25d Merge pull request #3908 from nicoddemus/optimize-release
Skip the "test" stage when making a release
2018-08-29 18:53:36 -03:00
Anthony Sottile
f1bd46266b Merge pull request #3909 from asottile/update_release
Update release procedure
2018-08-29 14:37:52 -07:00
Anthony Sottile
77cad3c436 Update release procedure [ci skip] 2018-08-29 14:13:08 -07:00
Bruno Oliveira
3ca70692de Skip the "test" stage when making a release
Given that our guidelines demand that the CI have already passed, it seems
wasteful to run all those jobs again for the exact same commit.

As discussed in https://github.com/pytest-dev/pytest/pull/3906#issuecomment-417094481,
this will skip the "test" stage when building a tag for deployment.
2018-08-29 17:54:58 -03:00
Daniel Hahler
417516c378 squash! Travis: report coverage with all builds
doctesting: remove changedir

With coverage 5 we could use COVERAGE_RCFILE to make it find the
.coveragerc, or we could add `--rcfile` to _PYTEST_TOX_COVERAGE_RUN, but
I've thought that this should not be the job that has to test if
`--pyargs` actually works.
2018-08-29 22:53:20 +02:00
Daniel Hahler
f730291e67 Travis: report coverage with all builds
- Skips pypy for coverage, reports only py37 to coveralls
- tox: allow for TOXENV=py37-coverage
- tracks coverage in subprocesses, using coverage-enable-subprocess, and
  parallel=1
- removes usedevelop with doctesting to match `--source` being used with
  coverage
- keep coveralls for now, used with AppVeyor
2018-08-29 22:30:28 +02:00
Anthony Sottile
d76fb8345c Merge pull request #3906 from asottile/release-3.7.4
Preparing release version 3.7.4
2018-08-29 13:03:34 -07:00
Anthony Sottile
aea962dc21 Preparing release version 3.7.4 2018-08-29 08:57:54 -07:00
Bruno Oliveira
4345efaffc Merge pull request #3902 from stevepiercy/fix-pytest.org-links
Fix pytest.org links
2018-08-29 08:20:01 -03:00
Bruno Oliveira
bf47033169 Fix linting 2018-08-28 21:05:34 -03:00
Steve Piercy
37a65684d6 add changelog entry 2018-08-28 14:51:27 -07:00
Steve Piercy
eab5020e24 Fix hostname 2018-08-28 14:45:04 -07:00
Steve Piercy
8ef21f56d3 Fix 404 2018-08-28 14:42:16 -07:00
Steve Piercy
103d980b2d Use https, save a redirect 2018-08-28 14:41:13 -07:00
Steve Piercy
28c3ef1c77 Use https, save a redirect, fix hostname 2018-08-28 14:40:20 -07:00
Steve Piercy
67c3c28877 Use https, save a redirect 2018-08-28 14:39:32 -07:00
Steve Piercy
e040fd20a3 Use https, save a redirect 2018-08-28 14:38:55 -07:00
Steve Piercy
00e0b43010 Use https, save a redirect 2018-08-28 14:36:47 -07:00
Steve Piercy
f19cfbb825 Fix 404 to a somewhat better historical note 2018-08-28 14:35:08 -07:00
Steve Piercy
bde3d1a0cd Use https; save a redirect 2018-08-28 14:34:39 -07:00
Steve Piercy
2e090896d5 Use https 2018-08-28 14:34:22 -07:00
Steve Piercy
b0a32da0b5 Use https; save a redirect 2018-08-28 14:27:11 -07:00
Bruno Oliveira
10c1c7c41a Merge pull request #3895 from nicoddemus/issue-3506
Avoid possible infinite recursion when writing pyc files in assert rewrite
2018-08-28 18:16:10 -03:00
Daniel Hahler
16f452ef98 Merge pull request #3894 from blueyed/baseline
Travis: add baseline stage
2018-08-28 22:19:08 +02:00
Bruno Oliveira
b77e533693 Merge pull request #3893 from jirikuncar/3892-macos
travis: run tests on macOS
2018-08-28 17:06:17 -03:00
Bruno Oliveira
a605ad4d11 Merge pull request #3880 from jeffreyrack/3829-progress_display_mode
#3829 -- Add the ability to show test progress as number of tests completed instead of a percent.
2018-08-28 16:54:14 -03:00
Jeffrey Rackauckas
4b94760c8e Removed spacing in count display. 2018-08-27 20:23:17 -07:00
Bruno Oliveira
82a7ca9615 Avoid possible infinite recursion when writing pyc files in assert rewrite
What happens is that atomic_write on Python 2.7 on Windows will try
to convert the paths to unicode, but this triggers the import of
the encoding module for the file system codec, which in turn triggers
the rewrite, which in turn again tries to import the module, and so on.

This short-circuits the cases where we try to import another file when
writing a pyc file; I don't expect this to affect anything because
the only modules that could be affected are those imported by
atomic_writes.

Fix #3506
2018-08-27 21:29:45 -03:00
Bruno Oliveira
23295e1e98 Fix docs linting 2018-08-27 20:21:08 -03:00
Bruno Oliveira
32575f92c9 set TOXENV in test-macos template otherwise it will inherit "coveralls" 2018-08-27 20:07:51 -03:00
Bruno Oliveira
a260e58020 Drop 3.6 from OS-X to reduce build time 2018-08-27 20:03:12 -03:00
Bruno Oliveira
b2f7e02a02 Reorganize osx environments to avoid repetition as suggested in review 2018-08-27 20:02:16 -03:00
Bruno Oliveira
29e114b463 Try to fix test in MacOS-X 2018-08-27 19:27:51 -03:00
Bruno Oliveira
2a059b1c1b Merge pull request #3885 from nicoddemus/bad-output-classic
Fix bad console output when using console_output_style=classic
2018-08-27 19:07:02 -03:00
Daniel Hahler
cdc72bf5a3 Travis: add baseline stage
Fixes https://github.com/pytest-dev/pytest/issues/3876.
2018-08-27 23:46:24 +02:00
Jiri Kuncar
f786335dbb travis: run tests on macOS
closes #3892
2018-08-27 17:22:27 +02:00
Jiri Kuncar
ab5af524a4 Fix macOS specific code that uses capturemanager.
https://github.com/pytest-dev/pytest/issues/3888#issuecomment-416206606

closes #3888

Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
2018-08-27 16:07:59 +02:00
Bruno Oliveira
9620b167d9 Merge pull request #3887 from asottile/improve_test_code
Improve the coverage of testing/code
2018-08-27 07:20:45 -03:00
Jeffrey Rackauckas
8f4685e024 Move count display style to be part of console_output_style, fixed test progress for count console output style. 2018-08-26 19:21:00 -07:00
Anthony Sottile
10544c4cb8 Merge pull request #3886 from nicoddemus/ff-quiet
Cache now obeys -q when showing summary for --lf and --ff
2018-08-26 18:32:22 -07:00
Anthony Sottile
1e8e17c01e Improve the coverage of testing/code 2018-08-26 16:13:22 -07:00
Bruno Oliveira
80eef29681 Merge pull request #3884 from nicoddemus/merge-master-into-features
Merge master into features
2018-08-26 19:41:30 -03:00
Bruno Oliveira
47bb53f5cb Cache now obeys -q when showing summary for --lf and --ff
Related to #3853
2018-08-26 18:08:19 -03:00
Bruno Oliveira
6991a16edb Fix bad console output when using console_output_style=classic
Fix #3883
2018-08-26 17:12:55 -03:00
Bruno Oliveira
2f2d5861bb Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2018-08-26 16:45:00 -03:00
Bruno Oliveira
a31967431f Merge pull request #3882 from nicoddemus/release-3.7.3
Release 3.7.3
2018-08-26 16:41:40 -03:00
Bruno Oliveira
e74ad4ff9b Fix typo in CHANGELOG 2018-08-26 12:27:02 -03:00
Bruno Oliveira
70bdacf01a Fix collection example docs 2018-08-26 12:58:47 +00:00
Bruno Oliveira
b69f853acb Tweak CHANGELOG for 3.7.3 2018-08-26 09:46:46 -03:00
Bruno Oliveira
c31018d9bc Preparing release version 3.7.3 2018-08-26 12:43:43 +00:00
Bruno Oliveira
7ae23901d3 Merge pull request #3881 from GandalfSaxe/patch-2
Code block: :: missing and 4 spaces instead of 5
2018-08-26 09:22:30 -03:00
Bruno Oliveira
4d19b94347 Merge pull request #3877 from blueyed/codecov-master
tox: coveralls: also report to codecov
2018-08-26 09:19:03 -03:00
Bruno Oliveira
c15b537e3d Merge pull request #3878 from asottile/skip_install_linting
Use skip_install for testing tox env
2018-08-26 09:17:40 -03:00
Bruno Oliveira
2577a6ce8a Merge pull request #3873 from nicoddemus/sys-path-fix
Remove dangerous sys.path manipulations in test_pluginmanager
2018-08-26 08:53:57 -03:00
Bruno Oliveira
dd5f5ca4cb Merge pull request #3872 from nicoddemus/tests-in-init-files
Collect tests from __init__.py files if they match 'python_files'
2018-08-26 08:50:17 -03:00
Gandalf Saxe
508774742e Code block: :: missing and 4 spaces instead of 5
I just noticed the newly committed code block doesn't format as a code block without `::` in the paragraph before. Perhaps doesn't make a difference, but also corrected 5 spaces to 4 which seems standard.
2018-08-26 11:54:08 +02:00
Jeffrey Rackauckas
2a917a582e Removing accidental change to test 2018-08-25 22:21:50 -07:00
Jeffrey Rackauckas
325319dc3b Fixing xdist test to properly configure an ini file. 2018-08-25 22:18:29 -07:00
Jeffrey Rackauckas
dda5e5ea32 Fixing backticks in changelog file. 2018-08-25 21:55:00 -07:00
Jeffrey Rackauckas
5e260c4d34 Fixing changelog file. 2018-08-25 21:50:19 -07:00
Daniel Hahler
d3f5324386 tox: coveralls: also report to codecov
This is meant to get base coverage on master for codecov.
2018-08-26 02:14:22 +02:00
Anthony Sottile
3da88d794f Use skip_install for testing tox env 2018-08-25 16:48:01 -07:00
Bruno Oliveira
71b4995775 Merge pull request #3874 from blueyed/improve-pre-commit
Travis: use TOXENV=linting for linting stage
2018-08-25 20:14:27 -03:00
Bruno Oliveira
b0541e9d31 Correctly restore sys.path in test and remove dead code in test_pytester
The code in test_pytester has been refactored into a class right
above the dead code, and the code has been left there by mistake
apparently.
2018-08-25 18:17:52 -03:00
Daniel Hahler
415fcb912b Travis: use TOXENV=linting for linting stage
This will run it with `--show-diff-on-failure` then, and helps to keep
it in line / in a central place.
2018-08-25 23:14:09 +02:00
Bruno Oliveira
f872fcb5d0 Remove dangerous sys.path manipulations in test_pluginmanager
Noticed these while working in something else
2018-08-25 17:33:29 -03:00
Bruno Oliveira
de6f2c0336 Collect tests from __init__.py files if they match 'python_files'
Fix #3773
2018-08-25 11:18:52 -03:00
Bruno Oliveira
be4b359c74 Merge pull request #3861 from jonozzz/fix-3854
Fix #3854
2018-08-25 10:44:08 -03:00
Bruno Oliveira
72a58bbafe Merge pull request #3871 from schmamps/cmdclass
Correct cmdclass for doc: Good Integration Practices
2018-08-24 22:09:35 -03:00
turturica
c336449729 Make linting happy. Argh. 2018-08-24 18:05:35 -07:00
turturica
1e4ecda884 Fix the package fixture ordering in Windows. 2018-08-24 18:01:38 -07:00
turturica
8cf0e46bbf test_package_ordering: Collect *.py, but keep a mix of case for filenames. The test doesn't make sense for Windows, because of its case-insensitivity. 2018-08-24 16:23:50 -07:00
Bruno Oliveira
f0226e9329 Fix test_package_ordering on Windows 2018-08-24 20:15:33 -03:00
turturica
dce8df45d5 Added changelog items. 2018-08-24 15:51:42 -07:00
Andrew Champion
f6948597e4 add to changelog 2018-08-24 12:29:18 -07:00
turturica
e3df1031ca Add encoding: utf8 for python 2.7 2018-08-24 12:26:18 -07:00
Andrew Champion
14ffadf004 correct cmdclass 2018-08-24 12:07:22 -07:00
turturica
459b040d21 Fix dedent after merge. 2018-08-24 11:54:04 -07:00
turturica
3396225f74 Merge branch 'master' of github.com:pytest-dev/pytest into fix-3854 2018-08-24 11:47:24 -07:00
Bruno Oliveira
c82906105c Merge pull request #3865 from GandalfSaxe/patch-1
Move information on `pip install -e` to the top
2018-08-24 07:28:51 -03:00
Anthony Sottile
4c14740798 Merge pull request #3868 from asottile/bytes_py26_plus
Use `bytes` directly instead of `binary_type`
2018-08-23 23:16:59 -07:00
Jeffrey Rackauckas
5fefc48f33 Fixing pre-commit hooks 2018-08-23 23:00:02 -07:00
turturica
72e6482994 Make linting happy. 2018-08-23 22:58:36 -07:00
Jeffrey Rackauckas
93f783228c Add the progress_display_mode ini option 2018-08-23 22:56:25 -07:00
turturica
5f8b50c094 Address #3796 and add a test for it. 2018-08-23 22:48:44 -07:00
Anthony Sottile
99e31f6fb1 Use bytes directly instead of binary_type
`bytes` is an alias for `str` in python2.6+
2018-08-23 18:55:21 -07:00
Anthony Sottile
f2e35c8c4f Merge pull request #3859 from asottile/pyupgrade_1_4
Some pyupgrade 1.4.x changes
2018-08-23 18:32:53 -07:00
Bruno Oliveira
40b4fe64af Fix linting 2018-08-23 22:11:17 -03:00
Bruno Oliveira
d10d59c013 Merge pull request #3858 from mimi1vx/test_mock
Use unittest.mock if is only aviable
2018-08-23 19:02:39 -03:00
wim glenn
d54aa8ce13 Merge pull request #3848 from wimglenn/pytester_unicode_bugfixes
fixed a bunch of unicode bugs in pytester.py
2018-08-23 13:45:49 -05:00
Anthony Sottile
52fa8c98bb Merge pull request #3864 from asottile/source_to_dedent
Replace Source with dedent where possible
2018-08-23 10:45:11 -07:00
Gandalf Saxe
3f336869e2 Move information on pip install -e to the top
Should fix complaints in #2421.
2018-08-23 18:07:28 +02:00
Anthony Sottile
85482d575e Replace Source with dedent where possible 2018-08-23 09:06:17 -07:00
Bruno Oliveira
6f7365509d Merge pull request #3860 from asottile/purge_more_py
Purge more usage of `py` module
2018-08-23 06:05:32 -03:00
Anthony Sottile
7099ea9bb0 py.builtin._reraise -> six.reraise 2018-08-22 23:00:58 -07:00
Anthony Sottile
dccac69d82 py.builtin.text -> six.text_type 2018-08-22 23:00:06 -07:00
Anthony Sottile
c2cd337886 py.builtin.exec_ => six.exec_ 2018-08-22 23:00:06 -07:00
Anthony Sottile
0fc4a806e5 py.builtins._totext -> string literals or six.text_type 2018-08-22 23:00:04 -07:00
turturica
4d3c1ab4f0 Fixes #3854 2018-08-22 21:42:59 -07:00
turturica
e4f76f6350 Merge branch 'master' of github.com:pytest-dev/pytest into fix-3854 2018-08-22 20:36:52 -07:00
Anthony Sottile
0d65783dce Fix unicode errors when changing to .format(...) 2018-08-22 19:00:43 -07:00
Anthony Sottile
8bb8b91357 pyupgrade 1.4: tests 2018-08-22 18:47:21 -07:00
Bruno Oliveira
8804c7333a Fix CHANGELOG formatting 2018-08-22 20:06:13 -03:00
Bruno Oliveira
17eec5b97e Merge pull request #3856 from jennirinker/master
Resolving Issue #3824
2018-08-22 19:03:55 -03:00
Ondřej Súkup
cd07c4d4ff Use unittest.mock if is only aviable
from Python 3.3 is mock part of python standard library in unittest namespace
2018-08-22 23:49:40 +02:00
wim glenn
917b99e438 More unicode whack-a-mole
It seems pytest's very comprehensive CI sniffed out a few other places with similar bugs.  Ideally we should find all the places where args are not stringy and solve it at the source, but who knows how many people are relying on the implicit string conversion.  See [here](https://github.com/pytest-dev/pytest/blob/master/src/_pytest/config/__init__.py#L160-L166) for one such problem area (args with a single py.path.local instance is converted here, but a list or tuple containing some are not).
2018-08-22 13:40:21 -05:00
wim glenn
b08e156b79 strip trailing whitespace 2018-08-22 11:27:36 -05:00
wim glenn
8e2c7b4979 Add a failing testcase for PR #3848 2018-08-22 11:00:51 -05:00
Bruno Oliveira
5a7aa123ea Improve docs formatting 2018-08-22 11:22:30 -03:00
Jennifer Rinker
a12eadd9ef resolving Issue #3824 - expanding docs 2018-08-22 15:37:35 +02:00
Bruno Oliveira
2137e2b15b Merge pull request #3846 from nicoddemus/issue-3843
Fix collection error when tests is specified with --doctest-modules
2018-08-22 08:17:07 -03:00
wim glenn
89446af51e fixed a bunch of unicode bugs in pytester.py 2018-08-22 01:30:23 -05:00
Ronny Pfannschmidt
3b521bedf8 Merge pull request #3841 from sankt-petersbug/fix-3816
Fix '--show-capture=no' capture teardown logs
2018-08-22 07:16:53 +02:00
Ronny Pfannschmidt
5b2c8fa007 Merge pull request #3845 from natanlao/patch-1
Remove warning about #568 from documentation
2018-08-22 07:12:40 +02:00
Bruno Oliveira
eb8d145195 Add link to issue in the CHANGELOG entry 2018-08-21 21:08:21 -03:00
Natan Lao
80bea79512 Add changelog entry 2018-08-21 17:04:56 -07:00
Bruno Oliveira
07a560ff24 Fix collection error when tests is specified with --doctest-modules
The problem was that _matchnodes would receive two items: [DoctestModule, Module]. It would then collect the first one, *cache it*, and fail to match against the name in the command line. Next, it would reuse the cached item (DoctestModule) instead of collecting the Module which would eventually find the "test" name on it.

Added the type of the node to the cache key to avoid this problem, although I'm not a big fan of caches that have different key types.

Fix #3843
2018-08-21 21:02:46 -03:00
Natan Lao
717775a1c6 Remove warning about #568 from documentation
The documentation (https://docs.pytest.org/en/latest/skipping.html) references
issue #568, which has since been fixed.
2018-08-21 16:57:33 -07:00
Bruno Oliveira
672f4bb5aa Improve CHANGELOG 2018-08-21 20:19:48 -03:00
Bruno Oliveira
f1079a8222 Merge pull request #3832 from Sup3rGeo/bugfix/capsys-with-cli-logging
Bugfix/capsys with cli logging (again)
2018-08-21 20:12:31 -03:00
Bruno Oliveira
044d2b8e6e Merge pull request #3838 from wimglenn/runresult_xfail
Support xfailed and xpassed outcomes in RunResult.
2018-08-20 20:01:51 -03:00
Sankt Petersbug
223eef6261 Fix '--show-capture=no' capture teardown logs
Add a check before printing teardown logs.

'print_teardown_sections' method does not check '--show-capture' option
value, and teardown logs are always printed.

Resolves: #3816
2018-08-20 15:01:21 -05:00
Bruno Oliveira
43657f252f Merge pull request #3830 from nicoddemus/capfd-fixture-capture
Fixtures during teardown can use capsys and capfd to get output from tests
2018-08-20 15:32:45 -03:00
Victor
70ebab3537 Renamed snap_global_capture to read_global_capture. 2018-08-20 17:48:14 +02:00
Ronny Pfannschmidt
d3bdfc704b Merge pull request #3839 from asottile/more_flexible
Use more flexible `language_version: python3`
2018-08-20 16:13:31 +02:00
Anthony Sottile
4de247cfa0 Use more flexible language_version: python3 2018-08-20 06:27:35 -07:00
Victor
d611b03589 Parametrized tests for capfd as well. Separated global capture test. 2018-08-20 12:23:59 +02:00
Anthony Sottile
308d789d92 Merge pull request #3835 from wimglenn/issue3833
more autodocs for pytester
2018-08-20 00:30:28 -07:00
wim glenn
539a22c750 Added support for xfailed and xpassed outcomes to the `pytester.RunResult.assert_outcomes` signature. 2018-08-20 01:24:19 -05:00
wim glenn
e4bea9068b end of line for this file, perhaps? 2018-08-19 23:39:10 -05:00
wim glenn
e620798d33 more autodocs for pytester 2018-08-19 23:21:45 -05:00
victor
7ea4992f16 Fixed linting. 2018-08-19 15:46:02 +02:00
victor
0564b52c0e Fixed integration with other modules/tests 2018-08-19 15:26:57 +02:00
victor
8b2c91836b Fixed activation and used just runtest_protocol hook 2018-08-19 14:30:50 +02:00
victor
9e382e8d29 Fixed test. 2018-08-19 14:29:57 +02:00
victor
2255892d65 Improved test to cover more cases. 2018-08-19 13:44:12 +02:00
victor
7d9b198f73 Refactoring: Separated suspend from snapping (stopped always snapping when suspending - solves bug but still missing tests), reorganized functions and context managers. 2018-08-19 02:32:36 +02:00
Bruno Oliveira
a6cdd0d9da Merge pull request #3831 from nicoddemus/merge-master-into-features
Merge master into features
2018-08-18 19:43:36 -03:00
Bruno Oliveira
c64a8c9c7f Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2018-08-18 15:54:53 -03:00
Bruno Oliveira
f4c5994d27 Fixtures during teardown can use capsys and capfd to get output from tests
Fix #3033
2018-08-18 14:46:24 -03:00
Tyler Richard
c24c7e75e2 Added regression test for capfd in a fixture 2018-08-18 14:11:04 -03:00
Tyler Richard
273670b2a2 Fixes capfd so data is available after teardown. 2018-08-18 14:11:04 -03:00
Bruno Oliveira
28aff051ab Merge pull request #3822 from Sup3rGeo/bugfix/capsys-with-cli-logging
Bugfix/capsys with cli logging
2018-08-18 14:06:27 -03:00
Bruno Oliveira
29975e5b37 Merge pull request #3827 from Vlad-Shcherbina/funcfixtureinfo-type-hints
Replace broken type annotations with type comments
2018-08-18 12:54:47 -03:00
Bruno Oliveira
5cf7d1dba2 "suspend" method of capture fixture private
Also change the context-manager to global_and_fixture_disabled to
better convey its meaning
2018-08-18 11:38:08 -03:00
Bruno Oliveira
2fe824b8c4 Merge pull request #3821 from nicoddemus/release-3.7.2
Preparing release version 3.7.2
2018-08-18 11:18:18 -03:00
Bruno Oliveira
f674217c43 Moved dummy_context_manager to compat module 2018-08-18 11:15:58 -03:00
Bruno Oliveira
9f7345d663 Avoid leaving a reference to the last item on CaptureManager 2018-08-18 11:08:03 -03:00
victor
eb2d074530 Black changes. 2018-08-18 14:27:09 +02:00
victor
9fa7745795 Refactor, tests passing. 2018-08-18 13:40:08 +02:00
victor
14db2f91ba Fixed global not called if no capsys fixture. Using now capsys context manager as well. 2018-08-18 12:16:47 +02:00
Vlad Shcherbina
c3e494f6cf Replace broken type annotations with type comments
Fixes #3826.
2018-08-18 01:05:30 +03:00
Victor
090f67a980 Refactored implementation and updated tests. 2018-08-17 13:41:26 +02:00
Victor
3059bfb1b3 Update test with another problem. 2018-08-17 13:00:27 +02:00
Victor
e391c47ed8 Update capture suspend test for logging. 2018-08-17 00:44:15 +02:00
Victor
f66764e1c0 Added changelog and updated AUTHORS. 2018-08-17 00:33:56 +02:00
Bruno Oliveira
e0b088b52e Changelog tweaks 2018-08-16 19:32:41 -03:00
Bruno Oliveira
e5a3c870b4 Preparing release version 3.7.2 2018-08-16 22:29:00 +00:00
Victor
2b71cb9c38 Added activation/deactivation of capture fixture in logging emit. 2018-08-17 00:26:12 +02:00
Victor
da9d814da4 Added test. 2018-08-17 00:20:51 +02:00
Ronny Pfannschmidt
7d4c4c66d4 Merge pull request #3805 from asottile/cause_cycles
Fix traceback reporting for exceptions with `__cause__` cycles.
2018-08-16 07:16:51 +02:00
Ronny Pfannschmidt
939a792c41 Merge pull request #3798 from jonozzz/fix-3751
Fix #3751
2018-08-16 06:52:16 +02:00
Anthony Sottile
17644ff285 Fix traceback reporting for exceptions with __cause__ cycles. 2018-08-15 18:15:07 -07:00
Bruno Oliveira
64faa41d06 Merge pull request #3802 from jonozzz/fix-3768
Fix test collection from packages mixed with directories. #3768 and #3789
2018-08-15 21:42:25 -03:00
Anthony Sottile
ca1bb9a3a1 Merge pull request #3815 from sankt-petersbug/fix-3671
Fix #3671 - `filterwarnings` Is an Unregistered Marker
2018-08-15 17:07:46 -07:00
Sankt Petersbug
78ef531420 corrected the position of myname 2018-08-14 20:33:55 -05:00
Sankt Petersbug
212ee450b7 simplified test function 2018-08-14 20:29:42 -05:00
Sankt Petersbug
c1c08852f9 lint checks 2018-08-14 19:54:51 -05:00
Sankt Petersbug
e06a077ac2 added changelog 2018-08-14 16:16:37 -05:00
Sankt Petersbug
cb77e65c97 updated AUTHORS 2018-08-14 16:16:25 -05:00
Sankt Petersbug
6367f0f5f1 fix filterwarnings mark not registered 2018-08-14 16:13:15 -05:00
Daniel Hahler
b88e09a697 Merge pull request #3548 from blueyed/fix-docs
tox: clean up docs target
2018-08-14 15:22:46 +02:00
Ronny Pfannschmidt
68bbd42213 Merge pull request #3795 from nicoddemus/changelog-3774
Add CHANGELOG for issue #3774, missing from PR #3780
2018-08-14 09:32:20 +02:00
Ronny Pfannschmidt
22ee2093b8 Merge pull request #3801 from nicoddemus/improve-warning-addoption
Improve warning messages when addoption is called with string as `type`
2018-08-14 09:30:17 +02:00
Anthony Sottile
87a99275fb Merge pull request #3807 from anowlcalledjosh/metafunc-config-doc
Unhide documentation for metafunc.config
2018-08-13 15:32:43 -07:00
Josh Holland
abbd7c30a4 Unhide documentation for metafunc.config
Fixes #3746.
2018-08-11 20:48:55 +01:00
Bruno Oliveira
abae60c8d0 Add CHANGELOG entries 2018-08-10 22:04:42 -03:00
turturica
e92893ed24 Add test for packages mixed with modules. 2018-08-10 17:29:30 -07:00
Bruno Oliveira
27b5435a40 Fix docs formatting and improve test a bit 2018-08-10 18:19:07 -03:00
turturica
50db718a6a Add a test description. 2018-08-10 13:57:29 -07:00
turturica
bfd0addaeb Fix test collection from packages mixed with directories. #3768 and #3789 2018-08-10 12:56:08 -07:00
Bruno Oliveira
be11d3e195 Improve warning messages when addoption is called with string as type
Encountered the warning myself and to me the message was not clear about
what should be done to fix the warning
2018-08-10 12:49:06 -03:00
turturica
266f05c4c4 Fix #3751 2018-08-09 18:28:22 -07:00
turturica
d0bd01beca Collect any tests from a package's __init__.py 2018-08-09 18:06:38 -07:00
Bruno Oliveira
220288ac77 Add CHANGELOG for issue #3774, missing from PR #3780 2018-08-09 12:33:02 -03:00
Bruno Oliveira
4d8903fd0b Merge pull request #3780 from nicoddemus/mock-integration-fix
Fix issue where fixtures would lose the decorated functionality
2018-08-09 12:26:09 -03:00
Bruno Oliveira
67106f056b Use a custom holder class so we can be sure __pytest_wrapper__ was set by us 2018-08-09 09:22:00 -03:00
Ronny Pfannschmidt
5d3c5123f8 Merge pull request #3792 from decisio/pr-3788-fix-teardown-exception
Pr 3788 fix teardown exception
2018-08-09 06:53:22 +02:00
Bruno Oliveira
5f97711377 Merge pull request #3787 from hsoft/no-plugin-autoload
Add option to disable plugin auto-loading
2018-08-08 21:30:50 -03:00
Bruno Oliveira
74d9f56d0f Improve CHANGELOG a bit 2018-08-08 21:24:14 -03:00
Wes Thomas
051db6a33d Trimming Trailing Whitespace 2018-08-08 18:18:18 -05:00
Wes Thomas
aa358433b0 Fix AttributeError bug in TestCaseFunction.teardown by creating TestCaseFunction._testcase as attribute of class with a None default. 2018-08-08 18:13:21 -05:00
Virgil Dupras
126896f69d Add option to disable plugin auto-loading
If `PYTEST_DISABLE_PLUGIN_AUTOLOAD` is set, disable auto-loading of
plugins through setuptools entrypoints. Only plugins that have been
explicitly specified are loaded.

ref #3784.
2018-08-07 13:16:28 -04:00
Bruno Oliveira
e723069165 Merge pull request #3771 from nicoddemus/package-infinite-recursion-bug
Fix infinite recursion collection bug with pytest_ignore_collect hook
2018-08-06 10:09:31 -03:00
Bruno Oliveira
855fd17014 Merge pull request #3779 from nicoddemus/changelog-title
Add a changelog blurb and title, similar to tox
2018-08-05 18:03:57 -03:00
Bruno Oliveira
d11781920b Merge pull request #3782 from nicoddemus/pytest-non-functions
Only consider actual functions when collecting hooks
2018-08-05 09:07:01 -03:00
Bruno Oliveira
2c0d2eef40 Only consider actual functions when considering hooks
Fix #3775
2018-08-04 16:37:07 -03:00
Bruno Oliveira
ef8ec01e39 Fix issue where fixtures would lose the decorated functionality
Fix #3774
2018-08-04 15:14:00 -03:00
Bruno Oliveira
0a1c2a7ca1 Add a changelog blurb and title, similar to tox 2018-08-04 13:15:20 -03:00
Bruno Oliveira
fe0a76e1a6 Fix recursion bug if a pytest_ignore_collect returns False instead of None 2018-08-03 15:40:33 -03:00
Bruno Oliveira
dcafb8c48c Add example for package recursion bug 2018-08-03 15:40:33 -03:00
Bruno Oliveira
a76cc8f8c4 Add changelog for #3742
This was missing from PR #3751
2018-08-02 15:28:26 -03:00
Bruno Oliveira
4d2fa581e1 Merge pull request #3769 from nicoddemus/release-3.7.1
Preparing release version 3.7.1
2018-08-02 15:21:48 -03:00
Bruno Oliveira
f7a3f45a18 Preparing release version 3.7.1 2018-08-02 12:04:39 +00:00
Daniel Hahler
dff7b203f7 tox: clean up docs target 2018-08-02 13:07:03 +02:00
Anthony Sottile
4705fd2bbe Merge pull request #3765 from asottile/require_changelog_rst
Enforce that changelog files are .rst
2018-08-01 23:47:09 -07:00
Ronny Pfannschmidt
ca0476953e Merge pull request #3751 from nicoddemus/collect-file-bug
Workaround for #3742
2018-08-02 07:35:46 +02:00
Ronny Pfannschmidt
7e92930fa9 Merge pull request #3764 from asottile/fix_3763
Fix `TypeError` when the assertion message is `bytes` in python 3.
2018-08-02 07:19:51 +02:00
Ronny Pfannschmidt
33769d0328 Merge pull request #3754 from nicoddemus/fix-function-call-warning
Refactor direct fixture call warning to avoid incompatibility with plugins
2018-08-02 07:17:15 +02:00
Bruno Oliveira
5db2e6c7a1 Merge pull request #3761 from nicoddemus/numpy-recursion-error
Fix recursion in pytest.approx() with arrays in numpy<1.13
2018-08-01 23:40:30 -03:00
Bruno Oliveira
804fc4063a Merge pull request #3741 from kalekundert/approx_misc_tweaks
Miscellaneous improvements to approx()
2018-08-01 23:40:21 -03:00
Bruno Oliveira
82a2174867 Fix typo in CHANGELOG 2018-08-01 20:11:16 -03:00
Anthony Sottile
a80e031c62 Enforce that changelog files are .rst 2018-08-01 15:22:43 -07:00
Anthony Sottile
452e5c1cf0 Fix TypeError when the assertion message is bytes in python 3. 2018-08-01 15:09:25 -07:00
Bruno Oliveira
c6b11b9f62 Refactor direct fixture call warning to avoid incompatibility with plugins
This refactors the code so we have the real function object right during
collection. This avoids having to unwrap it later and lose attached information
such as "async" functions.

Fix #3747
2018-08-01 16:38:43 -03:00
Kale Kundert
b8255308d6 Make the infinite-recusrion fix more explicit.
So we remember what happened and don't accidentally regress in the
future.
2018-08-01 12:11:03 -07:00
Bruno Oliveira
a5c0fb7f6b Rename recursive_map -> _recursive_list_map as requested in review 2018-08-01 15:17:58 -03:00
Bruno Oliveira
f25683354e Merge pull request #3760 from RonnyPfannschmidt/fix-3757-pin-pathlib
fix #3757 by pinning to pathlib2 that supports __fspath__
2018-08-01 09:44:30 -03:00
Bruno Oliveira
7d13599ba1 Fix recursion in pytest.approx() with arrays in numpy<1.13 2018-08-01 08:04:09 -03:00
Bruno Oliveira
43664d7841 Use ids for parametrized values in test_expected_value_type_error 2018-08-01 07:34:08 -03:00
Bruno Oliveira
2a2f888909 Move recursive_map from local to free function 2018-08-01 07:30:40 -03:00
Bruno Oliveira
ad5ddaf55a Simplify is_numpy_array as suggested in review 2018-08-01 07:28:39 -03:00
Bruno Oliveira
4588130c1e Merge pull request #3756 from RonnyPfannschmidt/fix-3745
fix #3745 - display absolute cache_dir if necessary
2018-08-01 07:09:19 -03:00
Bruno Oliveira
5003bae0de Fix 'at' string for non-numeric messages in approx() 2018-08-01 07:07:37 -03:00
Bruno Oliveira
6e32a1f73d Use parametrize in repr test for nd arrays 2018-08-01 07:04:25 -03:00
Bruno Oliveira
611d254ed5 Improve error checking messages: add position and use pprint 2018-08-01 07:01:00 -03:00
Ronny Pfannschmidt
57a8f208bc fix #3757 by pinning to pathlib2 that supports __fspath__ 2018-08-01 11:45:39 +02:00
Ronny Pfannschmidt
fcdc1d867e fix #3745 - display absolute cache_dir if necessary 2018-08-01 08:25:37 +02:00
Bruno Oliveira
098dca3a9f Use {!r} for a few other messages as well 2018-07-31 21:14:51 -03:00
Bruno Oliveira
8e2ed76227 Create appropriate CHANGELOG entries 2018-07-31 21:11:26 -03:00
Bruno Oliveira
bf7c188cc0 Improve error message for invalid types passed to pytest.approx()
* Hide the internal traceback
* Use !r representation instead of !s (the default for {} formatting)
2018-07-31 21:08:24 -03:00
Bruno Oliveira
8c9efd8608 Only call _collectfile on package instances
As discussed in #3751, this feels like a hack, pushing it only so we can
see how it fares on CI and if there are better solutions out there
2018-07-31 19:06:30 -03:00
Bruno Oliveira
e1ad1a14af Add example script and failure for #3742 2018-07-31 17:50:55 -03:00
Kale Kundert
327fe4cfcc Update the changelog. 2018-07-31 11:40:02 -07:00
Kale Kundert
d02491931a Fix the unused import. 2018-07-31 11:33:46 -07:00
Kale Kundert
032db159c9 Let black reformat the code... 2018-07-31 11:23:23 -07:00
Kale Kundert
cd2085ee71 approx(): Detect type errors earlier. 2018-07-31 00:26:35 -07:00
Kale Kundert
ad305e71d7 Improve docstrings for Approx classes. 2018-07-30 23:26:57 -07:00
Kale Kundert
7d8688d54b Reflect dimension in approx repr for numpy arrays. 2018-07-30 23:23:17 -07:00
Bruno Oliveira
253419316c Merge pull request #3738 from nicoddemus/release-3.7.0
Release 3.7.0
2018-07-30 20:38:22 -03:00
Bruno Oliveira
997ef59306 Fix typos in CHANGELOG 2018-07-30 18:31:35 -03:00
Bruno Oliveira
60b1913ba2 Preparing release version 3.7.0 2018-07-30 20:14:42 +00:00
Bruno Oliveira
2c09930b6d Use proper quotes for python 3.7 on travis.yml 2018-07-30 20:13:17 +00:00
Bruno Oliveira
d461e931dd Use python 3.6 for regendoc 2018-07-30 20:12:52 +00:00
Bruno Oliveira
eada0b1fd7 Merge remote-tracking branch 'upstream/master' into release-3.7.0 2018-07-30 20:12:30 +00:00
Bruno Oliveira
150535b6c1 Merge pull request #3696 from abrammer/approx_numpy_tolerance_bugfix
bugfix in ApproxNumpy initialisation, use keywords for arguments to fix
2018-07-30 17:09:18 -03:00
Ronny Pfannschmidt
f1ec02cdcd Merge pull request #3733 from nicoddemus/py37
Test with Python 3.7 on Travis and AppVeyor
2018-07-30 20:02:03 +02:00
Ronny Pfannschmidt
9f5d73d44a Merge pull request #3735 from nicoddemus/deprecate-pytest-namespace
Deprecate pytest namespace
2018-07-30 19:55:45 +02:00
Bruno Oliveira
8609f8d25a Move warning definition to deprecated module 2018-07-30 14:25:29 -03:00
Bruno Oliveira
953a618102 Update CHANGELOG entry about pytest_namespace deprecation 2018-07-30 12:18:37 -03:00
Bruno Oliveira
cf6d8e7e53 Fix test and update warning in pytest_namespace docs 2018-07-30 12:16:42 -03:00
Bruno Oliveira
8af78f417f Merge pull request #3732 from nicoddemus/merge-master-into-features
Merge master into features
2018-07-30 07:26:19 -03:00
abrammer
535fd1f311 may as well include inf test while we're at it 2018-07-29 23:12:04 -04:00
abrammer
762eaf443a update changelog to include the addition of tests 2018-07-29 22:57:39 -04:00
abrammer
330640eb96 update tests to check tolerance args and expecing nan in numpy arrays 2018-07-29 22:47:38 -04:00
Bruno Oliveira
e3d412d1f4 Warn when implementations exist for pytest_namespace hook
This hook has been deprecated and will be removed in the future.

Fix #2639
2018-07-29 22:20:23 -03:00
Bruno Oliveira
6f9a12a8a3 Merge pull request #3486 from ammarnajjar/last-failed-no-failures_docs_correction
--last-failed-no-failures docs correction
2018-07-29 21:26:03 -03:00
Bruno Oliveira
0e47599572 Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2018-07-29 21:15:51 -03:00
Bruno Oliveira
c480223e88 Test with Python 3.7 on Travis and AppVeyor 2018-07-29 21:14:38 -03:00
Bruno Oliveira
0b522d40a7 Merge pull request #3734 from nicoddemus/fix-docs
Fix reference to _Result in docs
2018-07-29 21:14:09 -03:00
Bruno Oliveira
d900a6c8bd Merge pull request #3731 from asottile/pygrep_hooks
Use upstream rst-backticks hook
2018-07-29 20:52:28 -03:00
Bruno Oliveira
fe46fbb719 Fix reference to _Result in docs 2018-07-29 20:50:24 -03:00
Anthony Sottile
8d401cdb9d Use upstream rst-backticks hook 2018-07-29 15:46:06 -07:00
Bruno Oliveira
3f3f6f1be4 Merge pull request #3729 from nicoddemus/fix-changelog-titles
Fix "Pytest" to "pytest" in the CHANGELOG
2018-07-29 19:42:24 -03:00
Bruno Oliveira
b6da5cc54c Fix "Pytest" to "pytest" in the CHANGELOG
Now that we have fixed towncrier to render the proper title, seems fitting
to update the others
2018-07-28 12:57:18 -03:00
Bruno Oliveira
eaeeedc9c3 Merge pull request #3728 from nicoddemus/release-3.6.4
Release 3.6.4
2018-07-28 12:53:49 -03:00
Bruno Oliveira
317cd41215 Preparing release version 3.6.4 2018-07-28 12:59:04 +00:00
Bruno Oliveira
7f27512a48 Pin pluggy to <0.8 2018-07-28 09:46:35 -03:00
Kale Kundert
bf127a63b2 Need to iterate over the flattened array. 2018-07-27 11:24:42 -07:00
Bruno Oliveira
fe16f81da1 Merge pull request #3705 from nicoddemus/deprecate-call-fixture-func
Deprecate calling fixture functions directly
2018-07-27 15:09:09 -03:00
Bruno Oliveira
d0ba242c46 Implement change suggested by @kalekundert in PR 2018-07-27 15:07:20 -03:00
Bruno Oliveira
fe06be8590 Merge pull request #3723 from pytest-dev/nicoddemus-patch-1
Use "pytest" on the CHANGELOG
2018-07-27 10:23:11 -03:00
Bruno Oliveira
79b4ca92d8 Use "pytest" on the CHANGELOG 2018-07-27 09:21:18 -03:00
Bruno Oliveira
57b0c60cb4 Remove Testdir.run_example as recommended 2018-07-26 20:10:40 -03:00
Bruno Oliveira
6e57d123bb Mark test_idval_hypothesis as flaky on Windows (#3707) 2018-07-26 19:58:42 -03:00
Bruno Oliveira
011f88f7e7 Deprecate calling fixture functions directly
This will now issue a RemovedInPytest4Warning when the user calls
a fixture function directly, instead of requesting it from test
functions as is expected

Fix #3661
2018-07-26 19:58:42 -03:00
Bruno Oliveira
2eb9301ad5 Improve CHANGELOG 2018-07-25 08:09:31 -03:00
abrammer
f0db64ac2e drop the duplicate approx call
update test to include both np.array(actual) and np.array(expected)
2018-07-24 21:18:44 -04:00
abrammer
514ca6f4ad add test wrt #3695 checking numpy array tolerance args 2018-07-23 23:40:06 -04:00
Bruno Oliveira
b7419bd9bb Merge pull request #3710 from bmwiedemann/date
Do not claim copyright for future years
2018-07-23 11:14:39 -03:00
Bernhard M. Wiedemann
2e344d4d63 Do not claim copyright for future years
When building today's python-pytest-doc openSUSE package
in the year 2033, the documentation .html files state
Copyright 2015-2033 , holger krekel and pytest-dev team.

That cannot be correct, because nobody did anything copyright-worthy
for this file in 2033.

See also https://stackoverflow.com/questions/2390230/do-copyright-dates-need-to-be-updated

Additionally, this change makes the package build reproducible.
See https://reproducible-builds.org/ for why this is good.
2018-07-23 15:02:59 +02:00
Ronny Pfannschmidt
f8749eeb5c Merge pull request #3708 from nicoddemus/small-refactors
Small refactorings
2018-07-23 06:53:08 +02:00
Anthony Sottile
f76142508f Merge pull request #3694 from drewrisinger/patch-2
Fix mark.rst typos & grammar
2018-07-22 09:15:33 -07:00
Anthony Sottile
be2afb950a Merge pull request #3706 from ehershey/patch-1
typo - $PYTEST_ADDOTPS -> $PYTEST_ADDOPTS
2018-07-22 09:03:23 -07:00
E Hershey
19de1b7f29 typo - PYTEST_ADDOTPS -> PYTEST_ADDOPTS 2018-07-22 11:39:32 -04:00
Bruno Oliveira
f5165064ee Make yield_fixture just call fixture to do its work
Since fixture and yield_fixture are identical, they should call
the same code; as it was, the code inside them was already starting
to deviate.
2018-07-22 09:41:03 -03:00
Bruno Oliveira
c9a0881309 Isolate the code that resolves the fixturefunc to a separate function
pytest_fixture_setup was somewhat convoluted because it was trying
to do too many things.
2018-07-22 09:37:41 -03:00
Bruno Oliveira
5167933395 Move teardown code of yield fixtures to a partial to avoid leaks
As it were before, it was keeping a reference to fixturefunc and it
alive when an error occurred
2018-07-22 09:27:34 -03:00
Alan Brammer
75db608479 update changelog 2018-07-18 17:56:00 -04:00
Alan
7bff5866b1 bugfix in ApproxNumpy initialisation, use keywords for arguments now 2018-07-18 17:29:55 -04:00
Anthony Sottile
9720c3301a Merge pull request #3690 from drewrisinger/patch-1
Fix fixture.rst typos & grammar
2018-07-17 18:13:41 -07:00
Drew
254689ff83 Fix mark.rst typos & grammar
Fix minor typos
2018-07-17 11:19:40 -04:00
Drew
21f5222784 Fix fixture.rst spelling & grammar
Fix a few typos.
2018-07-17 10:53:57 -04:00
Bruno Oliveira
0bb29d5649 Merge pull request #3685 from nicoddemus/merge-master-into-features
Merge master into features
2018-07-15 16:53:39 -03:00
Bruno Oliveira
db33f03c15 Merge pull request #3681 from tadeoos/980-fix-truncated-locals-in-verbose
Fix truncated locals in verbose mode
2018-07-15 14:43:15 -03:00
Bruno Oliveira
ac9ceaacd8 Merge remote-tracking branch 'upstream/master' into merge-master-into-features 2018-07-15 11:54:14 -03:00
Bruno Oliveira
771d3e8f4f Merge pull request #3684 from Vlad-Shcherbina/type_comments
Replace broken type annotations with type comments
2018-07-15 11:52:12 -03:00
Bruno Oliveira
82a11e6207 Merge pull request #3680 from nicoddemus/labels
Manage GH labels using the new 'labels' tool
2018-07-15 11:34:20 -03:00
Bruno Oliveira
a1c3df1889 Merge pull request #3683 from caramelomartins/master
[#3402] CITATION
2018-07-15 11:33:06 -03:00
Bruno Oliveira
a821af6b1c Merge pull request #3682 from nicoddemus/tox-release
Revamp the release script: drop invoke and use tox directly
2018-07-15 11:32:20 -03:00
Tadek Teleżyński
d2fe619120 Fix truncated locals in verbose mode 2018-07-15 11:30:26 -03:00
Vlad Shcherbina
58e77f58bd Replace broken type annotations with type comments
Fixes #3635.
2018-07-15 16:58:39 +03:00
Hugo Martins
6a4fa4f485 Fix more linting issues 2018-07-14 16:44:47 +01:00
Hugo Martins
5be03bff61 Add changelog information 2018-07-14 16:37:55 +01:00
Hugo Martins
e9fd038aae Fix linting issues 2018-07-14 16:35:33 +01:00
Hugo Martins
a8464a95ce Add CITATION
Relates to #3402
2018-07-14 16:32:29 +01:00
Bruno Oliveira
a0b0c37feb Revamp the release script: drop invoke and use tox directly
Following the lead from tox, use a simple Python script instead of depending
on ``invoke``.

Other changes:

* Some colors using ``colorama``.
* Run ``pre-commit`` before the final commit to ensure everything is neatly
  formatted.
* Drop generating local tag: legacy from the time we used ``devpi`` as staging
  area, currently we no longer use it, and we should push a
  tag from the last HEAD of the PR always to ensure it is correct.
2018-07-14 11:35:37 -03:00
Bruno Oliveira
35ffd29404 Manage GH labels using the new 'labels' tool 2018-07-14 10:12:52 -03:00
Bruno Oliveira
0565a7a4e1 Merge pull request #3679 from nicoddemus/parametrized-internal-refactor
Refactor parametrize() code for readability
2018-07-12 21:31:06 -03:00
Bruno Oliveira
6c3713226c Merge pull request #3642 from caramelomartins/master
Fixes # 3592 - Clarify Fixtures' Documentation
2018-07-11 23:31:51 -03:00
Bruno Oliveira
f6ceedd15b Merge pull request #3636 from RonnyPfannschmidt/fixturetest-examples
[RFC] Fixturetest examples - move test contents to use example scripts for contents
2018-07-11 23:29:33 -03:00
Bruno Oliveira
3e599dc149 Check that param sets match number of args during _for_parametrize
It makes sense to validate them during creation of the parameter set
2018-07-11 22:57:53 -03:00
Bruno Oliveira
54fbc6f6e1 Refactor parametrize() code for readability
Extract the parametrize() block of code into methods for better
readability
2018-07-11 21:29:21 -03:00
Bruno Oliveira
aa47b64e2a Improve CHANGELOG entry 2018-07-11 21:07:21 -03:00
Bruno Oliveira
251adbf644 Merge with upstream/master 2018-07-11 20:46:14 -03:00
Bruno Oliveira
2c4759ce57 Run regendocs 2018-07-11 20:37:50 -03:00
Bruno Oliveira
4dfe2eee94 Fix finalize call 2018-07-11 20:24:39 -03:00
Bruno Oliveira
5226c7fac3 Merge pull request #3665 from nicoddemus/changelog-tweaks
Small tweaks to the changelog entries
2018-07-10 21:12:50 -03:00
Bruno Oliveira
593b451373 Merge pull request #3670 from asottile/remove_unused_fix_lint
Remove unused fix-lint tox environment
2018-07-10 19:08:31 -03:00
Anthony Sottile
898544e147 Merge pull request #3669 from asottile/yesqa
Remove some extraneous `# noqa` comments
2018-07-10 14:53:08 -07:00
Anthony Sottile
61301d934e Remove some extraneous # noqa comments
This was partially automated with https://github.com/asottile/yesqa

_with a few caveats_:
- it was run under python2 (chosen arbitrarily, when run under python3 other
  things were changed)
- I used `git checkout -p` to revert the removal of `noqa` comments from
  `cmp()` lines.
2018-07-08 17:05:52 -07:00
Anthony Sottile
af0059079c Remove unused fix-lint tox environment 2018-07-08 17:05:01 -07:00
Bruno Oliveira
9ef7878cbc Merge pull request #3668 from asottile/remove_obsolete_future_imports
Remove obsolete __future__ imports
2018-07-08 13:41:59 -03:00
Anthony Sottile
4ae93a7a07 Remove obsolete __future__ imports 2018-07-08 08:37:02 -07:00
Bruno Oliveira
d4faa4056b Merge pull request #3667 from asottile/avoid_sys_path_pollution_742
Use -mpytest when invoking pytest in pytester
2018-07-08 11:51:16 -03:00
Anthony Sottile
42bbb4fa8a Use -mpytest when invoking pytest in pytester 2018-07-07 17:18:44 -07:00
Bruno Oliveira
12c5b6104c Merge pull request #3666 from nicoddemus/deploy-on-tags
Skip deploy stage entirely unless we have a tag
2018-07-07 20:40:14 -03:00
Bruno Oliveira
aa9d1ad2eb Merge pull request #3663 from nicoddemus/usefixtures-reference
Add reference docs for pytest.mark.usefixtures
2018-07-07 12:12:31 -03:00
Bruno Oliveira
49e82a4be8 Skip deploy stage entirely unless we have a tag
Borrowed from https://github.com/tox-dev/tox/pull/877
2018-07-07 12:12:07 -03:00
Bruno Oliveira
803302e70c Fix end-of-line in 2220.bugfix.rst 2018-07-07 11:13:48 -03:00
Bruno Oliveira
05f1d0d3ef Update README for CHANGELOG about using multiple paragraphs 2018-07-07 11:07:13 -03:00
Bruno Oliveira
1cd62f8c38 Update CHANGELOG template to put issue links at the start of entries
This allows us to use the new multi-line entries available with
towncrier 18.6.0
2018-07-07 11:02:33 -03:00
Bruno Oliveira
a522fc745a Small tweaks to the changelog entries 2018-07-07 10:43:37 -03:00
Bruno Oliveira
303133f013 Merge pull request #3647 from jeffreyrack/3610-add-trace-option
3610 add trace option
2018-07-07 10:05:34 -03:00
Bruno Oliveira
d26a596072 Add a warning about usefixtures mark not working in fixtures
Fix #1014
2018-07-07 10:01:10 -03:00
Bruno Oliveira
f359b50fe5 Adjust copyright in README 2018-07-06 21:03:27 -03:00
Bruno Oliveira
18b2fc11ad Dummy change 2018-07-06 20:57:30 -03:00
Bruno Oliveira
d7b722e2ae Add reference docs for pytest.mark.usefixtures 2018-07-06 20:55:42 -03:00
Ronny Pfannschmidt
1e94ac784f Merge pull request #3389 from jonozzz/features
Add package scoped fixtures #2283
2018-07-06 11:42:36 +02:00
Bruno Oliveira
027d2336b8 Add minimal docs for package-scoped fixtures (experimental) 2018-07-05 21:56:31 -03:00
Bruno Oliveira
3c19370cec Merge remote-tracking branch 'upstream/features' into jonozzz/features 2018-07-05 18:15:17 -03:00
Bruno Oliveira
7e8f7bfa16 Merge pull request #3660 from asottile/code_highlight_fix
Correct code blocks in docs
2018-07-05 07:17:03 -03:00
Bruno Oliveira
3f5e06ecc4 Merge pull request #3659 from nicoddemus/merge-master-into-features
Merge master into features
2018-07-04 21:11:28 -03:00
Anthony Sottile
50f030d233 Correct code blocks in docs 2018-07-04 15:16:34 -07:00
Bruno Oliveira
7696d5371a Merge remote-tracking branch 'upstream/master' into features 2018-07-04 18:49:35 -03:00
Bruno Oliveira
b64c26674d Merge pull request #3656 from nicoddemus/release-3.6.3
Release 3.6.3
2018-07-04 18:45:45 -03:00
Bruno Oliveira
63b25304c3 Run pre-commit fixers 2018-07-03 22:20:29 -03:00
Bruno Oliveira
73d787df3a HOWTORELEASE: create branch first and run pre-commit after generate-release task
This makes more sense because we need to install from
tasks/requirements.txt
2018-07-03 22:15:23 -03:00
Bruno Oliveira
fa3161011a Improve CHANGELOG for 3.6.3 2018-07-03 22:07:51 -03:00
Bruno Oliveira
2921ca6e64 Run pre-commit on all doc files 2018-07-03 21:58:18 -03:00
Bruno Oliveira
43c0346d68 Preparing release version 3.6.3 2018-07-04 00:51:21 +00:00
Bruno Oliveira
3ed8e28ef3 Merge pull request #3654 from LeastAuthority/3653.deprecated-convert
Switch to new API
2018-07-03 21:46:26 -03:00
Bruno Oliveira
b84a646389 Add note to the changelog 2018-07-03 21:08:27 -03:00
Hugo Martins
8232fd1a2d Fix remaining "smtp" references 2018-07-03 23:24:59 +01:00
Hugo Martins
f52a5d3be2 Merge remote-tracking branch 'upstream/master' 2018-07-03 23:11:35 +01:00
Jean-Paul Calderone
b815f67e65 add changelog 2018-07-03 13:40:04 -04:00
Jean-Paul Calderone
55ebf261ce Switch to new API 2018-07-03 13:37:03 -04:00
Jeffrey Rackauckas
067de257e1 Fix test_pdb.py with pexpect 2018-07-02 21:03:21 -07:00
Jeffrey Rackauckas
4a925ef5e9 Fixing bug in test. 2018-07-02 20:29:59 -07:00
Jeffrey Rackauckas
4afb8c428b Fix python 2 issues 2018-07-02 20:20:42 -07:00
Jeffrey Rackauckas
2f1a2cf07f Fixing --trace test. 2018-07-02 19:55:08 -07:00
Jeffrey Rackauckas
6cc4fe2412 Fixing bad indentation 2018-07-02 19:53:46 -07:00
Jeffrey Rackauckas
10a8691eca Add support for yielded functions. 2018-07-02 19:46:26 -07:00
Jeffrey Rackauckas
b75320ba95 Fix --trace option with yield tests. 2018-07-02 19:08:41 -07:00
Bruno Oliveira
b50911285a Merge pull request #3648 from eelstork/patch-1
Fix monkeypatch doc
2018-07-02 10:34:05 -03:00
T.E.A de Souza
a43205b4bc Fix monkeypatch doc
`delenv` is incorrectly documented.
2018-07-02 21:01:41 +08:00
Jeffrey Rackauckas
bc268a58d1 Adding needed newline 2018-07-01 20:22:50 -07:00
Jeffrey Rackauckas
0b70477930 Fix linting issues. 2018-07-01 20:18:00 -07:00
Jeffrey Rackauckas
8801162275 Fixing tabbing in usage.rst. 2018-07-01 18:54:04 -07:00
Jeffrey Rackauckas
a604a71185 Fixing usage.rst title. 2018-07-01 18:53:18 -07:00
Jeffrey Rackauckas
66fa6bb42e Fix flake8 issues. 2018-07-01 18:50:57 -07:00
Jeffrey Rackauckas
713d32c4da Adding documentation for the --trace option. 2018-07-01 18:49:39 -07:00
Jeffrey Rackauckas
57198d477b Adding changelog entry for the --trace option. 2018-07-01 12:14:35 -07:00
Jeffrey Rackauckas
533f4cc10c Fix test to pass 2018-06-30 21:36:27 -07:00
Jeffrey Rackauckas
a46b94950c Properly set immediately_break value 2018-06-30 21:32:25 -07:00
Jeffrey Rackauckas
952bbefaac Add initial test. 2018-06-30 18:26:58 -07:00
Jeffrey Rackauckas
54d3cd587d Adding the --trace option. 2018-06-30 18:09:06 -07:00
Bruno Oliveira
2b75a311a7 Merge pull request #3637 from RonnyPfannschmidt/fix-3631
fix #3631 - don't store legacy markinfo when its impossible
2018-06-30 17:48:46 -03:00
Bruno Oliveira
26e1784e52 Merge pull request #3641 from Sup3rGeo/bugfix/logfile-unicode
Fixes #3630
2018-06-30 17:47:24 -03:00
victor
dad3e77319 Improve test readability. 2018-06-30 18:57:24 +02:00
Victor
3a1c15316b Updated test for python 2.7 2018-06-30 16:11:20 +02:00
Hugo Martins
f7c929c932 Fix linting errors in docs/fixtures.rst 2018-06-30 14:34:19 +01:00
Hugo Martins
b48f1d378b Clarify examples in fixtures' documentation 2018-06-30 02:01:49 +01:00
Victor
a6636fddcd Fixed open function with encoding in python 2.7 2018-06-29 17:04:30 +02:00
Victor
738933938a Added changelog. 2018-06-29 16:18:16 +02:00
Victor
342f2cdc17 Fixes #3630 2018-06-29 16:09:39 +02:00
Ronny Pfannschmidt
5bd5b8c68a fix #3631 - don't store legacy markinfo when its impossible 2018-06-29 14:01:20 +02:00
Ronny Pfannschmidt
0fd86ec8a8 move some fill fixture acceptance tests contents to the examples script folder 2018-06-29 10:58:33 +02:00
Ronny Pfannschmidt
4ae7e9788c fix quotes in scope order test 2018-06-29 07:13:18 +02:00
Ronny Pfannschmidt
5582ad0445 remove use of formatting in test_func_closure_module_auto
this makes it apparent that pytester should supply some kind of variable support
2018-06-29 07:07:03 +02:00
Ronny Pfannschmidt
982b614010 remove format calls for most fixture tests 2018-06-29 07:07:03 +02:00
Ronny Pfannschmidt
7845ab4bc3 remove test file formatting from TestContextManagerFixtureFuncs 2018-06-29 07:07:03 +02:00
Bruno Oliveira
8680dfc939 Merge pull request #3629 from egnartsms/issue-2220-param-breaks-dep
Make test parametrization override indirect fixtures
2018-06-28 21:43:21 -03:00
Serhii Mozghovyi
76ac670f7d Add changelog description 2018-06-28 23:42:18 +03:00
Bruno Oliveira
7b47dfb744 Merge pull request #3634 from RonnyPfannschmidt/merge-from-master
Merge from master
2018-06-28 14:05:18 -03:00
Ronny Pfannschmidt
3c73d6298a merge from master to features 2018-06-28 17:32:41 +02:00
Serhii Mozghovyi
c220fb235a Minor fix (code improvement) 2018-06-28 14:53:06 +03:00
Serhii Mozghovyi
1dc5e97ac2 Make test parametrization override indirect fixtures 2018-06-28 14:32:29 +03:00
Bruno Oliveira
e9371a58a0 Merge pull request #3622 from RonnyPfannschmidt/builtin-serialize
move report classes to own file to prepare for serialisazion
2018-06-27 15:17:09 -03:00
Bruno Oliveira
a48c47b53b Merge pull request #3624 from nicoddemus/skip-appveyor-tags
Skip AppVeyor builds on tag pushes
2018-06-27 12:12:21 -03:00
Bruno Oliveira
ea379ba10f Merge pull request #3623 from RonnyPfannschmidt/pytester-runexamples
Pytester runexamples
2018-06-27 09:13:29 -03:00
Bruno Oliveira
9a56bb05be Skip AppVeyor builds on tag pushes
We don't deploy anything on tags with AppVeyor, we use Travis instead, so we
might as well save resources
2018-06-27 08:28:34 -03:00
Ronny Pfannschmidt
17e01993d9 regendoc and invocation fixes 2018-06-27 08:28:21 +02:00
Ronny Pfannschmidt
8a6345515b regendoc 2018-06-27 06:52:54 +02:00
Ronny Pfannschmidt
581d49635e add docs and changelog 2018-06-27 06:52:36 +02:00
Bruno Oliveira
ef1b91ba87 Merge pull request #3606 from RonnyPfannschmidt/fix-3605
Fix 3605
2018-06-26 22:14:28 -03:00
Ronny Pfannschmidt
e860ff7299 port some acceptance tests over to copy_example 2018-06-26 22:59:40 +02:00
Ronny Pfannschmidt
0672bc633f enable pytester to run examples copied from the cwd 2018-06-26 22:48:33 +02:00
Ronny Pfannschmidt
2dfb52f7e0 fix rebase artifacts 2018-06-26 22:10:26 +02:00
Ronny Pfannschmidt
cc6eb9f83c move test reports to own file 2018-06-26 22:09:15 +02:00
Ronny Pfannschmidt
643e5a9c44 fix docs 2018-06-26 21:57:31 +02:00
Ronny Pfannschmidt
b8486037d3 fix #3605 - unpack markdecorators from parameterization 2018-06-26 21:57:31 +02:00
Ronny Pfannschmidt
78a82c05ef consistent failure on all python versions for test_markers_from_parametrize 2018-06-26 21:57:31 +02:00
Ronny Pfannschmidt
853975d93b add failing test for #3605 2018-06-26 21:57:31 +02:00
Ronny Pfannschmidt
6b239263da Merge pull request #3620 from RonnyPfannschmidt/merge-from-master
Merge from master
2018-06-26 21:56:09 +02:00
Ronny Pfannschmidt
89e0a3ec27 merge from master to features 2018-06-26 17:01:05 +02:00
Ronny Pfannschmidt
f93995e15c Merge pull request #3614 from asottile/upgrade_hooks
Upgrade hooks
2018-06-26 16:30:56 +02:00
Anthony Sottile
f940967e23 Fix test offset after black moved code 2018-06-26 06:35:48 -07:00
Anthony Sottile
cbaa7dd56a Upgrade pre-commit hooks except pyupgrade 2018-06-26 06:35:27 -07:00
Ronny Pfannschmidt
8133d1955e Merge pull request #3615 from marcelotrevisani/bug-3593-pytest-approx
Bug fix #3593 - approx repr in a 0-d numpy array
2018-06-26 13:04:23 +02:00
Bruno Oliveira
738b715655 Merge pull request #3619 from jdufresne/pypi
Update pypi.python.org URLs to pypi.org
2018-06-26 00:00:52 -03:00
Jon Dufresne
1d5316a28b Update pypi.python.org URLs to pypi.org
For details on the new PyPI, see the blog post:

https://pythoninsider.blogspot.ca/2018/04/new-pypi-launched-legacy-pypi-shutting.html
2018-06-25 18:08:49 -07:00
Marcelo Duarte Trevisani
0030ceb11c Bug fix #3593 - approx method in a single element of numpy array
If the user pass as a expected value a numpy array created like
numpy.array(5); it will creates an array with one element without shape,
when used with approx it will raise an error
'TypeError: iteration over a 0-d array'
2018-06-25 22:55:16 +02:00
Bruno Oliveira
5b186cd609 Merge pull request #3594 from pytest-dev/interal-pathlib
[WIP] port cache plugin internals to pathlib
2018-06-25 11:09:36 -03:00
Ronny Pfannschmidt
5a156b3645 disable pypy on windows until scandir works for it 2018-06-24 22:54:26 +02:00
Ronny Pfannschmidt
42b3125783 Merge pull request #3612 from mimi1vx/patch-1
Prefer unittest.mock before mock
2018-06-24 16:33:49 +02:00
Bruno Oliveira
50a0d4fa95 Merge pull request #3613 from asottile/module_spec_warnings
Fix `ImportWarning` triggered by explicit relative imports
2018-06-23 18:27:19 -03:00
Ondřej Súkup
deff54aae0 Try import mock, but on python 3.3+ can use also stdlib unittest.mock
From Python 3.3 is mock part of python standard library in unittest namespace
2018-06-23 23:27:07 +02:00
Anthony Sottile
22a2734d9a Merge pull request #3611 from AdamEr8/doc-fix-skipif
Doc Fix: skipif's example description
2018-06-23 14:06:30 -07:00
Anthony Sottile
17985b893d Remove warning filter as well 2018-06-23 10:22:09 -07:00
Anthony Sottile
1d55c49a9a Fix ImportWarning triggered by explicit relative imports 2018-06-23 07:55:49 -07:00
Ronny Pfannschmidt
95f00de0df use paths for config.cache.get key 2018-06-23 00:14:06 +02:00
Ronny Pfannschmidt
c4c666cbc4 use Pathlib instead of path splitting 2018-06-23 00:07:57 +02:00
Ronny Pfannschmidt
ee30bf45c9 rebase onto readme addition 2018-06-23 00:03:10 +02:00
Ronny Pfannschmidt
603df1ea1c whops, its supported starting with python 3.6, not python 3.5 2018-06-22 23:56:22 +02:00
Ronny Pfannschmidt
abbf73ad1a use pathlib2 up to python3.4 - damn the stdlib 2018-06-22 23:56:22 +02:00
Ronny Pfannschmidt
1226cdab47 fix warnings and json dumping of cacheprovider 2018-06-22 23:56:22 +02:00
Ronny Pfannschmidt
ab80e0fba0 sort compat flake8 mess correctly 2018-06-22 23:56:22 +02:00
Ronny Pfannschmidt
fb992a0c81 reorder attr.ib specs 2018-06-22 23:56:22 +02:00
Ronny Pfannschmidt
23581d44bd add missed file 2018-06-22 23:56:22 +02:00
Ronny Pfannschmidt
c7eb53317b port cache plugin internals to pathlib
warning logging got broken by detanglement from config
2018-06-22 23:56:22 +02:00
Bruno Oliveira
8cc210708c Improve changelog and change it to doc 2018-06-22 09:14:59 -03:00
Bruno Oliveira
4970f6d5c2 Improve reason in skipif example 2018-06-22 09:14:12 -03:00
AdamEr8
f883628939 Changelog mistake
Used pytest.fixture.skipif instead of pytest.mark.skipif
2018-06-22 08:51:26 +03:00
AdamEr8
40839b5a3a Rename prnum.trivial.rst to 3611.trivial.rst 2018-06-22 08:46:34 +03:00
AdamEr8
5e56d77542 Create prnum.trivial.rst
Added changelog file
2018-06-22 08:33:35 +03:00
Bruno Oliveira
de98939ebf Merge pull request #3608 from avirlrma/features
add reamde for .pytest_cache
2018-06-21 21:05:23 -03:00
Bruno Oliveira
0d3914b626 Remove extra '\' left at the end of a line in cache's readme contents 2018-06-21 20:12:50 -03:00
Bruno Oliveira
eb94bce3e2 Change 3519 to trivial 2018-06-21 20:11:22 -03:00
Bruno Oliveira
b897008887 Improve CHANGELOG grammar 2018-06-21 20:09:32 -03:00
Anthony Sottile
630428c611 Merge pull request #3609 from asottile/remove_warning_py2_functools_reduce
Silence usage of `reduce` warning in python 2
2018-06-21 15:08:31 -07:00
Anthony Sottile
8b4c59e606 Silence usage of reduce warning in python 2 2018-06-21 13:27:00 -07:00
avirlrma
998d540b73 fixed changelog entry 2018-06-21 17:56:26 +05:30
avirlrma
c672bfa32e added changelog entry
moved cache readme tests to test_cacheprovider.py
2018-06-21 17:43:10 +05:30
avirlrma
8f1d8ac970 fixed linting errors
ran black
removed unused imports and variables
2018-06-21 15:15:55 +05:30
AdamEr8
1ac1ee6fcb Fixed text description above skipif's example
@pytest.mark.skipif's example's description (above the code) was the opposite of the condition in the code,
fixed the description to match the code.
2018-06-21 12:09:56 +03:00
avirlrma
53d4710c62 added tests for .pytest_cache README
Helper class to check if readme exists in .pytest_cache directory
 Tests to check for readme when tests pass and when they fail
2018-06-21 14:25:00 +05:30
avirlrma
31f089db6a add reamde for .pytest_cache
method - `ensure_readme()`
2018-06-21 13:14:58 +05:30
Ronny Pfannschmidt
b7b9c54d27 Merge pull request #3603 from nicoddemus/fix-freeze-job
Fix reference to py36-freeze in travis and appveyor
2018-06-21 09:33:59 +02:00
Ronny Pfannschmidt
e86fe38144 Merge pull request #3598 from nicoddemus/small-callspec2-cleanup
Remove unused attribute and parameter in CallSpec2
2018-06-20 18:04:34 +02:00
Bruno Oliveira
5b26178397 Merge pull request #3602 from nicoddemus/release-3.6.2
Release 3.6.2
2018-06-20 08:12:43 -03:00
Bruno Oliveira
130100bba1 Fix reference to py36-freeze in travis and appveyor
Travis and AppVeyor were executing "py35-freeze", which does not actually
exist in tox.ini.
2018-06-20 07:53:41 -03:00
Bruno Oliveira
93e55ad2fa Remove unused attribute and parameter in CallSpec2 2018-06-18 21:48:49 -03:00
Bruno Oliveira
9d60cf25c0 Merge pull request #2207 from RonnyPfannschmidt/fix/519
add example scripts for issue #519
2018-06-15 15:05:18 -03:00
Bruno Oliveira
9e32b6ae48 Small typo and grammar fix 2018-06-15 15:05:00 -03:00
Ronny Pfannschmidt
99402cf1c0 add a readme to the example scripts 2018-06-15 20:02:01 +02:00
Ronny Pfannschmidt
3ac2ae3c8c black 2018-06-15 18:13:45 +02:00
Ronny Pfannschmidt
ea906056fa add the actually expected fixtureorder for #519 2018-06-15 18:04:24 +02:00
Ronny Pfannschmidt
c081c5ee23 add example scripts for issue #519 2018-06-15 18:04:24 +02:00
Bruno Oliveira
3dcdaab103 Merge pull request #3585 from wcooley/feature/3579-caplog-messages
Add `messages` property to `caplog` fixture.
2018-06-15 12:41:33 -03:00
Wil Cooley
3615977608 Add messages property to caplog fixture. 2018-06-14 12:22:33 -07:00
Bruno Oliveira
94c41bec64 Merge pull request #3576 from RonnyPfannschmidt/addmarker-api
fix addmarker - extract mark from markdecorator
2018-06-13 18:36:40 -03:00
Ronny Pfannschmidt
8d072205e9 fix whitespace 2018-06-13 22:00:22 +02:00
Bruno Oliveira
b5102d03a6 Fix add_marker docs 2018-06-13 14:57:10 -03:00
Ronny Pfannschmidt
791bb3502c changelog 2018-06-13 17:29:42 +02:00
Ronny Pfannschmidt
eb0c6a8287 fix addmarker - extract mark from markdecorator 2018-06-13 17:27:00 +02:00
Ammar Najjar
9ddd573774 Issue #3295: add changelog doc entry for adding a missing argument in
the examples
2018-05-17 23:11:37 +02:00
Ammar Najjar
f99da9058f Issue #3295: Correct the usage of --last-failed-no-failures documentation
- add the missing --last-failed argument in the presented examples, for they are missleading and lead to think that the missing argument is not needed.
2018-05-17 23:07:55 +02:00
turturica
7d0dba18de Removed _CompatProperty("Package") 2018-04-27 10:23:15 -07:00
turturica
6fc7f07a80 Workaround for py36-xdist failure. 2018-04-26 23:05:03 -07:00
turturica
05b5b64379 Merge remote-tracking branch 'upstream/features' into features 2018-04-25 21:20:39 -07:00
turturica
229c8e551d Fix parametrized fixtures reordering. 2018-04-25 18:44:54 -07:00
turturica
d483b401ee Merge remote-tracking branch 'upstream/features' into features 2018-04-24 13:45:10 -07:00
turturica
acacf75f49 Added another package-scoped fixture test.
Changed existing complex tests to use package fixtures.
2018-04-24 13:32:58 -07:00
turturica
f8350c6304 Fix an issue that popped up only on Windows. 2018-04-21 19:51:33 -07:00
turturica
fedc78522b Build a stack of all previous packages instead of just the one closest to the initial argument(s).
Address #3358 by caching nodes in a session dict.
2018-04-21 18:39:42 -07:00
turturica
b0474398ec Fix a formatting error. 2018-04-20 18:18:44 -07:00
turturica
dc90c9108f Collapse all parent nested package fixtures when pointing to a sub-node.
Example:
Given this hierarchy: p1.s1.s2.s3
I want to run pytest p1/s1/s2/s3/foo.py

If there are any package fixtures defined at p1..s2 levels, they should also be executed.
2018-04-20 17:15:09 -07:00
turturica
69031d0033 Forgot one file from previous commit. 2018-04-20 15:54:21 -07:00
turturica
e44d4e6508 Merge remote-tracking branch 'upstream/features' into features 2018-04-20 15:21:24 -07:00
turturica
c416b1d935 Don't stop at the first package when looking up package-scoped fixtures.
Example:
package1.subpackage1
package1.subpackage2

package1's setup/teardown were executed again when exiting subpackage1 and entering subpackage2.
2018-04-20 15:04:58 -07:00
turturica
7d923c389e Merge remote-tracking branch 'upstream/features' into features 2018-04-18 00:11:03 -07:00
turturica
c02e8d8b0d Fix test collection when tests are passed as IDs at the command line. Note this is still broken due to #3358. 2018-04-16 11:44:05 -07:00
turturica
35df2cdbee Fix linting error. 2018-04-11 15:45:43 -07:00
turturica
2b1410895e Add package scoped fixtures #2283 2018-04-11 15:39:42 -07:00
203 changed files with 7698 additions and 3300 deletions

View File

@@ -1,4 +1,9 @@
[run]
omit =
# standlonetemplate is read dynamically and tested by test_genscript
*standalonetemplate.py
source = pytest,_pytest,testing/
parallel = 1
branch = 1
[paths]
source = src/
.tox/*/lib/python*/site-packages/
.tox\*\Lib\site-packages\

2
.gitattributes vendored
View File

@@ -1 +1 @@
CHANGELOG merge=union
*.bat text eol=crlf

149
.github/labels.toml vendored Normal file
View File

@@ -0,0 +1,149 @@
["os: cygwin"]
color = "006b75"
description = "cygwin platform-specific problem"
name = "os: cygwin"
["os: linux"]
color = "1d76db"
description = "linux platform-specific problem"
name = "os: linux"
["os: mac"]
color = "bfdadc"
description = "mac platform-specific problem"
name = "os: mac"
["os: windows"]
color = "fbca04"
description = "windows platform-specific problem"
name = "os: windows"
["plugin: argcomplete"]
color = "d4c5f9"
description = "related to the argcomplete builtin plugin"
name = "plugin: argcomplete"
["plugin: cache"]
color = "c7def8"
description = "related to the cache builtin plugin"
name = "plugin: cache"
["plugin: capture"]
color = "1d76db"
description = "related to the capture builtin plugin"
name = "plugin: capture"
["plugin: debugging"]
color = "dd52a8"
description = "related to the debugging builtin plugin"
name = "plugin: debugging"
["plugin: doctests"]
color = "fad8c7"
description = "related to the doctests builtin plugin"
name = "plugin: doctests"
["plugin: junitxml"]
color = "c5def5"
description = "related to the junitxml builtin plugin"
name = "plugin: junitxml"
["plugin: logging"]
color = "ff5432"
description = "related to the logging builtin plugin"
name = "plugin: logging"
["plugin: monkeypatch"]
color = "0e8a16"
description = "related to the monkeypatch builtin plugin"
name = "plugin: monkeypatch"
["plugin: nose"]
color = "bfdadc"
description = "related to the nose integration builtin plugin"
name = "plugin: nose"
["plugin: pastebin"]
color = "bfd4f2"
description = "related to the pastebin builtin plugin"
name = "plugin: pastebin"
["plugin: pytester"]
color = "c5def5"
description = "related to the pytester builtin plugin"
name = "plugin: pytester"
["plugin: tmpdir"]
color = "bfd4f2"
description = "related to the tmpdir builtin plugin"
name = "plugin: tmpdir"
["plugin: unittest"]
color = "006b75"
description = "related to the unittest integration builtin plugin"
name = "plugin: unittest"
["plugin: warnings"]
color = "fef2c0"
description = "related to the warnings builtin plugin"
name = "plugin: warnings"
["plugin: xdist"]
color = "5319e7"
description = "related to the xdist external plugin"
name = "plugin: xdist"
["status: critical"]
color = "e11d21"
description = "grave problem or usability issue that affects lots of users"
name = "status: critical"
["status: easy"]
color = "bfe5bf"
description = "easy issue that is friendly to new contributor"
name = "status: easy"
["status: help wanted"]
color = "159818"
description = "developers would like help from experts on this topic"
name = "status: help wanted"
["status: needs information"]
color = "5319e7"
description = "reporter needs to provide more information; can be closed after 2 or more weeks of inactivity"
name = "status: needs information"
["topic: collection"]
color = "006b75"
description = "related to the collection phase"
name = "topic: collection"
["topic: config"]
color = "006b75"
description = "related to config handling, argument parsing and config file"
name = "topic: config"
["topic: fixtures"]
color = "5319e7"
description = "anything involving fixtures directly or indirectly"
name = "topic: fixtures"
["topic: marks"]
color = "b60205"
description = "related to marks, either the general marks or builtin"
name = "topic: marks"
["topic: parametrize"]
color = "fbca04"
description = "related to @pytest.mark.parametrize"
name = "topic: parametrize"
["topic: reporting"]
color = "fef2c0"
description = "related to terminal output and user-facing messages and errors"
name = "topic: reporting"
["topic: rewrite"]
color = "0e8a16"
description = "related to the assertion rewrite mechanism"
name = "topic: rewrite"

6
.gitignore vendored
View File

@@ -24,6 +24,7 @@ src/_pytest/_version.py
.eggs/
doc/*/_build
doc/*/.doctrees
build/
dist/
*.egg-info
@@ -35,6 +36,11 @@ env/
.cache
.pytest_cache
.coverage
.coverage.*
coverage.xml
.ropeproject
.idea
.hypothesis
.pydevproject
.project
.settings

View File

@@ -1,19 +1,19 @@
exclude: doc/en/example/py2py3/test_py2.py
repos:
- repo: https://github.com/ambv/black
rev: 18.4a4
rev: 18.6b4
hooks:
- id: black
args: [--safe, --quiet]
language_version: python3.6
language_version: python3
- repo: https://github.com/asottile/blacken-docs
rev: v0.1.1
rev: v0.2.0
hooks:
- id: blacken-docs
additional_dependencies: [black==18.5b1]
language_version: python3.6
additional_dependencies: [black==18.6b4]
language_version: python3
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v1.2.3
rev: v1.3.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
@@ -25,6 +25,10 @@ repos:
rev: v1.2.0
hooks:
- id: pyupgrade
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.0.0
hooks:
- id: rst-backticks
- repo: local
hooks:
- id: rst
@@ -33,4 +37,9 @@ repos:
files: ^(CHANGELOG.rst|HOWTORELEASE.rst|README.rst|changelog/.*)$
language: python
additional_dependencies: [pygments, restructuredtext_lint]
python_version: python3.6
- id: changelogs-rst
name: changelog filenames
language: fail
entry: 'changelog files must be named ####.(feature|bugfix|doc|removal|vendor|trivial).rst'
exclude: changelog/(\d+\.(feature|bugfix|doc|removal|vendor|trivial).rst|README.rst|_template.rst)
files: ^changelog/

View File

@@ -1,50 +1,71 @@
sudo: false
language: python
stages:
- linting
- test
- deploy
- baseline
- name: test
if: repo = pytest-dev/pytest AND tag IS NOT present
- name: deploy
if: repo = pytest-dev/pytest AND tag IS present
python:
- '3.6'
install:
- pip install --upgrade --pre tox
env:
matrix:
# coveralls is not listed in tox's envlist, but should run in travis
- TOXENV=coveralls
# note: please use "tox --listenvs" to populate the build matrix below
# please remove the linting env in all cases
- TOXENV=py27
- TOXENV=py34
- TOXENV=py36
- TOXENV=py27-pexpect
- TOXENV=py27-xdist
- TOXENV=py27-trial
- TOXENV=py27-numpy
- TOXENV=py27-pluggymaster
- TOXENV=py27-pluggymaster PYTEST_NO_COVERAGE=1
- TOXENV=py36-pexpect
- TOXENV=py36-xdist
- TOXENV=py36-trial
- TOXENV=py36-numpy
- TOXENV=py36-pluggymaster
- TOXENV=py36-pluggymaster PYTEST_NO_COVERAGE=1
- TOXENV=py27-nobyte
- TOXENV=doctesting
- TOXENV=docs
- TOXENV=docs PYTEST_NO_COVERAGE=1
jobs:
include:
- env: TOXENV=pypy
# Coverage tracking is slow with pypy, skip it.
- env: TOXENV=pypy PYTEST_NO_COVERAGE=1
python: 'pypy-5.4'
- env: TOXENV=py35
python: '3.5'
- env: TOXENV=py35-freeze
python: '3.5'
- env: TOXENV=py36-freeze PYTEST_NO_COVERAGE=1
python: '3.6'
- env: TOXENV=py37
python: 'nightly'
python: '3.7'
sudo: required
dist: xenial
- &test-macos
language: generic
os: osx
osx_image: xcode9.4
sudo: required
install:
- python -m pip install --pre tox
env: TOXENV=py27
- <<: *test-macos
env: TOXENV=py37
before_install:
- brew update
- brew upgrade python
- brew unlink python
- brew link python
- stage: baseline
env: TOXENV=py27
- env: TOXENV=py34
- env: TOXENV=py36
- env: TOXENV=linting PYTEST_NO_COVERAGE=1
- stage: deploy
python: '3.6'
env:
env: PYTEST_NO_COVERAGE=1
install: pip install -U setuptools setuptools_scm
script: skip
deploy:
@@ -57,17 +78,35 @@ jobs:
on:
tags: true
repo: pytest-dev/pytest
- stage: linting
python: '3.6'
env:
install:
- pip install pre-commit
- pre-commit install-hooks
script:
- pre-commit run --all-files
before_script:
- |
if [[ "$PYTEST_NO_COVERAGE" != 1 ]]; then
export COVERAGE_FILE="$PWD/.coverage"
export COVERAGE_PROCESS_START="$PWD/.coveragerc"
export _PYTEST_TOX_COVERAGE_RUN="coverage run -m"
export _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess
fi
script: tox --recreate
after_success:
- |
if [[ "$PYTEST_NO_COVERAGE" != 1 ]]; then
set -e
pip install coverage
coverage combine
coverage xml --ignore-errors
coverage report -m --ignore-errors
bash <(curl -s https://codecov.io/bash) -Z -X gcov -X coveragepy -X search -X xcode -X gcovout -X fix -f coverage.xml -F "${TOXENV//-/,},linux"
# Coveralls does not support merged reports.
if [[ "$TOXENV" = py37 ]]; then
pip install coveralls
coveralls
fi
fi
notifications:
irc:
channels:

20
AUTHORS
View File

@@ -10,6 +10,7 @@ Ahn Ki-Wook
Alan Velasco
Alexander Johnson
Alexei Kozlenok
Allan Feldman
Anatoly Bubenkoff
Anders Hovmöller
Andras Tim
@@ -46,7 +47,9 @@ Christian Boelsen
Christian Theunert
Christian Tismer
Christopher Gilling
CrazyMerlyn
Cyrus Maden
Dhiren Serai
Daniel Grana
Daniel Hahler
Daniel Nuri
@@ -71,6 +74,7 @@ Endre Galaczi
Eric Hunsberger
Eric Siegerman
Erik M. Bray
Fabio Zadrozny
Feng Ma
Florian Bruhin
Floris Bruynooghe
@@ -89,6 +93,8 @@ Hugo van Kemenade
Hui Wang (coldnight)
Ian Bicking
Ian Lesperance
Ionuț Turturică
Iwan Briquemont
Jaap Broekhuizen
Jan Balster
Janne Vanhala
@@ -97,6 +103,7 @@ Javier Domingo Cansino
Javier Romero
Jeff Rackauckas
Jeff Widman
Jenni Rinker
John Eddie Ayson
John Towler
Jon Sonesen
@@ -126,6 +133,7 @@ Maik Figura
Mandeep Bhutani
Manuel Krebber
Marc Schlaich
Marcelo Duarte Trevisani
Marcin Bachry
Mark Abramowitz
Markus Unterwaditzer
@@ -157,6 +165,7 @@ Oleg Sushchenko
Oliver Bestwalter
Omar Kohl
Omer Hadari
Ondřej Súkup
Patrick Hayes
Paweł Adamczak
Pedro Algarvio
@@ -171,6 +180,7 @@ Raphael Pierzina
Raquel Alegre
Ravi Chandra
Roberto Polli
Roland Puntaier
Romain Dorgueil
Roman Bolshakov
Ronny Pfannschmidt
@@ -179,7 +189,9 @@ Russel Winder
Ryan Wooden
Samuel Dion-Girardeau
Samuele Pedroni
Sankt Petersbug
Segev Finer
Serhii Mozghovyi
Simon Gomizelj
Skylar Downes
Srinivas Reddy Thatiparthy
@@ -188,6 +200,7 @@ Stefan Zimmermann
Stefano Taschini
Steffen Allner
Stephan Obermann
Tadek Teleżyński
Tarcisio Fischer
Tareq Alayan
Ted Xiao
@@ -200,14 +213,17 @@ Trevor Bekolay
Tyler Goodlet
Tzu-ping Chung
Vasily Kuznetsov
Victor Maryama
Victor Uriarte
Vidar T. Fauske
Virgil Dupras
Vitaly Lashmanov
Vlad Dragos
Wil Cooley
William Lee
Wim Glenn
Wouter van Ackooy
Xuan Luong
Xuecong Liao
Zac Hatfield-Dodds
Zoltán Máté
Roland Puntaier
Allan Feldman

View File

@@ -1,3 +1,13 @@
=================
Changelog history
=================
Versions follow `Semantic Versioning <https://semver.org/>`_ (``<major>.<minor>.<patch>``).
Backward incompatible (breaking) changes will only be introduced in major versions
with advance notice in the **Deprecations** section of releases.
..
You should *NOT* be adding new change log entries to this file, this
file is managed by towncrier. You *may* edit previous change logs to
@@ -8,7 +18,455 @@
.. towncrier release notes start
Pytest 3.6.2 (2018-06-20)
pytest 3.8.2 (2018-10-02)
=========================
Deprecations and Removals
-------------------------
- `#4036 <https://github.com/pytest-dev/pytest/issues/4036>`_: The ``item`` parameter of ``pytest_warning_captured`` hook is now documented as deprecated. We realized only after
the ``3.8`` release that this parameter is incompatible with ``pytest-xdist``.
Our policy is to not deprecate features during bugfix releases, but in this case we believe it makes sense as we are
only documenting it as deprecated, without issuing warnings which might potentially break test suites. This will get
the word out that hook implementers should not use this parameter at all.
In a future release ``item`` will always be ``None`` and will emit a proper warning when a hook implementation
makes use of it.
Bug Fixes
---------
- `#3539 <https://github.com/pytest-dev/pytest/issues/3539>`_: Fix reload on assertion rewritten modules.
- `#4034 <https://github.com/pytest-dev/pytest/issues/4034>`_: The ``.user_properties`` attribute of ``TestReport`` objects is a list
of (name, value) tuples, but could sometimes be instantiated as a tuple
of tuples. It is now always a list.
- `#4039 <https://github.com/pytest-dev/pytest/issues/4039>`_: No longer issue warnings about using ``pytest_plugins`` in non-top-level directories when using ``--pyargs``: the
current ``--pyargs`` mechanism is not reliable and might give false negatives.
- `#4040 <https://github.com/pytest-dev/pytest/issues/4040>`_: Exclude empty reports for passed tests when ``-rP`` option is used.
- `#4051 <https://github.com/pytest-dev/pytest/issues/4051>`_: Improve error message when an invalid Python expression is passed to the ``-m`` option.
- `#4056 <https://github.com/pytest-dev/pytest/issues/4056>`_: ``MonkeyPatch.setenv`` and ``MonkeyPatch.delenv`` issue a warning if the environment variable name is not ``str`` on Python 2.
In Python 2, adding ``unicode`` keys to ``os.environ`` causes problems with ``subprocess`` (and possible other modules),
making this a subtle bug specially susceptible when used with ``from __future__ import unicode_literals``.
Improved Documentation
----------------------
- `#3928 <https://github.com/pytest-dev/pytest/issues/3928>`_: Add possible values for fixture scope to docs.
pytest 3.8.1 (2018-09-22)
=========================
Bug Fixes
---------
- `#3286 <https://github.com/pytest-dev/pytest/issues/3286>`_: ``.pytest_cache`` directory is now automatically ignored by Git. Users who would like to contribute a solution for other SCMs please consult/comment on this issue.
- `#3749 <https://github.com/pytest-dev/pytest/issues/3749>`_: Fix the following error during collection of tests inside packages::
TypeError: object of type 'Package' has no len()
- `#3941 <https://github.com/pytest-dev/pytest/issues/3941>`_: Fix bug where indirect parametrization would consider the scope of all fixtures used by the test function to determine the parametrization scope, and not only the scope of the fixtures being parametrized.
- `#3973 <https://github.com/pytest-dev/pytest/issues/3973>`_: Fix crash of the assertion rewriter if a test changed the current working directory without restoring it afterwards.
- `#3998 <https://github.com/pytest-dev/pytest/issues/3998>`_: Fix issue that prevented some caplog properties (for example ``record_tuples``) from being available when entering the debugger with ``--pdb``.
- `#3999 <https://github.com/pytest-dev/pytest/issues/3999>`_: Fix ``UnicodeDecodeError`` in python2.x when a class returns a non-ascii binary ``__repr__`` in an assertion which also contains non-ascii text.
Improved Documentation
----------------------
- `#3996 <https://github.com/pytest-dev/pytest/issues/3996>`_: New `Deprecations and Removals <https://docs.pytest.org/en/latest/deprecations.html>`_ page shows all currently
deprecated features, the rationale to do so, and alternatives to update your code. It also list features removed
from pytest in past major releases to help those with ancient pytest versions to upgrade.
Trivial/Internal Changes
------------------------
- `#3955 <https://github.com/pytest-dev/pytest/issues/3955>`_: Improve pre-commit detection for changelog filenames
- `#3975 <https://github.com/pytest-dev/pytest/issues/3975>`_: Remove legacy code around im_func as that was python2 only
pytest 3.8.0 (2018-09-05)
=========================
Deprecations and Removals
-------------------------
- `#2452 <https://github.com/pytest-dev/pytest/issues/2452>`_: ``Config.warn`` and ``Node.warn`` have been
deprecated, see `<https://docs.pytest.org/en/latest/deprecations.html#config-warn-and-node-warn>`_ for rationale and
examples.
- `#3936 <https://github.com/pytest-dev/pytest/issues/3936>`_: ``@pytest.mark.filterwarnings`` second parameter is no longer regex-escaped,
making it possible to actually use regular expressions to check the warning message.
**Note**: regex-escaping the match string was an implementation oversight that might break test suites which depend
on the old behavior.
Features
--------
- `#2452 <https://github.com/pytest-dev/pytest/issues/2452>`_: Internal pytest warnings are now issued using the standard ``warnings`` module, making it possible to use
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.
- `#2908 <https://github.com/pytest-dev/pytest/issues/2908>`_: ``DeprecationWarning`` and ``PendingDeprecationWarning`` are now shown by default if no other warning filter is
configured. This makes pytest more compliant with
`PEP-0506 <https://www.python.org/dev/peps/pep-0565/#recommended-filter-settings-for-test-runners>`_. See
`the docs <https://docs.pytest.org/en/latest/warnings.html#deprecationwarning-and-pendingdeprecationwarning>`_ for
more info.
- `#3251 <https://github.com/pytest-dev/pytest/issues/3251>`_: Warnings are now captured and displayed during test collection.
- `#3784 <https://github.com/pytest-dev/pytest/issues/3784>`_: ``PYTEST_DISABLE_PLUGIN_AUTOLOAD`` environment variable disables plugin auto-loading when set.
- `#3829 <https://github.com/pytest-dev/pytest/issues/3829>`_: Added the ``count`` option to ``console_output_style`` to enable displaying the progress as a count instead of a percentage.
- `#3837 <https://github.com/pytest-dev/pytest/issues/3837>`_: Added support for 'xfailed' and 'xpassed' outcomes to the ``pytester.RunResult.assert_outcomes`` signature.
Bug Fixes
---------
- `#3911 <https://github.com/pytest-dev/pytest/issues/3911>`_: Terminal writer now takes into account unicode character width when writing out progress.
- `#3913 <https://github.com/pytest-dev/pytest/issues/3913>`_: Pytest now returns with correct exit code (EXIT_USAGEERROR, 4) when called with unknown arguments.
- `#3918 <https://github.com/pytest-dev/pytest/issues/3918>`_: Improve performance of assertion rewriting.
Improved Documentation
----------------------
- `#3566 <https://github.com/pytest-dev/pytest/issues/3566>`_: Added a blurb in usage.rst for the usage of -r flag which is used to show an extra test summary info.
- `#3907 <https://github.com/pytest-dev/pytest/issues/3907>`_: Corrected type of the exceptions collection passed to ``xfail``: ``raises`` argument accepts a ``tuple`` instead of ``list``.
Trivial/Internal Changes
------------------------
- `#3853 <https://github.com/pytest-dev/pytest/issues/3853>`_: Removed ``"run all (no recorded failures)"`` message printed with ``--failed-first`` and ``--last-failed`` when there are no failed tests.
pytest 3.7.4 (2018-08-29)
=========================
Bug Fixes
---------
- `#3506 <https://github.com/pytest-dev/pytest/issues/3506>`_: Fix possible infinite recursion when writing ``.pyc`` files.
- `#3853 <https://github.com/pytest-dev/pytest/issues/3853>`_: Cache plugin now obeys the ``-q`` flag when ``--last-failed`` and ``--failed-first`` flags are used.
- `#3883 <https://github.com/pytest-dev/pytest/issues/3883>`_: Fix bad console output when using ``console_output_style=classic``.
- `#3888 <https://github.com/pytest-dev/pytest/issues/3888>`_: Fix macOS specific code using ``capturemanager`` plugin in doctests.
Improved Documentation
----------------------
- `#3902 <https://github.com/pytest-dev/pytest/issues/3902>`_: Fix pytest.org links
pytest 3.7.3 (2018-08-26)
=========================
Bug Fixes
---------
- `#3033 <https://github.com/pytest-dev/pytest/issues/3033>`_: Fixtures during teardown can again use ``capsys`` and ``capfd`` to inspect output captured during tests.
- `#3773 <https://github.com/pytest-dev/pytest/issues/3773>`_: Fix collection of tests from ``__init__.py`` files if they match the ``python_files`` configuration option.
- `#3796 <https://github.com/pytest-dev/pytest/issues/3796>`_: Fix issue where teardown of fixtures of consecutive sub-packages were executed once, at the end of the outer
package.
- `#3816 <https://github.com/pytest-dev/pytest/issues/3816>`_: Fix bug where ``--show-capture=no`` option would still show logs printed during fixture teardown.
- `#3819 <https://github.com/pytest-dev/pytest/issues/3819>`_: Fix ``stdout/stderr`` not getting captured when real-time cli logging is active.
- `#3843 <https://github.com/pytest-dev/pytest/issues/3843>`_: Fix collection error when specifying test functions directly in the command line using ``test.py::test`` syntax together with ``--doctest-modules``.
- `#3848 <https://github.com/pytest-dev/pytest/issues/3848>`_: Fix bugs where unicode arguments could not be passed to ``testdir.runpytest`` on Python 2.
- `#3854 <https://github.com/pytest-dev/pytest/issues/3854>`_: Fix double collection of tests within packages when the filename starts with a capital letter.
Improved Documentation
----------------------
- `#3824 <https://github.com/pytest-dev/pytest/issues/3824>`_: Added example for multiple glob pattern matches in ``python_files``.
- `#3833 <https://github.com/pytest-dev/pytest/issues/3833>`_: Added missing docs for ``pytester.Testdir``.
- `#3870 <https://github.com/pytest-dev/pytest/issues/3870>`_: Correct documentation for setuptools integration.
Trivial/Internal Changes
------------------------
- `#3826 <https://github.com/pytest-dev/pytest/issues/3826>`_: Replace broken type annotations with type comments.
- `#3845 <https://github.com/pytest-dev/pytest/issues/3845>`_: Remove a reference to issue `#568 <https://github.com/pytest-dev/pytest/issues/568>`_ from the documentation, which has since been
fixed.
pytest 3.7.2 (2018-08-16)
=========================
Bug Fixes
---------
- `#3671 <https://github.com/pytest-dev/pytest/issues/3671>`_: Fix ``filterwarnings`` not being registered as a builtin mark.
- `#3768 <https://github.com/pytest-dev/pytest/issues/3768>`_, `#3789 <https://github.com/pytest-dev/pytest/issues/3789>`_: Fix test collection from packages mixed with normal directories.
- `#3771 <https://github.com/pytest-dev/pytest/issues/3771>`_: Fix infinite recursion during collection if a ``pytest_ignore_collect`` hook returns ``False`` instead of ``None``.
- `#3774 <https://github.com/pytest-dev/pytest/issues/3774>`_: Fix bug where decorated fixtures would lose functionality (for example ``@mock.patch``).
- `#3775 <https://github.com/pytest-dev/pytest/issues/3775>`_: Fix bug where importing modules or other objects with prefix ``pytest_`` prefix would raise a ``PluginValidationError``.
- `#3788 <https://github.com/pytest-dev/pytest/issues/3788>`_: Fix ``AttributeError`` during teardown of ``TestCase`` subclasses which raise an exception during ``__init__``.
- `#3804 <https://github.com/pytest-dev/pytest/issues/3804>`_: Fix traceback reporting for exceptions with ``__cause__`` cycles.
Improved Documentation
----------------------
- `#3746 <https://github.com/pytest-dev/pytest/issues/3746>`_: Add documentation for ``metafunc.config`` that had been mistakenly hidden.
pytest 3.7.1 (2018-08-02)
=========================
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()``.
- `#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'``.
- `#3745 <https://github.com/pytest-dev/pytest/issues/3745>`_: Display the absolute path if ``cache_dir`` is not relative to the ``rootdir`` instead of failing.
- `#3747 <https://github.com/pytest-dev/pytest/issues/3747>`_: Fix compatibility problem with plugins and the warning code issued by fixture functions when they are called directly.
- `#3748 <https://github.com/pytest-dev/pytest/issues/3748>`_: Fix infinite recursion in ``pytest.approx`` with arrays in ``numpy<1.13``.
- `#3757 <https://github.com/pytest-dev/pytest/issues/3757>`_: Pin pathlib2 to ``>=2.2.0`` as we require ``__fspath__`` support.
- `#3763 <https://github.com/pytest-dev/pytest/issues/3763>`_: Fix ``TypeError`` when the assertion message is ``bytes`` in python 3.
pytest 3.7.0 (2018-07-30)
=========================
Deprecations and Removals
-------------------------
- `#2639 <https://github.com/pytest-dev/pytest/issues/2639>`_: ``pytest_namespace`` has been `deprecated <https://docs.pytest.org/en/latest/deprecations.html#pytest-namespace>`_.
- `#3661 <https://github.com/pytest-dev/pytest/issues/3661>`_: Calling a fixture function directly, as opposed to request them in a test function, now issues a ``RemovedInPytest4Warning``. See `the documentation for rationale and examples <https://docs.pytest.org/en/latest/deprecations.html#calling-fixtures-directly>`_.
Features
--------
- `#2283 <https://github.com/pytest-dev/pytest/issues/2283>`_: New ``package`` fixture scope: fixtures are finalized when the last test of a *package* finishes. This feature is considered **experimental**, so use it sparingly.
- `#3576 <https://github.com/pytest-dev/pytest/issues/3576>`_: ``Node.add_marker`` now supports an ``append=True/False`` parameter to determine whether the mark comes last (default) or first.
- `#3579 <https://github.com/pytest-dev/pytest/issues/3579>`_: Fixture ``caplog`` now has a ``messages`` property, providing convenient access to the format-interpolated log messages without the extra data provided by the formatter/handler.
- `#3610 <https://github.com/pytest-dev/pytest/issues/3610>`_: New ``--trace`` option to enter the debugger at the start of a test.
- `#3623 <https://github.com/pytest-dev/pytest/issues/3623>`_: Introduce ``pytester.copy_example`` as helper to do acceptance tests against examples from the project.
Bug Fixes
---------
- `#2220 <https://github.com/pytest-dev/pytest/issues/2220>`_: Fix a bug where fixtures overridden by direct parameters (for example parametrization) were being instantiated even if they were not being used by a test.
- `#3695 <https://github.com/pytest-dev/pytest/issues/3695>`_: Fix ``ApproxNumpy`` initialisation argument mixup, ``abs`` and ``rel`` tolerances were flipped causing strange comparsion results.
Add tests to check ``abs`` and ``rel`` tolerances for ``np.array`` and test for expecting ``nan`` with ``np.array()``
- `#980 <https://github.com/pytest-dev/pytest/issues/980>`_: Fix truncated locals output in verbose mode.
Improved Documentation
----------------------
- `#3295 <https://github.com/pytest-dev/pytest/issues/3295>`_: Correct the usage documentation of ``--last-failed-no-failures`` by adding the missing ``--last-failed`` argument in the presented examples, because they are misleading and lead to think that the missing argument is not needed.
Trivial/Internal Changes
------------------------
- `#3519 <https://github.com/pytest-dev/pytest/issues/3519>`_: Now a ``README.md`` file is created in ``.pytest_cache`` to make it clear why the directory exists.
pytest 3.6.4 (2018-07-28)
=========================
Bug Fixes
---------
- Invoke pytest using ``-mpytest`` so ``sys.path`` does not get polluted by packages installed in ``site-packages``. (`#742 <https://github.com/pytest-dev/pytest/issues/742>`_)
Improved Documentation
----------------------
- Use ``smtp_connection`` instead of ``smtp`` in fixtures documentation to avoid possible confusion. (`#3592 <https://github.com/pytest-dev/pytest/issues/3592>`_)
Trivial/Internal Changes
------------------------
- Remove obsolete ``__future__`` imports. (`#2319 <https://github.com/pytest-dev/pytest/issues/2319>`_)
- Add CITATION to provide information on how to formally cite pytest. (`#3402 <https://github.com/pytest-dev/pytest/issues/3402>`_)
- Replace broken type annotations with type comments. (`#3635 <https://github.com/pytest-dev/pytest/issues/3635>`_)
- Pin ``pluggy`` to ``<0.8``. (`#3727 <https://github.com/pytest-dev/pytest/issues/3727>`_)
pytest 3.6.3 (2018-07-04)
=========================
Bug Fixes
---------
- Fix ``ImportWarning`` triggered by explicit relative imports in
assertion-rewritten package modules. (`#3061
<https://github.com/pytest-dev/pytest/issues/3061>`_)
- Fix error in ``pytest.approx`` when dealing with 0-dimension numpy
arrays. (`#3593 <https://github.com/pytest-dev/pytest/issues/3593>`_)
- No longer raise ``ValueError`` when using the ``get_marker`` API. (`#3605
<https://github.com/pytest-dev/pytest/issues/3605>`_)
- Fix problem where log messages with non-ascii characters would not
appear in the output log file.
(`#3630 <https://github.com/pytest-dev/pytest/issues/3630>`_)
- No longer raise ``AttributeError`` when legacy marks can't be stored in
functions. (`#3631 <https://github.com/pytest-dev/pytest/issues/3631>`_)
Improved Documentation
----------------------
- The description above the example for ``@pytest.mark.skipif`` now better
matches the code. (`#3611
<https://github.com/pytest-dev/pytest/issues/3611>`_)
Trivial/Internal Changes
------------------------
- Internal refactoring: removed unused ``CallSpec2tox ._globalid_args``
attribute and ``metafunc`` parameter from ``CallSpec2.copy()``. (`#3598
<https://github.com/pytest-dev/pytest/issues/3598>`_)
- Silence usage of ``reduce`` warning in Python 2 (`#3609
<https://github.com/pytest-dev/pytest/issues/3609>`_)
- Fix usage of ``attr.ib`` deprecated ``convert`` parameter. (`#3653
<https://github.com/pytest-dev/pytest/issues/3653>`_)
pytest 3.6.2 (2018-06-20)
=========================
Bug Fixes
@@ -26,7 +484,7 @@ Bug Fixes
raises an exception. (`#3569
<https://github.com/pytest-dev/pytest/issues/3569>`_)
- Fix encoding error with `print` statements in doctests (`#3583
- Fix encoding error with ``print`` statements in doctests (`#3583
<https://github.com/pytest-dev/pytest/issues/3583>`_)
@@ -54,7 +512,7 @@ Trivial/Internal Changes
<https://github.com/pytest-dev/pytest/issues/3567>`_)
Pytest 3.6.1 (2018-06-05)
pytest 3.6.1 (2018-06-05)
=========================
Bug Fixes
@@ -98,7 +556,7 @@ Trivial/Internal Changes
<https://github.com/pytest-dev/pytest/issues/3529>`_)
Pytest 3.6.0 (2018-05-23)
pytest 3.6.0 (2018-05-23)
=========================
Features
@@ -184,7 +642,7 @@ Trivial/Internal Changes
3.7 or newer. (`#3497 <https://github.com/pytest-dev/pytest/issues/3497>`_)
Pytest 3.5.1 (2018-04-23)
pytest 3.5.1 (2018-04-23)
=========================
@@ -236,7 +694,7 @@ Trivial/Internal Changes
<https://github.com/pytest-dev/pytest/issues/3398>`_)
Pytest 3.5.0 (2018-03-21)
pytest 3.5.0 (2018-03-21)
=========================
Deprecations and Removals
@@ -247,7 +705,7 @@ Deprecations and Removals
<https://github.com/pytest-dev/pytest/issues/2770>`_)
- Defining ``pytest_plugins`` is now deprecated in non-top-level conftest.py
files, because they "leak" to the entire directory tree. (`#3084
files, because they "leak" to the entire directory tree. `See the docs <https://docs.pytest.org/en/latest/deprecations.html#pytest-plugins-in-non-top-level-conftest-files>`_ for the rationale behind this decision (`#3084
<https://github.com/pytest-dev/pytest/issues/3084>`_)
@@ -299,7 +757,7 @@ Features
``pytest_runtest_logfinish`` hooks when live logs are enabled. (`#3189
<https://github.com/pytest-dev/pytest/issues/3189>`_)
- Passing `--log-cli-level` in the command-line now automatically activates
- Passing ``--log-cli-level`` in the command-line now automatically activates
live logging. (`#3190 <https://github.com/pytest-dev/pytest/issues/3190>`_)
- Add command line option ``--deselect`` to allow deselection of individual
@@ -388,7 +846,7 @@ Trivial/Internal Changes
<https://github.com/pytest-dev/pytest/issues/3308>`_)
Pytest 3.4.2 (2018-03-04)
pytest 3.4.2 (2018-03-04)
=========================
Bug Fixes
@@ -425,7 +883,7 @@ Trivial/Internal Changes
<https://github.com/pytest-dev/pytest/issues/3259>`_)
Pytest 3.4.1 (2018-02-20)
pytest 3.4.1 (2018-02-20)
=========================
Bug Fixes
@@ -486,7 +944,7 @@ Trivial/Internal Changes
<https://github.com/pytest-dev/pytest/issues/985>`_)
Pytest 3.4.0 (2018-01-30)
pytest 3.4.0 (2018-01-30)
=========================
Deprecations and Removals
@@ -618,7 +1076,7 @@ Trivial/Internal Changes
<https://github.com/pytest-dev/pytest/issues/3129>`_)
Pytest 3.3.2 (2017-12-25)
pytest 3.3.2 (2017-12-25)
=========================
Bug Fixes
@@ -651,11 +1109,11 @@ Trivial/Internal Changes
- Code cleanup. (`#3015 <https://github.com/pytest-dev/pytest/issues/3015>`_,
`#3021 <https://github.com/pytest-dev/pytest/issues/3021>`_)
- Clean up code by replacing imports and references of `_ast` to `ast`. (`#3018
<https://github.com/pytest-dev/pytest/issues/3018>`_)
- Clean up code by replacing imports and references of ``_ast`` to ``ast``.
(`#3018 <https://github.com/pytest-dev/pytest/issues/3018>`_)
Pytest 3.3.1 (2017-12-05)
pytest 3.3.1 (2017-12-05)
=========================
Bug Fixes
@@ -697,13 +1155,13 @@ Trivial/Internal Changes
<https://github.com/pytest-dev/pytest/issues/2949>`_)
Pytest 3.3.0 (2017-11-23)
pytest 3.3.0 (2017-11-23)
=========================
Deprecations and Removals
-------------------------
- Pytest no longer supports Python **2.6** and **3.3**. Those Python versions
- pytest no longer supports Python **2.6** and **3.3**. Those Python versions
are EOL for some time now and incur maintenance and compatibility costs on
the pytest core team, and following up with the rest of the community we
decided that they will no longer be supported starting on this version. Users
@@ -757,7 +1215,7 @@ Features
- Match ``warns`` signature to ``raises`` by adding ``match`` keyword. (`#2708
<https://github.com/pytest-dev/pytest/issues/2708>`_)
- Pytest now captures and displays output from the standard ``logging`` module.
- pytest now captures and displays output from the standard ``logging`` module.
The user can control the logging level to be captured by specifying options
in ``pytest.ini``, the command line and also during individual tests using
markers. Also, a ``caplog`` fixture is available that enables users to test
@@ -822,7 +1280,7 @@ Bug Fixes
avoids a number of potential problems. (`#2751
<https://github.com/pytest-dev/pytest/issues/2751>`_)
- Pytest no longer complains about warnings with unicode messages being
- pytest no longer complains about warnings with unicode messages being
non-ascii compatible even for ascii-compatible messages. As a result of this,
warnings with unicode messages are converted first to an ascii representation
for safety. (`#2809 <https://github.com/pytest-dev/pytest/issues/2809>`_)
@@ -874,7 +1332,7 @@ Trivial/Internal Changes
<https://github.com/pytest-dev/pytest/issues/2922>`_)
Pytest 3.2.5 (2017-11-15)
pytest 3.2.5 (2017-11-15)
=========================
Bug Fixes
@@ -885,7 +1343,7 @@ Bug Fixes
<https://github.com/pytest-dev/pytest/issues/2926>`_)
Pytest 3.2.4 (2017-11-13)
pytest 3.2.4 (2017-11-13)
=========================
Bug Fixes
@@ -934,7 +1392,7 @@ Improved Documentation
<https://github.com/pytest-dev/pytest/issues/911>`_)
Pytest 3.2.3 (2017-10-03)
pytest 3.2.3 (2017-10-03)
=========================
Bug Fixes
@@ -974,13 +1432,13 @@ Trivial/Internal Changes
(`#2765 <https://github.com/pytest-dev/pytest/issues/2765>`_)
Pytest 3.2.2 (2017-09-06)
pytest 3.2.2 (2017-09-06)
=========================
Bug Fixes
---------
- Calling the deprecated `request.getfuncargvalue()` now shows the source of
- Calling the deprecated ``request.getfuncargvalue()`` now shows the source of
the call. (`#2681 <https://github.com/pytest-dev/pytest/issues/2681>`_)
- Allow tests declared as ``@staticmethod`` to use fixtures. (`#2699
@@ -1002,10 +1460,10 @@ Improved Documentation
``pytest.mark.MARKER_NAME.__call__`` (`#2604
<https://github.com/pytest-dev/pytest/issues/2604>`_)
- In one of the simple examples, use `pytest_collection_modifyitems()` to skip
- In one of the simple examples, use ``pytest_collection_modifyitems()`` to skip
tests based on a command-line option, allowing its sharing while preventing a
user error when acessing `pytest.config` before the argument parsing. (`#2653
<https://github.com/pytest-dev/pytest/issues/2653>`_)
user error when acessing ``pytest.config`` before the argument parsing.
(`#2653 <https://github.com/pytest-dev/pytest/issues/2653>`_)
Trivial/Internal Changes
@@ -1021,7 +1479,7 @@ Trivial/Internal Changes
<https://github.com/pytest-dev/pytest/issues/2739>`_)
Pytest 3.2.1 (2017-08-08)
pytest 3.2.1 (2017-08-08)
=========================
Bug Fixes
@@ -1051,7 +1509,7 @@ Improved Documentation
<https://github.com/pytest-dev/pytest/issues/2626>`_)
Pytest 3.2.0 (2017-07-30)
pytest 3.2.0 (2017-07-30)
=========================
Deprecations and Removals
@@ -1083,7 +1541,7 @@ Features
from parent classes or modules. (`#2516 <https://github.com/pytest-
dev/pytest/issues/2516>`_)
- Collection ignores local virtualenvs by default; `--collect-in-virtualenv`
- Collection ignores local virtualenvs by default; ``--collect-in-virtualenv``
overrides this behavior. (`#2518 <https://github.com/pytest-
dev/pytest/issues/2518>`_)
@@ -1217,7 +1675,7 @@ Trivial/Internal Changes
<https://github.com/pytest-dev/pytest/issues/2620>`_)
Pytest 3.1.3 (2017-07-03)
pytest 3.1.3 (2017-07-03)
=========================
Bug Fixes
@@ -1263,7 +1721,7 @@ Trivial/Internal Changes
(`#2499 <https://github.com/pytest-dev/pytest/issues/2499>`_)
Pytest 3.1.2 (2017-06-08)
pytest 3.1.2 (2017-06-08)
=========================
Bug Fixes
@@ -1295,7 +1753,7 @@ Improved Documentation
and improve overall flow of the ``skipping`` docs. (#810)
Pytest 3.1.1 (2017-05-30)
pytest 3.1.1 (2017-05-30)
=========================
Bug Fixes

16
CITATION Normal file
View File

@@ -0,0 +1,16 @@
NOTE: Change "x.y" by the version you use. If you are unsure about which version
you are using run: `pip show pytest`.
Text:
[pytest] pytest x.y, 2004
Krekel et al., https://github.com/pytest-dev/pytest
BibTeX:
@misc{pytestx.y,
title = {pytest x.y},
author = {Krekel, Holger and Oliveira, Bruno and Pfannschmidt, Ronny and Bruynooghe, Floris and Laugher, Brianna and Bruhin, Florian},
year = {2004},
url = {https://github.com/pytest-dev/pytest},
}

View File

@@ -10,10 +10,6 @@ taking a lot of time to make a new one.
pytest releases must be prepared on **Linux** because the docs and examples expect
to be executed in that platform.
#. Install development dependencies in a virtual environment with::
pip3 install -U -r tasks/requirements.txt
#. Create a branch ``release-X.Y.Z`` with the version for the release.
* **patch releases**: from the latest ``master``;
@@ -22,18 +18,23 @@ taking a lot of time to make a new one.
Ensure your are in a clean work tree.
#. Generate docs, changelog, announcements and a **local** tag::
#. Using ``tox``, generate docs, changelog, announcements::
invoke generate.pre-release <VERSION>
$ tox -e release -- <VERSION>
This will generate a commit with all the changes ready for pushing.
#. Open a PR for this branch targeting ``master``.
#. After all tests pass and the PR has been approved, publish to PyPI by pushing the tag::
git tag <VERSION>
git push git@github.com:pytest-dev/pytest.git <VERSION>
Wait for the deploy to complete, then make sure it is `available on PyPI <https://pypi.org/project/pytest>`_.
#. Merge the PR into ``master``.
#. Send an email announcement with the contents from::
doc/en/announce/release-<VERSION>.rst

View File

@@ -1,8 +1,9 @@
.. image:: http://docs.pytest.org/en/latest/_static/pytest1.png
:target: http://docs.pytest.org
.. image:: https://docs.pytest.org/en/latest/_static/pytest1.png
:target: https://docs.pytest.org/en/latest/
:align: center
:alt: pytest
------
.. image:: https://img.shields.io/pypi/v/pytest.svg
@@ -14,8 +15,9 @@
.. image:: https://img.shields.io/pypi/pyversions/pytest.svg
:target: https://pypi.org/project/pytest/
.. image:: https://img.shields.io/coveralls/pytest-dev/pytest/master.svg
:target: https://coveralls.io/r/pytest-dev/pytest
.. image:: https://codecov.io/gh/pytest-dev/pytest/branch/master/graph/badge.svg
:target: https://codecov.io/gh/pytest-dev/pytest
:alt: Code coverage Status
.. image:: https://travis-ci.org/pytest-dev/pytest.svg?branch=master
:target: https://travis-ci.org/pytest-dev/pytest
@@ -24,7 +26,7 @@
:target: https://ci.appveyor.com/project/pytestbot/pytest
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
:target: https://github.com/ambv/black
:target: https://github.com/ambv/black
.. image:: https://www.codetriage.com/pytest-dev/pytest/badges/users.svg
:target: https://www.codetriage.com/pytest-dev/pytest
@@ -65,23 +67,23 @@ To execute it::
========================== 1 failed in 0.04 seconds ===========================
Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started <http://docs.pytest.org/en/latest/getting-started.html#our-first-test-run>`_ for more examples.
Due to ``pytest``'s detailed assertion introspection, only plain ``assert`` statements are used. See `getting-started <https://docs.pytest.org/en/latest/getting-started.html#our-first-test-run>`_ for more examples.
Features
--------
- Detailed info on failing `assert statements <http://docs.pytest.org/en/latest/assert.html>`_ (no need to remember ``self.assert*`` names);
- Detailed info on failing `assert statements <https://docs.pytest.org/en/latest/assert.html>`_ (no need to remember ``self.assert*`` names);
- `Auto-discovery
<http://docs.pytest.org/en/latest/goodpractices.html#python-test-discovery>`_
<https://docs.pytest.org/en/latest/goodpractices.html#python-test-discovery>`_
of test modules and functions;
- `Modular fixtures <http://docs.pytest.org/en/latest/fixture.html>`_ for
- `Modular fixtures <https://docs.pytest.org/en/latest/fixture.html>`_ for
managing small or parametrized long-lived test resources;
- Can run `unittest <http://docs.pytest.org/en/latest/unittest.html>`_ (or trial),
`nose <http://docs.pytest.org/en/latest/nose.html>`_ test suites out of the box;
- Can run `unittest <https://docs.pytest.org/en/latest/unittest.html>`_ (or trial),
`nose <https://docs.pytest.org/en/latest/nose.html>`_ test suites out of the box;
- Python 2.7, Python 3.4+, PyPy 2.3, Jython 2.5 (untested);
@@ -91,7 +93,7 @@ Features
Documentation
-------------
For full documentation, including installation, tutorials and PDF documents, please see http://docs.pytest.org.
For full documentation, including installation, tutorials and PDF documents, please see https://docs.pytest.org/en/latest/.
Bugs/Requests
@@ -103,13 +105,13 @@ Please use the `GitHub issue tracker <https://github.com/pytest-dev/pytest/issue
Changelog
---------
Consult the `Changelog <http://docs.pytest.org/en/latest/changelog.html>`__ page for fixes and enhancements of each version.
Consult the `Changelog <https://docs.pytest.org/en/latest/changelog.html>`__ page for fixes and enhancements of each version.
License
-------
Copyright Holger Krekel and others, 2004-2017.
Copyright Holger Krekel and others, 2004-2018.
Distributed under the terms of the `MIT`_ license, pytest is free and open source software.

View File

@@ -1,34 +1,30 @@
environment:
COVERALLS_REPO_TOKEN:
secure: 2NJ5Ct55cHJ9WEg3xbSqCuv0rdgzzb6pnzOIG5OkMbTndw3wOBrXntWFoQrXiMFi
# this is pytest's token in coveralls.io, encrypted
# using pytestbot account as detailed here:
# https://www.appveyor.com/docs/build-configuration#secure-variables
matrix:
# coveralls is not in the default env list
- TOXENV: "coveralls"
# note: please use "tox --listenvs" to populate the build matrix below
- TOXENV: "linting"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py27"
- TOXENV: "py34"
- TOXENV: "py35"
- TOXENV: "py36"
- TOXENV: "py37"
- TOXENV: "pypy"
- TOXENV: "py27-pexpect"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py27-xdist"
- TOXENV: "py27-trial"
- TOXENV: "py27-numpy"
- TOXENV: "py27-pluggymaster"
- TOXENV: "py36-pexpect"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py36-xdist"
- TOXENV: "py36-trial"
- TOXENV: "py36-numpy"
- TOXENV: "py36-pluggymaster"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "py27-nobyte"
- TOXENV: "doctesting"
- TOXENV: "py35-freeze"
- TOXENV: "py36-freeze"
PYTEST_NO_COVERAGE: "1"
- TOXENV: "docs"
PYTEST_NO_COVERAGE: "1"
install:
- echo Installed Pythons
@@ -36,13 +32,24 @@ install:
- if "%TOXENV%" == "pypy" call scripts\install-pypy.bat
- C:\Python36\python -m pip install --upgrade pip
- C:\Python36\python -m pip install --upgrade --pre tox
build: false # Not a C# project, build stuff at the test step instead.
before_test:
- call scripts\prepare-coverage.bat
test_script:
- call scripts\call-tox.bat
- C:\Python36\python -m tox
on_success:
- call scripts\upload-coverage.bat
cache:
- '%LOCALAPPDATA%\pip\cache'
- '%USERPROFILE%\.cache\pre-commit'
# We don't deploy anything on tags with AppVeyor, we use Travis instead, so we
# might as well save resources
skip_tags: true

View File

@@ -1,4 +1,4 @@
import py
import six
for i in range(1000):
py.builtin.exec_("def test_func_%d(): pass" % i)
six.exec_("def test_func_%d(): pass" % i)

View File

@@ -26,7 +26,7 @@ changelog using that instead.
If you are not sure what issue type to use, don't hesitate to ask in your PR.
Note that the ``towncrier`` tool will automatically
reflow your text, so it will work best if you stick to a single paragraph, but multiple sentences and links are OK
and encouraged. You can install ``towncrier`` and then run ``towncrier --draft``
``towncrier`` preserves multiple paragraphs and formatting (code blocks, lists, and so on), but for entries
other than ``features`` it is usually better to stick to a single paragraph to keep it concise. You can install
``towncrier`` and then run ``towncrier --draft``
if you want to get a preview of how your change will look in the final release notes.

View File

@@ -14,7 +14,7 @@
{% if definitions[category]['showcontent'] %}
{% for text, values in sections[section][category]|dictsort(by='value') %}
{% set issue_joiner = joiner(', ') %}
- {{ text }}{% if category != 'vendor' %} ({% for value in values|sort %}{{ issue_joiner() }}`{{ value }} <https://github.com/pytest-dev/pytest/issues/{{ value[1:] }}>`_{% endfor %}){% endif %}
- {% for value in values|sort %}{{ issue_joiner() }}`{{ value }} <https://github.com/pytest-dev/pytest/issues/{{ value[1:] }}>`_{% endfor %}: {{ text }}
{% endfor %}

View File

@@ -6,6 +6,16 @@ Release announcements
:maxdepth: 2
release-3.8.2
release-3.8.1
release-3.8.0
release-3.7.4
release-3.7.3
release-3.7.2
release-3.7.1
release-3.7.0
release-3.6.4
release-3.6.3
release-3.6.2
release-3.6.1
release-3.6.0

View File

@@ -23,7 +23,7 @@ a full list of details. A few feature highlights:
called if the corresponding setup method succeeded.
- integrate tab-completion on command line options if you
have `argcomplete <http://pypi.python.org/pypi/argcomplete>`_
have `argcomplete <https://pypi.org/project/argcomplete/>`_
configured.
- allow boolean expression directly with skipif/xfail

View File

@@ -124,7 +124,7 @@ The py.test Development Team
Thanks `@biern`_ for the PR.
* Fix `traceback style docs`_ to describe all of the available options
(auto/long/short/line/native/no), with `auto` being the default since v2.6.
(auto/long/short/line/native/no), with ``auto`` being the default since v2.6.
Thanks `@hackebrot`_ for the PR.
* Fix (`#1422`_): junit record_xml_property doesn't allow multiple records

View File

@@ -0,0 +1,28 @@
pytest-3.6.3
=======================================
pytest 3.6.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 http://doc.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* AdamEr8
* Anthony Sottile
* Bruno Oliveira
* Jean-Paul Calderone
* Jon Dufresne
* Marcelo Duarte Trevisani
* Ondřej Súkup
* Ronny Pfannschmidt
* T.E.A de Souza
* Victor
* victor
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,24 @@
pytest-3.6.4
=======================================
pytest 3.6.4 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 http://doc.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Anthony Sottile
* Bernhard M. Wiedemann
* Bruno Oliveira
* Drew
* E Hershey
* Hugo Martins
* Vlad Shcherbina
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,41 @@
pytest-3.7.0
=======================================
The pytest team is proud to announce the 3.7.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:
http://doc.pytest.org/en/latest/changelog.html
For complete documentation, please visit:
http://docs.pytest.org
As usual, you can upgrade from pypi via:
pip install -U pytest
Thanks to all who contributed to this release, among them:
* Alan
* Alan Brammer
* Ammar Najjar
* Anthony Sottile
* Bruno Oliveira
* Jeffrey Rackauckas
* Kale Kundert
* Ronny Pfannschmidt
* Serhii Mozghovyi
* Tadek Teleżyński
* Wil Cooley
* abrammer
* avirlrma
* turturica
Happy testing,
The Pytest Development Team

View File

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

View File

@@ -0,0 +1,25 @@
pytest-3.7.2
=======================================
pytest 3.7.2 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Anthony Sottile
* Bruno Oliveira
* Daniel Hahler
* Josh Holland
* Ronny Pfannschmidt
* Sankt Petersbug
* Wes Thomas
* turturica
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,33 @@
pytest-3.7.3
=======================================
pytest 3.7.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 http://doc.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Andrew Champion
* Anthony Sottile
* Bruno Oliveira
* Daniel Hahler
* Gandalf Saxe
* Jennifer Rinker
* Natan Lao
* Ondřej Súkup
* Ronny Pfannschmidt
* Sankt Petersbug
* Tyler Richard
* Victor
* Vlad Shcherbina
* turturica
* victor
* wim glenn
Happy testing,
The pytest Development Team

View File

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

View File

@@ -0,0 +1,38 @@
pytest-3.8.0
=======================================
The pytest team is proud to announce the 3.8.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:
* Anthony Sottile
* Bruno Oliveira
* CrazyMerlyn
* Daniel Hahler
* Fabio Zadrozny
* Jeffrey Rackauckas
* Ronny Pfannschmidt
* Virgil Dupras
* dhirensr
* hoefling
* wim glenn
Happy testing,
The Pytest Development Team

View File

@@ -0,0 +1,25 @@
pytest-3.8.1
=======================================
pytest 3.8.1 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Ankit Goel
* Anthony Sottile
* Bruno Oliveira
* Daniel Hahler
* Maximilian Albert
* Ronny Pfannschmidt
* William Jamir Silva
* wim glenn
Happy testing,
The pytest Development Team

View File

@@ -0,0 +1,28 @@
pytest-3.8.2
=======================================
pytest 3.8.2 has just been released to PyPI.
This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:
* Ankit Goel
* Anthony Sottile
* Bruno Oliveira
* Daniel Hahler
* Denis Otkidach
* Harry Percival
* Jeffrey Rackauckas
* Jose Carlos Menezes
* Ronny Pfannschmidt
* Zac-HD
* iwanb
Happy testing,
The pytest Development Team

View File

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

View File

@@ -7,14 +7,16 @@ Keeping backwards compatibility has a very high priority in the pytest project.
With the pytest 3.0 release we introduced a clear communication scheme for when we will actually remove the old busted joint and politely ask you to use the new hotness instead, while giving you enough time to adjust your tests or raise concerns if there are valid reasons to keep deprecated functionality around.
To communicate changes we are already issuing deprecation warnings, but they are not displayed by default. In pytest 3.0 we changed the default setting so that pytest deprecation warnings are displayed if not explicitly silenced (with ``--disable-pytest-warnings``).
To communicate changes we issue deprecation warnings using a custom warning hierarchy (see :ref:`internal-warnings`). These warnings may be suppressed using the standard means: ``-W`` command-line flag or ``filterwarnings`` ini options (see :ref:`warnings`), but we suggest to use these sparingly and temporarily, and heed the warnings when possible.
We will only remove deprecated functionality in major releases (e.g. if we deprecate something in 3.0 we will remove it in 4.0), and keep it around for at least two minor releases (e.g. if we deprecate something in 3.9 and 4.0 is the next release, we will not remove it in 4.0 but in 5.0).
We will only start the removal of deprecated functionality in major releases (e.g. if we deprecate something in 3.0 we will start to remove it in 4.0), and keep it around for at least two minor releases (e.g. if we deprecate something in 3.9 and 4.0 is the next release, we start to remove it in 5.0, not in 4.0).
When the deprecation expires (e.g. 4.0 is released), we won't remove the deprecated functionality immediately, but will use the standard warning filters to turn them into **errors** by default. This approach makes it explicit that removal is imminent, and still gives you time to turn the deprecated feature into a warning instead of an error so it can be dealt with in your own time. In the next minor release (e.g. 4.1), the feature will be effectively removed.
Deprecation Roadmap
-------------------
We track deprecation and removal of features using milestones and the `deprecation <https://github.com/pytest-dev/pytest/issues?q=label%3A%22type%3A+deprecation%22>`_ and `removal <https://github.com/pytest-dev/pytest/labels/type%3A%20removal>`_ labels on GitHub.
Features currently deprecated and removed in previous releases can be found in :ref:`deprecations`.
Following our deprecation policy, after starting issuing deprecation warnings we keep features for *at least* two minor versions before considering removal.
We track future deprecation and removal of features using milestones and the `deprecation <https://github.com/pytest-dev/pytest/issues?q=label%3A%22type%3A+deprecation%22>`_ and `removal <https://github.com/pytest-dev/pytest/labels/type%3A%20removal>`_ labels on GitHub.

View File

@@ -90,7 +90,7 @@ For information about fixtures, see :ref:`fixtures`. To see a complete list of a
monkeypatch.setitem(mapping, name, value)
monkeypatch.delitem(obj, name, raising=True)
monkeypatch.setenv(name, value, prepend=False)
monkeypatch.delenv(name, value, raising=True)
monkeypatch.delenv(name, raising=True)
monkeypatch.syspath_prepend(path)
monkeypatch.chdir(path)

View File

@@ -162,8 +162,8 @@ When no tests failed in the last run, or when no cached ``lastfailed`` data was
found, ``pytest`` can be configured either to run all of the tests or no tests,
using the ``--last-failed-no-failures`` option, which takes one of the following values::
pytest --last-failed-no-failures all # run all tests (default behavior)
pytest --last-failed-no-failures none # run no tests and exit
pytest --last-failed --last-failed-no-failures all # run all tests (default behavior)
pytest --last-failed --last-failed-no-failures none # run no tests and exit
The new config.cache object
--------------------------------

View File

@@ -1,7 +1,4 @@
.. _changelog:
Changelog history
=================================
.. include:: ../../CHANGELOG.rst

View File

@@ -65,7 +65,7 @@ master_doc = "contents"
# General information about the project.
project = u"pytest"
year = datetime.datetime.utcnow().year
copyright = u"2015{} , holger krekel and pytest-dev team".format(year)
copyright = u"20152018 , holger krekel and pytest-dev team"
# The language for content autogenerated by Sphinx. Refer to documentation
@@ -329,7 +329,7 @@ texinfo_documents = [
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {"python": ("http://docs.python.org/3", None)}
intersphinx_mapping = {"python": ("https://docs.python.org/3", None)}
def setup(app):

View File

@@ -39,6 +39,7 @@ Full pytest documentation
bash-completion
backwards-compatibility
deprecations
historical-notes
license
contributing

View File

@@ -32,7 +32,7 @@ Here's a summary what ``pytest`` uses ``rootdir`` for:
class name, function name and parametrization (if any).
* Is used by plugins as a stable location to store project/test run specific information;
for example, the internal :ref:`cache <cache>` plugin creates a ``.cache`` subdirectory
for example, the internal :ref:`cache <cache>` plugin creates a ``.pytest_cache`` subdirectory
in ``rootdir`` to store its cross-test run state.
Important to emphasize that ``rootdir`` is **NOT** used to modify ``sys.path``/``PYTHONPATH`` or
@@ -139,7 +139,7 @@ line options while the environment is in use::
Here's how the command-line is built in the presence of ``addopts`` or the environment variable::
<pytest.ini:addopts> $PYTEST_ADDOTPS <extra command-line arguments>
<pytest.ini:addopts> $PYTEST_ADDOPTS <extra command-line arguments>
So if the user executes in the command-line::

325
doc/en/deprecations.rst Normal file
View File

@@ -0,0 +1,325 @@
.. _deprecations:
Deprecations and Removals
=========================
This page lists all pytest features that are currently deprecated or have been removed in past major releases.
The objective is to give users a clear rationale why a certain feature has been removed, and what alternatives
should be used instead.
Deprecated Features
-------------------
Below is a complete list of all pytest features which are considered deprecated. Using those features will issue
:class:`_pytest.warning_types.PytestWarning` or subclasses, which can be filtered using
:ref:`standard warning filters <warnings>`.
``Config.warn`` and ``Node.warn``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.8
Those methods were part of the internal pytest warnings system, but since ``3.8`` pytest is using the builtin warning
system for its own warnings, so those two functions are now deprecated.
``Config.warn`` should be replaced by calls to the standard ``warnings.warn``, example:
.. code-block:: python
config.warn("C1", "some warning")
Becomes:
.. code-block:: python
warnings.warn(pytest.PytestWarning("some warning"))
``Node.warn`` now supports two signatures:
* ``node.warn(PytestWarning("some message"))``: is now the **recommended** way to call this function.
The warning instance must be a PytestWarning or subclass.
* ``node.warn("CI", "some message")``: this code/message form is now **deprecated** and should be converted to the warning instance form above.
``pytest_namespace``
~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.7
This hook is deprecated because it greatly complicates the pytest internals regarding configuration and initialization, making some
bug fixes and refactorings impossible.
Example of usage:
.. code-block:: python
class MySymbol:
...
def pytest_namespace():
return {"my_symbol": MySymbol()}
Plugin authors relying on this hook should instead require that users now import the plugin modules directly (with an appropriate public API).
As a stopgap measure, plugin authors may still inject their names into pytest's namespace, usually during ``pytest_configure``:
.. code-block:: python
import pytest
def pytest_configure():
pytest.my_symbol = MySymbol()
Calling fixtures directly
~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.7
Calling a fixture function directly, as opposed to request them in a test function, is deprecated.
For example:
.. code-block:: python
@pytest.fixture
def cell():
return ...
@pytest.fixture
def full_cell():
cell = cell()
cell.make_full()
return cell
This is a great source of confusion to new users, which will often call the fixture functions and request them from test functions interchangeably, which breaks the fixture resolution model.
In those cases just request the function directly in the dependent fixture:
.. code-block:: python
@pytest.fixture
def cell():
return ...
@pytest.fixture
def full_cell(cell):
cell.make_full()
return cell
``Node.get_marker``
~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.6
As part of a large :ref:`marker-revamp`, :meth:`_pytest.nodes.Node.get_marker` is deprecated. See
:ref:`the documentation <update marker code>` on tips on how to update your code.
record_xml_property
~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.5
The ``record_xml_property`` fixture is now deprecated in favor of the more generic ``record_property``, which
can be used by other consumers (for example ``pytest-html``) to obtain custom information about the test run.
This is just a matter of renaming the fixture as the API is the same:
.. code-block:: python
def test_foo(record_xml_property):
...
Change to:
.. code-block:: python
def test_foo(record_property):
...
pytest_plugins in non-top-level conftest files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.5
Defining ``pytest_plugins`` is now deprecated in non-top-level conftest.py
files because they will activate referenced plugins *globally*, which is surprising because for all other pytest
features ``conftest.py`` files are only *active* for tests at or below it.
Metafunc.addcall
~~~~~~~~~~~~~~~~
.. deprecated:: 3.3
:meth:`_pytest.python.Metafunc.addcall` was a precursor to the current parametrized mechanism. Users should use
:meth:`_pytest.python.Metafunc.parametrize` instead.
marks in ``pytest.mark.parametrize``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.2
Applying marks to values of a ``pytest.mark.parametrize`` call is now deprecated. For example:
.. code-block:: python
@pytest.mark.parametrize(
"a, b", [(3, 9), pytest.mark.xfail(reason="flaky")(6, 36), (10, 100)]
)
def test_foo(a, b):
...
This code applies the ``pytest.mark.xfail(reason="flaky")`` mark to the ``(6, 36)`` value of the above parametrization
call.
This was considered hard to read and understand, and also its implementation presented problems to the code preventing
further internal improvements in the marks architecture.
To update the code, use ``pytest.param``:
.. code-block:: python
@pytest.mark.parametrize(
"a, b",
[(3, 9), pytest.param((6, 36), marks=pytest.mark.xfail(reason="flaky")), (10, 100)],
)
def test_foo(a, b):
...
Passing command-line string to ``pytest.main()``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.0
Passing a command-line string to ``pytest.main()`` is deprecated:
.. code-block:: python
pytest.main("-v -s")
Pass a list instead:
.. code-block:: python
pytest.main(["-v", "-s"])
By passing a string, users expect that pytest will interpret that command-line using the shell rules they are working
on (for example ``bash`` or ``Powershell``), but this is very hard/impossible to do in a portable way.
``yield`` tests
~~~~~~~~~~~~~~~
.. deprecated:: 3.0
pytest supports ``yield``-style tests, where a test function actually ``yield`` functions and values
that are then turned into proper test methods. Example:
.. code-block:: python
def check(x, y):
assert x ** x == y
def test_squared():
yield check, 2, 4
yield check, 3, 9
This would result into two actual test functions being generated.
This form of test function doesn't support fixtures properly, and users should switch to ``pytest.mark.parametrize``:
.. code-block:: python
@pytest.mark.parametrize("x, y", [(2, 4), (3, 9)])
def test_squared():
assert x ** x == y
``pytest_funcarg__`` prefix
~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.0
In very early pytest versions fixtures could be defined using the ``pytest_funcarg__`` prefix:
.. code-block:: python
def pytest_funcarg__data():
return SomeData()
Switch over to the ``@pytest.fixture`` decorator:
.. code-block:: python
@pytest.fixture
def data():
return SomeData()
[pytest] section in setup.cfg files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.0
``[pytest]`` sections in ``setup.cfg`` files should now be named ``[tool:pytest]``
to avoid conflicts with other distutils commands.
Result log (``--result-log``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. deprecated:: 3.0
The ``--resultlog`` command line option has been deprecated: it is little used
and there are more modern and better alternatives, for example `pytest-tap <https://tappy.readthedocs.io/en/latest/>`_.
Removed Features
----------------
As stated in our :ref:`backwards-compatibility` policy, deprecated features are removed only in major releases after
an appropriate period of deprecation has passed.
Reinterpretation mode (``--assert=reinterp``)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 3.0.*
Reinterpretation mode has now been removed and only plain and rewrite
mode are available, consequently the ``--assert=reinterp`` option is
no longer available. This also means files imported from plugins or
``conftest.py`` will not benefit from improved assertions by
default, you should use ``pytest.register_assert_rewrite()`` to
explicitly turn on assertion rewriting for those files.
Removed command-line options
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 3.0.*
The following deprecated commandline options were removed:
* ``--genscript``: no longer supported;
* ``--no-assert``: use ``--assert=plain`` instead;
* ``--nomagic``: use ``--assert=plain`` instead;
* ``--report``: use ``-r`` instead;
py.test-X* entry points
~~~~~~~~~~~~~~~~~~~~~~~
*Removed in version 3.0.*
Removed all ``py.test-X*`` entry points. The versioned, suffixed entry points
were never documented and a leftover from a pre-virtualenv era. These entry
points also created broken entry points in wheels, so removing them also
removes a source of confusion for users.

View File

@@ -39,6 +39,11 @@ avoid creating labels just for the sake of creating them.
Each label should include a description in the GitHub's interface stating its purpose.
Labels are managed using `labels <https://github.com/hackebrot/labels>`_. All the labels in the repository
are kept in ``.github/labels.toml``, so any changes should be via PRs to that file.
After a PR is accepted and merged, one of the maintainers must manually synchronize the labels file with the
GitHub repository.
Temporary labels
~~~~~~~~~~~~~~~~

View File

@@ -1,6 +1,6 @@
from pytest import raises
import _pytest._code
import py
import six
def otherfunc(a, b):
@@ -25,9 +25,7 @@ def pytest_generate_tests(metafunc):
class TestFailing(object):
def test_simple(self):
def f():
return 42
@@ -40,7 +38,6 @@ class TestFailing(object):
otherfunc_multi(42, 6 * 9)
def test_not(self):
def f():
return 42
@@ -48,7 +45,6 @@ class TestFailing(object):
class TestSpecialisedExplanations(object):
def test_eq_text(self):
assert "spam" == "eggs"
@@ -106,7 +102,6 @@ class TestSpecialisedExplanations(object):
def test_attribute():
class Foo(object):
b = 1
@@ -115,7 +110,6 @@ def test_attribute():
def test_attribute_instance():
class Foo(object):
b = 1
@@ -123,9 +117,7 @@ def test_attribute_instance():
def test_attribute_failure():
class Foo(object):
def _get_b(self):
raise Exception("Failed to get attrib")
@@ -136,7 +128,6 @@ def test_attribute_failure():
def test_attribute_multiple():
class Foo(object):
b = 1
@@ -151,7 +142,6 @@ def globf(x):
class TestRaises(object):
def test_raises(self):
s = "qwe" # NOQA
raises(TypeError, "int(s)")
@@ -187,15 +177,13 @@ def test_dynamic_compile_shows_nicely():
name = "abc-123"
module = imp.new_module(name)
code = _pytest._code.compile(src, name, "exec")
py.builtin.exec_(code, module.__dict__)
six.exec_(code, module.__dict__)
sys.modules[name] = module
module.foo()
class TestMoreErrors(object):
def test_complex_error(self):
def f():
return 44
@@ -218,7 +206,6 @@ class TestMoreErrors(object):
assert s.startswith(g)
def test_startswith_nested(self):
def f():
return "123"
@@ -246,9 +233,7 @@ class TestMoreErrors(object):
class TestCustomAssertMsg(object):
def test_single_line(self):
class A(object):
a = 1
@@ -256,7 +241,6 @@ class TestCustomAssertMsg(object):
assert A.a == b, "A.a appears not to be b"
def test_multiline(self):
class A(object):
a = 1
@@ -266,7 +250,6 @@ class TestCustomAssertMsg(object):
), "A.a appears not to be b\n" "or does not appear to be b\none of those"
def test_custom_repr(self):
class JSON(object):
a = 1

View File

@@ -10,4 +10,4 @@ def pytest_runtest_setup(item):
return
mod = item.getparent(pytest.Module).obj
if hasattr(mod, "hello"):
print("mod.hello %r" % (mod.hello,))
print("mod.hello {!r}".format(mod.hello))

View File

@@ -2,7 +2,7 @@
import py
failure_demo = py.path.local(__file__).dirpath("failure_demo.py")
pytest_plugins = "pytester",
pytest_plugins = ("pytester",)
def test_failure_demo_fails_properly(testdir):

View File

@@ -3,7 +3,6 @@ def setup_module(module):
class TestStateFullThing(object):
def setup_class(cls):
cls.classcount += 1

View File

@@ -10,7 +10,6 @@ def setup(request):
class CostlySetup(object):
def __init__(self):
import time

View File

@@ -31,7 +31,7 @@ You can then restrict a test run to only run tests marked with ``webtest``::
$ pytest -v -m webtest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items / 3 deselected
@@ -44,7 +44,7 @@ Or the inverse, running all tests except the webtest ones::
$ pytest -v -m "not webtest"
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items / 1 deselected
@@ -64,7 +64,7 @@ tests based on their module, class, method, or function name::
$ pytest -v test_server.py::TestClass::test_method
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 1 item
@@ -77,7 +77,7 @@ You can also select on the class::
$ pytest -v test_server.py::TestClass
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 1 item
@@ -90,7 +90,7 @@ Or select multiple nodes::
$ pytest -v test_server.py::TestClass test_server.py::test_send_http
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 2 items
@@ -128,7 +128,7 @@ select tests based on their names::
$ pytest -v -k http # running with the above defined example module
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items / 3 deselected
@@ -141,7 +141,7 @@ And you can also run all tests except the ones that match the keyword::
$ pytest -k "not send_http" -v
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items / 1 deselected
@@ -156,7 +156,7 @@ Or to select "http" and "quick" tests::
$ pytest -k "http or quick" -v
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 4 items / 2 deselected
@@ -200,15 +200,17 @@ You can ask which markers exist for your test suite - the list includes our just
$ pytest --markers
@pytest.mark.webtest: mark a test as a webtest.
@pytest.mark.filterwarnings(warning): add a warning filter to the given test. see https://docs.pytest.org/en/latest/warnings.html#pytest-mark-filterwarnings
@pytest.mark.skip(reason=None): skip the given test function with an optional reason. Example: skip(reason="no way of currently testing this") skips the test.
@pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html
@pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see https://docs.pytest.org/en/latest/skipping.html
@pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html
@pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See https://docs.pytest.org/en/latest/skipping.html
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples.
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see https://docs.pytest.org/en/latest/parametrize.html for more info and examples.
@pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures
@pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see https://docs.pytest.org/en/latest/fixture.html#usefixtures
@pytest.mark.tryfirst: mark a hook implementation function such that the plugin machinery will try to call it first/as early as possible.
@@ -299,10 +301,10 @@ Skip and xfail marks can also be applied in this way, see :ref:`skip/xfail with
.. note::
If the data you are parametrizing happen to be single callables, you need to be careful
when marking these items. `pytest.mark.xfail(my_func)` won't work because it's also the
when marking these items. ``pytest.mark.xfail(my_func)`` won't work because it's also the
signature of a function being decorated. To resolve this ambiguity, you need to pass a
reason argument:
`pytest.mark.xfail(func_bar, reason="Issue#7")`.
``pytest.mark.xfail(func_bar, reason="Issue#7")``.
.. _`adding a custom marker from a plugin`:
@@ -374,15 +376,17 @@ The ``--markers`` option always gives you a list of available markers::
$ pytest --markers
@pytest.mark.env(name): mark test to run only on named environment
@pytest.mark.filterwarnings(warning): add a warning filter to the given test. see https://docs.pytest.org/en/latest/warnings.html#pytest-mark-filterwarnings
@pytest.mark.skip(reason=None): skip the given test function with an optional reason. Example: skip(reason="no way of currently testing this") skips the test.
@pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see http://pytest.org/latest/skipping.html
@pytest.mark.skipif(condition): skip the given test function if eval(condition) results in a True value. Evaluation happens within the module global context. Example: skipif('sys.platform == "win32"') skips the test if we are on the win32 platform. see https://docs.pytest.org/en/latest/skipping.html
@pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See http://pytest.org/latest/skipping.html
@pytest.mark.xfail(condition, reason=None, run=True, raises=None, strict=False): mark the test function as an expected failure if eval(condition) has a True value. Optionally specify a reason for better reporting and run=False if you don't even want to execute the test function. If only specific exception(s) are expected, you can list them in raises, and if the test fails in other ways, it will be reported as a true failure. See https://docs.pytest.org/en/latest/skipping.html
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see http://pytest.org/latest/parametrize.html for more info and examples.
@pytest.mark.parametrize(argnames, argvalues): call a test function multiple times passing in different arguments in turn. argvalues generally needs to be a list of values if argnames specifies only one name or a list of tuples of values if argnames specifies multiple names. Example: @parametrize('arg1', [1,2]) would lead to two calls of the decorated test function, one with arg1=1 and another with arg1=2.see https://docs.pytest.org/en/latest/parametrize.html for more info and examples.
@pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see http://pytest.org/latest/fixture.html#usefixtures
@pytest.mark.usefixtures(fixturename1, fixturename2, ...): mark tests as needing all of the specified fixtures. see https://docs.pytest.org/en/latest/fixture.html#usefixtures
@pytest.mark.tryfirst: mark a hook implementation function such that the plugin machinery will try to call it first/as early as possible.

View File

@@ -2,9 +2,10 @@
module containing a parametrized tests testing cross-python
serialization via the pickle module.
"""
import textwrap
import py
import pytest
import _pytest._code
pythonlist = ["python2.7", "python3.4", "python3.5"]
@@ -21,46 +22,47 @@ def python2(request, python1):
class Python(object):
def __init__(self, version, picklefile):
self.pythonpath = py.path.local.sysfind(version)
if not self.pythonpath:
pytest.skip("%r not found" % (version,))
pytest.skip("{!r} not found".format(version))
self.picklefile = picklefile
def dumps(self, obj):
dumpfile = self.picklefile.dirpath("dump.py")
dumpfile.write(
_pytest._code.Source(
"""
import pickle
f = open(%r, 'wb')
s = pickle.dump(%r, f, protocol=2)
f.close()
"""
% (str(self.picklefile), obj)
textwrap.dedent(
"""\
import pickle
f = open({!r}, 'wb')
s = pickle.dump({!r}, f, protocol=2)
f.close()
""".format(
str(self.picklefile), obj
)
)
)
py.process.cmdexec("%s %s" % (self.pythonpath, dumpfile))
py.process.cmdexec("{} {}".format(self.pythonpath, dumpfile))
def load_and_is_true(self, expression):
loadfile = self.picklefile.dirpath("load.py")
loadfile.write(
_pytest._code.Source(
"""
import pickle
f = open(%r, 'rb')
obj = pickle.load(f)
f.close()
res = eval(%r)
if not res:
raise SystemExit(1)
"""
% (str(self.picklefile), expression)
textwrap.dedent(
"""\
import pickle
f = open({!r}, 'rb')
obj = pickle.load(f)
f.close()
res = eval({!r})
if not res:
raise SystemExit(1)
""".format(
str(self.picklefile), expression
)
)
)
print(loadfile)
py.process.cmdexec("%s %s" % (self.pythonpath, loadfile))
py.process.cmdexec("{} {}".format(self.pythonpath, loadfile))
@pytest.mark.parametrize("obj", [42, {}, {1: 3}])

View File

@@ -59,7 +59,7 @@ consulted when reporting in ``verbose`` mode::
nonpython $ pytest -v
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: $REGENDOC_TMPDIR/nonpython, inifile:
collecting ... collected 2 items
@@ -84,8 +84,9 @@ interesting to just look at the collection tree::
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR/nonpython, inifile:
collected 2 items
<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

@@ -9,7 +9,6 @@ def pytest_collect_file(parent, path):
class YamlFile(pytest.File):
def collect(self):
import yaml # we need a yaml parser, e.g. PyYAML
@@ -19,7 +18,6 @@ class YamlFile(pytest.File):
class YamlItem(pytest.Item):
def __init__(self, name, parent, spec):
super(YamlItem, self).__init__(name, parent)
self.spec = spec

View File

@@ -411,8 +411,10 @@ is to be run with different sets of arguments for its three arguments:
Running it results in some skips if we don't have all the python interpreters installed and otherwise runs all combinations (5 interpreters times 5 interpreters times 3 objects to serialize/deserialize)::
. $ pytest -rs -q multipython.py
........................... [100%]
27 passed in 0.12 seconds
...sss...sssssssss...sss... [100%]
========================= short test summary info ==========================
SKIP [15] $REGENDOC_TMPDIR/CWD/multipython.py:29: 'python3.4' not found
12 passed, 15 skipped in 0.12 seconds
Indirect parametrization of optional implementations/imports
--------------------------------------------------------------------

View File

@@ -5,7 +5,6 @@ py3 = sys.version_info[0] >= 3
class DummyCollector(pytest.collect.File):
def collect(self):
return []

View File

@@ -7,7 +7,6 @@ def test_function():
class TestClass(object):
def test_method(self):
pass

View File

@@ -100,19 +100,21 @@ Changing naming conventions
You can configure different naming conventions by setting
the :confval:`python_files`, :confval:`python_classes` and
:confval:`python_functions` configuration options. Example::
:confval:`python_functions` configuration options.
Here is an example::
# content of pytest.ini
# Example 1: have pytest look for "check" instead of "test"
# can also be defined in tox.ini or setup.cfg file, although the section
# name in setup.cfg files should be "tool:pytest"
[pytest]
python_files=check_*.py
python_classes=Check
python_functions=*_check
python_files = check_*.py
python_classes = Check
python_functions = *_check
This would make ``pytest`` look for tests in files that match the ``check_*
.py`` glob-pattern, ``Check`` prefixes in classes, and functions and methods
that match ``*_check``. For example, if we have::
that match ``*_check``. For example, if we have::
# content of check_myapp.py
class CheckMyApp(object):
@@ -121,7 +123,7 @@ that match ``*_check``. For example, if we have::
def complex_check(self):
pass
then the test collection looks like this::
The test collection would look like this::
$ pytest --collect-only
=========================== test session starts ============================
@@ -136,11 +138,19 @@ then the test collection looks like this::
======================= no tests ran in 0.12 seconds =======================
You can check for multiple glob patterns by adding a space between the patterns::
# Example 2: have pytest look for files with "test" and "example"
# content of pytest.ini, tox.ini, or setup.cfg file (replace "pytest"
# with "tool:pytest" for setup.cfg)
[pytest]
python_files = test_*.py example_*.py
.. note::
the ``python_functions`` and ``python_classes`` options has no effect
for ``unittest.TestCase`` test discovery because pytest delegates
detection of test case methods to unittest code.
discovery of test case methods to unittest code.
Interpreting cmdline arguments as Python packages
-----------------------------------------------------

View File

@@ -32,7 +32,6 @@ get on the terminal - we are working on that)::
self = <failure_demo.TestFailing object at 0xdeadbeef>
def test_simple(self):
def f():
return 42
@@ -44,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:37: AssertionError
failure_demo.py:35: AssertionError
____________________ TestFailing.test_simple_multiline _____________________
self = <failure_demo.TestFailing object at 0xdeadbeef>
@@ -52,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:40:
failure_demo.py:38:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
a = 42, b = 54
@@ -67,7 +66,6 @@ get on the terminal - we are working on that)::
self = <failure_demo.TestFailing object at 0xdeadbeef>
def test_not(self):
def f():
return 42
@@ -75,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:47: AssertionError
failure_demo.py:44: AssertionError
_________________ TestSpecialisedExplanations.test_eq_text _________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -86,7 +84,7 @@ get on the terminal - we are working on that)::
E - spam
E + eggs
failure_demo.py:53: AssertionError
failure_demo.py:49: AssertionError
_____________ TestSpecialisedExplanations.test_eq_similar_text _____________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -99,7 +97,7 @@ get on the terminal - we are working on that)::
E + foo 2 bar
E ? ^
failure_demo.py:56: AssertionError
failure_demo.py:52: AssertionError
____________ TestSpecialisedExplanations.test_eq_multiline_text ____________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -112,7 +110,7 @@ get on the terminal - we are working on that)::
E + eggs
E bar
failure_demo.py:59: AssertionError
failure_demo.py:55: AssertionError
______________ TestSpecialisedExplanations.test_eq_long_text _______________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -129,7 +127,7 @@ get on the terminal - we are working on that)::
E + 1111111111b222222222
E ? ^
failure_demo.py:64: AssertionError
failure_demo.py:60: AssertionError
_________ TestSpecialisedExplanations.test_eq_long_text_multiline __________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -149,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:69: AssertionError
failure_demo.py:65: AssertionError
_________________ TestSpecialisedExplanations.test_eq_list _________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -160,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:72: AssertionError
failure_demo.py:68: AssertionError
______________ TestSpecialisedExplanations.test_eq_list_long _______________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -173,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:77: AssertionError
failure_demo.py:73: AssertionError
_________________ TestSpecialisedExplanations.test_eq_dict _________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -191,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:80: AssertionError
failure_demo.py:76: AssertionError
_________________ TestSpecialisedExplanations.test_eq_set __________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -209,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:83: AssertionError
failure_demo.py:79: AssertionError
_____________ TestSpecialisedExplanations.test_eq_longer_list ______________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -220,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:86: AssertionError
failure_demo.py:82: AssertionError
_________________ TestSpecialisedExplanations.test_in_list _________________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -229,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:89: AssertionError
failure_demo.py:85: AssertionError
__________ TestSpecialisedExplanations.test_not_in_text_multiline __________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -248,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:93: AssertionError
failure_demo.py:89: AssertionError
___________ TestSpecialisedExplanations.test_not_in_text_single ____________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -261,7 +259,7 @@ get on the terminal - we are working on that)::
E single foo line
E ? +++
failure_demo.py:97: AssertionError
failure_demo.py:93: AssertionError
_________ TestSpecialisedExplanations.test_not_in_text_single_long _________
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -274,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:101: AssertionError
failure_demo.py:97: AssertionError
______ TestSpecialisedExplanations.test_not_in_text_single_long_term _______
self = <failure_demo.TestSpecialisedExplanations object at 0xdeadbeef>
@@ -287,11 +285,10 @@ 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:105: AssertionError
failure_demo.py:101: AssertionError
______________________________ test_attribute ______________________________
def test_attribute():
class Foo(object):
b = 1
@@ -300,11 +297,10 @@ 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:114: AssertionError
failure_demo.py:109: AssertionError
_________________________ test_attribute_instance __________________________
def test_attribute_instance():
class Foo(object):
b = 1
@@ -313,13 +309,11 @@ 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:122: AssertionError
failure_demo.py:116: AssertionError
__________________________ test_attribute_failure __________________________
def test_attribute_failure():
class Foo(object):
def _get_b(self):
raise Exception("Failed to get attrib")
@@ -328,7 +322,7 @@ get on the terminal - we are working on that)::
i = Foo()
> assert i.b == 2
failure_demo.py:135:
failure_demo.py:127:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <failure_demo.test_attribute_failure.<locals>.Foo object at 0xdeadbeef>
@@ -337,11 +331,10 @@ get on the terminal - we are working on that)::
> raise Exception("Failed to get attrib")
E Exception: Failed to get attrib
failure_demo.py:130: Exception
failure_demo.py:122: Exception
_________________________ test_attribute_multiple __________________________
def test_attribute_multiple():
class Foo(object):
b = 1
@@ -355,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:146: AssertionError
failure_demo.py:137: AssertionError
__________________________ TestRaises.test_raises __________________________
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -364,13 +357,13 @@ get on the terminal - we are working on that)::
s = "qwe" # NOQA
> raises(TypeError, "int(s)")
failure_demo.py:157:
failure_demo.py:147:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> int(s)
E ValueError: invalid literal for int() with base 10: 'qwe'
<0-codegen $PYTHON_PREFIX/lib/python3.5/site-packages/_pytest/python_api.py:634>:1: ValueError
<0-codegen $PYTHON_PREFIX/lib/python3.6/site-packages/_pytest/python_api.py:682>:1: ValueError
______________________ TestRaises.test_raises_doesnt _______________________
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -379,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:160: Failed
failure_demo.py:150: Failed
__________________________ TestRaises.test_raise ___________________________
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -388,7 +381,7 @@ get on the terminal - we are working on that)::
> raise ValueError("demo error")
E ValueError: demo error
failure_demo.py:163: ValueError
failure_demo.py:153: ValueError
________________________ TestRaises.test_tupleerror ________________________
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -397,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:166: ValueError
failure_demo.py:156: ValueError
______ TestRaises.test_reinterpret_fails_with_print_for_the_fun_of_it ______
self = <failure_demo.TestRaises object at 0xdeadbeef>
@@ -408,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:171: TypeError
failure_demo.py:161: TypeError
--------------------------- Captured stdout call ---------------------------
items is [1, 2, 3]
________________________ TestRaises.test_some_error ________________________
@@ -419,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:174: NameError
failure_demo.py:164: NameError
____________________ test_dynamic_compile_shows_nicely _____________________
def test_dynamic_compile_shows_nicely():
@@ -430,24 +423,23 @@ get on the terminal - we are working on that)::
name = "abc-123"
module = imp.new_module(name)
code = _pytest._code.compile(src, name, "exec")
py.builtin.exec_(code, module.__dict__)
six.exec_(code, module.__dict__)
sys.modules[name] = module
> module.foo()
failure_demo.py:192:
failure_demo.py:182:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def foo():
> assert 1 == 0
E AssertionError
<2-codegen 'abc-123' $REGENDOC_TMPDIR/assertion/failure_demo.py:189>:2: AssertionError
<2-codegen 'abc-123' $REGENDOC_TMPDIR/assertion/failure_demo.py:179>:2: AssertionError
____________________ TestMoreErrors.test_complex_error _____________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
def test_complex_error(self):
def f():
return 44
@@ -456,7 +448,7 @@ get on the terminal - we are working on that)::
> somefunc(f(), g())
failure_demo.py:205:
failure_demo.py:193:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
failure_demo.py:11: in somefunc
otherfunc(x, y)
@@ -478,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:209: ValueError
failure_demo.py:197: ValueError
____________________ TestMoreErrors.test_z2_type_error _____________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -488,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:213: TypeError
failure_demo.py:201: TypeError
______________________ TestMoreErrors.test_startswith ______________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -501,13 +493,12 @@ 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:218: AssertionError
failure_demo.py:206: AssertionError
__________________ TestMoreErrors.test_startswith_nested ___________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
def test_startswith_nested(self):
def f():
return "123"
@@ -521,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:228: AssertionError
failure_demo.py:215: AssertionError
_____________________ TestMoreErrors.test_global_func ______________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -532,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:231: AssertionError
failure_demo.py:218: AssertionError
_______________________ TestMoreErrors.test_instance _______________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -543,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:235: AssertionError
failure_demo.py:222: AssertionError
_______________________ TestMoreErrors.test_compare ________________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -553,7 +544,7 @@ get on the terminal - we are working on that)::
E assert 11 < 5
E + where 11 = globf(10)
failure_demo.py:238: AssertionError
failure_demo.py:225: AssertionError
_____________________ TestMoreErrors.test_try_finally ______________________
self = <failure_demo.TestMoreErrors object at 0xdeadbeef>
@@ -564,13 +555,12 @@ get on the terminal - we are working on that)::
> assert x == 0
E assert 1 == 0
failure_demo.py:243: AssertionError
failure_demo.py:230: AssertionError
___________________ TestCustomAssertMsg.test_single_line ___________________
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
def test_single_line(self):
class A(object):
a = 1
@@ -580,13 +570,12 @@ 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:256: AssertionError
failure_demo.py:241: AssertionError
____________________ TestCustomAssertMsg.test_multiline ____________________
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
def test_multiline(self):
class A(object):
a = 1
@@ -600,13 +589,12 @@ 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:264: AssertionError
failure_demo.py:248: AssertionError
___________________ TestCustomAssertMsg.test_custom_repr ___________________
self = <failure_demo.TestCustomAssertMsg object at 0xdeadbeef>
def test_custom_repr(self):
class JSON(object):
a = 1
@@ -623,11 +611,11 @@ 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:278: AssertionError
failure_demo.py:261: AssertionError
============================= warnings summary =============================
<undetermined location>
Metafunc.addcall is deprecated and scheduled to be removed in pytest 4.0.
Please use Metafunc.parametrize instead.
$REGENDOC_TMPDIR/assertion/failure_demo.py:24: RemovedInPytest4Warning: Metafunc.addcall is deprecated and scheduled to be removed in pytest 4.0.
Please use Metafunc.parametrize instead.
metafunc.addcall(funcargs=dict(param1=3, param2=6))
-- Docs: http://doc.pytest.org/en/latest/warnings.html
-- Docs: https://docs.pytest.org/en/latest/warnings.html
================== 42 failed, 1 warnings in 0.12 seconds ===================

View File

@@ -357,7 +357,7 @@ which will add info only when run with "--v"::
$ pytest -v
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
info1: did you know that ...
did you?

View File

@@ -55,18 +55,18 @@ using it::
import pytest
@pytest.fixture
def smtp():
def smtp_connection():
import smtplib
return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
def test_ehlo(smtp):
response, msg = smtp.ehlo()
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
assert 0 # for demo purposes
Here, the ``test_ehlo`` needs the ``smtp`` fixture value. pytest
Here, the ``test_ehlo`` needs the ``smtp_connection`` fixture value. pytest
will discover and call the :py:func:`@pytest.fixture <_pytest.python.fixture>`
marked ``smtp`` fixture function. Running the test looks like this::
marked ``smtp_connection`` fixture function. Running the test looks like this::
$ pytest test_smtpsimple.py
=========================== test session starts ============================
@@ -79,10 +79,10 @@ marked ``smtp`` fixture function. Running the test looks like this::
================================= FAILURES =================================
________________________________ test_ehlo _________________________________
smtp = <smtplib.SMTP object at 0xdeadbeef>
smtp_connection = <smtplib.SMTP object at 0xdeadbeef>
def test_ehlo(smtp):
response, msg = smtp.ehlo()
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
> assert 0 # for demo purposes
E assert 0
@@ -91,18 +91,18 @@ marked ``smtp`` fixture function. Running the test looks like this::
========================= 1 failed in 0.12 seconds =========================
In the failure traceback we see that the test function was called with a
``smtp`` argument, the ``smtplib.SMTP()`` instance created by the fixture
``smtp_connection`` argument, the ``smtplib.SMTP()`` instance created by the fixture
function. The test function fails on our deliberate ``assert 0``. Here is
the exact protocol used by ``pytest`` to call the test function this way:
1. pytest :ref:`finds <test discovery>` the ``test_ehlo`` because
of the ``test_`` prefix. The test function needs a function argument
named ``smtp``. A matching fixture function is discovered by
looking for a fixture-marked function named ``smtp``.
named ``smtp_connection``. A matching fixture function is discovered by
looking for a fixture-marked function named ``smtp_connection``.
2. ``smtp()`` is called to create an instance.
2. ``smtp_connection()`` is called to create an instance.
3. ``test_ehlo(<SMTP instance>)`` is called and fails in the last
3. ``test_ehlo(<smtp_connection instance>)`` is called and fails in the last
line of the test function.
Note that if you misspell a function argument or want
@@ -154,7 +154,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>`__
and `pytest-datafiles <https://pypi.python.org/pypi/pytest-datafiles>`__.
and `pytest-datafiles <https://pypi.org/project/pytest-datafiles/>`__.
.. _smtpshared:
@@ -167,10 +167,11 @@ Fixtures requiring network access depend on connectivity and are
usually time-expensive to create. Extending the previous example, we
can add a ``scope="module"`` parameter to the
:py:func:`@pytest.fixture <_pytest.python.fixture>` invocation
to cause the decorated ``smtp`` fixture function to only be invoked once
per test *module* (the default is to invoke once per test *function*).
to cause the decorated ``smtp_connection`` fixture function to only be invoked
once per test *module* (the default is to invoke once per test *function*).
Multiple test functions in a test module will thus
each receive the same ``smtp`` fixture instance, thus saving time.
each receive the same ``smtp_connection`` fixture instance, thus saving time.
Possible values for ``scope`` are: ``function``, ``class``, ``module``, ``package`` or ``session``.
The next example puts the fixture function into a separate ``conftest.py`` file
so that tests from multiple test modules in the directory can
@@ -181,23 +182,24 @@ access the fixture function::
import smtplib
@pytest.fixture(scope="module")
def smtp():
def smtp_connection():
return smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
The name of the fixture again is ``smtp`` and you can access its result by
listing the name ``smtp`` as an input parameter in any test or fixture
function (in or below the directory where ``conftest.py`` is located)::
The name of the fixture again is ``smtp_connection`` and you can access its
result by listing the name ``smtp_connection`` as an input parameter in any
test or fixture function (in or below the directory where ``conftest.py`` is
located)::
# content of test_module.py
def test_ehlo(smtp):
response, msg = smtp.ehlo()
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
assert b"smtp.gmail.com" in msg
assert 0 # for demo purposes
def test_noop(smtp):
response, msg = smtp.noop()
def test_noop(smtp_connection):
response, msg = smtp_connection.noop()
assert response == 250
assert 0 # for demo purposes
@@ -215,10 +217,10 @@ inspect what is going on and can now run the tests::
================================= FAILURES =================================
________________________________ test_ehlo _________________________________
smtp = <smtplib.SMTP object at 0xdeadbeef>
smtp_connection = <smtplib.SMTP object at 0xdeadbeef>
def test_ehlo(smtp):
response, msg = smtp.ehlo()
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
assert b"smtp.gmail.com" in msg
> assert 0 # for demo purposes
@@ -227,10 +229,10 @@ inspect what is going on and can now run the tests::
test_module.py:6: AssertionError
________________________________ test_noop _________________________________
smtp = <smtplib.SMTP object at 0xdeadbeef>
smtp_connection = <smtplib.SMTP object at 0xdeadbeef>
def test_noop(smtp):
response, msg = smtp.noop()
def test_noop(smtp_connection):
response, msg = smtp_connection.noop()
assert response == 250
> assert 0 # for demo purposes
E assert 0
@@ -239,18 +241,18 @@ inspect what is going on and can now run the tests::
========================= 2 failed in 0.12 seconds =========================
You see the two ``assert 0`` failing and more importantly you can also see
that the same (module-scoped) ``smtp`` object was passed into the two
test functions because pytest shows the incoming argument values in the
traceback. As a result, the two test functions using ``smtp`` run as
quick as a single one because they reuse the same instance.
that the same (module-scoped) ``smtp_connection`` object was passed into the
two test functions because pytest shows the incoming argument values in the
traceback. As a result, the two test functions using ``smtp_connection`` run
as quick as a single one because they reuse the same instance.
If you decide that you rather want to have a session-scoped ``smtp``
If you decide that you rather want to have a session-scoped ``smtp_connection``
instance, you can simply declare it:
.. code-block:: python
@pytest.fixture(scope="session")
def smtp():
def smtp_connection():
# the returned fixture value will be shared for
# all tests needing it
...
@@ -258,6 +260,22 @@ instance, you can simply declare it:
Finally, the ``class`` scope will invoke the fixture once per test *class*.
``package`` scope (experimental)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. versionadded:: 3.7
In pytest 3.7 the ``package`` scope has been introduced. Package-scoped fixtures
are finalized when the last test of a *package* finishes.
.. warning::
This functionality is considered **experimental** and may be removed in future
versions if hidden corner-cases or serious problems with this functionality
are discovered after it gets more usage in the wild.
Use this new feature sparingly and please make sure to report any issues you find.
Higher-scoped fixtures are instantiated first
---------------------------------------------
@@ -323,11 +341,11 @@ the code after the *yield* statement serves as the teardown code:
@pytest.fixture(scope="module")
def smtp():
smtp = smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
yield smtp # provide the fixture value
def smtp_connection():
smtp_connection = smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
yield smtp_connection # provide the fixture value
print("teardown smtp")
smtp.close()
smtp_connection.close()
The ``print`` and ``smtp.close()`` statements will execute when the last test in
the module has finished execution, regardless of the exception status of the
@@ -340,7 +358,7 @@ Let's execute it::
2 failed in 0.12 seconds
We see that the ``smtp`` instance is finalized after the two
We see that the ``smtp_connection`` instance is finalized after the two
tests finished execution. Note that if we decorated our fixture
function with ``scope='function'`` then fixture setup and cleanup would
occur around each single test. In either case the test
@@ -358,13 +376,13 @@ Note that we can also seamlessly use the ``yield`` syntax with ``with`` statemen
@pytest.fixture(scope="module")
def smtp():
with smtplib.SMTP("smtp.gmail.com", 587, timeout=5) as smtp:
yield smtp # provide the fixture value
def smtp_connection():
with smtplib.SMTP("smtp.gmail.com", 587, timeout=5) as smtp_connection:
yield smtp_connection # provide the fixture value
The ``smtp`` connection will be closed after the test finished execution
because the ``smtp`` object automatically closes when
The ``smtp_connection`` connection will be closed after the test finished
execution because the ``smtp_connection`` object automatically closes when
the ``with`` statement ends.
Note that if an exception happens during the *setup* code (before the ``yield`` keyword), the
@@ -374,7 +392,7 @@ An alternative option for executing *teardown* code is to
make use of the ``addfinalizer`` method of the `request-context`_ object to register
finalization functions.
Here's the ``smtp`` fixture changed to use ``addfinalizer`` for cleanup:
Here's the ``smtp_connection`` fixture changed to use ``addfinalizer`` for cleanup:
.. code-block:: python
@@ -384,15 +402,15 @@ Here's the ``smtp`` fixture changed to use ``addfinalizer`` for cleanup:
@pytest.fixture(scope="module")
def smtp(request):
smtp = smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
def smtp_connection(request):
smtp_connection = smtplib.SMTP("smtp.gmail.com", 587, timeout=5)
def fin():
print("teardown smtp")
smtp.close()
print("teardown smtp_connection")
smtp_connection.close()
request.addfinalizer(fin)
return smtp # provide the fixture value
return smtp_connection # provide the fixture value
Both ``yield`` and ``addfinalizer`` methods work similarly by calling their code after the test
@@ -425,7 +443,7 @@ Fixtures can introspect the requesting test context
Fixture functions can accept the :py:class:`request <FixtureRequest>` object
to introspect the "requesting" test function, class or module context.
Further extending the previous ``smtp`` fixture example, let's
Further extending the previous ``smtp_connection`` fixture example, let's
read an optional server URL from the test module which uses our fixture::
# content of conftest.py
@@ -433,12 +451,12 @@ read an optional server URL from the test module which uses our fixture::
import smtplib
@pytest.fixture(scope="module")
def smtp(request):
def smtp_connection(request):
server = getattr(request.module, "smtpserver", "smtp.gmail.com")
smtp = smtplib.SMTP(server, 587, timeout=5)
yield smtp
print ("finalizing %s (%s)" % (smtp, server))
smtp.close()
smtp_connection = smtplib.SMTP(server, 587, timeout=5)
yield smtp_connection
print ("finalizing %s (%s)" % (smtp_connection, server))
smtp_connection.close()
We use the ``request.module`` attribute to optionally obtain an
``smtpserver`` attribute from the test module. If we just execute
@@ -456,8 +474,8 @@ server URL in its module namespace::
smtpserver = "mail.python.org" # will be read by smtp fixture
def test_showhelo(smtp):
assert 0, smtp.helo()
def test_showhelo(smtp_connection):
assert 0, smtp_connection.helo()
Running it::
@@ -466,13 +484,13 @@ Running it::
================================= FAILURES =================================
______________________________ test_showhelo _______________________________
test_anothersmtp.py:5: in test_showhelo
assert 0, smtp.helo()
assert 0, smtp_connection.helo()
E AssertionError: (250, b'mail.python.org')
E assert 0
------------------------- Captured stdout teardown -------------------------
finalizing <smtplib.SMTP object at 0xdeadbeef> (mail.python.org)
voila! The ``smtp`` fixture function picked up our mail server name
voila! The ``smtp_connection`` fixture function picked up our mail server name
from the module namespace.
.. _`fixture-factory`:
@@ -535,13 +553,13 @@ Parametrizing fixtures
Fixture functions can be parametrized in which case they will be called
multiple times, each time executing the set of dependent tests, i. e. the
tests that depend on this fixture. Test functions do usually not need
tests that depend on this fixture. Test functions usually do not need
to be aware of their re-running. Fixture parametrization helps to
write exhaustive functional tests for components which themselves can be
configured in multiple ways.
Extending the previous example, we can flag the fixture to create two
``smtp`` fixture instances which will cause all tests using the fixture
``smtp_connection`` fixture instances which will cause all tests using the fixture
to run twice. The fixture function gets access to each parameter
through the special :py:class:`request <FixtureRequest>` object::
@@ -551,11 +569,11 @@ through the special :py:class:`request <FixtureRequest>` object::
@pytest.fixture(scope="module",
params=["smtp.gmail.com", "mail.python.org"])
def smtp(request):
smtp = smtplib.SMTP(request.param, 587, timeout=5)
yield smtp
print ("finalizing %s" % smtp)
smtp.close()
def smtp_connection(request):
smtp_connection = smtplib.SMTP(request.param, 587, timeout=5)
yield smtp_connection
print("finalizing %s" % smtp_connection)
smtp_connection.close()
The main change is the declaration of ``params`` with
:py:func:`@pytest.fixture <_pytest.python.fixture>`, a list of values
@@ -568,10 +586,10 @@ So let's just do another run::
================================= FAILURES =================================
________________________ test_ehlo[smtp.gmail.com] _________________________
smtp = <smtplib.SMTP object at 0xdeadbeef>
smtp_connection = <smtplib.SMTP object at 0xdeadbeef>
def test_ehlo(smtp):
response, msg = smtp.ehlo()
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
assert b"smtp.gmail.com" in msg
> assert 0 # for demo purposes
@@ -580,10 +598,10 @@ So let's just do another run::
test_module.py:6: AssertionError
________________________ test_noop[smtp.gmail.com] _________________________
smtp = <smtplib.SMTP object at 0xdeadbeef>
smtp_connection = <smtplib.SMTP object at 0xdeadbeef>
def test_noop(smtp):
response, msg = smtp.noop()
def test_noop(smtp_connection):
response, msg = smtp_connection.noop()
assert response == 250
> assert 0 # for demo purposes
E assert 0
@@ -591,10 +609,10 @@ So let's just do another run::
test_module.py:11: AssertionError
________________________ test_ehlo[mail.python.org] ________________________
smtp = <smtplib.SMTP object at 0xdeadbeef>
smtp_connection = <smtplib.SMTP object at 0xdeadbeef>
def test_ehlo(smtp):
response, msg = smtp.ehlo()
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
assert response == 250
> assert b"smtp.gmail.com" in msg
E AssertionError: assert b'smtp.gmail.com' in b'mail.python.org\nPIPELINING\nSIZE 51200000\nETRN\nSTARTTLS\nAUTH DIGEST-MD5 NTLM CRAM-MD5\nENHANCEDSTATUSCODES\n8BITMIME\nDSN\nSMTPUTF8'
@@ -604,10 +622,10 @@ So let's just do another run::
finalizing <smtplib.SMTP object at 0xdeadbeef>
________________________ test_noop[mail.python.org] ________________________
smtp = <smtplib.SMTP object at 0xdeadbeef>
smtp_connection = <smtplib.SMTP object at 0xdeadbeef>
def test_noop(smtp):
response, msg = smtp.noop()
def test_noop(smtp_connection):
response, msg = smtp_connection.noop()
assert response == 250
> assert 0 # for demo purposes
E assert 0
@@ -618,7 +636,7 @@ So let's just do another run::
4 failed in 0.12 seconds
We see that our two test functions each ran twice, against the different
``smtp`` instances. Note also, that with the ``mail.python.org``
``smtp_connection`` instances. Note also, that with the ``mail.python.org``
connection the second test fails in ``test_ehlo`` because a
different server string is expected than what arrived.
@@ -709,7 +727,7 @@ Running this test will *skip* the invocation of ``data_set`` with value ``2``::
$ pytest test_fixture_marks.py -v
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 3 items
@@ -730,46 +748,46 @@ can use other fixtures themselves. This contributes to a modular design
of your fixtures and allows re-use of framework-specific fixtures across
many projects. As a simple example, we can extend the previous example
and instantiate an object ``app`` where we stick the already defined
``smtp`` resource into it::
``smtp_connection`` resource into it::
# content of test_appsetup.py
import pytest
class App(object):
def __init__(self, smtp):
self.smtp = smtp
def __init__(self, smtp_connection):
self.smtp_connection = smtp_connection
@pytest.fixture(scope="module")
def app(smtp):
return App(smtp)
def app(smtp_connection):
return App(smtp_connection)
def test_smtp_exists(app):
assert app.smtp
def test_smtp_connection_exists(app):
assert app.smtp_connection
Here we declare an ``app`` fixture which receives the previously defined
``smtp`` fixture and instantiates an ``App`` object with it. Let's run it::
``smtp_connection`` fixture and instantiates an ``App`` object with it. Let's run it::
$ pytest -v test_appsetup.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 2 items
test_appsetup.py::test_smtp_exists[smtp.gmail.com] PASSED [ 50%]
test_appsetup.py::test_smtp_exists[mail.python.org] PASSED [100%]
test_appsetup.py::test_smtp_connection_exists[smtp.gmail.com] PASSED [ 50%]
test_appsetup.py::test_smtp_connection_exists[mail.python.org] PASSED [100%]
========================= 2 passed in 0.12 seconds =========================
Due to the parametrization of ``smtp`` the test will run twice with two
Due to the parametrization of ``smtp_connection``, the test will run twice with two
different ``App`` instances and respective smtp servers. There is no
need for the ``app`` fixture to be aware of the ``smtp`` parametrization
as pytest will fully analyse the fixture dependency graph.
need for the ``app`` fixture to be aware of the ``smtp_connection``
parametrization because pytest will fully analyse the fixture dependency graph.
Note, that the ``app`` fixture has a scope of ``module`` and uses a
module-scoped ``smtp`` fixture. The example would still work if ``smtp``
was cached on a ``session`` scope: it is fine for fixtures to use
module-scoped ``smtp_connection`` fixture. The example would still work if
``smtp_connection`` was cached on a ``session`` scope: it is fine for fixtures to use
"broader" scoped fixtures but not the other way round:
A session-scoped fixture could not use a module-scoped one in a
meaningful way.
@@ -788,7 +806,7 @@ first execute with one instance and then finalizers are called
before the next fixture instance is created. Among other things,
this eases testing of applications which create and use global state.
The following example uses two parametrized fixture, one of which is
The following example uses two parametrized fixtures, one of which is
scoped on a per-module basis, and all the functions perform ``print`` calls
to show the setup/teardown flow::
@@ -821,7 +839,7 @@ Let's run the tests in verbose mode and with looking at the print-output::
$ pytest -v -s test_module.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.5
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python
cachedir: .pytest_cache
rootdir: $REGENDOC_TMPDIR, inifile:
collecting ... collected 8 items
@@ -943,7 +961,7 @@ a generic feature of the mark mechanism:
Note that the assigned variable *must* be called ``pytestmark``, assigning e.g.
``foomark`` will not activate the fixtures.
Lastly you can put fixtures required by all tests in your project
It is also possible to put fixtures required by all tests in your project
into an ini-file:
.. code-block:: ini
@@ -953,6 +971,22 @@ into an ini-file:
usefixtures = cleandir
.. warning::
Note this mark has no effect in **fixture functions**. For example,
this **will not work as expected**:
.. code-block:: python
@pytest.mark.usefixtures("my_other_fixture")
@pytest.fixture
def my_fixture_that_sadly_wont_use_my_other_fixture():
...
Currently this will not generate any error or warning, but this is intended
to be handled by `#3664 <https://github.com/pytest-dev/pytest/issues/3664>`_.
.. _`autouse`:
.. _`autouse fixtures`:

View File

@@ -7,7 +7,7 @@ pytest-2.3: reasoning for fixture/funcarg evolution
**Target audience**: Reading this document requires basic knowledge of
python testing, xUnit setup methods and the (previous) basic pytest
funcarg mechanism, see http://pytest.org/2.2.4/funcargs.html
funcarg mechanism, see https://docs.pytest.org/en/latest/historical-notes.html#funcargs-and-pytest-funcarg.
If you are new to pytest, then you can simply ignore this
section and read the other sections.

View File

@@ -1,7 +1,7 @@
Installation and Getting Started
===================================
**Pythons**: Python 2.7, 3.4, 3.5, 3.6, Jython, PyPy-2.3
**Pythons**: Python 2.7, 3.4, 3.5, 3.6, 3.7, Jython, PyPy-2.3
**Platforms**: Unix/Posix and Windows
@@ -27,7 +27,7 @@ Install ``pytest``
2. Check that you installed the correct version::
$ pytest --version
This is pytest version 3.x.y, imported from $PYTHON_PREFIX/lib/python3.5/site-packages/pytest.py
This is pytest version 3.x.y, imported from $PYTHON_PREFIX/lib/python3.6/site-packages/pytest.py
.. _`simpletest`:

View File

@@ -4,6 +4,27 @@
Good Integration Practices
=================================================
Install package with pip
-------------------------------------------------
For development, we recommend to use virtualenv_ environments and pip_
for installing your application and any dependencies
as well as the ``pytest`` package itself. This ensures your code and
dependencies are isolated from the system Python installation.
First you need to place a ``setup.py`` file in the root of your package with the following minimum content::
from setuptools import setup, find_packages
setup(name="PACKAGENAME", packages=find_packages())
Where ``PACKAGENAME`` is the name of your package. You can then install your package in "editable" mode by running from the same directory::
pip install -e .
which lets you change your source code (both tests and application) and rerun tests at will.
This is similar to running ``python setup.py develop`` or ``conda develop`` in that it installs
your package using a symlink to your development code.
.. _`test discovery`:
.. _`Python test discovery`:
@@ -177,19 +198,6 @@ Note that this layout also works in conjunction with the ``src`` layout mentione
tox
------
For development, we recommend to use virtualenv_ environments and pip_
for installing your application and any dependencies
as well as the ``pytest`` package itself. This ensures your code and
dependencies are isolated from the system Python installation.
You can then install your package in "editable" mode::
pip install -e .
which lets you change your source code (both tests and application) and rerun tests at will.
This is similar to running `python setup.py develop` or `conda develop` in that it installs
your package using a symlink to your development code.
Once you are done with your work and want to make sure that your actual
package passes all tests you may want to look into `tox`_, the
virtualenv test automation tool and its `pytest support
@@ -282,7 +290,7 @@ your own setuptools Test command for invoking pytest.
setup(
# ...,
tests_require=["pytest"],
cmdclass={"test": PyTest},
cmdclass={"pytest": PyTest},
)
Now if you run::

View File

@@ -52,22 +52,22 @@ should add ``--strict`` to ``addopts``:
serial
.. `marker-iteration`
.. _marker-revamp:
Marker revamp and iteration
---------------------------
.. versionadded:: 3.6
pytest's marker implementation traditionally worked by simply updating the ``__dict__`` attribute of functions to add markers, in a cumulative manner. As a result of the this, markers would unintendely be passed along class hierarchies in surprising ways plus the API for retriving them was inconsistent, as markers from parameterization would be stored differently than markers applied using the ``@pytest.mark`` decorator and markers added via ``node.add_marker``.
pytest's marker implementation traditionally worked by simply updating the ``__dict__`` attribute of functions to cumulatively add markers. As a result, markers would unintentionally be passed along class hierarchies in surprising ways. Further, the API for retrieving them was inconsistent, as markers from parameterization would be stored differently than markers applied using the ``@pytest.mark`` decorator and markers added via ``node.add_marker``.
This state of things made it technically next to impossible to use data from markers correctly without having a deep understanding of the internals, leading to subtle and hard to understand bugs in more advanced usages.
Depending on how a marker got declared/changed one would get either a ``MarkerInfo`` which might contain markers from sibling classes,
``MarkDecorators`` when marks came from parameterization or from a ``node.add_marker`` call, discarding prior marks. Also ``MarkerInfo`` acts like a single mark, when it in fact represents a merged view on multiple marks with the same name.
On top of that markers where not accessible the same way for modules, classes, and functions/methods,
in fact, markers where only accessible in functions, even if they where declared on classes/modules.
On top of that markers were not accessible the same way for modules, classes, and functions/methods.
In fact, markers were only accessible in functions, even if they were declared on classes/modules.
A new API to access markers has been introduced in pytest 3.6 in order to solve the problems with the initial design, providing :func:`_pytest.nodes.Node.iter_markers` method to iterate over markers in a consistent manner and reworking the internals, which solved great deal of problems with the initial design.
@@ -85,7 +85,7 @@ In general there are two scenarios on how markers should be handled:
1. Marks overwrite each other. Order matters but you only want to think of your mark as a single item. E.g.
``log_level('info')`` at a module level can be overwritten by ``log_level('debug')`` for a specific test.
In this case replace use ``Node.get_closest_marker(name)``:
In this case, use ``Node.get_closest_marker(name)``:
.. code-block:: python
@@ -99,7 +99,7 @@ In general there are two scenarios on how markers should be handled:
if marker:
level = marker.args[0]
2. Marks compose additive. E.g. ``skipif(condition)`` marks means you just want to evaluate all of them,
2. Marks compose in an additive manner. E.g. ``skipif(condition)`` marks mean you just want to evaluate all of them,
order doesn't even matter. You probably want to think of your marks as a set here.
In this case iterate over each mark and handle their ``*args`` and ``**kwargs`` individually.
@@ -129,27 +129,27 @@ Here is a non-exhaustive list of issues fixed by the new implementation:
* Marks don't pick up nested classes (`#199 <https://github.com/pytest-dev/pytest/issues/199>`_).
* markers stains on all related classes (`#568 <https://github.com/pytest-dev/pytest/issues/568>`_).
* Markers stain on all related classes (`#568 <https://github.com/pytest-dev/pytest/issues/568>`_).
* combining marks - args and kwargs calculation (`#2897 <https://github.com/pytest-dev/pytest/issues/2897>`_).
* Combining marks - args and kwargs calculation (`#2897 <https://github.com/pytest-dev/pytest/issues/2897>`_).
* ``request.node.get_marker('name')`` returns ``None`` for markers applied in classes (`#902 <https://github.com/pytest-dev/pytest/issues/902>`_).
* marks applied in parametrize are stored as markdecorator (`#2400 <https://github.com/pytest-dev/pytest/issues/2400>`_).
* Marks applied in parametrize are stored as markdecorator (`#2400 <https://github.com/pytest-dev/pytest/issues/2400>`_).
* fix marker interaction in a backward incompatible way (`#1670 <https://github.com/pytest-dev/pytest/issues/1670>`_).
* Fix marker interaction in a backward incompatible way (`#1670 <https://github.com/pytest-dev/pytest/issues/1670>`_).
* Refactor marks to get rid of the current "marks transfer" mechanism (`#2363 <https://github.com/pytest-dev/pytest/issues/2363>`_).
* Introduce FunctionDefinition node, use it in generate_tests (`#2522 <https://github.com/pytest-dev/pytest/issues/2522>`_).
* remove named marker attributes and collect markers in items (`#891 <https://github.com/pytest-dev/pytest/issues/891>`_).
* Remove named marker attributes and collect markers in items (`#891 <https://github.com/pytest-dev/pytest/issues/891>`_).
* skipif mark from parametrize hides module level skipif mark (`#1540 <https://github.com/pytest-dev/pytest/issues/1540>`_).
* skipif + parametrize not skipping tests (`#1296 <https://github.com/pytest-dev/pytest/issues/1296>`_).
* marker transfer incompatible with inheritance (`#535 <https://github.com/pytest-dev/pytest/issues/535>`_).
* Marker transfer incompatible with inheritance (`#535 <https://github.com/pytest-dev/pytest/issues/535>`_).
More details can be found in the `original PR <https://github.com/pytest-dev/pytest/pull/3317>`_.

View File

@@ -161,6 +161,25 @@ Skip a test function if a condition is ``True``.
:keyword str reason: Reason why the test function is being skipped.
.. _`pytest.mark.usefixtures ref`:
pytest.mark.usefixtures
~~~~~~~~~~~~~~~~~~~~~~~
**Tutorial**: :ref:`usefixtures`.
Mark a test function as using the given fixture names.
.. warning::
This mark can be used with *test functions* only, having no affect when applied
to a **fixture** function.
.. py:function:: pytest.mark.usefixtures(*names)
:param args: the names of the fixture to use, as strings
.. _`pytest.mark.xfail ref`:
pytest.mark.xfail
@@ -441,7 +460,7 @@ To use it, include in your top-most ``conftest.py`` file::
.. autoclass:: Testdir()
:members: runpytest,runpytest_subprocess,runpytest_inprocess,makeconftest,makepyfile
:members:
.. autoclass:: RunResult()
:members:
@@ -592,6 +611,8 @@ Session related reporting hooks:
.. autofunction:: pytest_terminal_summary
.. autofunction:: pytest_fixture_setup
.. autofunction:: pytest_fixture_post_finalizer
.. autofunction:: pytest_logwarning
.. autofunction:: pytest_warning_captured
And here is the central hook for reporting about
test execution:
@@ -768,7 +789,7 @@ TestReport
_Result
~~~~~~~
.. autoclass:: pluggy._Result
.. autoclass:: pluggy.callers._Result
:members:
Special Variables
@@ -847,6 +868,11 @@ Contains comma-separated list of modules that should be loaded as plugins:
export PYTEST_PLUGINS=mymodule.plugin,xdist
PYTEST_DISABLE_PLUGIN_AUTOLOAD
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When set, disables plugin auto-loading through setuptools entrypoints. Only explicitly specified plugins will be
loaded.
PYTEST_CURRENT_TEST
~~~~~~~~~~~~~~~~~~~
@@ -916,6 +942,7 @@ passed multiple times. The expected format is ``name=value``. For example::
* ``classic``: classic pytest output.
* ``progress``: like classic pytest output, but with a progress indicator.
* ``count``: like progress, but shows progress as the number of tests completed instead of a percent.
The default is ``progress``, but you can fallback to ``classic`` if you prefer or
the new mode is causing unexpected problems:
@@ -1210,7 +1237,8 @@ passed multiple times. The expected format is ``name=value``. For example::
.. confval:: python_classes
One or more name prefixes or glob-style patterns determining which classes
are considered for test collection. By default, pytest will consider any
are considered for test collection. Search for multiple glob patterns by
adding a space between patterns. By default, pytest will consider any
class prefixed with ``Test`` as a test collection. Here is an example of how
to collect tests from classes that end in ``Suite``:
@@ -1227,15 +1255,33 @@ passed multiple times. The expected format is ``name=value``. For example::
.. confval:: python_files
One or more Glob-style file patterns determining which python files
are considered as test modules. By default, pytest will consider
any file matching with ``test_*.py`` and ``*_test.py`` globs as a test
module.
are considered as test modules. Search for multiple glob patterns by
adding a space between patterns:
.. code-block:: ini
[pytest]
python_files = test_*.py check_*.py example_*.py
Or one per line:
.. code-block:: ini
[pytest]
python_files =
test_*.py
check_*.py
example_*.py
By default, files matching ``test_*.py`` and ``*_test.py`` will be considered
test modules.
.. confval:: python_functions
One or more name prefixes or glob-patterns determining which test functions
and methods are considered tests. By default, pytest will consider any
and methods are considered tests. Search for multiple glob patterns by
adding a space between patterns. By default, pytest will consider any
function prefixed with ``test`` as a test. Here is an example of how
to collect test functions and methods that end in ``_test``:

View File

@@ -80,11 +80,11 @@ during import time.
If you wish to skip something conditionally then you can use ``skipif`` instead.
Here is an example of marking a test function to be skipped
when run on a Python3.6 interpreter::
when run on an interpreter earlier than Python3.6 ::
import sys
@pytest.mark.skipif(sys.version_info < (3,6),
reason="requires python3.6")
reason="requires python3.6 or higher")
def test_function():
...
@@ -136,12 +136,6 @@ You can use the ``skipif`` marker (as any other marker) on classes::
If the condition is ``True``, this marker will produce a skip result for
each of the test methods of that class.
.. warning::
The use of ``skipif`` on classes that use inheritance is strongly
discouraged. `A Known bug <https://github.com/pytest-dev/pytest/issues/568>`_
in pytest's markers may cause unexpected behavior in super classes.
If you want to skip all test functions of a module, you may use
the ``pytestmark`` name on the global level:
@@ -283,7 +277,7 @@ on a particular platform::
~~~~~~~~~~~~~~~~~~~~
If you want to be more specific as to why the test is failing, you can specify
a single exception, or a list of exceptions, in the ``raises`` argument.
a single exception, or a tuple of exceptions, in the ``raises`` argument.
.. code-block:: python

View File

@@ -14,6 +14,9 @@ Talks and Tutorials
Books
---------------------------------------------
- `pytest Quick Start Guide, by Bruno Oliveira (2018)
<https://www.packtpub.com/web-development/pytest-quick-start-guide>`_.
- `Python Testing with pytest, by Brian Okken (2017)
<https://pragprog.com/book/bopytest/python-testing-with-pytest>`_.

View File

@@ -140,6 +140,49 @@ will be shown (because KeyboardInterrupt is caught by pytest). By using this
option you make sure a trace is shown.
.. _`pytest.detailed_failed_tests_usage`:
Detailed summary report
-----------------------
.. versionadded:: 2.9
The ``-r`` flag can be used to display test results summary at the end of the test session,
making it easy in large test suites to get a clear picture of all failures, skips, xfails, etc.
Example::
$ pytest -ra
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 0 items
======================= no tests ran in 0.12 seconds =======================
The ``-r`` options accepts a number of characters after it, with ``a`` used above meaning "all except passes".
Here is the full list of available characters that can be used:
- ``f`` - failed
- ``E`` - error
- ``s`` - skipped
- ``x`` - xfailed
- ``X`` - xpassed
- ``p`` - passed
- ``P`` - passed with output
- ``a`` - all except ``pP``
More than one character can be used, so for example to only see failed and skipped tests, you can execute::
$ pytest -rfs
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 0 items
======================= no tests ran in 0.12 seconds =======================
.. _pdb-option:
Dropping to PDB_ (Python Debugger) on failures
@@ -171,6 +214,18 @@ for example::
>>> sys.last_value
AssertionError('assert result == "ok"',)
.. _trace-option:
Dropping to PDB_ (Python Debugger) at the start of a test
----------------------------------------------------------
``pytest`` allows one to drop into the PDB_ prompt immediately at the start of each test via a command line option::
pytest --trace
This will invoke the Python debugger at the start of every test.
.. _breakpoints:
Setting breakpoints
@@ -200,7 +255,7 @@ Pytest supports the use of ``breakpoint()`` with the following behaviours:
- When ``breakpoint()`` is called and ``PYTHONBREAKPOINT`` is set to the default value, pytest will use the custom internal PDB trace UI instead of the system default ``Pdb``.
- When tests are complete, the system will default back to the system ``Pdb`` trace UI.
- If ``--pdb`` is called on execution of pytest, the custom internal Pdb trace UI is used on ``bothbreakpoint()`` and failed tests/unhandled exceptions.
- If ``--pdb`` is called on execution of pytest, the custom internal Pdb trace UI is used on both ``breakpoint()`` and failed tests/unhandled exceptions.
- If ``--pdbcls`` is used, the custom class debugger will be executed when a test fails (as expected within existing behaviour), but also when ``breakpoint()`` is called from within a test, the custom class debugger will be instantiated.
.. _durations:

View File

@@ -29,15 +29,12 @@ Running pytest now produces this output::
test_show_warnings.py . [100%]
============================= warnings summary =============================
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"))
$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: http://doc.pytest.org/en/latest/warnings.html
-- Docs: https://docs.pytest.org/en/latest/warnings.html
=================== 1 passed, 1 warnings in 0.12 seconds ===================
Pytest by default catches all warnings except for ``DeprecationWarning`` and ``PendingDeprecationWarning``.
The ``-W`` flag can be passed to control which warnings will be displayed or even turn
them into errors::
@@ -78,6 +75,53 @@ Both ``-W`` command-line option and ``filterwarnings`` ini option are based on P
`-W option`_ and `warnings.simplefilter`_, so please refer to those sections in the Python
documentation for other examples and advanced usage.
Disabling warning summary
-------------------------
Although not recommended, you can use the ``--disable-warnings`` command-line option to suppress the
warning summary entirely from the test run output.
Disabling warning capture entirely
----------------------------------
This plugin is enabled by default but can be disabled entirely in your ``pytest.ini`` file with:
.. code-block:: ini
[pytest]
addopts = -p no:warnings
Or passing ``-p no:warnings`` in the command-line. This might be useful if your test suites handles warnings
using an external system.
.. _`deprecation-warnings`:
DeprecationWarning and PendingDeprecationWarning
------------------------------------------------
.. versionadded:: 3.8
By default pytest will display ``DeprecationWarning`` and ``PendingDeprecationWarning`` if no other warning filters
are configured.
To disable showing ``DeprecationWarning`` and ``PendingDeprecationWarning`` warnings, you might define any warnings
filter either in the command-line or in the ini file, or you can use:
.. code-block:: ini
[pytest]
filterwarnings =
ignore::DeprecationWarning
ignore::PendingDeprecationWarning
.. note::
This makes pytest more compliant with `PEP-0506 <https://www.python.org/dev/peps/pep-0565/#recommended-filter-settings-for-test-runners>`_ which suggests that those warnings should
be shown by default by test runners, but pytest doesn't follow ``PEP-0506`` completely because resetting all
warning filters like suggested in the PEP will break existing test suites that configure warning filters themselves
by calling ``warnings.simplefilter`` (see issue `#2430 <https://github.com/pytest-dev/pytest/issues/2430>`_
for an example of that).
.. _`filterwarnings`:
@@ -144,18 +188,6 @@ decorator or to all tests in a module by setting the ``pytestmark`` variable:
.. _`pytest-warnings`: https://github.com/fschulze/pytest-warnings
Disabling warning capture
-------------------------
This feature is enabled by default but can be disabled entirely in your ``pytest.ini`` file with:
.. code-block:: ini
[pytest]
addopts = -p no:warnings
Or passing ``-p no:warnings`` in the command-line.
.. _`asserting warnings`:
.. _assertwarnings:
@@ -296,3 +328,53 @@ You can also use it as a contextmanager::
def test_global():
with pytest.deprecated_call():
myobject.deprecated_method()
.. _internal-warnings:
Internal pytest warnings
------------------------
.. versionadded:: 3.8
pytest may generate its own warnings in some situations, such as improper usage or deprecated features.
For example, pytest will emit a warning if it encounters a class that matches :confval:`python_classes` but also
defines an ``__init__`` constructor, as this prevents the class from being instantiated:
.. code-block:: python
# content of test_pytest_warnings.py
class Test:
def __init__(self):
pass
def test_foo(self):
assert 1 == 1
::
$ 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:
-- Docs: https://docs.pytest.org/en/latest/warnings.html
1 warnings in 0.12 seconds
These warnings might be filtered using the same builtin mechanisms used to filter other types of warnings.
Please read our :ref:`backwards-compatibility` to learn how we proceed about deprecating and eventually removing
features.
The following warning types ares used by pytest and are part of the public API:
.. autoclass:: pytest.PytestWarning
.. autoclass:: pytest.PytestDeprecationWarning
.. autoclass:: pytest.RemovedInPytest4Warning
.. autoclass:: pytest.PytestExperimentalApiWarning

View File

@@ -386,11 +386,51 @@ 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
.. code:: ini
# content of pytest.ini
[pytest]
pytester_example_dir = .
.. code:: python
# content of test_example.py
def test_plugin(testdir):
testdir.copy_example("test_example.py")
testdir.runpytest("-k", "test_example")
def test_example():
pass
.. code::
$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-3.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
collected 2 items
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")
-- Docs: https://docs.pytest.org/en/latest/warnings.html
=================== 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
<_pytest.pytester.RunResult>` documentation.
.. _`writinghooks`:
Writing hook functions

View File

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

View File

@@ -1,8 +0,0 @@
REM skip "coveralls" run in PRs or forks
if "%TOXENV%" == "coveralls" (
if not defined COVERALLS_REPO_TOKEN (
echo skipping coveralls run because COVERALLS_REPO_TOKEN is not defined
exit /b 0
)
)
C:\Python36\python -m tox

View File

@@ -0,0 +1,10 @@
REM scripts called by AppVeyor to setup the environment variables to enable coverage
if not defined PYTEST_NO_COVERAGE (
set "COVERAGE_FILE=%CD%\.coverage"
set "COVERAGE_PROCESS_START=%CD%\.coveragerc"
set "_PYTEST_TOX_COVERAGE_RUN=coverage run -m"
set "_PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess"
echo Coverage setup completed
) else (
echo Skipping coverage setup, PYTEST_NO_COVERAGE is set
)

View File

@@ -9,11 +9,11 @@ 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:
http://doc.pytest.org/en/latest/changelog.html
https://docs.pytest.org/en/latest/changelog.html
For complete documentation, please visit:
http://docs.pytest.org
https://docs.pytest.org/en/latest/
As usual, you can upgrade from pypi via:

View File

@@ -7,7 +7,7 @@ This is a bug-fix release, being a drop-in replacement. To upgrade::
pip install --upgrade pytest
The full changelog is available at http://doc.pytest.org/en/latest/changelog.html.
The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
Thanks to all who contributed to this release, among them:

111
scripts/release.py Normal file
View File

@@ -0,0 +1,111 @@
"""
Invoke development tasks.
"""
import argparse
from colorama import init, Fore
from pathlib import Path
from subprocess import check_output, check_call, call
def announce(version):
"""Generates a new release announcement entry in the docs."""
# Get our list of authors
stdout = check_output(["git", "describe", "--abbrev=0", "--tags"])
stdout = stdout.decode("utf-8")
last_version = stdout.strip()
stdout = check_output(
["git", "log", "{}..HEAD".format(last_version), "--format=%aN"]
)
stdout = stdout.decode("utf-8")
contributors = set(stdout.splitlines())
template_name = (
"release.minor.rst" if version.endswith(".0") else "release.patch.rst"
)
template_text = (
Path(__file__).parent.joinpath(template_name).read_text(encoding="UTF-8")
)
contributors_text = (
"\n".join("* {}".format(name) for name in sorted(contributors)) + "\n"
)
text = template_text.format(version=version, contributors=contributors_text)
target = Path(__file__).parent.joinpath(
"../doc/en/announce/release-{}.rst".format(version)
)
target.write_text(text, encoding="UTF-8")
print(f"{Fore.CYAN}[generate.announce] {Fore.RESET}Generated {target.name}")
# Update index with the new release entry
index_path = Path(__file__).parent.joinpath("../doc/en/announce/index.rst")
lines = index_path.read_text(encoding="UTF-8").splitlines()
indent = " "
for index, line in enumerate(lines):
if line.startswith("{}release-".format(indent)):
new_line = indent + target.stem
if line != new_line:
lines.insert(index, new_line)
index_path.write_text("\n".join(lines) + "\n", encoding="UTF-8")
print(
f"{Fore.CYAN}[generate.announce] {Fore.RESET}Updated {index_path.name}"
)
else:
print(
f"{Fore.CYAN}[generate.announce] {Fore.RESET}Skip {index_path.name} (already contains release)"
)
break
check_call(["git", "add", str(target)])
def regen():
"""Call regendoc tool to update examples and pytest output in the docs."""
print(f"{Fore.CYAN}[generate.regen] {Fore.RESET}Updating docs")
check_call(["tox", "-e", "regen"])
def fix_formatting():
"""Runs pre-commit in all files to ensure they are formatted correctly"""
print(
f"{Fore.CYAN}[generate.fix linting] {Fore.RESET}Fixing formatting using pre-commit"
)
call(["pre-commit", "run", "--all-files"])
def pre_release(version):
"""Generates new docs, release announcements and creates a local tag."""
announce(version)
regen()
changelog(version, write_out=True)
fix_formatting()
msg = "Preparing release version {}".format(version)
check_call(["git", "commit", "-a", "-m", msg])
print()
print(f"{Fore.CYAN}[generate.pre_release] {Fore.GREEN}All done!")
print()
print(f"Please push your branch and open a PR.")
def changelog(version, write_out=False):
if write_out:
addopts = []
else:
addopts = ["--draft"]
check_call(["towncrier", "--yes", "--version", version] + addopts)
def main():
init(autoreset=True)
parser = argparse.ArgumentParser()
parser.add_argument("version", help="Release version")
options = parser.parse_args()
pre_release(options.version)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,11 @@
REM script called by AppVeyor to combine and upload coverage information to codecov
if not defined PYTEST_NO_COVERAGE (
echo Prepare to upload coverage information
C:\Python36\Scripts\pip install codecov
C:\Python36\Scripts\coverage combine
C:\Python36\Scripts\coverage xml --ignore-errors
C:\Python36\Scripts\coverage report -m --ignore-errors
C:\Python36\Scripts\codecov --required -X gcov pycov search -f coverage.xml --flags %TOXENV:-= % windows
) else (
echo Skipping coverage upload, PYTEST_NO_COVERAGE is set
)

View File

@@ -59,7 +59,7 @@ def get_environment_marker_support_level():
def main():
extras_require = {}
install_requires = [
"py>=1.5.0",
"py>=1.5.0", # if py gets upgrade to >=1.6, remove _width_of_current_line in terminal.py
"six>=1.10.0",
"setuptools",
"attrs>=17.4.0",
@@ -69,26 +69,30 @@ def main():
# if _PYTEST_SETUP_SKIP_PLUGGY_DEP is set, skip installing pluggy;
# used by tox.ini to test with pluggy master
if "_PYTEST_SETUP_SKIP_PLUGGY_DEP" not in os.environ:
install_requires.append("pluggy>=0.5,<0.7")
install_requires.append("pluggy>=0.7")
environment_marker_support_level = get_environment_marker_support_level()
if environment_marker_support_level >= 2:
install_requires.append('funcsigs;python_version<"3.0"')
install_requires.append('pathlib2>=2.2.0;python_version<"3.6"')
install_requires.append('colorama;sys_platform=="win32"')
elif environment_marker_support_level == 1:
extras_require[':python_version<"3.0"'] = ["funcsigs"]
extras_require[':python_version<"3.6"'] = ["pathlib2>=2.2.0"]
extras_require[':sys_platform=="win32"'] = ["colorama"]
else:
if sys.platform == "win32":
install_requires.append("colorama")
if sys.version_info < (3, 0):
install_requires.append("funcsigs")
if sys.version_info < (3, 6):
install_requires.append("pathlib2>=2.2.0")
setup(
name="pytest",
description="pytest: simple powerful testing with Python",
long_description=long_description,
use_scm_version={"write_to": "src/_pytest/_version.py"},
url="http://pytest.org",
url="https://docs.pytest.org/en/latest/",
project_urls={
"Source": "https://github.com/pytest-dev/pytest",
"Tracker": "https://github.com/pytest-dev/pytest/issues",

View File

@@ -2,7 +2,7 @@
# CHANGES:
# - some_str is replaced, trying to create unicode strings
#
from __future__ import absolute_import, division, print_function
from __future__ import absolute_import, division, print_function, unicode_literals
import types
from six import text_type
@@ -51,17 +51,17 @@ def format_exception_only(etype, value):
pass
else:
filename = filename or "<string>"
lines.append(' File "%s", line %d\n' % (filename, lineno))
lines.append(' File "{}", line {}\n'.format(filename, lineno))
if badline is not None:
if isinstance(badline, bytes): # python 2 only
badline = badline.decode("utf-8", "replace")
lines.append(u" %s\n" % badline.strip())
lines.append(" {}\n".format(badline.strip()))
if offset is not None:
caretspace = badline.rstrip("\n")[:offset].lstrip()
# non-space whitespace (likes tabs) must be kept for alignment
caretspace = ((c.isspace() and c or " ") for c in caretspace)
# only three spaces to account for offset1 == pos 0
lines.append(" %s^\n" % "".join(caretspace))
lines.append(" {}^\n".format("".join(caretspace)))
value = msg
lines.append(_format_final_exc_line(stype, value))
@@ -72,9 +72,9 @@ def _format_final_exc_line(etype, value):
"""Return a list of a single line -- normal case for format_exception_only"""
valuestr = _some_str(value)
if value is None or not valuestr:
line = "%s\n" % etype
line = "{}\n".format(etype)
else:
line = "%s: %s\n" % (etype, valuestr)
line = "{}: {}\n".format(etype, valuestr)
return line
@@ -83,7 +83,7 @@ def _some_str(value):
return text_type(value)
except Exception:
try:
return str(value)
return bytes(value).decode("UTF-8", "replace")
except Exception:
pass
return "<unprintable %s object>" % type(value).__name__
return "<unprintable {} object>".format(type(value).__name__)

View File

@@ -1,5 +1,6 @@
from __future__ import absolute_import, division, print_function
import inspect
import pprint
import sys
import traceback
from inspect import CO_VARARGS, CO_VARKEYWORDS
@@ -10,6 +11,7 @@ from weakref import ref
from _pytest.compat import _PY2, _PY3, PY35, safe_str
from six import text_type
import py
import six
builtin_repr = repr
@@ -127,7 +129,7 @@ class Frame(object):
"""
f_locals = self.f_locals.copy()
f_locals.update(vars)
py.builtin.exec_(code, self.f_globals, f_locals)
six.exec_(code, self.f_globals, f_locals)
def repr(self, object):
""" return a 'safe' (non-recursive, one-line) string repr for 'object'
@@ -274,6 +276,7 @@ class Traceback(list):
""" Traceback objects encapsulate and offer higher level
access to Traceback entries.
"""
Entry = TracebackEntry
def __init__(self, tb, excinfo=None):
@@ -382,8 +385,11 @@ class ExceptionInfo(object):
""" wraps sys.exc_info() objects and offers
help for navigating the traceback.
"""
_striptext = ""
_assert_start_repr = "AssertionError(u'assert " if _PY2 else "AssertionError('assert "
_assert_start_repr = (
"AssertionError(u'assert " if _PY2 else "AssertionError('assert "
)
def __init__(self, tup=None, exprinfo=None):
import _pytest._code
@@ -424,7 +430,7 @@ class ExceptionInfo(object):
text = text.rstrip()
if tryshort:
if text.startswith(self._striptext):
text = text[len(self._striptext):]
text = text[len(self._striptext) :]
return text
def errisinstance(self, exc):
@@ -444,6 +450,7 @@ class ExceptionInfo(object):
abspath=False,
tbfilter=True,
funcargs=False,
truncate_locals=True,
):
""" return str()able representation of this exception info.
showlocals: show locals per traceback entry
@@ -468,6 +475,7 @@ class ExceptionInfo(object):
abspath=abspath,
tbfilter=tbfilter,
funcargs=funcargs,
truncate_locals=truncate_locals,
)
return fmt.repr_excinfo(self)
@@ -497,6 +505,7 @@ class ExceptionInfo(object):
@attr.s
class FormattedExcinfo(object):
""" presenting information about failing Functions and Generators. """
# for traceback entries
flow_marker = ">"
fail_marker = "E"
@@ -506,6 +515,7 @@ class FormattedExcinfo(object):
abspath = attr.ib(default=True)
tbfilter = attr.ib(default=True)
funcargs = attr.ib(default=False)
truncate_locals = attr.ib(default=True)
astcache = attr.ib(default=attr.Factory(dict), init=False, repr=False)
def _getindent(self, source):
@@ -556,7 +566,7 @@ class FormattedExcinfo(object):
for line in source.lines[:line_index]:
lines.append(space_prefix + line)
lines.append(self.flow_marker + " " + source.lines[line_index])
for line in source.lines[line_index + 1:]:
for line in source.lines[line_index + 1 :]:
lines.append(space_prefix + line)
if excinfo is not None:
indent = 4 if short else self._getindent(source)
@@ -588,7 +598,10 @@ class FormattedExcinfo(object):
# This formatting could all be handled by the
# _repr() function, which is only reprlib.Repr in
# disguise, so is very configurable.
str_repr = self._saferepr(value)
if self.truncate_locals:
str_repr = self._saferepr(value)
else:
str_repr = pprint.pformat(value)
# if len(str_repr) < 70 or not isinstance(value,
# (list, tuple, dict)):
lines.append("%-10s = %s" % (name, str_repr))
@@ -691,7 +704,7 @@ class FormattedExcinfo(object):
else:
if recursionindex is not None:
extraline = "!!! Recursion detected (same locals & position)"
traceback = traceback[:recursionindex + 1]
traceback = traceback[: recursionindex + 1]
else:
extraline = None
@@ -707,7 +720,9 @@ class FormattedExcinfo(object):
repr_chain = []
e = excinfo.value
descr = None
while e is not None:
seen = set()
while e is not None and id(e) not in seen:
seen.add(id(e))
if excinfo:
reprtraceback = self.repr_traceback(excinfo)
reprcrash = excinfo._getreprcrash()
@@ -722,15 +737,19 @@ class FormattedExcinfo(object):
repr_chain += [(reprtraceback, reprcrash, descr)]
if e.__cause__ is not None:
e = e.__cause__
excinfo = ExceptionInfo(
(type(e), e, e.__traceback__)
) if e.__traceback__ else None
excinfo = (
ExceptionInfo((type(e), e, e.__traceback__))
if e.__traceback__
else None
)
descr = "The above exception was the direct cause of the following exception:"
elif (e.__context__ is not None and not e.__suppress_context__):
elif e.__context__ is not None and not e.__suppress_context__:
e = e.__context__
excinfo = ExceptionInfo(
(type(e), e, e.__traceback__)
) if e.__traceback__ else None
excinfo = (
ExceptionInfo((type(e), e, e.__traceback__))
if e.__traceback__
else None
)
descr = "During handling of the above exception, another exception occurred:"
else:
e = None
@@ -739,7 +758,6 @@ class FormattedExcinfo(object):
class TerminalRepr(object):
def __str__(self):
s = self.__unicode__()
if _PY2:
@@ -759,7 +777,6 @@ class TerminalRepr(object):
class ExceptionRepr(TerminalRepr):
def __init__(self):
self.sections = []
@@ -773,7 +790,6 @@ class ExceptionRepr(TerminalRepr):
class ExceptionChainRepr(ExceptionRepr):
def __init__(self, chain):
super(ExceptionChainRepr, self).__init__()
self.chain = chain
@@ -792,7 +808,6 @@ class ExceptionChainRepr(ExceptionRepr):
class ReprExceptionInfo(ExceptionRepr):
def __init__(self, reprtraceback, reprcrash):
super(ReprExceptionInfo, self).__init__()
self.reprtraceback = reprtraceback
@@ -831,7 +846,6 @@ class ReprTraceback(TerminalRepr):
class ReprTracebackNative(ReprTraceback):
def __init__(self, tblines):
self.style = "native"
self.reprentries = [ReprEntryNative(tblines)]
@@ -885,7 +899,6 @@ class ReprEntry(TerminalRepr):
class ReprFileLocation(TerminalRepr):
def __init__(self, path, lineno, message):
self.path = str(path)
self.lineno = lineno
@@ -903,7 +916,6 @@ class ReprFileLocation(TerminalRepr):
class ReprLocals(TerminalRepr):
def __init__(self, lines):
self.lines = lines
@@ -913,7 +925,6 @@ class ReprLocals(TerminalRepr):
class ReprFuncArgs(TerminalRepr):
def __init__(self, args):
self.args = args

View File

@@ -1,4 +1,4 @@
from __future__ import absolute_import, division, generators, print_function
from __future__ import absolute_import, division, print_function
import ast
from ast import PyCF_ONLY_AST as _AST_FLAG
@@ -17,6 +17,7 @@ class Source(object):
""" an immutable object holding a source code fragment,
possibly deindenting it.
"""
_compilecounter = 0
def __init__(self, *parts, **kwargs):
@@ -60,7 +61,7 @@ class Source(object):
if key.step not in (None, 1):
raise IndexError("cannot slice a Source with a step")
newsource = Source()
newsource.lines = self.lines[key.start:key.stop]
newsource.lines = self.lines[key.start : key.stop]
return newsource
def __len__(self):
@@ -151,12 +152,7 @@ class Source(object):
return "\n".join(self.lines)
def compile(
self,
filename=None,
mode="exec",
flag=generators.compiler_flag,
dont_inherit=0,
_genframe=None,
self, filename=None, mode="exec", flag=0, dont_inherit=0, _genframe=None
):
""" return compiled code object. if filename is None
invent an artificial filename which displays
@@ -178,7 +174,7 @@ class Source(object):
except SyntaxError:
ex = sys.exc_info()[1]
# re-represent syntax errors from parsing python strings
msglines = self.lines[:ex.lineno]
msglines = self.lines[: ex.lineno]
if ex.offset:
msglines.append(" " * ex.offset + "^")
msglines.append("(code was compiled probably from here: %s)" % filename)
@@ -200,9 +196,7 @@ class Source(object):
#
def compile_(
source, filename=None, mode="exec", flags=generators.compiler_flag, dont_inherit=0
):
def compile_(source, filename=None, mode="exec", flags=0, dont_inherit=0):
""" compile the given source to a raw code object,
and maintain an internal cache which allows later
retrieval of the source code for the code object
@@ -313,7 +307,7 @@ def deindent(lines, offset=None):
except (IndentationError, tokenize.TokenError):
pass
# Add any lines we didn't see. E.g. if an exception was raised.
newlines.extend(lines[len(newlines):])
newlines.extend(lines[len(newlines) :])
return newlines

View File

@@ -8,6 +8,7 @@ import marshal
import os
import re
import six
import string
import struct
import sys
import types
@@ -16,7 +17,8 @@ import atomicwrites
import py
from _pytest.assertion import util
from _pytest.compat import PurePath, spec_from_file_location
from _pytest.paths import fnmatch_ex
# pytest caches rewritten pycs in __pycache__.
if hasattr(imp, "get_tag"):
@@ -56,12 +58,27 @@ class AssertionRewritingHook(object):
self._rewritten_names = set()
self._register_with_pkg_resources()
self._must_rewrite = set()
# flag to guard against trying to rewrite a pyc file while we are already writing another pyc file,
# which might result in infinite recursion (#3506)
self._writing_pyc = False
self._basenames_to_check_rewrite = {"conftest"}
self._marked_for_rewrite_cache = {}
self._session_paths_checked = False
def set_session(self, session):
self.session = session
self._session_paths_checked = False
def _imp_find_module(self, name, path=None):
"""Indirection so we can mock calls to find_module originated from the hook during testing"""
return imp.find_module(name, path)
def find_module(self, name, path=None):
if self._writing_pyc:
return None
state = self.config._assertstate
if self._early_rewrite_bailout(name, state):
return None
state.trace("find_module called for: %s" % name)
names = name.rsplit(".", 1)
lastname = names[-1]
@@ -74,7 +91,7 @@ class AssertionRewritingHook(object):
pth = path[0]
if pth is None:
try:
fd, fn, desc = imp.find_module(lastname, path)
fd, fn, desc = self._imp_find_module(lastname, path)
except ImportError:
return None
if fd is not None:
@@ -143,12 +160,54 @@ class AssertionRewritingHook(object):
# Probably a SyntaxError in the test.
return None
if write:
_write_pyc(state, co, source_stat, pyc)
self._writing_pyc = True
try:
_write_pyc(state, co, source_stat, pyc)
finally:
self._writing_pyc = False
else:
state.trace("found cached rewritten pyc for %r" % (fn,))
self.modules[name] = co, pyc
return self
def _early_rewrite_bailout(self, name, state):
"""
This is a fast way to get out of rewriting modules. Profiling has
shown that the call to imp.find_module (inside of the find_module
from this class) is a major slowdown, so, this method tries to
filter what we're sure won't be rewritten before getting to it.
"""
if self.session is not None and not self._session_paths_checked:
self._session_paths_checked = True
for path in self.session._initialpaths:
# Make something as c:/projects/my_project/path.py ->
# ['c:', 'projects', 'my_project', 'path.py']
parts = str(path).split(os.path.sep)
# add 'path' to basenames to be checked.
self._basenames_to_check_rewrite.add(os.path.splitext(parts[-1])[0])
# Note: conftest already by default in _basenames_to_check_rewrite.
parts = name.split(".")
if parts[-1] in self._basenames_to_check_rewrite:
return False
# For matching the name it must be as if it was a filename.
path = PurePath(os.path.sep.join(parts) + ".py")
for pat in self.fnpats:
# if the pattern contains subdirectories ("tests/**.py" for example) we can't bail out based
# on the name alone because we need to match against the full path
if os.path.dirname(pat):
return False
if fnmatch_ex(pat, path):
return False
if self._is_marked_for_rewrite(name, state):
return False
state.trace("early skip of rewriting module: %s" % (name,))
return True
def _should_rewrite(self, name, fn_pypath, state):
# always rewrite conftest files
fn = str(fn_pypath)
@@ -168,12 +227,20 @@ class AssertionRewritingHook(object):
state.trace("matched test file %r" % (fn,))
return True
for marked in self._must_rewrite:
if name == marked or name.startswith(marked + "."):
state.trace("matched marked file %r (from %r)" % (name, marked))
return True
return self._is_marked_for_rewrite(name, state)
return False
def _is_marked_for_rewrite(self, name, state):
try:
return self._marked_for_rewrite_cache[name]
except KeyError:
for marked in self._must_rewrite:
if name == marked or name.startswith(marked + "."):
state.trace("matched marked file %r (from %r)" % (name, marked))
self._marked_for_rewrite_cache[name] = True
return True
self._marked_for_rewrite_cache[name] = False
return False
def mark_rewrite(self, *names):
"""Mark import names as needing to be rewritten.
@@ -190,30 +257,37 @@ class AssertionRewritingHook(object):
):
self._warn_already_imported(name)
self._must_rewrite.update(names)
self._marked_for_rewrite_cache.clear()
def _warn_already_imported(self, name):
self.config.warn(
"P1", "Module already imported so cannot be rewritten: %s" % name
from _pytest.warning_types import PytestWarning
from _pytest.warnings import _issue_config_warning
_issue_config_warning(
PytestWarning("Module already imported so cannot be rewritten: %s" % name),
self.config,
)
def load_module(self, name):
# If there is an existing module object named 'fullname' in
# sys.modules, the loader must use that existing module. (Otherwise,
# the reload() builtin will not work correctly.)
if name in sys.modules:
return sys.modules[name]
co, pyc = self.modules.pop(name)
# I wish I could just call imp.load_compiled here, but __file__ has to
# be set properly. In Python 3.2+, this all would be handled correctly
# by load_compiled.
mod = sys.modules[name] = imp.new_module(name)
if name in sys.modules:
# If there is an existing module object named 'fullname' in
# sys.modules, the loader must use that existing module. (Otherwise,
# the reload() builtin will not work correctly.)
mod = sys.modules[name]
else:
# I wish I could just call imp.load_compiled here, but __file__ has to
# be set properly. In Python 3.2+, this all would be handled correctly
# by load_compiled.
mod = sys.modules[name] = imp.new_module(name)
try:
mod.__file__ = co.co_filename
# Normally, this attribute is 3.2+.
mod.__cached__ = pyc
mod.__loader__ = self
py.builtin.exec_(co, mod.__dict__)
# Normally, this attribute is 3.4+
mod.__spec__ = spec_from_file_location(name, co.co_filename, loader=self)
six.exec_(co, mod.__dict__)
except: # noqa
if name in sys.modules:
del sys.modules[name]
@@ -222,7 +296,7 @@ class AssertionRewritingHook(object):
def is_package(self, name):
try:
fd, fn, desc = imp.find_module(name)
fd, fn, desc = self._imp_find_module(name)
except ImportError:
return False
if fd is not None:
@@ -309,7 +383,7 @@ def _rewrite_test(config, fn):
if (
not source.startswith(BOM_UTF8)
and cookie_re.match(source[0:end1]) is None
and cookie_re.match(source[end1 + 1:end2]) is None
and cookie_re.match(source[end1 + 1 : end2]) is None
):
if hasattr(state, "_indecode"):
# encodings imported us again, so don't rewrite.
@@ -392,12 +466,15 @@ def _saferepr(obj):
JSON reprs.
"""
repr = py.io.saferepr(obj)
if isinstance(repr, six.text_type):
t = six.text_type
else:
t = six.binary_type
return repr.replace(t("\n"), t("\\n"))
r = py.io.saferepr(obj)
# only occurs in python2.x, repr must return text in python3+
if isinstance(r, bytes):
# Represent unprintable bytes as `\x##`
r = u"".join(
u"\\x{:x}".format(ord(c)) if c not in string.printable else c.decode()
for c in r
)
return r.replace(u"\n", u"\\n")
from _pytest.assertion.util import format_explanation as _format_explanation # noqa
@@ -415,20 +492,18 @@ def _format_assertmsg(obj):
# contains a newline it gets escaped, however if an object has a
# .__repr__() which contains newlines it does not get escaped.
# However in either case we want to preserve the newline.
if isinstance(obj, six.text_type) or isinstance(obj, six.binary_type):
s = obj
is_repr = False
else:
s = py.io.saferepr(obj)
is_repr = True
if isinstance(s, six.text_type):
t = six.text_type
else:
t = six.binary_type
s = s.replace(t("\n"), t("\n~")).replace(t("%"), t("%%"))
if is_repr:
s = s.replace(t("\\n"), t("\n~"))
return s
replaces = [(u"\n", u"\n~"), (u"%", u"%%")]
if not isinstance(obj, six.string_types):
obj = py.io.saferepr(obj)
replaces.append((u"\\n", u"\n~"))
if isinstance(obj, bytes):
replaces = [(r1.encode(), r2.encode()) for r1, r2 in replaces]
for r1, r2 in replaces:
obj = obj.replace(r1, r2)
return obj
def _should_repr_global_name(obj):
@@ -438,10 +513,9 @@ def _should_repr_global_name(obj):
def _format_boolop(explanations, is_or):
explanation = "(" + (is_or and " or " or " and ").join(explanations) + ")"
if isinstance(explanation, six.text_type):
t = six.text_type
return explanation.replace(u"%", u"%%")
else:
t = six.binary_type
return explanation.replace(t("%"), t("%%"))
return explanation.replace(b"%", b"%%")
def _call_reprcompare(ops, results, expls, each_obj):
@@ -731,13 +805,17 @@ class AssertionRewriter(ast.NodeVisitor):
the expression is false.
"""
if isinstance(assert_.test, ast.Tuple) and self.config is not None:
fslocation = (self.module_path, assert_.lineno)
self.config.warn(
"R1",
"assertion is always true, perhaps " "remove parentheses?",
fslocation=fslocation,
if isinstance(assert_.test, ast.Tuple) and len(assert_.test.elts) >= 1:
from _pytest.warning_types import PytestWarning
import warnings
warnings.warn_explicit(
PytestWarning("assertion is always true, perhaps remove parentheses?"),
category=None,
filename=str(self.module_path),
lineno=assert_.lineno,
)
self.statements = []
self.variables = []
self.variable_counter = itertools.count()

View File

@@ -187,9 +187,9 @@ def _diff_text(left, right, verbose=False):
r = r.replace(r"\r", "\r")
return r
if isinstance(left, six.binary_type):
if isinstance(left, bytes):
left = escape_for_readable_diff(left)
if isinstance(right, six.binary_type):
if isinstance(right, bytes):
right = escape_for_readable_diff(right)
if not verbose:
i = 0 # just in case left or right has zero length
@@ -322,7 +322,7 @@ def _compare_eq_dict(left, right, verbose=False):
def _notin_text(term, text, verbose=False):
index = text.find(term)
head = text[:index]
tail = text[index + len(term):]
tail = text[index + len(term) :]
correct_text = head + tail
diff = _diff_text(correct_text, text, verbose)
newdiff = [u("%s is contained here:") % py.io.saferepr(term, maxsize=42)]

View File

@@ -5,39 +5,55 @@ the name cache was not chosen to ensure pluggy automatically
ignores the external pytest-cache
"""
from __future__ import absolute_import, division, print_function
from collections import OrderedDict
import py
import six
import attr
import pytest
import json
import os
from os.path import sep as _sep, altsep as _altsep
import shutil
from . import paths
from .compat import _PY2 as PY2, Path
README_CONTENT = u"""\
# pytest cache directory #
This directory contains data from the pytest's cache plugin,
which provides the `--lf` and `--ff` options, as well as the `cache` fixture.
**Do not** commit this to version control.
See [the docs](https://docs.pytest.org/en/latest/cache.html) for more information.
"""
@attr.s
class Cache(object):
_cachedir = attr.ib(repr=False)
_config = attr.ib(repr=False)
def __init__(self, config):
self.config = config
self._cachedir = Cache.cache_dir_from_config(config)
self.trace = config.trace.root.get("cache")
if config.getoption("cacheclear"):
self.trace("clearing cachedir")
if self._cachedir.check():
self._cachedir.remove()
self._cachedir.mkdir()
@classmethod
def for_config(cls, config):
cachedir = cls.cache_dir_from_config(config)
if config.getoption("cacheclear") and cachedir.exists():
shutil.rmtree(str(cachedir))
cachedir.mkdir()
return cls(cachedir, config)
@staticmethod
def cache_dir_from_config(config):
cache_dir = config.getini("cache_dir")
cache_dir = os.path.expanduser(cache_dir)
cache_dir = os.path.expandvars(cache_dir)
if os.path.isabs(cache_dir):
return py.path.local(cache_dir)
else:
return config.rootdir.join(cache_dir)
return paths.resolve_from_str(config.getini("cache_dir"), config.rootdir)
def warn(self, fmt, **args):
from _pytest.warnings import _issue_config_warning
from _pytest.warning_types import PytestWarning
_issue_config_warning(
PytestWarning(fmt.format(**args) if args else fmt), self._config
)
def makedir(self, name):
""" return a directory path object with the given name. If the
@@ -49,12 +65,15 @@ class Cache(object):
Make sure the name contains your plugin or application
identifiers to prevent clashes with other cache users.
"""
if _sep in name or _altsep is not None and _altsep in name:
name = Path(name)
if len(name.parts) > 1:
raise ValueError("name is not allowed to contain path separators")
return self._cachedir.ensure_dir("d", name)
res = self._cachedir.joinpath("d", name)
res.mkdir(exist_ok=True, parents=True)
return py.path.local(res)
def _getvaluepath(self, key):
return self._cachedir.join("v", *key.split("/"))
return self._cachedir.joinpath("v", Path(key))
def get(self, key, default):
""" return cached value for the given key. If no value
@@ -68,13 +87,11 @@ class Cache(object):
"""
path = self._getvaluepath(key)
if path.check():
try:
with path.open("r") as f:
return json.load(f)
except ValueError:
self.trace("cache-invalid at %s" % (path,))
return default
try:
with path.open("r") as f:
return json.load(f)
except (ValueError, IOError, OSError):
return default
def set(self, key, value):
""" save value for the given key.
@@ -87,22 +104,28 @@ class Cache(object):
"""
path = self._getvaluepath(key)
try:
path.dirpath().ensure_dir()
except (py.error.EEXIST, py.error.EACCES):
self.config.warn(
code="I9", message="could not create cache path %s" % (path,)
)
path.parent.mkdir(exist_ok=True, parents=True)
except (IOError, OSError):
self.warn("could not create cache path {path}", path=path)
return
try:
f = path.open("w")
except py.error.ENOTDIR:
self.config.warn(
code="I9", message="cache could not write path %s" % (path,)
)
f = path.open("wb" if PY2 else "w")
except (IOError, OSError):
self.warn("cache could not write path {path}", path=path)
else:
with f:
self.trace("cache-write %s: %r" % (key, value))
json.dump(value, f, indent=2, sort_keys=True)
self._ensure_supporting_files()
def _ensure_supporting_files(self):
"""Create supporting files in the cache dir that are not really part of the cache."""
if self._cachedir.is_dir():
readme_path = self._cachedir / "README.md"
if not readme_path.is_file():
readme_path.write_text(README_CONTENT)
msg = u"# created by pytest automatically, do not change\n*"
self._cachedir.joinpath(".gitignore").write_text(msg, encoding="UTF-8")
class LFPlugin(object):
@@ -117,17 +140,14 @@ class LFPlugin(object):
self._no_failures_behavior = self.config.getoption("last_failed_no_failures")
def pytest_report_collectionfinish(self):
if self.active:
if self.active and self.config.getoption("verbose") >= 0:
if not self._previously_failed_count:
mode = "run {} (no recorded failures)".format(
self._no_failures_behavior
)
else:
noun = "failure" if self._previously_failed_count == 1 else "failures"
suffix = " first" if self.config.getoption("failedfirst") else ""
mode = "rerun previous {count} {noun}{suffix}".format(
count=self._previously_failed_count, suffix=suffix, noun=noun
)
return None
noun = "failure" if self._previously_failed_count == 1 else "failures"
suffix = " first" if self.config.getoption("failedfirst") else ""
mode = "rerun previous {count} {noun}{suffix}".format(
count=self._previously_failed_count, suffix=suffix, noun=noun
)
return "run-last-failure: %s" % mode
def pytest_runtest_logreport(self, report):
@@ -199,9 +219,7 @@ class NFPlugin(object):
items[:] = self._get_increasing_order(
six.itervalues(new_items)
) + self._get_increasing_order(
six.itervalues(other_items)
)
) + self._get_increasing_order(six.itervalues(other_items))
self.cached_nodeids = [x.nodeid for x in items if isinstance(x, pytest.Item)]
def _get_increasing_order(self, items):
@@ -276,7 +294,7 @@ def pytest_cmdline_main(config):
@pytest.hookimpl(tryfirst=True)
def pytest_configure(config):
config.cache = Cache(config)
config.cache = Cache.for_config(config)
config.pluginmanager.register(LFPlugin(config), "lfplugin")
config.pluginmanager.register(NFPlugin(config), "nfplugin")
@@ -299,41 +317,47 @@ def cache(request):
def pytest_report_header(config):
if config.option.verbose:
relpath = py.path.local().bestrelpath(config.cache._cachedir)
return "cachedir: %s" % relpath
cachedir = config.cache._cachedir
# TODO: evaluate generating upward relative paths
# starting with .., ../.. if sensible
try:
displaypath = cachedir.relative_to(config.rootdir)
except ValueError:
displaypath = cachedir
return "cachedir: {}".format(displaypath)
def cacheshow(config, session):
from pprint import pprint
from pprint import pformat
tw = py.io.TerminalWriter()
tw.line("cachedir: " + str(config.cache._cachedir))
if not config.cache._cachedir.check():
if not config.cache._cachedir.is_dir():
tw.line("cache is empty")
return 0
dummy = object()
basedir = config.cache._cachedir
vdir = basedir.join("v")
vdir = basedir / "v"
tw.sep("-", "cache values")
for valpath in sorted(vdir.visit(lambda x: x.isfile())):
key = valpath.relto(vdir).replace(valpath.sep, "/")
for valpath in sorted(x for x in vdir.rglob("*") if x.is_file()):
key = valpath.relative_to(vdir)
val = config.cache.get(key, dummy)
if val is dummy:
tw.line("%s contains unreadable content, " "will be ignored" % key)
else:
tw.line("%s contains:" % key)
stream = py.io.TextIO()
pprint(val, stream=stream)
for line in stream.getvalue().splitlines():
for line in pformat(val).splitlines():
tw.line(" " + line)
ddir = basedir.join("d")
if ddir.isdir() and ddir.listdir():
ddir = basedir / "d"
if ddir.is_dir():
contents = sorted(ddir.rglob("*"))
tw.sep("-", "cache directories")
for p in sorted(basedir.join("d").visit()):
for p in contents:
# if p.check(dir=1):
# print("%s/" % p.relto(basedir))
if p.isfile():
key = p.relto(basedir)
tw.line("%s is a file of length %d" % (key, p.size()))
if p.is_file():
key = p.relative_to(basedir)
tw.line("{} is a file of length {:d}".format(key, p.stat().st_size))
return 0

View File

@@ -16,7 +16,6 @@ import six
import pytest
from _pytest.compat import CaptureIO
patchsysdict = {0: "stdin", 1: "stdout", 2: "stderr"}
@@ -63,8 +62,9 @@ def pytest_load_initial_conftests(early_config, parser, args):
# finally trigger conftest loading but while capturing (issue93)
capman.start_global_capturing()
outcome = yield
out, err = capman.suspend_global_capture()
capman.suspend_global_capture()
if outcome.excinfo is not None:
out, err = capman.read_global_capture()
sys.stdout.write(out)
sys.stderr.write(err)
@@ -85,6 +85,7 @@ class CaptureManager(object):
def __init__(self, method):
self._method = method
self._global_capturing = None
self._current_item = None
def _getcapture(self, method):
if method == "fd":
@@ -96,6 +97,8 @@ class CaptureManager(object):
else:
raise ValueError("unknown capturing method: %r" % method)
# Global capturing control
def start_global_capturing(self):
assert self._global_capturing is None
self._global_capturing = self._getcapture(self._method)
@@ -110,16 +113,15 @@ class CaptureManager(object):
def resume_global_capture(self):
self._global_capturing.resume_capturing()
def suspend_global_capture(self, item=None, in_=False):
if item is not None:
self.deactivate_fixture(item)
def suspend_global_capture(self, in_=False):
cap = getattr(self, "_global_capturing", None)
if cap is not None:
try:
outerr = cap.readouterr()
finally:
cap.suspend_capturing(in_=in_)
return outerr
cap.suspend_capturing(in_=in_)
def read_global_capture(self):
return self._global_capturing.readouterr()
# Fixture Control (its 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
@@ -135,12 +137,53 @@ class CaptureManager(object):
if fixture is not None:
fixture.close()
def suspend_fixture(self, item):
fixture = getattr(item, "_capture_fixture", None)
if fixture is not None:
fixture._suspend()
def resume_fixture(self, item):
fixture = getattr(item, "_capture_fixture", None)
if fixture is not None:
fixture._resume()
# Helper context managers
@contextlib.contextmanager
def global_and_fixture_disabled(self):
"""Context manager to temporarily disables global and current fixture capturing."""
# Need to undo local capsys-et-al if exists before disabling global capture
self.suspend_fixture(self._current_item)
self.suspend_global_capture(in_=False)
try:
yield
finally:
self.resume_global_capture()
self.resume_fixture(self._current_item)
@contextlib.contextmanager
def item_capture(self, when, item):
self.resume_global_capture()
self.activate_fixture(item)
try:
yield
finally:
self.deactivate_fixture(item)
self.suspend_global_capture(in_=False)
out, err = self.read_global_capture()
item.add_report_section(when, "stdout", out)
item.add_report_section(when, "stderr", err)
# Hooks
@pytest.hookimpl(hookwrapper=True)
def pytest_make_collect_report(self, collector):
if isinstance(collector, pytest.File):
self.resume_global_capture()
outcome = yield
out, err = self.suspend_global_capture()
self.suspend_global_capture()
out, err = self.read_global_capture()
rep = outcome.get_result()
if out:
rep.sections.append(("Captured stdout", out))
@@ -150,29 +193,25 @@ class CaptureManager(object):
yield
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_setup(self, item):
self.resume_global_capture()
# no need to activate a capture fixture because they activate themselves during creation; this
# only makes sense when a fixture uses a capture fixture, otherwise the capture fixture will
# be activated during pytest_runtest_call
def pytest_runtest_protocol(self, item):
self._current_item = item
yield
self.suspend_capture_item(item, "setup")
self._current_item = None
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_setup(self, item):
with self.item_capture("setup", item):
yield
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(self, item):
self.resume_global_capture()
# it is important to activate this fixture during the call phase so it overwrites the "global"
# capture
self.activate_fixture(item)
yield
self.suspend_capture_item(item, "call")
with self.item_capture("call", item):
yield
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_teardown(self, item):
self.resume_global_capture()
self.activate_fixture(item)
yield
self.suspend_capture_item(item, "teardown")
with self.item_capture("teardown", item):
yield
@pytest.hookimpl(tryfirst=True)
def pytest_keyboard_interrupt(self, excinfo):
@@ -182,11 +221,6 @@ class CaptureManager(object):
def pytest_internalerror(self, excinfo):
self.stop_global_capturing()
def suspend_capture_item(self, item, when, in_=False):
out, err = self.suspend_global_capture(item, in_=in_)
item.add_report_section(when, "stdout", out)
item.add_report_section(when, "stderr", err)
capture_fixtures = {"capfd", "capfdbinary", "capsys", "capsysbinary"}
@@ -290,40 +324,54 @@ class CaptureFixture(object):
def __init__(self, captureclass, request):
self.captureclass = captureclass
self.request = request
self._capture = None
self._captured_out = self.captureclass.EMPTY_BUFFER
self._captured_err = self.captureclass.EMPTY_BUFFER
def _start(self):
self._capture = MultiCapture(
out=True, err=True, in_=False, Capture=self.captureclass
)
self._capture.start_capturing()
# Start if not started yet
if getattr(self, "_capture", None) is None:
self._capture = MultiCapture(
out=True, err=True, in_=False, Capture=self.captureclass
)
self._capture.start_capturing()
def close(self):
cap = self.__dict__.pop("_capture", None)
if cap is not None:
self._outerr = cap.pop_outerr_to_orig()
cap.stop_capturing()
if self._capture is not None:
out, err = self._capture.pop_outerr_to_orig()
self._captured_out += out
self._captured_err += err
self._capture.stop_capturing()
self._capture = None
def readouterr(self):
"""Read and return the captured output so far, resetting the internal buffer.
:return: captured content as a namedtuple with ``out`` and ``err`` string attributes
"""
try:
return self._capture.readouterr()
except AttributeError:
return self._outerr
captured_out, captured_err = self._captured_out, self._captured_err
if self._capture is not None:
out, err = self._capture.readouterr()
captured_out += out
captured_err += err
self._captured_out = self.captureclass.EMPTY_BUFFER
self._captured_err = self.captureclass.EMPTY_BUFFER
return CaptureResult(captured_out, captured_err)
def _suspend(self):
"""Suspends this fixture's own capturing temporarily."""
self._capture.suspend_capturing()
def _resume(self):
"""Resumes this fixture's own capturing temporarily."""
self._capture.resume_capturing()
@contextlib.contextmanager
def disabled(self):
"""Temporarily disables capture while inside the 'with' block."""
self._capture.suspend_capturing()
capmanager = self.request.config.pluginmanager.getplugin("capturemanager")
capmanager.suspend_global_capture(item=None, in_=False)
try:
with capmanager.global_and_fixture_disabled():
yield
finally:
capmanager.resume_global_capture()
self._capture.resume_capturing()
def safe_text_dupfile(f, mode, default_encoding="UTF8"):
@@ -440,6 +488,7 @@ class MultiCapture(object):
class NoCapture(object):
EMPTY_BUFFER = None
__init__ = start = done = suspend = resume = lambda *args: None
@@ -449,6 +498,8 @@ class FDCaptureBinary(object):
snap() produces `bytes`
"""
EMPTY_BUFFER = bytes()
def __init__(self, targetfd, tmpfile=None):
self.targetfd = targetfd
try:
@@ -522,6 +573,8 @@ class FDCapture(FDCaptureBinary):
snap() produces text
"""
EMPTY_BUFFER = str()
def snap(self):
res = FDCaptureBinary.snap(self)
enc = getattr(self.tmpfile, "encoding", None)
@@ -532,6 +585,8 @@ class FDCapture(FDCaptureBinary):
class SysCapture(object):
EMPTY_BUFFER = str()
def __init__(self, fd, tmpfile=None):
name = patchsysdict[fd]
self._old = getattr(sys, name)
@@ -569,6 +624,7 @@ class SysCapture(object):
class SysCaptureBinary(SysCapture):
EMPTY_BUFFER = bytes()
def snap(self):
res = self.tmpfile.buffer.getvalue()

View File

@@ -8,6 +8,7 @@ import functools
import inspect
import re
import sys
from contextlib import contextmanager
import py
@@ -22,6 +23,7 @@ except ImportError: # pragma: no cover
# Only available in Python 3.4+ or as a backport
enum = None
__all__ = ["Path", "PurePath"]
_PY3 = sys.version_info > (3, 0)
_PY2 = not _PY3
@@ -32,7 +34,6 @@ if _PY3:
else:
from funcsigs import signature, Parameter as Parameter
NoneType = type(None)
NOTSET = object()
@@ -40,15 +41,29 @@ PY35 = sys.version_info[:2] >= (3, 5)
PY36 = sys.version_info[:2] >= (3, 6)
MODULE_NOT_FOUND_ERROR = "ModuleNotFoundError" if PY36 else "ImportError"
if PY36:
from pathlib import Path, PurePath
else:
from pathlib2 import Path, PurePath
if _PY3:
from collections.abc import MutableMapping as MappingMixin # noqa
from collections.abc import Mapping, Sequence # noqa
from collections.abc import MutableMapping as MappingMixin
from collections.abc import Mapping, Sequence
else:
# those raise DeprecationWarnings in Python >=3.7
from collections import MutableMapping as MappingMixin # noqa
from collections import Mapping, Sequence # noqa
if sys.version_info >= (3, 4):
from importlib.util import spec_from_file_location
else:
def spec_from_file_location(*_, **__):
return None
def _format_args(func):
return str(signature(func))
@@ -72,16 +87,13 @@ def iscoroutinefunction(func):
Note: copied and modified from Python 3.5's builtin couroutines.py to avoid import asyncio directly,
which in turns also initializes the "logging" module as side-effect (see issue #8).
"""
return (
getattr(func, "_is_coroutine", False)
or (
hasattr(inspect, "iscoroutinefunction")
and inspect.iscoroutinefunction(func)
)
return getattr(func, "_is_coroutine", False) or (
hasattr(inspect, "iscoroutinefunction") and inspect.iscoroutinefunction(func)
)
def getlocation(function, curdir):
function = get_real_func(function)
fn = py.path.local(inspect.getfile(function))
lineno = function.__code__.co_firstlineno
if fn.relto(curdir):
@@ -138,20 +150,23 @@ def getfuncargnames(function, is_method=False, cls=None):
# If this function should be treated as a bound method even though
# it's passed as an unbound method or function, remove the first
# parameter name.
if (
is_method
or (
cls
and not isinstance(cls.__dict__.get(function.__name__, None), staticmethod)
)
if is_method or (
cls and not isinstance(cls.__dict__.get(function.__name__, None), staticmethod)
):
arg_names = arg_names[1:]
# Remove any names that will be replaced with mocks.
if hasattr(function, "__wrapped__"):
arg_names = arg_names[num_mock_patch_args(function):]
arg_names = arg_names[num_mock_patch_args(function) :]
return arg_names
@contextmanager
def dummy_context_manager():
"""Context manager that does nothing, useful in situations where you might need an actual context manager or not
depending on some condition. Using this allow to keep the same code"""
yield
def get_default_arg_names(function):
# Note: this code intentionally mirrors the code at the beginning of getfuncargnames,
# to get the arguments which were excluded from its result because they had default values
@@ -229,12 +244,31 @@ else:
return val.encode("unicode-escape")
class _PytestWrapper(object):
"""Dummy wrapper around a function object for internal use only.
Used to correctly unwrap the underlying function object
when we are creating fixtures, because we wrap the function object ourselves with a decorator
to issue warnings when the fixture function is called directly.
"""
def __init__(self, obj):
self.obj = obj
def get_real_func(obj):
""" gets the real function object of the (possibly) wrapped object by
functools.wraps or functools.partial.
"""
start_obj = obj
for i in range(100):
# __pytest_wrapped__ is set by @pytest.fixture when wrapping the fixture function
# to trigger a warning if it gets called directly instead of by pytest: we don't
# want to unwrap further than this otherwise we lose useful wrappings like @mock.patch (#3774)
new_obj = getattr(obj, "__pytest_wrapped__", None)
if isinstance(new_obj, _PytestWrapper):
obj = new_obj.obj
break
new_obj = getattr(obj, "__wrapped__", None)
if new_obj is None:
break
@@ -250,6 +284,21 @@ def get_real_func(obj):
return obj
def get_real_method(obj, holder):
"""
Attempts to obtain the real function object that might be wrapping ``obj``, while at the same time
returning a bound method to ``holder`` if the original object was a bound method.
"""
try:
is_method = hasattr(obj, "__func__")
obj = get_real_func(obj)
except Exception:
return obj
if is_method and hasattr(obj, "__get__") and callable(obj.__get__):
obj = obj.__get__(holder)
return obj
def getfslineno(obj):
# xxx let decorators etc specify a sane ordering
obj = get_real_func(obj)
@@ -340,7 +389,6 @@ if _PY2:
from py.io import TextIO
class CaptureIO(TextIO):
@property
def encoding(self):
return getattr(self, "_encoding", "UTF-8")
@@ -350,7 +398,6 @@ else:
import io
class CaptureIO(io.TextIOWrapper):
def __init__(self):
super(CaptureIO, self).__init__(
io.BytesIO(), encoding="UTF-8", newline="", write_through=True

View File

@@ -1,6 +1,7 @@
""" command line options, ini-file and conftest.py processing. """
from __future__ import absolute_import, division, print_function
import argparse
import inspect
import shlex
import traceback
import types
@@ -30,7 +31,6 @@ hookspec = HookspecMarker("pytest")
class ConftestImportFailure(Exception):
def __init__(self, path, excinfo):
Exception.__init__(self, path, excinfo)
self.path = path
@@ -51,6 +51,8 @@ def main(args=None, plugins=None):
:arg plugins: list of plugin objects to be auto-registered during
initialization.
"""
from _pytest.main import EXIT_USAGEERROR
try:
try:
config = _prepareconfig(args, plugins)
@@ -69,10 +71,10 @@ def main(args=None, plugins=None):
tw = py.io.TerminalWriter(sys.stderr)
for msg in e.args:
tw.line("ERROR: {}\n".format(msg), red=True)
return 4
return EXIT_USAGEERROR
class cmdline(object): # NOQA compatibility namespace
class cmdline(object): # compatibility namespace
main = staticmethod(main)
@@ -176,7 +178,9 @@ def _prepareconfig(args=None, plugins=None):
else:
pluginmanager.register(plugin)
if warning:
config.warn("C1", warning)
from _pytest.warnings import _issue_config_warning
_issue_config_warning(warning, config=config)
return pluginmanager.hook.pytest_cmdline_parse(
pluginmanager=pluginmanager, args=args
)
@@ -253,6 +257,10 @@ class PytestPluginManager(PluginManager):
method = getattr(plugin, name)
opts = super(PytestPluginManager, self).parse_hookimpl_opts(plugin, name)
# consider only actual functions for hooks (#3775)
if not inspect.isroutine(method):
return
# collect unmarked hooks as long as they have the `pytest_' prefix
if opts is None and name.startswith("pytest_"):
opts = {}
@@ -318,9 +326,11 @@ class PytestPluginManager(PluginManager):
self._configured = True
def _warn(self, message):
kwargs = message if isinstance(message, dict) else {
"code": "I1", "message": message, "fslocation": None, "nodeid": None
}
kwargs = (
message
if isinstance(message, dict)
else {"code": "I1", "message": message, "fslocation": None, "nodeid": None}
)
self.hook.pytest_logwarning.call_historic(kwargs=kwargs)
#
@@ -335,10 +345,13 @@ class PytestPluginManager(PluginManager):
here.
"""
current = py.path.local()
self._confcutdir = current.join(
namespace.confcutdir, abs=True
) if namespace.confcutdir else None
self._confcutdir = (
current.join(namespace.confcutdir, abs=True)
if namespace.confcutdir
else None
)
self._noconftest = namespace.noconftest
self._using_pyargs = namespace.pyargs
testpaths = namespace.file_or_dir
foundanchor = False
for path in testpaths:
@@ -404,10 +417,21 @@ class PytestPluginManager(PluginManager):
_ensure_removed_sysmodule(conftestpath.purebasename)
try:
mod = conftestpath.pyimport()
if hasattr(mod, "pytest_plugins") and self._configured:
from _pytest.deprecated import PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
if (
hasattr(mod, "pytest_plugins")
and self._configured
and not self._using_pyargs
):
from _pytest.deprecated import (
PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST
)
warnings.warn(PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST)
warnings.warn_explicit(
PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST,
category=None,
filename=str(conftestpath),
lineno=0,
)
except Exception:
raise ConftestImportFailure(conftestpath, sys.exc_info())
@@ -477,7 +501,8 @@ class PytestPluginManager(PluginManager):
except ImportError as e:
new_exc_type = ImportError
new_exc_message = 'Error importing plugin "%s": %s' % (
modname, safe_str(e.args[0])
modname,
safe_str(e.args[0]),
)
new_exc = new_exc_type(new_exc_message)
@@ -518,7 +543,6 @@ def _ensure_removed_sysmodule(modname):
class Notset(object):
def __repr__(self):
return "<NOTSET>"
@@ -592,7 +616,29 @@ class Config(object):
fin()
def warn(self, code, message, fslocation=None, nodeid=None):
""" generate a warning for this test session. """
"""
.. deprecated:: 3.8
Use :py:func:`warnings.warn` or :py:func:`warnings.warn_explicit` directly instead.
Generate a warning for this test session.
"""
from _pytest.warning_types import RemovedInPytest4Warning
if isinstance(fslocation, (tuple, list)) and len(fslocation) > 2:
filename, lineno = fslocation[:2]
else:
filename = "unknown file"
lineno = 0
msg = "config.warn has been deprecated, use warnings.warn instead"
if nodeid:
msg = "{}: {}".format(nodeid, msg)
warnings.warn_explicit(
RemovedInPytest4Warning(msg),
category=None,
filename=filename,
lineno=lineno,
)
self.hook.pytest_logwarning.call_historic(
kwargs=dict(
code=code, message=message, fslocation=fslocation, nodeid=nodeid
@@ -657,8 +703,8 @@ class Config(object):
r = determine_setup(
ns.inifilename,
ns.file_or_dir + unknown_args,
warnfunc=self.warn,
rootdir_cmd_arg=ns.rootdir or None,
config=self,
)
self.rootdir, self.inifile, self.inicfg = r
self._parser.extra_info["rootdir"] = self.rootdir
@@ -696,6 +742,10 @@ class Config(object):
self.pluginmanager.rewrite_hook = hook
if os.environ.get("PYTEST_DISABLE_PLUGIN_AUTOLOAD"):
# We don't autoload from setuptools entry points, no need to continue.
return
# 'RECORD' available for plugins installed normally (pip install)
# 'SOURCES.txt' available for plugins installed in dev mode (pip install -e)
# for installed plugins 'SOURCES.txt' returns an empty list, and vice-versa
@@ -721,7 +771,10 @@ class Config(object):
self._checkversion()
self._consider_importhook(args)
self.pluginmanager.consider_preparse(args)
self.pluginmanager.load_setuptools_entrypoints("pytest11")
if not os.environ.get("PYTEST_DISABLE_PLUGIN_AUTOLOAD"):
# Don't autoload from setuptools entry point. Only explicitly specified
# plugins are going to be loaded.
self.pluginmanager.load_setuptools_entrypoints("pytest11")
self.pluginmanager.consider_env()
self.known_args_namespace = ns = self._parser.parse_known_args(
args, namespace=copy.copy(self.option)

View File

@@ -2,6 +2,13 @@ import six
import warnings
import argparse
from gettext import gettext as _
import sys as _sys
import py
from ..main import EXIT_USAGEERROR
FILE_OR_DIR = "file_or_dir"
@@ -70,7 +77,8 @@ class Parser(object):
self.optparser = self._getparser()
try_argcomplete(self.optparser)
return self.optparser.parse_args([str(x) for x in args], namespace=namespace)
args = [str(x) if isinstance(x, py.path.local) else x for x in args]
return self.optparser.parse_args(args, namespace=namespace)
def _getparser(self):
from _pytest._argcomplete import filescompleter
@@ -106,7 +114,7 @@ class Parser(object):
the remaining arguments unknown at this point.
"""
optparser = self._getparser()
args = [str(x) for x in args]
args = [str(x) if isinstance(x, py.path.local) else x for x in args]
return optparser.parse_known_args(args, namespace=namespace)
def addini(self, name, help, type=None, default=None):
@@ -149,6 +157,7 @@ class Argument(object):
and ignoring choices and integer prefixes
https://docs.python.org/3/library/optparse.html#optparse-standard-option-types
"""
_typ_map = {"int": int, "string": str, "float": float, "complex": complex}
def __init__(self, *names, **attrs):
@@ -173,23 +182,23 @@ class Argument(object):
if isinstance(typ, six.string_types):
if typ == "choice":
warnings.warn(
"type argument to addoption() is a string %r."
" For parsearg this is optional and when supplied"
" should be a type."
"`type` argument to addoption() is the string %r."
" For choices this is optional and can be omitted, "
" but when supplied should be a type (for example `str` or `int`)."
" (options: %s)" % (typ, names),
DeprecationWarning,
stacklevel=3,
stacklevel=4,
)
# argparse expects a type here take it from
# the type of the first element
attrs["type"] = type(attrs["choices"][0])
else:
warnings.warn(
"type argument to addoption() is a string %r."
" For parsearg this should be a type."
"`type` argument to addoption() is the string %r, "
" but when supplied should be a type (for example `str` or `int`)."
" (options: %s)" % (typ, names),
DeprecationWarning,
stacklevel=3,
stacklevel=4,
)
attrs["type"] = Argument._typ_map[typ]
# used in test_parseopt -> test_parse_defaultgetter
@@ -274,7 +283,6 @@ class Argument(object):
class OptionGroup(object):
def __init__(self, name, description="", parser=None):
self.name = name
self.description = description
@@ -312,7 +320,6 @@ class OptionGroup(object):
class MyOptionParser(argparse.ArgumentParser):
def __init__(self, parser, extra_info=None):
if not extra_info:
extra_info = {}
@@ -327,6 +334,16 @@ class MyOptionParser(argparse.ArgumentParser):
# an usage error to provide more contextual information to the user
self.extra_info = extra_info
def error(self, message):
"""error(message: string)
Prints a usage message incorporating the message to stderr and
exits.
Overrides the method in parent class to change exit code"""
self.print_usage(_sys.stderr)
args = {"prog": self.prog, "message": message}
self.exit(EXIT_USAGEERROR, _("%(prog)s: error: %(message)s\n") % args)
def parse_args(self, args=None, namespace=None):
"""allow splitting of positional arguments"""
args, argv = self.parse_known_args(args, namespace)
@@ -378,9 +395,8 @@ class DropShorterLongHelpFormatter(argparse.HelpFormatter):
xxoption = option[2:]
if xxoption.split()[0] not in option_map:
shortened = xxoption.replace("-", "")
if (
shortened not in short_long
or len(short_long[shortened]) < len(xxoption)
if shortened not in short_long or len(short_long[shortened]) < len(
xxoption
):
short_long[shortened] = xxoption
# now short_long has been filled out to the longest with dashes

View File

@@ -5,4 +5,5 @@ class UsageError(Exception):
class PrintHelp(Exception):
"""Raised when pytest should print it's help to skip the rest of the
argument parsing and validation."""
pass

View File

@@ -10,15 +10,12 @@ def exists(path, ignore=EnvironmentError):
return False
def getcfg(args, warnfunc=None):
def getcfg(args, config=None):
"""
Search the list of arguments for a valid ini-file for pytest,
and return a tuple of (rootdir, inifile, cfg-dict).
note: warnfunc is an optional function used to warn
about ini-files that use deprecated features.
This parameter should be removed when pytest
adopts standard deprecation warnings (#1804).
note: config is optional and used only to issue warnings explicitly (#2891).
"""
from _pytest.deprecated import CFG_PYTEST_SECTION
@@ -34,9 +31,15 @@ def getcfg(args, warnfunc=None):
if exists(p):
iniconfig = py.iniconfig.IniConfig(p)
if "pytest" in iniconfig.sections:
if inibasename == "setup.cfg" and warnfunc:
warnfunc(
"C1", CFG_PYTEST_SECTION.format(filename=inibasename)
if inibasename == "setup.cfg" and config is not None:
from _pytest.warnings import _issue_config_warning
from _pytest.warning_types import RemovedInPytest4Warning
_issue_config_warning(
RemovedInPytest4Warning(
CFG_PYTEST_SECTION.format(filename=inibasename)
),
config=config,
)
return base, p, iniconfig["pytest"]
if (
@@ -74,7 +77,6 @@ def get_common_ancestor(paths):
def get_dirs_from_args(args):
def is_option(x):
return str(x).startswith("-")
@@ -96,7 +98,7 @@ def get_dirs_from_args(args):
return [get_dir_from_path(path) for path in possible_paths if path.exists()]
def determine_setup(inifile, args, warnfunc=None, rootdir_cmd_arg=None):
def determine_setup(inifile, args, rootdir_cmd_arg=None, config=None):
dirs = get_dirs_from_args(args)
if inifile:
iniconfig = py.iniconfig.IniConfig(inifile)
@@ -106,23 +108,30 @@ def determine_setup(inifile, args, warnfunc=None, rootdir_cmd_arg=None):
for section in sections:
try:
inicfg = iniconfig[section]
if is_cfg_file and section == "pytest" and warnfunc:
if is_cfg_file and section == "pytest" and config is not None:
from _pytest.deprecated import CFG_PYTEST_SECTION
from _pytest.warning_types import RemovedInPytest4Warning
from _pytest.warnings import _issue_config_warning
warnfunc("C1", CFG_PYTEST_SECTION.format(filename=str(inifile)))
_issue_config_warning(
RemovedInPytest4Warning(
CFG_PYTEST_SECTION.format(filename=str(inifile))
),
config,
)
break
except KeyError:
inicfg = None
rootdir = get_common_ancestor(dirs)
else:
ancestor = get_common_ancestor(dirs)
rootdir, inifile, inicfg = getcfg([ancestor], warnfunc=warnfunc)
rootdir, inifile, inicfg = getcfg([ancestor], config=config)
if rootdir is None:
for rootdir in ancestor.parts(reverse=True):
if rootdir.join("setup.py").exists():
break
else:
rootdir, inifile, inicfg = getcfg(dirs, warnfunc=warnfunc)
rootdir, inifile, inicfg = getcfg(dirs, config=config)
if rootdir is None:
rootdir = get_common_ancestor([py.path.local(), ancestor])
is_fs_root = os.path.splitdrive(str(rootdir))[1] == "/"

View File

@@ -5,6 +5,8 @@ import sys
import os
from doctest import UnexpectedException
from _pytest.config import hookimpl
try:
from builtins import breakpoint # noqa
@@ -28,6 +30,12 @@ def pytest_addoption(parser):
help="start a custom interactive Python debugger on errors. "
"For example: --pdbcls=IPython.terminal.debugger:TerminalPdb",
)
group._addoption(
"--trace",
dest="trace",
action="store_true",
help="Immediately break when running each test.",
)
def pytest_configure(config):
@@ -38,6 +46,8 @@ def pytest_configure(config):
else:
pdb_cls = pdb.Pdb
if config.getvalue("trace"):
config.pluginmanager.register(PdbTrace(), "pdbtrace")
if config.getvalue("usepdb"):
config.pluginmanager.register(PdbInvoke(), "pdbinvoke")
@@ -65,12 +75,13 @@ def pytest_configure(config):
class pytestPDB(object):
""" Pseudo PDB that defers to the real pdb. """
_pluginmanager = None
_config = None
_pdb_cls = pdb.Pdb
@classmethod
def set_trace(cls):
def set_trace(cls, set_break=True):
""" invoke PDB set_trace debugging, dropping any IO capturing. """
import _pytest.config
@@ -83,15 +94,16 @@ class pytestPDB(object):
tw.line()
tw.sep(">", "PDB set_trace (IO-capturing turned off)")
cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config)
cls._pdb_cls().set_trace(frame)
if set_break:
cls._pdb_cls().set_trace(frame)
class PdbInvoke(object):
def pytest_exception_interact(self, node, call, report):
capman = node.config.pluginmanager.getplugin("capturemanager")
if capman:
out, err = capman.suspend_global_capture(in_=True)
capman.suspend_global_capture(in_=True)
out, err = capman.read_global_capture()
sys.stdout.write(out)
sys.stdout.write(err)
_enter_pdb(node, call.excinfo, report)
@@ -104,6 +116,30 @@ class PdbInvoke(object):
post_mortem(tb)
class PdbTrace(object):
@hookimpl(hookwrapper=True)
def pytest_pyfunc_call(self, pyfuncitem):
_test_pytest_function(pyfuncitem)
yield
def _test_pytest_function(pyfuncitem):
pytestPDB.set_trace(set_break=False)
testfunction = pyfuncitem.obj
pyfuncitem.obj = pdb.runcall
if pyfuncitem._isyieldedfunction():
arg_list = list(pyfuncitem._args)
arg_list.insert(0, testfunction)
pyfuncitem._args = tuple(arg_list)
else:
if "func" in pyfuncitem._fixtureinfo.argnames:
raise ValueError("--trace can't be used with a fixture named func!")
pyfuncitem.funcargs["func"] = testfunction
new_list = list(pyfuncitem._fixtureinfo.argnames)
new_list.append("func")
pyfuncitem._fixtureinfo.argnames = tuple(new_list)
def _enter_pdb(node, excinfo, rep):
# XXX we re-use the TerminalReporter's terminalwriter
# because this seems to avoid some encoding related troubles
@@ -114,7 +150,9 @@ def _enter_pdb(node, excinfo, rep):
showcapture = node.config.option.showcapture
for sectionname, content in (
("stdout", rep.capstdout), ("stderr", rep.capstderr), ("log", rep.caplog)
("stdout", rep.capstdout),
("stderr", rep.capstderr),
("log", rep.caplog),
):
if showcapture in (sectionname, "all") and content:
tw.sep(">", "captured " + sectionname)
@@ -148,9 +186,7 @@ def _find_last_non_hidden_frame(stack):
def post_mortem(t):
class Pdb(pytestPDB._pdb_cls):
def get_stack(self, f, t):
stack, i = pdb.Pdb.get_stack(self, f, t)
if f is None:

View File

@@ -7,14 +7,16 @@ be removed when the time comes.
"""
from __future__ import absolute_import, division, print_function
from _pytest.warning_types import RemovedInPytest4Warning
class RemovedInPytest4Warning(DeprecationWarning):
"""warning class for features removed in pytest 4.0"""
MAIN_STR_ARGS = RemovedInPytest4Warning(
"passing a string to pytest.main() is deprecated, "
"pass a list of arguments instead."
)
MAIN_STR_ARGS = "passing a string to pytest.main() is deprecated, " "pass a list of arguments instead."
YIELD_TESTS = "yield tests are deprecated, and scheduled to be removed in pytest 4.0"
YIELD_TESTS = RemovedInPytest4Warning(
"yield tests are deprecated, and scheduled to be removed in pytest 4.0"
)
FUNCARG_PREFIX = (
'{name}: declaring fixtures using "pytest_funcarg__" prefix is deprecated '
@@ -22,9 +24,17 @@ FUNCARG_PREFIX = (
"Please remove the prefix and use the @pytest.fixture decorator instead."
)
CFG_PYTEST_SECTION = "[pytest] section in {filename} files is deprecated, use [tool:pytest] instead."
FIXTURE_FUNCTION_CALL = (
'Fixture "{name}" called directly. Fixtures are not meant to be called directly, '
"are created automatically when test functions request them as parameters. "
"See https://docs.pytest.org/en/latest/fixture.html for more information."
)
GETFUNCARGVALUE = "use of getfuncargvalue is deprecated, use getfixturevalue"
CFG_PYTEST_SECTION = (
"[pytest] section in {filename} files is deprecated, use [tool:pytest] instead."
)
GETFUNCARGVALUE = "getfuncargvalue is deprecated, use getfixturevalue"
RESULT_LOG = (
"--result-log is deprecated and scheduled for removal in pytest 4.0.\n"
@@ -43,7 +53,11 @@ MARK_PARAMETERSET_UNPACKING = RemovedInPytest4Warning(
"For more details, see: https://docs.pytest.org/en/latest/parametrize.html"
)
RECORD_XML_PROPERTY = (
NODE_WARN = RemovedInPytest4Warning(
"Node.warn(code, message) form has been deprecated, use Node.warn(warning_instance) instead."
)
RECORD_XML_PROPERTY = RemovedInPytest4Warning(
'Fixture renamed from "record_xml_property" to "record_property" as user '
"properties are now available to all reporters.\n"
'"record_xml_property" is now deprecated.'
@@ -53,7 +67,7 @@ COLLECTOR_MAKEITEM = RemovedInPytest4Warning(
"pycollector makeitem was removed " "as it is an accidentially leaked internal api"
)
METAFUNC_ADD_CALL = (
METAFUNC_ADD_CALL = RemovedInPytest4Warning(
"Metafunc.addcall is deprecated and scheduled to be removed in pytest 4.0.\n"
"Please use Metafunc.parametrize instead."
)
@@ -63,3 +77,7 @@ PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST = RemovedInPytest4Warning(
"because it affects the entire directory tree in a non-explicit way.\n"
"Please move it to the top level conftest file instead."
)
PYTEST_NAMESPACE = RemovedInPytest4Warning(
"pytest_namespace is deprecated and will be removed soon"
)

View File

@@ -105,7 +105,6 @@ def _is_doctest(config, path, parent):
class ReprFailDoctest(TerminalRepr):
def __init__(self, reprlocation_lines):
# List of (reprlocation, lines) tuples
self.reprlocation_lines = reprlocation_lines
@@ -118,7 +117,6 @@ class ReprFailDoctest(TerminalRepr):
class MultipleDoctestFailures(Exception):
def __init__(self, failures):
super(MultipleDoctestFailures, self).__init__()
self.failures = failures
@@ -172,7 +170,6 @@ def _get_runner(checker=None, verbose=None, optionflags=0, continue_on_failure=T
class DoctestItem(pytest.Item):
def __init__(self, name, parent, runner=None, dtest=None):
super(DoctestItem, self).__init__(name, parent)
self.runner = runner
@@ -206,7 +203,8 @@ class DoctestItem(pytest.Item):
return
capman = self.config.pluginmanager.getplugin("capturemanager")
if capman:
out, err = capman.suspend_global_capture(in_=True)
capman.suspend_global_capture(in_=True)
out, err = capman.read_global_capture()
sys.stdout.write(out)
sys.stderr.write(err)
@@ -243,7 +241,7 @@ class DoctestItem(pytest.Item):
for (i, x) in enumerate(lines)
]
# trim docstring error lines to 10
lines = lines[max(example.lineno - 9, 0):example.lineno + 1]
lines = lines[max(example.lineno - 9, 0) : example.lineno + 1]
else:
lines = [
"EXAMPLE LOCATION UNKNOWN, not showing all tests of that example"
@@ -255,9 +253,7 @@ class DoctestItem(pytest.Item):
if isinstance(failure, doctest.DocTestFailure):
lines += checker.output_difference(
example, failure.got, report_choice
).split(
"\n"
)
).split("\n")
else:
inner_excinfo = ExceptionInfo(failure.exc_info)
lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)]
@@ -347,7 +343,6 @@ def _check_all_skipped(test):
class DoctestModule(pytest.Module):
def collect(self):
import doctest
@@ -480,9 +475,7 @@ def _get_report_choice(key):
DOCTEST_REPORT_CHOICE_NDIFF: doctest.REPORT_NDIFF,
DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE: doctest.REPORT_ONLY_FIRST_FAILURE,
DOCTEST_REPORT_CHOICE_NONE: 0,
}[
key
]
}[key]
def _fix_spoof_python2(runner, encoding):
@@ -502,7 +495,6 @@ def _fix_spoof_python2(runner, encoding):
from doctest import _SpoofOut
class UnicodeSpoof(_SpoofOut):
def getvalue(self):
result = _SpoofOut.getvalue(self)
if encoding and isinstance(result, bytes):

View File

@@ -5,6 +5,8 @@ import inspect
import sys
import warnings
from collections import OrderedDict, deque, defaultdict
import six
from more_itertools import flatten
import attr
@@ -27,7 +29,10 @@ from _pytest.compat import (
getfuncargnames,
safe_getattr,
FuncargnamesCompatAttr,
get_real_method,
_PytestWrapper,
)
from _pytest.deprecated import FIXTURE_FUNCTION_CALL, RemovedInPytest4Warning
from _pytest.outcomes import fail, TEST_OUTCOME
FIXTURE_MSG = 'fixtures cannot have "pytest_funcarg__" prefix and be decorated with @pytest.fixture:\n{}'
@@ -45,6 +50,7 @@ def pytest_sessionstart(session):
scopename2class.update(
{
"package": _pytest.python.Package,
"class": _pytest.python.Class,
"module": _pytest.python.Module,
"function": _pytest.nodes.Item,
@@ -58,6 +64,7 @@ scopename2class = {}
scope2props = dict(session=())
scope2props["package"] = ("fspath",)
scope2props["module"] = ("fspath", "module")
scope2props["class"] = scope2props["module"] + ("cls",)
scope2props["instance"] = scope2props["class"] + ("instance",)
@@ -65,7 +72,6 @@ scope2props["function"] = scope2props["instance"] + ("function", "keywords")
def scopeproperty(name=None, doc=None):
def decoratescope(func):
scopename = name or func.__name__
@@ -81,6 +87,21 @@ def scopeproperty(name=None, doc=None):
return decoratescope
def get_scope_package(node, fixturedef):
import pytest
cls = pytest.Package
current = node
fixture_package_name = "%s/%s" % (fixturedef.baseid, "__init__.py")
while current and (
type(current) is not cls or fixture_package_name != current.nodeid
):
current = current.parent
if current is None:
return node.session
return current
def get_scope_node(node, scope):
cls = scopename2class.get(scope)
if cls is None:
@@ -174,9 +195,11 @@ def get_parametrized_fixture_keys(item, scopenum):
continue
if scopenum == 0: # session
key = (argname, param_index)
elif scopenum == 1: # module
elif scopenum == 1: # package
key = (argname, param_index, item.fspath.dirpath())
elif scopenum == 2: # module
key = (argname, param_index, item.fspath)
elif scopenum == 2: # class
elif scopenum == 3: # class
key = (argname, param_index, item.fspath, item.cls)
yield key
@@ -275,12 +298,43 @@ def get_direct_param_fixture_func(request):
return request.param
@attr.s(slots=True)
class FuncFixtureInfo(object):
# original function argument names
argnames = attr.ib(type=tuple)
# argnames that function immediately requires. These include argnames +
# fixture names specified via usefixtures and via autouse=True in fixture
# definitions.
initialnames = attr.ib(type=tuple)
names_closure = attr.ib() # type: List[str]
name2fixturedefs = attr.ib() # type: List[str, List[FixtureDef]]
def __init__(self, argnames, names_closure, name2fixturedefs):
self.argnames = argnames
self.names_closure = names_closure
self.name2fixturedefs = name2fixturedefs
def prune_dependency_tree(self):
"""Recompute names_closure from initialnames and name2fixturedefs
Can only reduce names_closure, which means that the new closure will
always be a subset of the old one. The order is preserved.
This method is needed because direct parametrization may shadow some
of the fixtures that were included in the originally built dependency
tree. In this way the dependency tree can get pruned, and the closure
of argnames may get reduced.
"""
closure = set()
working_set = set(self.initialnames)
while working_set:
argname = working_set.pop()
# argname may be smth not included in the original names_closure,
# in which case we ignore it. This currently happens with pseudo
# FixtureDefs which wrap 'get_direct_param_fixture_func(request)'.
# So they introduce the new dependency 'request' which might have
# been missing in the original tree (closure).
if argname not in closure and argname in self.names_closure:
closure.add(argname)
if argname in self.name2fixturedefs:
working_set.update(self.name2fixturedefs[argname][-1].argnames)
self.names_closure[:] = sorted(closure, key=self.names_closure.index)
class FixtureRequest(FuncargnamesCompatAttr):
@@ -582,7 +636,10 @@ class FixtureRequest(FuncargnamesCompatAttr):
if scope == "function":
# this might also be a non-function Item despite its attribute name
return self._pyfuncitem
node = get_scope_node(self._pyfuncitem, scope)
if scope == "package":
node = get_scope_package(self._pyfuncitem, self._fixturedef)
else:
node = get_scope_node(self._pyfuncitem, scope)
if node is None and scope == "class":
# fallback to function item itself
node = self._pyfuncitem
@@ -626,7 +683,7 @@ class ScopeMismatchError(Exception):
"""
scopes = "session module class function".split()
scopes = "session package module class function".split()
scopenum_function = scopes.index("function")
@@ -698,7 +755,6 @@ class FixtureLookupError(LookupError):
class FixtureLookupErrorRepr(TerminalRepr):
def __init__(self, filename, firstlineno, tblines, errorstring, argname):
self.tblines = tblines
self.errorstring = errorstring
@@ -737,23 +793,26 @@ def call_fixture_func(fixturefunc, request, kwargs):
if yieldctx:
it = fixturefunc(**kwargs)
res = next(it)
def teardown():
try:
next(it)
except StopIteration:
pass
else:
fail_fixturefunc(
fixturefunc, "yield_fixture function has more than one 'yield'"
)
request.addfinalizer(teardown)
finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, it)
request.addfinalizer(finalizer)
else:
res = fixturefunc(**kwargs)
return res
def _teardown_yield_fixture(fixturefunc, it):
"""Executes the teardown of a fixture function by advancing the iterator after the
yield and ensure the iteration ends (if not it means there is more than one yield in the function)"""
try:
next(it)
except StopIteration:
pass
else:
fail_fixturefunc(
fixturefunc, "yield_fixture function has more than one 'yield'"
)
class FixtureDef(object):
""" A container for a factory definition. """
@@ -798,7 +857,7 @@ class FixtureDef(object):
if exceptions:
e = exceptions[0]
del exceptions # ensure we don't keep all frames alive because of the traceback
py.builtin._reraise(*e)
six.reraise(*e)
finally:
hook = self._fixturemanager.session.gethookproxy(request.node.fspath)
@@ -825,7 +884,7 @@ class FixtureDef(object):
result, cache_key, err = cached_result
if my_cache_key == cache_key:
if err is not None:
py.builtin._reraise(*err)
six.reraise(*err)
else:
return result
# we have a previous but differently parametrized fixture instance
@@ -837,21 +896,17 @@ class FixtureDef(object):
return hook.pytest_fixture_setup(fixturedef=self, request=request)
def __repr__(self):
return (
"<FixtureDef name=%r scope=%r baseid=%r >"
% (self.argname, self.scope, self.baseid)
return "<FixtureDef name=%r scope=%r baseid=%r >" % (
self.argname,
self.scope,
self.baseid,
)
def pytest_fixture_setup(fixturedef, request):
""" Execution of fixture setup. """
kwargs = {}
for argname in fixturedef.argnames:
fixdef = request._get_active_fixturedef(argname)
result, arg_cache_key, exc = fixdef.cached_result
request._check_scope(argname, request.scope, fixdef.scope)
kwargs[argname] = result
def resolve_fixture_function(fixturedef, request):
"""Gets the actual callable that can be called to obtain the fixture value, dealing with unittest-specific
instances and bound methods.
"""
fixturefunc = fixturedef.func
if fixturedef.unittest:
if request.instance is not None:
@@ -865,6 +920,19 @@ def pytest_fixture_setup(fixturedef, request):
fixturefunc = getimfunc(fixturedef.func)
if fixturefunc != fixturedef.func:
fixturefunc = fixturefunc.__get__(request.instance)
return fixturefunc
def pytest_fixture_setup(fixturedef, request):
""" Execution of fixture setup. """
kwargs = {}
for argname in fixturedef.argnames:
fixdef = request._get_active_fixturedef(argname)
result, arg_cache_key, exc = fixdef.cached_result
request._check_scope(argname, request.scope, fixdef.scope)
kwargs[argname] = result
fixturefunc = resolve_fixture_function(fixturedef, request)
my_cache_key = request.param_index
try:
result = call_fixture_func(fixturefunc, request, kwargs)
@@ -883,6 +951,41 @@ def _ensure_immutable_ids(ids):
return tuple(ids)
def wrap_function_to_warning_if_called_directly(function, fixture_marker):
"""Wrap the given fixture function so we can issue warnings about it being called directly, instead of
used as an argument in a test function.
"""
is_yield_function = is_generator(function)
msg = FIXTURE_FUNCTION_CALL.format(name=fixture_marker.name or function.__name__)
warning = RemovedInPytest4Warning(msg)
if is_yield_function:
@functools.wraps(function)
def result(*args, **kwargs):
__tracebackhide__ = True
warnings.warn(warning, stacklevel=3)
for x in function(*args, **kwargs):
yield x
else:
@functools.wraps(function)
def result(*args, **kwargs):
__tracebackhide__ = True
warnings.warn(warning, stacklevel=3)
return function(*args, **kwargs)
if six.PY2:
result.__wrapped__ = function
# keep reference to the original function in our own custom attribute so we don't unwrap
# further than this point and lose useful wrappings like @mock.patch (#3774)
result.__pytest_wrapped__ = _PytestWrapper(function)
return result
@attr.s(frozen=True)
class FixtureFunctionMarker(object):
scope = attr.ib()
@@ -900,6 +1003,8 @@ class FixtureFunctionMarker(object):
"fixture is being applied more than once to the same function"
)
function = wrap_function_to_warning_if_called_directly(function, self)
function._pytestfixturefunction = self
return function
@@ -907,16 +1012,27 @@ class FixtureFunctionMarker(object):
def fixture(scope="function", params=None, autouse=False, ids=None, name=None):
"""Decorator to mark a fixture factory function.
This decorator can be used (with or without parameters) to define a
fixture function. The name of the fixture function can later be
referenced to cause its invocation ahead of running tests: test
modules or classes can use the pytest.mark.usefixtures(fixturename)
marker. Test functions can directly use fixture names as input
This decorator can be used, with or without parameters, to define a
fixture function.
The name of the fixture function can later be referenced to cause its
invocation ahead of running tests: test
modules or classes can use the ``pytest.mark.usefixtures(fixturename)``
marker.
Test functions can directly use fixture names as input
arguments in which case the fixture instance returned from the fixture
function will be injected.
Fixtures can provide their values to test functions using ``return`` or ``yield``
statements. When using ``yield`` the code block after the ``yield`` statement is executed
as teardown code regardless of the test outcome, and must yield exactly once.
:arg scope: the scope for which this fixture is shared, one of
"function" (default), "class", "module" or "session".
``"function"`` (default), ``"class"``, ``"module"``,
``"package"`` or ``"session"``.
``"package"`` is considered **experimental** at this time.
:arg params: an optional list of parameters which will cause multiple
invocations of the fixture function and all of the tests
@@ -937,10 +1053,6 @@ def fixture(scope="function", params=None, autouse=False, ids=None, name=None):
to resolve this is to name the decorated function
``fixture_<fixturename>`` and then use
``@pytest.fixture(name='<fixturename>')``.
Fixtures can optionally provide their values to test functions using a ``yield`` statement,
instead of ``return``. In this case, the code block after the ``yield`` statement is executed
as teardown code regardless of the test outcome. A fixture function must yield exactly once.
"""
if callable(scope) and params is None and autouse is False:
# direct decoration
@@ -956,13 +1068,7 @@ def yield_fixture(scope="function", params=None, autouse=False, ids=None, name=N
.. deprecated:: 3.0
Use :py:func:`pytest.fixture` directly instead.
"""
if callable(scope) and params is None and not autouse:
# direct decoration
return FixtureFunctionMarker("function", params, autouse, ids=ids, name=name)(
scope
)
else:
return FixtureFunctionMarker(scope, params, autouse, ids=ids, name=name)
return fixture(scope=scope, params=params, autouse=autouse, ids=ids, name=name)
defaultfuncargprefixmarker = fixture()
@@ -1035,11 +1141,12 @@ class FixtureManager(object):
usefixtures = flatten(
mark.args for mark in node.iter_markers(name="usefixtures")
)
initialnames = argnames
initialnames = tuple(usefixtures) + initialnames
initialnames = tuple(usefixtures) + argnames
fm = node.session._fixturemanager
names_closure, arg2fixturedefs = fm.getfixtureclosure(initialnames, node)
return FuncFixtureInfo(argnames, names_closure, arg2fixturedefs)
initialnames, names_closure, arg2fixturedefs = fm.getfixtureclosure(
initialnames, node
)
return FuncFixtureInfo(argnames, initialnames, names_closure, arg2fixturedefs)
def pytest_plugin_registered(self, plugin):
nodeid = None
@@ -1064,7 +1171,7 @@ class FixtureManager(object):
if nodeid.startswith(baseid):
if baseid:
i = len(baseid)
nextchar = nodeid[i:i + 1]
nextchar = nodeid[i : i + 1]
if nextchar and nextchar not in ":/":
continue
autousenames.extend(basenames)
@@ -1087,6 +1194,12 @@ class FixtureManager(object):
fixturenames_closure.append(arg)
merge(fixturenames)
# at this point, fixturenames_closure contains what we call "initialnames",
# which is a set of fixturenames the function immediately requests. We
# need to return it as well, so save this.
initialnames = tuple(fixturenames_closure)
arg2fixturedefs = {}
lastlen = -1
while lastlen != len(fixturenames_closure):
@@ -1108,7 +1221,7 @@ class FixtureManager(object):
return fixturedefs[-1].scopenum
fixturenames_closure.sort(key=sort_by_scope)
return fixturenames_closure, arg2fixturedefs
return initialnames, fixturenames_closure, arg2fixturedefs
def pytest_generate_tests(self, metafunc):
for argname in metafunc.fixturenames:
@@ -1144,6 +1257,8 @@ class FixtureManager(object):
items[:] = reorder_items(items)
def parsefactories(self, node_or_obj, nodeid=NOTSET, unittest=False):
from _pytest import deprecated
if nodeid is not NOTSET:
holderobj = node_or_obj
else:
@@ -1157,21 +1272,26 @@ class FixtureManager(object):
# The attribute can be an arbitrary descriptor, so the attribute
# access below can raise. safe_getatt() ignores such exceptions.
obj = safe_getattr(holderobj, name, None)
marker = getfixturemarker(obj)
# fixture functions have a pytest_funcarg__ prefix (pre-2.3 style)
# or are "@pytest.fixture" marked
marker = getfixturemarker(obj)
if marker is None:
if not name.startswith(self._argprefix):
continue
if not callable(obj):
continue
marker = defaultfuncargprefixmarker
from _pytest import deprecated
self.config.warn(
"C1", deprecated.FUNCARG_PREFIX.format(name=name), nodeid=nodeid
filename, lineno = getfslineno(obj)
warnings.warn_explicit(
RemovedInPytest4Warning(
deprecated.FUNCARG_PREFIX.format(name=name)
),
category=None,
filename=str(filename),
lineno=lineno + 1,
)
name = name[len(self._argprefix):]
name = name[len(self._argprefix) :]
elif not isinstance(marker, FixtureFunctionMarker):
# magic globals with __getattr__ might have got us a wrong
# fixture attribute
@@ -1181,6 +1301,15 @@ class FixtureManager(object):
name = marker.name
assert not name.startswith(self._argprefix), FIXTURE_MSG.format(name)
# during fixture definition we wrap the original fixture function
# to issue a warning if called directly, so here we unwrap it in order to not emit the warning
# when pytest itself calls the fixture function
if six.PY2 and unittest:
# hack on Python 2 because of the unbound methods
obj = get_real_func(obj)
else:
obj = get_real_method(obj, holderobj)
fixture_def = FixtureDef(
self,
nodeid,

View File

@@ -149,13 +149,14 @@ def showhelp(config):
type = "string"
spec = "%s (%s)" % (name, type)
line = " %-24s %s" % (spec, help)
tw.line(line[:tw.fullwidth])
tw.line(line[: tw.fullwidth])
tw.line()
tw.line("environment variables:")
vars = [
("PYTEST_ADDOPTS", "extra command line options"),
("PYTEST_PLUGINS", "comma-separated plugins to load during startup"),
("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "set to disable plugin auto-loading"),
("PYTEST_DEBUG", "set to enable debug tracing of pytest's internals"),
]
for name, help in vars:

View File

@@ -1,6 +1,8 @@
""" hook specifications for pytest plugins, invoked from main.py and builtin plugins. """
from pluggy import HookspecMarker
from .deprecated import PYTEST_NAMESPACE
hookspec = HookspecMarker("pytest")
@@ -22,10 +24,9 @@ def pytest_addhooks(pluginmanager):
"""
@hookspec(historic=True)
@hookspec(historic=True, warn_on_impl=PYTEST_NAMESPACE)
def pytest_namespace():
"""
(**Deprecated**) this hook causes direct monkeypatching on pytest, its use is strongly discouraged
return dict of name->object to be made globally available in
the pytest namespace.
@@ -33,6 +34,19 @@ def pytest_namespace():
.. note::
This hook is incompatible with ``hookwrapper=True``.
.. warning::
This hook has been **deprecated** and will be removed in pytest 4.0.
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
pytest namespace.
An 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.
"""
@@ -512,7 +526,17 @@ def pytest_terminal_summary(terminalreporter, exitstatus):
@hookspec(historic=True)
def pytest_logwarning(message, code, nodeid, fslocation):
""" process a warning specified by a message, a code string,
"""
.. deprecated:: 3.8
This hook is will stop working in a future release.
pytest no longer triggers this hook, but the
terminal writer still implements it to display warnings issued by
:meth:`_pytest.config.Config.warn` and :meth:`_pytest.nodes.Node.warn`. Calling those functions will be
an error in future releases.
process a warning specified by a message, a code string,
a nodeid and fslocation (both of which may be None
if the warning is not tied to a particular node/location).
@@ -521,6 +545,30 @@ def pytest_logwarning(message, code, nodeid, fslocation):
"""
@hookspec(historic=True)
def pytest_warning_captured(warning_message, when, item):
"""
Process a warning captured by the internal pytest warnings plugin.
:param warnings.WarningMessage warning_message:
The captured warning. This is the same object produced by :py:func:`warnings.catch_warnings`, and contains
the same attributes as the parameters of :py:func:`warnings.showwarning`.
:param str when:
Indicates when the warning was captured. Possible values:
* ``"config"``: during pytest configuration/initialization stage.
* ``"collect"``: during test collection.
* ``"runtest"``: during test execution.
:param pytest.Item|None item:
**DEPRECATED**: This parameter is incompatible with ``pytest-xdist``, and will always receive ``None``
in a future release.
The item being executed if ``when`` is ``"runtest"``, otherwise ``None``.
"""
# -------------------------------------------------------------------------
# doctest hooks
# -------------------------------------------------------------------------

View File

@@ -55,7 +55,6 @@ _py_ext_re = re.compile(r"\.py$")
def bin_xml_escape(arg):
def repl(matchobj):
i = ord(matchobj.group())
if i <= 0xFF:
@@ -67,7 +66,6 @@ def bin_xml_escape(arg):
class _NodeReporter(object):
def __init__(self, nodeid, xml):
self.id = nodeid
@@ -260,12 +258,11 @@ def record_property(request):
@pytest.fixture
def record_xml_property(record_property):
def record_xml_property(record_property, request):
"""(Deprecated) use record_property."""
import warnings
from _pytest import deprecated
warnings.warn(deprecated.RECORD_XML_PROPERTY, DeprecationWarning, stacklevel=2)
request.node.warn(deprecated.RECORD_XML_PROPERTY)
return record_property
@@ -276,9 +273,9 @@ def record_xml_attribute(request):
The fixture is callable with ``(name, value)``, with value being
automatically xml-encoded
"""
request.node.warn(
code="C3", message="record_xml_attribute is an experimental feature"
)
from _pytest.warning_types import PytestWarning
request.node.warn(PytestWarning("record_xml_attribute is an experimental feature"))
xml = getattr(request.config, "_xml", None)
if xml is not None:
node_reporter = xml.node_reporter(request.node.nodeid)
@@ -358,7 +355,6 @@ def mangle_test_address(address):
class LogXML(object):
def __init__(self, logfile, prefix, suite_name="pytest", logging="no"):
logfile = os.path.expanduser(os.path.expandvars(logfile))
self.logfile = os.path.normpath(os.path.abspath(logfile))
@@ -544,9 +540,7 @@ class LogXML(object):
skips=self.stats["skipped"],
tests=numtests,
time="%.3f" % suite_time_delta,
).unicode(
indent=0
)
).unicode(indent=0)
)
logfile.close()

View File

@@ -6,6 +6,7 @@ from contextlib import closing, contextmanager
import re
import six
from _pytest.compat import dummy_context_manager
from _pytest.config import create_terminal_writer
import pytest
import py
@@ -270,6 +271,22 @@ class LogCaptureFixture(object):
"""
return [(r.name, r.levelno, r.getMessage()) for r in self.records]
@property
def messages(self):
"""Returns a list of format-interpolated log messages.
Unlike 'records', which contains the format string and parameters for interpolation, log messages in this list
are all interpolated.
Unlike 'text', which contains the output from the handler, log messages in this list are unadorned with
levels, timestamps, etc, making exact comparisions more reliable.
Note that traceback or stack info (from :func:`logging.exception` or the `exc_info` or `stack_info` arguments
to the logging functions) is not included, as this is added by the formatter in the handler.
.. versionadded:: 3.7
"""
return [r.getMessage() for r in self.records]
def clear(self):
"""Reset the list of log records and the captured log text."""
self.handler.reset()
@@ -353,11 +370,6 @@ def pytest_configure(config):
config.pluginmanager.register(LoggingPlugin(config), "logging-plugin")
@contextmanager
def _dummy_context_manager():
yield
class LoggingPlugin(object):
"""Attaches to the logging module and captures log messages for each test.
"""
@@ -392,7 +404,9 @@ class LoggingPlugin(object):
config, "log_file_date_format", "log_date_format"
)
# Each pytest runtests session will write to a clean logfile
self.log_file_handler = logging.FileHandler(log_file, mode="w")
self.log_file_handler = logging.FileHandler(
log_file, mode="w", encoding="UTF-8"
)
log_file_formatter = logging.Formatter(
log_file_format, datefmt=log_file_date_format
)
@@ -409,9 +423,7 @@ class LoggingPlugin(object):
"""
return self._config.getoption(
"--log-cli-level"
) is not None or self._config.getini(
"log_cli"
)
) is not None or self._config.getini("log_cli")
@contextmanager
def _runtest_for(self, item, when):
@@ -433,8 +445,8 @@ class LoggingPlugin(object):
try:
yield # run test
finally:
del item.catch_log_handler
if when == "teardown":
del item.catch_log_handler
del item.catch_log_handlers
if self.print_logs:
@@ -521,7 +533,7 @@ class LoggingPlugin(object):
log_cli_handler, formatter=log_cli_formatter, level=log_cli_level
)
else:
self.live_logs_context = _dummy_context_manager()
self.live_logs_context = dummy_context_manager()
class _LiveLoggingStreamHandler(logging.StreamHandler):
@@ -556,9 +568,12 @@ class _LiveLoggingStreamHandler(logging.StreamHandler):
self._test_outcome_written = False
def emit(self, record):
if self.capture_manager is not None:
self.capture_manager.suspend_global_capture()
try:
ctx_manager = (
self.capture_manager.global_and_fixture_disabled()
if self.capture_manager
else dummy_context_manager()
)
with ctx_manager:
if not self._first_record_emitted:
self.stream.write("\n")
self._first_record_emitted = True
@@ -570,6 +585,3 @@ class _LiveLoggingStreamHandler(logging.StreamHandler):
self.stream.section("live log " + self._when, sep="-", bold=True)
self._section_name_shown = True
logging.StreamHandler.emit(self, record)
finally:
if self.capture_manager is not None:
self.capture_manager.resume_global_capture()

View File

@@ -343,7 +343,6 @@ def _patched_find_module():
class FSHookProxy(object):
def __init__(self, fspath, pm, remove_mods):
self.fspath = fspath
self.pm = pm
@@ -361,6 +360,7 @@ class NoMatch(Exception):
class Interrupted(KeyboardInterrupt):
""" signals an interrupted test run. """
__module__ = "builtins" # for py3
@@ -383,6 +383,9 @@ class Session(nodes.FSCollector):
self.trace = config.trace.root.get("collection")
self._norecursepatterns = config.getini("norecursedirs")
self.startdir = py.path.local()
self._initialpaths = frozenset()
# Keep track of any collected nodes in here, so we don't duplicate fixtures
self._node_cache = {}
self.config.pluginmanager.register(self, name="session")
@@ -439,13 +442,14 @@ class Session(nodes.FSCollector):
self.trace("perform_collect", self, args)
self.trace.root.indent += 1
self._notfound = []
self._initialpaths = set()
initialpaths = []
self._initialparts = []
self.items = items = []
for arg in args:
parts = self._parsearg(arg)
self._initialparts.append(parts)
self._initialpaths.add(parts[0])
initialpaths.append(parts[0])
self._initialpaths = frozenset(initialpaths)
rep = collect_one_node(self)
self.ihook.pytest_collectreport(report=rep)
self.trace.root.indent -= 1
@@ -480,19 +484,66 @@ class Session(nodes.FSCollector):
self.trace.root.indent -= 1
def _collect(self, arg):
from _pytest.python import Package
names = self._parsearg(arg)
path = names.pop(0)
if path.check(dir=1):
argpath = names.pop(0)
paths = []
root = self
# Start with a Session root, and delve to argpath item (dir or file)
# and stack all Packages found on the way.
# No point in finding packages when collecting doctests
if not self.config.option.doctestmodules:
for parent in argpath.parts():
pm = self.config.pluginmanager
if pm._confcutdir and pm._confcutdir.relto(parent):
continue
if parent.isdir():
pkginit = parent.join("__init__.py")
if pkginit.isfile():
if pkginit in self._node_cache:
root = self._node_cache[pkginit][0]
else:
col = root._collectfile(pkginit)
if col:
if isinstance(col[0], Package):
root = col[0]
# always store a list in the cache, matchnodes expects it
self._node_cache[root.fspath] = [root]
# If it's a directory argument, recurse and look for any Subpackages.
# Let the Package collector deal with subnodes, don't collect here.
if argpath.check(dir=1):
assert not names, "invalid arg %r" % (arg,)
for path in path.visit(
for path in argpath.visit(
fil=lambda x: x.check(file=1), rec=self._recurse, bf=True, sort=True
):
for x in self._collectfile(path):
yield x
pkginit = path.dirpath().join("__init__.py")
if pkginit.exists() and not any(x in pkginit.parts() for x in paths):
for x in root._collectfile(pkginit):
yield x
paths.append(x.fspath.dirpath())
if not any(x in path.parts() for x in paths):
for x in root._collectfile(path):
if (type(x), x.fspath) in self._node_cache:
yield self._node_cache[(type(x), x.fspath)]
else:
self._node_cache[(type(x), x.fspath)] = x
yield x
else:
assert path.check(file=1)
for x in self.matchnodes(self._collectfile(path), names):
yield x
assert argpath.check(file=1)
if argpath in self._node_cache:
col = self._node_cache[argpath]
else:
col = root._collectfile(argpath)
if col:
self._node_cache[argpath] = col
for y in self.matchnodes(col, names):
yield y
def _collectfile(self, path):
ihook = self.gethookproxy(path)
@@ -516,7 +567,6 @@ class Session(nodes.FSCollector):
"""Convert a dotted module name to path.
"""
try:
with _patched_find_module():
loader = pkgutil.find_loader(x)
@@ -577,7 +627,12 @@ class Session(nodes.FSCollector):
resultnodes.append(node)
continue
assert isinstance(node, nodes.Collector)
rep = collect_one_node(node)
key = (type(node), node.nodeid)
if key in self._node_cache:
rep = self._node_cache[key]
else:
rep = collect_one_node(node)
self._node_cache[key] = rep
if rep.passed:
has_matched = False
for x in rep.result:

View File

@@ -21,7 +21,6 @@ def cached_eval(config, expr, d):
class MarkEvaluator(object):
def __init__(self, item, name):
self.item = item
self._marks = None

View File

@@ -66,7 +66,10 @@ python_keywords_allowed_list = ["or", "and", "not"]
def matchmark(colitem, markexpr):
"""Tries to match on any marker names, attached to the given colitem."""
return eval(markexpr, {}, MarkMapping.from_item(colitem))
try:
return eval(markexpr, {}, MarkMapping.from_item(colitem))
except SyntaxError as e:
raise SyntaxError(str(e) + "\nMarker expression must be valid Python!")
def matchkeyword(colitem, keywordexpr):

View File

@@ -1,13 +1,14 @@
import inspect
import warnings
from collections import namedtuple
from functools import reduce
from operator import attrgetter
import attr
from ..deprecated import MARK_PARAMETERSET_UNPACKING, MARK_INFO_ATTRIBUTE
from ..compat import NOTSET, getfslineno, MappingMixin
from six.moves import map, reduce
from six.moves import map
EMPTY_PARAMETERSET_OPTION = "empty_parameter_set_mark"
@@ -24,9 +25,10 @@ def alias(name, warning=None):
def istestfunc(func):
return hasattr(func, "__call__") and getattr(
func, "__name__", "<lambda>"
) != "<lambda>"
return (
hasattr(func, "__call__")
and getattr(func, "__name__", "<lambda>") != "<lambda>"
)
def get_empty_parameterset_mark(config, argnames, func):
@@ -39,18 +41,20 @@ def get_empty_parameterset_mark(config, argnames, func):
raise LookupError(requested_mark)
fs, lineno = getfslineno(func)
reason = "got empty parameter set %r, function %s at %s:%d" % (
argnames, func.__name__, fs, lineno
argnames,
func.__name__,
fs,
lineno,
)
return mark(reason=reason)
class ParameterSet(namedtuple("ParameterSet", "values, marks, id")):
@classmethod
def param(cls, *values, **kw):
marks = kw.pop("marks", ())
if isinstance(marks, MarkDecorator):
marks = marks,
marks = (marks,)
else:
assert isinstance(marks, (tuple, list, set))
@@ -61,7 +65,7 @@ class ParameterSet(namedtuple("ParameterSet", "values, marks, id")):
return cls(values, marks, id_)
@classmethod
def extract_from(cls, parameterset, legacy_force_tuple=False):
def extract_from(cls, parameterset, belonging_definition, legacy_force_tuple=False):
"""
:param parameterset:
a legacy style parameterset that may or may not be a tuple,
@@ -71,6 +75,7 @@ class ParameterSet(namedtuple("ParameterSet", "values, marks, id")):
enforce tuple wrapping so single argument tuple values
don't get decomposed and break tests
:param belonging_definition: the item that we will be extracting the parameters from.
"""
if isinstance(parameterset, cls):
@@ -87,27 +92,43 @@ class ParameterSet(namedtuple("ParameterSet", "values, marks, id")):
argval = argval.args[-1]
assert not isinstance(argval, ParameterSet)
if legacy_force_tuple:
argval = argval,
argval = (argval,)
if newmarks:
warnings.warn(MARK_PARAMETERSET_UNPACKING)
if newmarks and belonging_definition is not None:
belonging_definition.warn(MARK_PARAMETERSET_UNPACKING)
return cls(argval, marks=newmarks, id=None)
@classmethod
def _for_parametrize(cls, argnames, argvalues, func, config):
def _for_parametrize(cls, argnames, argvalues, func, config, function_definition):
if not isinstance(argnames, (tuple, list)):
argnames = [x.strip() for x in argnames.split(",") if x.strip()]
force_tuple = len(argnames) == 1
else:
force_tuple = False
parameters = [
ParameterSet.extract_from(x, legacy_force_tuple=force_tuple)
ParameterSet.extract_from(
x,
legacy_force_tuple=force_tuple,
belonging_definition=function_definition,
)
for x in argvalues
]
del argvalues
if not parameters:
if parameters:
# check all parameter sets have the correct number of values
for param in parameters:
if len(param.values) != len(argnames):
raise ValueError(
'In "parametrize" the number of values ({}) must be '
"equal to the number of names ({})".format(
param.values, argnames
)
)
else:
# empty parameter set (likely computed at runtime): create a single
# parameter set with NOSET values, with the "empty parameter set" mark applied to it
mark = get_empty_parameterset_mark(config, argnames, func)
parameters.append(
ParameterSet(values=(NOTSET,) * len(argnames), marks=[mark], id=None)
@@ -120,9 +141,9 @@ class Mark(object):
#: name of the mark
name = attr.ib(type=str)
#: positional arguments of the mark decorator
args = attr.ib(type="List[object]")
args = attr.ib() # type: List[object]
#: keyword arguments of the mark decorator
kwargs = attr.ib(type="Dict[str, object]")
kwargs = attr.ib() # type: Dict[str, object]
def combined_with(self, other):
"""
@@ -221,9 +242,18 @@ def get_unpacked_marks(obj):
obtain the unpacked marks that are stored on an object
"""
mark_list = getattr(obj, "pytestmark", [])
if not isinstance(mark_list, list):
mark_list = [mark_list]
return normalize_mark_list(mark_list)
def normalize_mark_list(mark_list):
"""
normalizes marker decorating helpers to mark objects
:type mark_list: List[Union[Mark, Markdecorator]]
:rtype: List[Mark]
"""
return [getattr(mark, "mark", mark) for mark in mark_list] # unpack MarkDecorator
@@ -246,7 +276,7 @@ def store_legacy_markinfo(func, mark):
if holder is None:
holder = MarkInfo.for_mark(mark)
setattr(func, mark.name, holder)
else:
elif isinstance(holder, MarkInfo):
holder.add_mark(mark)
@@ -281,7 +311,7 @@ def _marked(func, mark):
class MarkInfo(object):
""" Marking object created by :class:`MarkDecorator` instances. """
_marks = attr.ib(convert=list)
_marks = attr.ib(converter=list)
@_marks.validator
def validate_marks(self, attribute, value):
@@ -332,6 +362,7 @@ class MarkGenerator(object):
will set a 'slowtest' :class:`MarkInfo` object
on the ``test_function`` object. """
_config = None
def __getattr__(self, name):
@@ -361,7 +392,6 @@ MARK_GEN = MarkGenerator()
class NodeKeywords(MappingMixin):
def __init__(self, node):
self.node = node
self.parent = node.parent
@@ -408,6 +438,7 @@ class NodeMarkers(object):
unstable api
"""
own_markers = attr.ib(default=attr.Factory(list))
def update(self, add_markers):

View File

@@ -4,9 +4,12 @@ from __future__ import absolute_import, division, print_function
import os
import sys
import re
import warnings
from contextlib import contextmanager
import six
import pytest
from _pytest.fixtures import fixture
RE_IMPORT_ERROR_NAME = re.compile("^No module named (.*)$")
@@ -22,7 +25,7 @@ def monkeypatch():
monkeypatch.setitem(mapping, name, value)
monkeypatch.delitem(obj, name, raising=True)
monkeypatch.setenv(name, value, prepend=False)
monkeypatch.delenv(name, value, raising=True)
monkeypatch.delenv(name, raising=True)
monkeypatch.syspath_prepend(path)
monkeypatch.chdir(path)
@@ -86,7 +89,6 @@ def derive_importpath(import_path, raising):
class Notset(object):
def __repr__(self):
return "<notset>"
@@ -210,22 +212,41 @@ class MonkeyPatch(object):
self._setitem.append((dic, name, dic.get(name, notset)))
del dic[name]
def _warn_if_env_name_is_not_str(self, name):
"""On Python 2, warn if the given environment variable name is not a native str (#4056)"""
if six.PY2 and not isinstance(name, str):
warnings.warn(
pytest.PytestWarning(
"Environment variable name {!r} should be str".format(name)
)
)
def setenv(self, name, value, prepend=None):
""" Set environment variable ``name`` to ``value``. If ``prepend``
is a character, read the current environment variable value
and prepend the ``value`` adjoined with the ``prepend`` character."""
value = str(value)
if not isinstance(value, str):
warnings.warn(
pytest.PytestWarning(
"Environment variable value {!r} should be str, converted to str implicitly".format(
value
)
)
)
value = str(value)
if prepend and name in os.environ:
value = value + prepend + os.environ[name]
self._warn_if_env_name_is_not_str(name)
self.setitem(os.environ, name, value)
def delenv(self, name, raising=True):
""" Delete ``name`` from the environment. Raise KeyError it does not
exist.
""" Delete ``name`` from the environment. Raise KeyError if it does
not exist.
If ``raising`` is set to False, no exception will be raised if the
environment variable is missing.
"""
self._warn_if_env_name_is_not_str(name)
self.delitem(os.environ, name, raising=raising)
def syspath_prepend(self, path):

View File

@@ -1,5 +1,6 @@
from __future__ import absolute_import, division, print_function
import os
import warnings
import six
import py
@@ -7,6 +8,7 @@ import attr
import _pytest
import _pytest._code
from _pytest.compat import getfslineno
from _pytest.mark.structures import NodeKeywords, MarkInfo
@@ -48,7 +50,7 @@ def ischildnode(baseid, nodeid):
node_parts = _splitnode(nodeid)
if len(node_parts) < len(base_parts):
return False
return node_parts[:len(base_parts)] == base_parts
return node_parts[: len(base_parts)] == base_parts
@attr.s
@@ -134,19 +136,98 @@ class Node(object):
def __repr__(self):
return "<%s %r>" % (self.__class__.__name__, getattr(self, "name", None))
def warn(self, code, message):
""" generate a warning with the given code and message for this
item. """
def warn(self, _code_or_warning=None, message=None, code=None):
"""Issue a warning for this item.
Warnings will be displayed after the test session, unless explicitly suppressed.
This can be called in two forms:
**Warning instance**
This was introduced in pytest 3.8 and uses the standard warning mechanism to issue warnings.
.. code-block:: python
node.warn(PytestWarning("some message"))
The warning instance must be a subclass of :class:`pytest.PytestWarning`.
**code/message (deprecated)**
This form was used in pytest prior to 3.8 and is considered deprecated. Using this form will emit another
warning about the deprecation:
.. code-block:: python
node.warn("CI", "some message")
:param Union[Warning,str] _code_or_warning:
warning instance or warning code (legacy). This parameter receives an underscore for backward
compatibility with the legacy code/message form, and will be replaced for something
more usual when the legacy form is removed.
:param Union[str,None] message: message to display when called in the legacy form.
:param str code: code for the warning, in legacy form when using keyword arguments.
:return:
"""
if message is None:
if _code_or_warning is None:
raise ValueError("code_or_warning must be given")
self._std_warn(_code_or_warning)
else:
if _code_or_warning and code:
raise ValueError(
"code_or_warning and code cannot both be passed to this function"
)
code = _code_or_warning or code
self._legacy_warn(code, message)
def _legacy_warn(self, code, message):
"""
.. deprecated:: 3.8
Use :meth:`Node.std_warn <_pytest.nodes.Node.std_warn>` instead.
Generate a warning with the given code and message for this item.
"""
from _pytest.deprecated import NODE_WARN
self._std_warn(NODE_WARN)
assert isinstance(code, str)
fslocation = getattr(self, "location", None)
if fslocation is None:
fslocation = getattr(self, "fspath", None)
fslocation = get_fslocation_from_item(self)
self.ihook.pytest_logwarning.call_historic(
kwargs=dict(
code=code, message=message, nodeid=self.nodeid, fslocation=fslocation
)
)
def _std_warn(self, warning):
"""Issue a warning for this item.
Warnings will be displayed after the test session, unless explicitly suppressed
:param Warning warning: the warning instance to issue. Must be a subclass of PytestWarning.
:raise ValueError: if ``warning`` instance is not a subclass of PytestWarning.
"""
from _pytest.warning_types import PytestWarning
if not isinstance(warning, PytestWarning):
raise ValueError(
"warning must be an instance of PytestWarning or subclass, got {!r}".format(
warning
)
)
path, lineno = get_fslocation_from_item(self)
warnings.warn_explicit(
warning,
category=None,
filename=str(path),
lineno=lineno + 1 if lineno is not None else None,
)
# methods for ordering nodes
@property
def nodeid(self):
@@ -173,10 +254,13 @@ class Node(object):
chain.reverse()
return chain
def add_marker(self, marker):
def add_marker(self, marker, append=True):
"""dynamically add a marker object to the node.
:type marker: str or pytest.mark.*
:type marker: ``str`` or ``pytest.mark.*`` object
:param marker:
``append=True`` whether to append the marker,
if ``False`` insert at position ``0``.
"""
from _pytest.mark import MarkDecorator, MARK_GEN
@@ -185,7 +269,10 @@ class Node(object):
elif not isinstance(marker, MarkDecorator):
raise ValueError("is not a string or pytest.mark.* Marker")
self.keywords[marker.name] = marker
self.own_markers.append(marker.mark)
if append:
self.own_markers.append(marker.mark)
else:
self.own_markers.insert(0, marker.mark)
def iter_markers(self, name=None):
"""
@@ -281,6 +368,11 @@ class Node(object):
else:
style = "long"
if self.config.option.verbose > 1:
truncate_locals = False
else:
truncate_locals = True
try:
os.getcwd()
abspath = False
@@ -293,11 +385,30 @@ class Node(object):
showlocals=self.config.option.showlocals,
style=style,
tbfilter=tbfilter,
truncate_locals=truncate_locals,
)
repr_failure = _repr_failure_py
def get_fslocation_from_item(item):
"""Tries to extract the actual location from an item, depending on available attributes:
* "fslocation": a pair (path, lineno)
* "obj": a Python object that the item wraps.
* "fspath": just a path
:rtype: a tuple of (str|LocalPath, int) with filename and line number.
"""
result = getattr(item, "location", None)
if result is not None:
return result[:2]
obj = getattr(item, "obj", None)
if obj is not None:
return getfslineno(obj)
return getattr(item, "fspath", "unknown location"), -1
class Collector(Node):
""" Collector instances create children through collect()
and thus iteratively build a tree.
@@ -335,7 +446,6 @@ def _check_initialpaths_for_relpath(session, fspath):
class FSCollector(Collector):
def __init__(self, fspath, parent=None, config=None, session=None, nodeid=None):
fspath = py.path.local(fspath) # xxx only for test_resultlog.py?
name = fspath.basename
@@ -353,7 +463,7 @@ class FSCollector(Collector):
if not nodeid:
nodeid = _check_initialpaths_for_relpath(session, fspath)
if os.sep != SEP:
if nodeid and os.sep != SEP:
nodeid = nodeid.replace(os.sep, SEP)
super(FSCollector, self).__init__(
@@ -369,6 +479,7 @@ class Item(Node):
""" a basic test invocation item. Note that for a single function
there might be multiple test invocation items.
"""
nextitem = None
def __init__(self, name, parent=None, config=None, session=None, nodeid=None):

View File

@@ -3,7 +3,6 @@ exception classes and constants handling test outcomes
as well as functions creating them
"""
from __future__ import absolute_import, division, print_function
import py
import sys
@@ -21,7 +20,7 @@ class OutcomeException(BaseException):
if self.msg:
val = self.msg
if isinstance(val, bytes):
val = py._builtin._totext(val, errors="replace")
val = val.decode("UTF-8", errors="replace")
return val
return "<%s instance>" % (self.__class__.__name__,)
@@ -43,6 +42,7 @@ class Skipped(OutcomeException):
class Failed(OutcomeException):
""" raised from an explicit call to pytest.fail() """
__module__ = "builtins"
@@ -67,13 +67,19 @@ exit.Exception = Exit
def skip(msg="", **kwargs):
""" skip an executing test with the given message. Note: it's usually
better to use the pytest.mark.skipif marker to declare a test to be
skipped under certain conditions like mismatching platforms or
dependencies. See the pytest_skipping plugin for details.
"""
Skip an executing test with the given message.
This function should be called only during testing (setup, call or teardown) or
during collection by using the ``allow_module_level`` flag.
:kwarg bool allow_module_level: allows this function to be called at
module level, skipping the rest of the module. Default to False.
.. note::
It is better to use the :ref:`pytest.mark.skipif ref` marker when possible to declare a test to be
skipped under certain conditions like mismatching platforms or
dependencies.
"""
__tracebackhide__ = True
allow_module_level = kwargs.pop("allow_module_level", False)
@@ -87,10 +93,12 @@ skip.Exception = Skipped
def fail(msg="", pytrace=True):
""" explicitly fail a currently-executing test with the given Message.
"""
Explicitly fail an executing test with the given message.
:arg pytrace: if false the msg represents the full failure information
and no python traceback will be reported.
:param str msg: the message to show the user as reason for the failure.
:param bool pytrace: if false the msg represents the full failure information and no
python traceback will be reported.
"""
__tracebackhide__ = True
raise Failed(msg=msg, pytrace=pytrace)
@@ -104,7 +112,15 @@ class XFailed(fail.Exception):
def xfail(reason=""):
""" xfail an executing test or setup functions with the given reason."""
"""
Imperatively xfail an executing test or setup functions with the given reason.
This function should be called only during testing (setup, call or teardown).
.. note::
It is better to use the :ref:`pytest.mark.xfail ref` marker when possible to declare a test to be
xfailed under certain conditions like known bugs or missing features.
"""
__tracebackhide__ = True
raise XFailed(reason)

52
src/_pytest/paths.py Normal file
View File

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

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