Compare commits

...

40 Commits
main ... 6.0.x

Author SHA1 Message Date
Bruno Oliveira e886b170dd
Merge pull request #7785 from nicoddemus/backport-7784
[6.0.x] Merge pull request #7784 from nicoddemus/use-new-pip-solver-7783
2020-09-23 09:39:07 -03:00
Bruno Oliveira 45a645db86 Merge pull request #7784 from nicoddemus/use-new-pip-solver-7783
Use new pip resolver in plugins tox env
2020-09-23 09:32:32 -03:00
Bruno Oliveira f5b1f44317
Merge pull request #7776 from nicoddemus/backport-7772
[6.0.x] Add docs about reusing fixtures from other projects (#7772)
2020-09-19 16:13:35 -03:00
Bruno Oliveira 89d03b2999
Merge pull request #7775 from nicoddemus/backport-7721
[6.0.x] Smoke tests for assorted plugins (#7721)
2020-09-19 16:12:09 -03:00
Bruno Oliveira 5e14e7d9c1 Add docs about reusing fixtures from other projects (#7772)
Co-authored-by: Ran Benita <ran@unusedvar.com>
2020-09-19 16:11:01 -03:00
Sorin Sbarnea 5819cb611e Smoke tests for assorted plugins (#7721)
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
Co-authored-by: Thomas Grainger <tagrain@gmail.com>
Co-authored-by: Kyle Altendorf <sda@fstab.net>
2020-09-19 15:59:07 -03:00
Ran Benita 687146e3f1
Merge pull request #7774 from bluetech/backport-7773
[6.0.x] Warning about record_testsuite_property not working with xdist
2020-09-19 21:39:48 +03:00
Ran Benita ae61fa4040 Merge pull request #7773 from nicoddemus/xml-properties-xdist-docs
Warning about record_testsuite_property not working with xdist

(cherry picked from commit 4e460cdd9e)
2020-09-19 21:20:40 +03:00
Bruno Oliveira d7d089469e
Merge pull request #7771 from nicoddemus/backport-7749
[6.0.x] Merge pull request #7749 from bluetech/fix-get_source-crash
2020-09-19 10:51:22 -03:00
Bruno Oliveira 6933bf6b4d Merge pull request #7749 from bluetech/fix-get_source-crash 2020-09-19 10:39:05 -03:00
Bruno Oliveira 819fef87a7
Merge pull request #7765 from nicoddemus/backport-7723
[6.0] Improve output for missing required plugins #7723
2020-09-17 10:08:38 -03:00
Sorin Sbarnea 604047ee1a Improve output for missing required plugins/unknown config keys (#7723)
Co-authored-by: Florian Bruhin <me@the-compiler.org>
2020-09-17 09:53:18 -03:00
Bruno Oliveira 52363fe560
Merge pull request #7756 from nicoddemus/backport-7747
[6.0] Add full command-line flags to the reference docs
2020-09-14 13:51:32 -03:00
Bruno Oliveira c923dbc96f Merge pull request #7747 from nicoddemus/cmdline-flags-docs
Add full command-line flags to the reference docs
2020-09-14 13:48:13 -03:00
Bruno Oliveira 2d680da78b
Merge pull request #7746 from nicoddemus/backport-7745
[6.0] Merge pull request #7745 from asottile/exec_globals_type_problem
2020-09-12 08:28:37 -03:00
Bruno Oliveira b3c444ddc1 Merge pull request #7745 from asottile/exec_globals_type_problem
Fix INTERNALERROR when accessing locals / globals with faulty `exec`
2020-09-12 08:10:34 -03:00
Ran Benita fe69bd5baf
Merge pull request #7720 from pytest-dev/release-6.0.2
Prepare release 6.0.2
2020-09-12 02:03:10 +03:00
pytest bot 09b1d7cc99 Prepare release version 6.0.2 2020-09-04 21:48:44 +00:00
Ran Benita ea65ea877e
Merge pull request #7717 from bluetech/backport-7614
[6.0.x] Properly remove log_print
2020-09-04 21:53:05 +03:00
Ran Benita f4f30d7073
Merge pull request #7716 from bluetech/backport-7697
[6.0.x] Add missing File reference to the docs
2020-09-04 21:52:51 +03:00
Ran Benita 309810ac2c
Merge pull request #7715 from bluetech/backport-7651
[6.0.x] capture: fix disabled()/global_and_fixture_disabled() enabling capturing when it was disabled
2020-09-04 21:52:29 +03:00
Bruno Oliveira e63fac3aec Merge pull request #7614 from The-Compiler/log-print
Properly remove log_print

(cherry picked from commit d688fefecb)
2020-09-04 21:28:41 +03:00
Bruno Oliveira cb91c5033e Merge pull request #7697 from nicoddemus/file-docs
(cherry picked from commit 21aa6c42b7)
2020-09-04 21:23:53 +03:00
Ran Benita 9a879ee23e Merge pull request #7651 from bluetech/capture-safe-disable
capture: fix disabled()/global_and_fixture_disabled() enabling capturing when it was disabled

(cherry picked from commit bb38ae9c52)
2020-09-04 21:16:07 +03:00
Bruno Oliveira e9d18bd8ac
Merge pull request #7711 from nicoddemus/backport-7708
[6.0] Merge pull request #7708 from nicoddemus/repr-line-7707
2020-09-04 12:41:17 -03:00
Bruno Oliveira 912870d33e Merge pull request #7708 from nicoddemus/repr-line-7707
Fix handle of exceptions in ReprEntry with tb=line
2020-09-04 12:06:38 -03:00
Bruno Oliveira 0115b716c0
Merge pull request #7688 from nicoddemus/backport-7687 2020-08-25 21:23:41 -03:00
Bruno Oliveira 9a91b67eeb Merge pull request #7687 from bluetech/idval-notset
python: fix empty parametrize() leading to "NotSetType.token" id
2020-08-25 19:57:06 -03:00
Ran Benita 79d0d3eff4
Merge pull request #7676 from bluetech/backport-7673
[6.0.x] logging: fix handler level restored incorrectly if caplog.set_level is called more than once
2020-08-23 12:24:50 +03:00
Ran Benita 834f55eddb Merge pull request #7673 from bluetech/logging-fix-handler-restore
logging: fix handler level restored incorrectly if caplog.set_level is called more than once
(cherry picked from commit 143e3ab846)
2020-08-23 12:07:24 +03:00
Bruno Oliveira 6110f84f78
Merge pull request #7588 from nicoddemus/backport-7557
Merge pull request #7557 from nicoddemus/announce-templates
2020-07-30 12:07:53 -03:00
Bruno Oliveira 5a339f0d74 Merge pull request #7557 from nicoddemus/announce-templates
(cherry picked from commit c7216ae0f6)
2020-07-30 12:04:36 -03:00
Bruno Oliveira 022bff27a7
Merge pull request #7584 from pytest-dev/release-6.0.1
Prepare release 6.0.1
2020-07-30 09:45:40 -03:00
pytest bot 92af2e22d2 Prepare release version 6.0.1 2020-07-30 11:50:12 +00:00
Ran Benita 0307213254
Merge pull request #7582 from bluetech/backport-7581
[6.0.x] Add missing changelog for issue 7569
2020-07-30 14:19:29 +03:00
Ran Benita df7b26704d Merge pull request #7581 from bluetech/logging-setlevel-handler-restore
Add missing changelog for issue 7569

(cherry picked from commit 645cbc91fc)
2020-07-30 13:41:54 +03:00
Bruno Oliveira 1516780829
Merge pull request #7578 from nicoddemus/backport-7555
[6.0.x] Warn about --basetemp removing the entire directory (#7555)
2020-07-29 12:13:16 -03:00
Bruno Oliveira b945b39b0b
Merge pull request #7577 from nicoddemus/backport-7427
[6.0.x] Fix --help crash on add_ini(.., help='') and improve message on help=None (#7427)
2020-07-29 12:10:42 -03:00
Mattreex 2d5b8a85c2 Warn about --basetemp removing the entire directory (#7555)
Co-authored-by: mattreex <mattreex.9@gail.com>
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
(cherry picked from commit 1e66ed0b1c)
2020-07-29 11:58:52 -03:00
hp310780 8963644da3 Fix --help crash on add_ini(.., help='') and improve message on help=None (#7427) 2020-07-29 11:49:09 -03:00
49 changed files with 838 additions and 91 deletions

View File

@ -41,6 +41,7 @@ jobs:
"docs",
"doctesting",
"plugins",
]
include:
@ -111,6 +112,11 @@ jobs:
tox_env: "py38-xdist"
use_coverage: true
- name: "plugins"
python: "3.7"
os: ubuntu-latest
tox_env: "plugins"
- name: "docs"
python: "3.7"
os: ubuntu-latest

View File

@ -0,0 +1,3 @@
Fixed an internal error crash with ``IndexError: list index out of range`` when
collecting a module which starts with a decorated function, the decorator
raises, and assertion rewriting is enabled.

View File

@ -1,2 +0,0 @@
Fix pylint ``not-callable`` lint on ``pytest.mark.parametrize()`` and the other builtin marks:
``skip``, ``skipif``, ``xfail``, ``usefixtures``, ``filterwarnings``.

View File

@ -1 +0,0 @@
Fix regression in plugins using ``TestReport.longreprtext`` (such as ``pytest-html``) when ``TestReport.longrepr`` is not a string.

View File

@ -0,0 +1 @@
When a plugin listed in ``required_plugins`` is missing, a simple error message is now shown instead of a stacktrace.

View File

@ -0,0 +1 @@
Fix INTERNALERROR when accessing locals / globals with faulty ``exec``.

View File

@ -6,6 +6,8 @@ Release announcements
:maxdepth: 2
release-6.0.2
release-6.0.1
release-6.0.0
release-6.0.0rc1
release-5.4.3

View File

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

View File

@ -0,0 +1,19 @@
pytest-6.0.2
=======================================
pytest 6.0.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/stable/changelog.html.
Thanks to all of the contributors to this release:
* Bruno Oliveira
* Ran Benita
Happy testing,
The pytest Development Team

View File

@ -28,6 +28,45 @@ with advance notice in the **Deprecations** section of releases.
.. towncrier release notes start
pytest 6.0.2 (2020-09-04)
=========================
Bug Fixes
---------
- `#7148 <https://github.com/pytest-dev/pytest/issues/7148>`_: Fixed ``--log-cli`` potentially causing unrelated ``print`` output to be swallowed.
- `#7672 <https://github.com/pytest-dev/pytest/issues/7672>`_: Fixed log-capturing level restored incorrectly if ``caplog.set_level`` is called more than once.
- `#7686 <https://github.com/pytest-dev/pytest/issues/7686>`_: Fixed `NotSetType.token` being used as the parameter ID when the parametrization list is empty.
Regressed in pytest 6.0.0.
- `#7707 <https://github.com/pytest-dev/pytest/issues/7707>`_: Fix internal error when handling some exceptions that contain multiple lines or the style uses multiple lines (``--tb=line`` for example).
pytest 6.0.1 (2020-07-30)
=========================
Bug Fixes
---------
- `#7394 <https://github.com/pytest-dev/pytest/issues/7394>`_: Passing an empty ``help`` value to ``Parser.add_option`` is now accepted instead of crashing when running ``pytest --help``.
Passing ``None`` raises a more informative ``TypeError``.
- `#7558 <https://github.com/pytest-dev/pytest/issues/7558>`_: Fix pylint ``not-callable`` lint on ``pytest.mark.parametrize()`` and the other builtin marks:
``skip``, ``skipif``, ``xfail``, ``usefixtures``, ``filterwarnings``.
- `#7559 <https://github.com/pytest-dev/pytest/issues/7559>`_: Fix regression in plugins using ``TestReport.longreprtext`` (such as ``pytest-html``) when ``TestReport.longrepr`` is not a string.
- `#7569 <https://github.com/pytest-dev/pytest/issues/7569>`_: Fix logging capture handler's level not reset on teardown after a call to ``caplog.set_level()``.
pytest 6.0.0 (2020-07-28)
=========================
@ -192,9 +231,9 @@ Breaking Changes
- `#7224 <https://github.com/pytest-dev/pytest/issues/7224>`_: The `item.catch_log_handler` and `item.catch_log_handlers` attributes, set by the
logging plugin and never meant to be public , are no longer available.
logging plugin and never meant to be public, are no longer available.
The deprecated ``--no-print-logs`` option is removed. Use ``--show-capture`` instead.
The deprecated ``--no-print-logs`` option and ``log_print`` ini option are removed. Use ``--show-capture`` instead.
- `#7226 <https://github.com/pytest-dev/pytest/issues/7226>`_: Removed the unused ``args`` parameter from ``pytest.Function.__init__``.

View File

@ -51,9 +51,10 @@ a public API and may break in the future.
.. versionremoved:: 6.0
Option ``--no-print-logs`` is removed. If you used ``--no-print-logs``, please use ``--show-capture`` instead.
The ``--no-print-logs`` option and ``log_print`` ini setting are removed. If
you used them, please use ``--show-capture`` instead.
``--show-capture`` command-line option was added in ``pytest 3.5.0`` and allows to specify how to
A ``--show-capture`` command-line option was added in ``pytest 3.5.0`` which allows to specify how to
display captured output when tests fail: ``no``, ``stdout``, ``stderr``, ``log`` or ``all`` (the default).

View File

@ -1136,8 +1136,8 @@ and teared down after every test that used it.
.. _`usefixtures`:
Using fixtures from classes, modules or projects
----------------------------------------------------------------------
Use fixtures in classes and modules with ``usefixtures``
--------------------------------------------------------
.. regendoc:wipe
@ -1531,3 +1531,37 @@ Given the tests file structure is:
In the example above, a parametrized fixture is overridden with a non-parametrized version, and
a non-parametrized fixture is overridden with a parametrized version for certain test module.
The same applies for the test folder level obviously.
Using fixtures from other projects
----------------------------------
Usually projects that provide pytest support will use :ref:`entry points <setuptools entry points>`,
so just installing those projects into an environment will make those fixtures available for use.
In case you want to use fixtures from a project that does not use entry points, you can
define :globalvar:`pytest_plugins` in your top ``conftest.py`` file to register that module
as a plugin.
Suppose you have some fixtures in ``mylibrary.fixtures`` and you want to reuse them into your
``app/tests`` directory.
All you need to do is to define :globalvar:`pytest_plugins` in ``app/tests/conftest.py``
pointing to that module.
.. code-block:: python
pytest_plugins = "mylibrary.fixtures"
This effectively registers ``mylibrary.fixtures`` as a plugin, making all its fixtures and
hooks available to tests in ``app/tests``.
.. note::
Sometimes users will *import* fixtures from other projects for use, however this is not
recommended: importing fixtures into a module will register them in pytest
as *defined* in that module.
This has minor consequences, such as appearing multiple times in ``pytest --help``,
but it is not **recommended** because this behavior might change/stop working
in future versions.

View File

@ -28,7 +28,7 @@ Install ``pytest``
.. code-block:: bash
$ pytest --version
pytest 6.0.0
pytest 6.0.2
.. _`simpletest`:

View File

@ -783,12 +783,19 @@ ExceptionInfo
:members:
pytest.ExitCode
~~~~~~~~~~~~~~~
ExitCode
~~~~~~~~
.. autoclass:: _pytest.config.ExitCode
:members:
File
~~~~
.. autoclass:: _pytest.nodes.File()
:members:
:show-inheritance:
FixtureDef
~~~~~~~~~~
@ -1466,20 +1473,6 @@ passed multiple times. The expected format is ``name=value``. For example::
For more information, see :ref:`logging`.
.. confval:: log_print
If set to ``False``, will disable displaying captured logging messages for failed tests.
.. code-block:: ini
[pytest]
log_print = False
For more information, see :ref:`logging`.
.. confval:: markers
When the ``--strict-markers`` or ``--strict`` command-line arguments are used,
@ -1666,3 +1659,296 @@ passed multiple times. The expected format is ``name=value``. For example::
[pytest]
xfail_strict = True
.. _`command-line-flags`:
Command-line Flags
------------------
All the command-line flags can be obtained by running ``pytest --help``::
$ pytest --help
usage: pytest [options] [file_or_dir] [file_or_dir] [...]
positional arguments:
file_or_dir
general:
-k EXPRESSION only run tests which match the given substring
expression. An expression is a python evaluatable
expression where all names are substring-matched
against test names and their parent classes.
Example: -k 'test_method or test_other' matches all
test functions and classes whose name contains
'test_method' or 'test_other', while -k 'not
test_method' matches those that don't contain
'test_method' in their names. -k 'not test_method
and not test_other' will eliminate the matches.
Additionally keywords are matched to classes and
functions containing extra names in their
'extra_keyword_matches' set, as well as functions
which have names assigned directly to them. The
matching is case-insensitive.
-m MARKEXPR only run tests matching given mark expression.
For example: -m 'mark1 and not mark2'.
--markers show markers (builtin, plugin and per-project ones).
-x, --exitfirst exit instantly on first error or failed test.
--fixtures, --funcargs
show available fixtures, sorted by plugin appearance
(fixtures with leading '_' are only shown with '-v')
--fixtures-per-test show fixtures per test
--pdb start the interactive Python debugger on errors or
KeyboardInterrupt.
--pdbcls=modulename:classname
start a custom interactive Python debugger on
errors. For example:
--pdbcls=IPython.terminal.debugger:TerminalPdb
--trace Immediately break when running each test.
--capture=method per-test capturing method: one of fd|sys|no|tee-sys.
-s shortcut for --capture=no.
--runxfail report the results of xfail tests as if they were
not marked
--lf, --last-failed rerun only the tests that failed at the last run (or
all if none failed)
--ff, --failed-first run all tests, but run the last failures first.
This may re-order tests and thus lead to repeated
fixture setup/teardown.
--nf, --new-first run tests from new files first, then the rest of the
tests sorted by file mtime
--cache-show=[CACHESHOW]
show cache contents, don't perform collection or
tests. Optional argument: glob (default: '*').
--cache-clear remove all cache contents at start of test run.
--lfnf={all,none}, --last-failed-no-failures={all,none}
which tests to run with no previously (known)
failures.
--sw, --stepwise exit on test failure and continue from last failing
test next time
--stepwise-skip ignore the first failing test but stop on the next
failing test
reporting:
--durations=N show N slowest setup/test durations (N=0 for all).
--durations-min=N Minimal duration in seconds for inclusion in slowest
list. Default 0.005
-v, --verbose increase verbosity.
--no-header disable header
--no-summary disable summary
-q, --quiet decrease verbosity.
--verbosity=VERBOSE set verbosity. Default is 0.
-r chars show extra test summary info as specified by chars:
(f)ailed, (E)rror, (s)kipped, (x)failed, (X)passed,
(p)assed, (P)assed with output, (a)ll except passed
(p/P), or (A)ll. (w)arnings are enabled by default
(see --disable-warnings), 'N' can be used to reset
the list. (default: 'fE').
--disable-warnings, --disable-pytest-warnings
disable warnings summary
-l, --showlocals show locals in tracebacks (disabled by default).
--tb=style traceback print mode
(auto/long/short/line/native/no).
--show-capture={no,stdout,stderr,log,all}
Controls how captured stdout/stderr/log is shown on
failed tests. Default is 'all'.
--full-trace don't cut any tracebacks (default is to cut).
--color=color color terminal output (yes/no/auto).
--code-highlight={yes,no}
Whether code should be highlighted (only if --color
is also enabled)
--pastebin=mode send failed|all info to bpaste.net pastebin service.
--junit-xml=path create junit-xml style report file at given path.
--junit-prefix=str prepend prefix to classnames in junit-xml output
pytest-warnings:
-W PYTHONWARNINGS, --pythonwarnings=PYTHONWARNINGS
set which warnings to report, see -W option of
python itself.
--maxfail=num exit after first num failures or errors.
--strict-config any warnings encountered while parsing the `pytest`
section of the configuration file raise errors.
--strict-markers, --strict
markers not registered in the `markers` section of
the configuration file raise errors.
-c file load configuration from `file` instead of trying to
locate one of the implicit configuration files.
--continue-on-collection-errors
Force test execution even if collection errors
occur.
--rootdir=ROOTDIR Define root directory for tests. Can be relative
path: 'root_dir', './root_dir',
'root_dir/another_dir/'; absolute path:
'/home/user/root_dir'; path with variables:
'$HOME/root_dir'.
collection:
--collect-only, --co only collect tests, don't execute them.
--pyargs try to interpret all arguments as python packages.
--ignore=path ignore path during collection (multi-allowed).
--ignore-glob=path ignore path pattern during collection (multi-
allowed).
--deselect=nodeid_prefix
deselect item (via node id prefix) during collection
(multi-allowed).
--confcutdir=dir only load conftest.py's relative to specified dir.
--noconftest Don't load any conftest.py files.
--keep-duplicates Keep duplicate tests.
--collect-in-virtualenv
Don't ignore tests in a local virtualenv directory
--import-mode={prepend,append,importlib}
prepend/append to sys.path when importing test
modules and conftest files, default is to prepend.
--doctest-modules run doctests in all .py modules
--doctest-report={none,cdiff,ndiff,udiff,only_first_failure}
choose another output format for diffs on doctest
failure
--doctest-glob=pat doctests file matching pattern, default: test*.txt
--doctest-ignore-import-errors
ignore doctest ImportErrors
--doctest-continue-on-failure
for a given doctest, continue to run after the first
failure
test session debugging and configuration:
--basetemp=dir base temporary directory for this test run.(warning:
this directory is removed if it exists)
-V, --version display pytest version and information about
plugins.When given twice, also display information
about plugins.
-h, --help show help message and configuration info
-p name early-load given plugin module name or entry point
(multi-allowed).
To avoid loading of plugins, use the `no:` prefix,
e.g. `no:doctest`.
--trace-config trace considerations of conftest.py files.
--debug store internal tracing debug information in
'pytestdebug.log'.
-o OVERRIDE_INI, --override-ini=OVERRIDE_INI
override ini option with "option=value" style, e.g.
`-o xfail_strict=True -o cache_dir=cache`.
--assert=MODE Control assertion debugging tools.
'plain' performs no assertion debugging.
'rewrite' (the default) rewrites assert statements
in test modules on import to provide assert
expression information.
--setup-only only setup fixtures, do not execute tests.
--setup-show show setup of fixtures while executing tests.
--setup-plan show what fixtures and tests would be executed but
don't execute anything.
logging:
--log-level=LEVEL level of messages to catch/display.
Not set by default, so it depends on the root/parent
log handler's effective level, where it is "WARNING"
by default.
--log-format=LOG_FORMAT
log format as used by the logging module.
--log-date-format=LOG_DATE_FORMAT
log date format as used by the logging module.
--log-cli-level=LOG_CLI_LEVEL
cli logging level.
--log-cli-format=LOG_CLI_FORMAT
log format as used by the logging module.
--log-cli-date-format=LOG_CLI_DATE_FORMAT
log date format as used by the logging module.
--log-file=LOG_FILE path to a file when logging will be written to.
--log-file-level=LOG_FILE_LEVEL
log file logging level.
--log-file-format=LOG_FILE_FORMAT
log format as used by the logging module.
--log-file-date-format=LOG_FILE_DATE_FORMAT
log date format as used by the logging module.
--log-auto-indent=LOG_AUTO_INDENT
Auto-indent multiline messages passed to the logging
module. Accepts true|on, false|off or an integer.
[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:
markers (linelist): markers for test functions
empty_parameter_set_mark (string):
default marker for empty parametersets
norecursedirs (args): directory patterns to avoid for recursion
testpaths (args): directories to search for tests when no files or
directories are given in the command line.
filterwarnings (linelist):
Each line specifies a pattern for
warnings.filterwarnings. Processed after
-W/--pythonwarnings.
usefixtures (args): list of default fixtures to be used with this
project
python_files (args): glob-style file patterns for Python test module
discovery
python_classes (args):
prefixes or glob names for Python test class
discovery
python_functions (args):
prefixes or glob names for Python test function and
method discovery
disable_test_id_escaping_and_forfeit_all_rights_to_community_support (bool):
disable string escape non-ascii characters, might
cause unwanted side effects(use at your own risk)
console_output_style (string):
console output: "classic", or with additional
progress information ("progress" (percentage) |
"count").
xfail_strict (bool): default for the strict parameter of xfail markers
when not given explicitly (default: False)
enable_assertion_pass_hook (bool):
Enables the pytest_assertion_pass hook.Make sure to
delete any previously generated pyc cache files.
junit_suite_name (string):
Test suite name for JUnit report
junit_logging (string):
Write captured log messages to JUnit report: one of
no|log|system-out|system-err|out-err|all
junit_log_passing_tests (bool):
Capture log information for passing tests to JUnit
report:
junit_duration_report (string):
Duration time to report: one of total|call
junit_family (string):
Emit XML for schema: one of legacy|xunit1|xunit2
doctest_optionflags (args):
option flags for doctests
doctest_encoding (string):
encoding used for doctest files
cache_dir (string): cache directory path.
log_level (string): default value for --log-level
log_format (string): default value for --log-format
log_date_format (string):
default value for --log-date-format
log_cli (bool): enable log display during test run (also known as
"live logging").
log_cli_level (string):
default value for --log-cli-level
log_cli_format (string):
default value for --log-cli-format
log_cli_date_format (string):
default value for --log-cli-date-format
log_file (string): default value for --log-file
log_file_level (string):
default value for --log-file-level
log_file_format (string):
default value for --log-file-format
log_file_date_format (string):
default value for --log-file-date-format
log_auto_indent (string):
default value for --log-auto-indent
faulthandler_timeout (string):
Dump the traceback of all threads if a test takes
more than TIMEOUT seconds to finish.
addopts (args): extra command line options
minversion (string): minimally required pytest version
required_plugins (args):
plugins that must be present for pytest to run
environment variables:
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
to see available markers type: pytest --markers
to see available fixtures type: pytest --fixtures
(shown according to specified file_or_dir or current dir if not specified; fixtures with leading '_' are only shown with the '-v' option

View File

@ -192,8 +192,13 @@ You can override the default temporary directory setting like this:
pytest --basetemp=mydir
When distributing tests on the local machine, ``pytest`` takes care to
configure a basetemp directory for the sub processes such that all temporary
.. warning::
The contents of ``mydir`` will be completely removed, so make sure to use a directory
for that purpose only.
When distributing tests on the local machine using ``pytest-xdist``, care is taken to
automatically configure a basetemp directory for the sub processes such that all temporary
data lands below a single per-test run basetemp directory.
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html

View File

@ -57,6 +57,8 @@ Getting help on version, option names, environment variables
pytest -h | --help # show help on command line and config file options
The full command-line flags can be found in the :ref:`reference <command-line-flags>`.
.. _maxfail:
Stopping after the first (or N) failures

View File

@ -10,7 +10,7 @@ build-backend = "setuptools.build_meta"
[tool.pytest.ini_options]
minversion = "2.0"
addopts = "-rfEX -p pytester --strict-markers"
python_files = ["test_*.py", "*_test.py", "testing/*/*.py"]
python_files = ["test_*.py", "*_test.py", "testing/python/*.py"]
python_classes = ["Test", "Acceptance"]
python_functions = ["test"]
# NOTE: "doc" is not included here, but gets tested explicitly via "doctesting".

View File

@ -3,23 +3,20 @@ pytest-{version}
The pytest team is proud to announce the {version} 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 new features, improvements, bug fixes, and breaking changes, so users
are encouraged to take a look at the CHANGELOG carefully:
This release contains a number of bug fixes and improvements, so users are encouraged
to take a look at the CHANGELOG:
https://docs.pytest.org/en/latest/changelog.html
https://docs.pytest.org/en/stable/changelog.html
For complete documentation, please visit:
https://docs.pytest.org/en/latest/
https://docs.pytest.org/en/stable/
As usual, you can upgrade from PyPI via:
pip install -U pytest
Thanks to all who contributed to this release, among them:
Thanks to all of the contributors to this release:
{contributors}

View File

@ -7,9 +7,9 @@ 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.
The full changelog is available at https://docs.pytest.org/en/stable/changelog.html.
Thanks to all who contributed to this release, among them:
Thanks to all of the contributors to this release:
{contributors}

View File

@ -246,10 +246,20 @@ class TracebackEntry:
Mostly for internal use.
"""
f = self.frame
tbh = f.f_locals.get(
"__tracebackhide__", f.f_globals.get("__tracebackhide__", False)
tbh = (
False
) # type: Union[bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool]]
for maybe_ns_dct in (self.frame.f_locals, self.frame.f_globals):
# in normal cases, f_locals and f_globals are dictionaries
# however via `exec(...)` / `eval(...)` they can be other types
# (even incorrect types!).
# as such, we suppress all exceptions while accessing __tracebackhide__
try:
tbh = maybe_ns_dct["__tracebackhide__"]
except Exception:
pass
else:
break
if tbh and callable(tbh):
return tbh(None if self._excinfo is None else self._excinfo())
return tbh
@ -1038,25 +1048,21 @@ class ReprEntry(TerminalRepr):
# such as "> assert 0"
fail_marker = "{} ".format(FormattedExcinfo.fail_marker)
indent_size = len(fail_marker)
indents = []
source_lines = []
failure_lines = []
seeing_failures = False
for line in self.lines:
is_source_line = not line.startswith(fail_marker)
if is_source_line:
assert not seeing_failures, (
"Unexpected failure lines between source lines:\n"
+ "\n".join(self.lines)
)
indents = [] # type: List[str]
source_lines = [] # type: List[str]
failure_lines = [] # type: List[str]
for index, line in enumerate(self.lines):
is_failure_line = line.startswith(fail_marker)
if is_failure_line:
# from this point on all lines are considered part of the failure
failure_lines.extend(self.lines[index:])
break
else:
if self.style == "value":
source_lines.append(line)
else:
indents.append(line[:indent_size])
source_lines.append(line[indent_size:])
else:
seeing_failures = True
failure_lines.append(line)
tw._write_source(source_lines, indents)

View File

@ -694,13 +694,18 @@ class AssertionRewriter(ast.NodeVisitor):
return
expect_docstring = False
elif (
not isinstance(item, ast.ImportFrom)
or item.level > 0
or item.module != "__future__"
isinstance(item, ast.ImportFrom)
and item.level == 0
and item.module == "__future__"
):
lineno = item.lineno
pass
else:
break
pos += 1
# Special case: for a decorated function, set the lineno to that of the
# first decorator, not the `def`. Issue #4984.
if isinstance(item, ast.FunctionDef) and item.decorator_list:
lineno = item.decorator_list[0].lineno
else:
lineno = item.lineno
imports = [

View File

@ -537,7 +537,7 @@ class MultiCapture:
self._in_suspended = True
def resume_capturing(self) -> None:
self._state = "resumed"
self._state = "started"
if self.out:
self.out.resume()
if self.err:
@ -558,6 +558,10 @@ class MultiCapture:
if self.in_:
self.in_.done()
def is_started(self) -> bool:
"""Whether actively capturing -- not suspended or stopped."""
return self._state == "started"
def readouterr(self) -> CaptureResult:
if self.out:
out = self.out.snap()
@ -697,11 +701,19 @@ class CaptureManager:
@contextlib.contextmanager
def global_and_fixture_disabled(self) -> Generator[None, None, None]:
"""Context manager to temporarily disable global and current fixture capturing."""
self.suspend()
do_fixture = self._capture_fixture and self._capture_fixture._is_started()
if do_fixture:
self.suspend_fixture()
do_global = self._global_capturing and self._global_capturing.is_started()
if do_global:
self.suspend_global_capture()
try:
yield
finally:
self.resume()
if do_global:
self.resume_global_capture()
if do_fixture:
self.resume_fixture()
@contextlib.contextmanager
def item_capture(self, when: str, item: Item) -> Generator[None, None, None]:
@ -810,6 +822,12 @@ class CaptureFixture:
if self._capture is not None:
self._capture.resume_capturing()
def _is_started(self) -> bool:
"""Whether actively capturing -- not disabled or closed."""
if self._capture is not None:
return self._capture.is_started()
return False
@contextlib.contextmanager
def disabled(self) -> Generator[None, None, None]:
"""Temporarily disables capture while inside the 'with' block."""

View File

@ -1174,9 +1174,8 @@ class Config:
missing_plugins.append(required_plugin)
if missing_plugins:
fail(
raise UsageError(
"Missing required plugins: {}".format(", ".join(missing_plugins)),
pytrace=False,
)
def _warn_or_fail_if_strict(self, message: str) -> None:

View File

@ -170,6 +170,8 @@ def showhelp(config: Config) -> None:
help, type, default = config._parser._inidict[name]
if type is None:
type = "string"
if help is None:
raise TypeError("help argument cannot be None for {}".format(name))
spec = "{} ({}):".format(name, type)
tw.write(" %s" % spec)
spec_len = len(spec)
@ -191,6 +193,7 @@ def showhelp(config: Config) -> None:
tw.write(" " * (indent_len - spec_len - 2))
wrapped = textwrap.wrap(help, columns - indent_len, break_on_hyphens=False)
if wrapped:
tw.line(wrapped[0])
for line in wrapped[1:]:
tw.line(indent + line)

View File

@ -377,6 +377,12 @@ def record_testsuite_property(request: FixtureRequest) -> Callable[[str, object]
record_testsuite_property("STORAGE_TYPE", "CEPH")
``name`` must be a string, ``value`` will be converted to a string and properly xml-escaped.
.. warning::
Currently this fixture **does not work** with the
`pytest-xdist <https://github.com/pytest-dev/pytest-xdist>`__ plugin. See issue
`#7767 <https://github.com/pytest-dev/pytest/issues/7767>`__ for details.
"""
__tracebackhide__ = True

View File

@ -437,6 +437,7 @@ class LogCaptureFixture:
# save the original log-level to restore it during teardown
self._initial_logger_levels.setdefault(logger, logger_obj.level)
logger_obj.setLevel(level)
if self._initial_handler_level is None:
self._initial_handler_level = self.handler.level
self.handler.setLevel(level)

View File

@ -604,7 +604,10 @@ class FSCollector(Collector):
class File(FSCollector):
""" base class for collecting tests from a file. """
"""Base class for collecting tests from a file.
:ref:`non-python tests`.
"""
class Item(Node):

View File

@ -162,9 +162,10 @@ def async_warn_and_skip(nodeid: str) -> None:
msg += (
"You need to install a suitable plugin for your async framework, for example:\n"
)
msg += " - anyio\n"
msg += " - pytest-asyncio\n"
msg += " - pytest-trio\n"
msg += " - pytest-tornasync\n"
msg += " - pytest-trio\n"
msg += " - pytest-twisted"
warnings.warn(PytestUnhandledCoroutineWarning(msg.format(nodeid)))
skip(msg="async def function and no async plugin installed (see warnings)")
@ -1254,6 +1255,9 @@ def _idval(
return str(val)
elif isinstance(val, REGEX_TYPE):
return ascii_escaped(val.pattern)
elif val is NOTSET:
# Fallback to default. Note that NOTSET is an enum.Enum.
pass
elif isinstance(val, enum.Enum):
return str(val)
elif isinstance(getattr(val, "__name__", None), str):

View File

@ -4,6 +4,8 @@ import os
import queue
import sys
import textwrap
from typing import Any
from typing import Dict
from typing import Tuple
from typing import Union
@ -1045,28 +1047,34 @@ raise ValueError()
@pytest.mark.parametrize(
"reproptions",
[
pytest.param(
{
"style": style,
"showlocals": showlocals,
"funcargs": funcargs,
"tbfilter": tbfilter,
}
for style in ("long", "short", "no")
},
id="style={},showlocals={},funcargs={},tbfilter={}".format(
style, showlocals, funcargs, tbfilter
),
)
for style in ["long", "short", "line", "no", "native", "value", "auto"]
for showlocals in (True, False)
for tbfilter in (True, False)
for funcargs in (True, False)
],
)
def test_format_excinfo(self, importasmod, reproptions):
mod = importasmod(
"""
def g(x):
raise ValueError(x)
def f():
g(3)
"""
)
excinfo = pytest.raises(ValueError, mod.f)
def test_format_excinfo(self, reproptions: Dict[str, Any]) -> None:
def bar():
assert False, "some error"
def foo():
bar()
# using inline functions as opposed to importasmod so we get source code lines
# in the tracebacks (otherwise getinspect doesn't find the source code).
with pytest.raises(AssertionError) as excinfo:
foo()
file = io.StringIO()
tw = TerminalWriter(file=file)
repr = excinfo.getrepr(**reproptions)
@ -1344,6 +1352,19 @@ raise ValueError()
)
assert out == expected_out
def test_exec_type_error_filter(self, importasmod):
"""See #7742"""
mod = importasmod(
"""\
def f():
exec("a = 1", {}, [])
"""
)
with pytest.raises(TypeError) as excinfo:
mod.f()
# previously crashed with `AttributeError: list has no attribute get`
excinfo.traceback.filter()
@pytest.mark.parametrize("style", ["short", "long"])
@pytest.mark.parametrize("encoding", [None, "utf8", "utf16"])

View File

@ -65,6 +65,7 @@ def test_change_level_undos_handler_level(testdir: Testdir) -> None:
def test1(caplog):
assert caplog.handler.level == 0
caplog.set_level(9999)
caplog.set_level(41)
assert caplog.handler.level == 41

View File

@ -0,0 +1,2 @@
*.html
assets/

View File

@ -0,0 +1,13 @@
This folder contains tests and support files for smoke testing popular plugins against the current pytest version.
The objective is to gauge if any intentional or unintentional changes in pytest break plugins.
As a rule of thumb, we should add plugins here:
1. That are used at large. This might be subjective in some cases, but if answer is yes to
the question: *if a new release of pytest causes pytest-X to break, will this break a ton of test suites out there?*.
2. That don't have large external dependencies: such as external services.
Besides adding the plugin as dependency, we should also add a quick test which uses some
minimal part of the plugin, a smoke test. Also consider reusing one of the existing tests if that's
possible.

View File

@ -0,0 +1,9 @@
Feature: Buy things with apple
Scenario: Buy fruits
Given A wallet with 50
When I buy some apples for 1
And I buy some bananas for 2
Then I have 47 left

View File

@ -0,0 +1,39 @@
from pytest_bdd import given
from pytest_bdd import scenario
from pytest_bdd import then
from pytest_bdd import when
import pytest
@scenario("bdd_wallet.feature", "Buy fruits")
def test_publish():
pass
@pytest.fixture
def wallet():
class Wallet:
amount = 0
return Wallet()
@given("A wallet with 50")
def fill_wallet(wallet):
wallet.amount = 50
@when("I buy some apples for 1")
def buy_apples(wallet):
wallet.amount -= 1
@when("I buy some bananas for 2")
def buy_bananas(wallet):
wallet.amount -= 2
@then("I have 47 left")
def check(wallet):
assert wallet.amount == 47

View File

@ -0,0 +1 @@
SECRET_KEY = "mysecret"

View File

@ -0,0 +1,4 @@
[pytest]
addopts = --strict-markers
filterwarnings =
error::pytest.PytestWarning

View File

@ -0,0 +1,8 @@
import anyio
import pytest
@pytest.mark.anyio
async def test_sleep():
await anyio.sleep(0)

View File

@ -0,0 +1,8 @@
import asyncio
import pytest
@pytest.mark.asyncio
async def test_sleep():
await asyncio.sleep(0)

View File

@ -0,0 +1,2 @@
def test_mocker(mocker):
mocker.MagicMock()

View File

@ -0,0 +1,8 @@
import trio
import pytest
@pytest.mark.trio
async def test_sleep():
await trio.sleep(0)

View File

@ -0,0 +1,18 @@
import pytest_twisted
from twisted.internet.task import deferLater
def sleep():
import twisted.internet.reactor
return deferLater(clock=twisted.internet.reactor, delay=0)
@pytest_twisted.inlineCallbacks
def test_inlineCallbacks():
yield sleep()
@pytest_twisted.ensureDeferred
async def test_inlineCallbacks_async():
await sleep()

View File

@ -0,0 +1,10 @@
import pytest
def test_foo():
assert True
@pytest.mark.parametrize("i", range(3))
def test_bar(i):
assert True

View File

@ -19,6 +19,7 @@ from hypothesis import strategies
import pytest
from _pytest import fixtures
from _pytest import python
from _pytest.compat import NOTSET
from _pytest.outcomes import fail
from _pytest.pytester import Testdir
from _pytest.python import _idval
@ -363,6 +364,14 @@ class TestMetafunc:
for val, expected in values:
assert _idval(val, "a", 6, None, nodeid=None, config=None) == expected
def test_notset_idval(self) -> None:
"""Test that a NOTSET value (used by an empty parameterset) generates
a proper ID.
Regression test for #7686.
"""
assert _idval(NOTSET, "a", 0, None, nodeid=None, config=None) == "a0"
def test_idmaker_autoname(self) -> None:
"""#250"""
result = idmaker(

View File

@ -992,7 +992,7 @@ class TestAssertionRewriteHookDetails:
e = OSError()
e.errno = 10
raise e
yield
yield # type:ignore[unreachable]
monkeypatch.setattr(
_pytest.assertion.rewrite, "atomic_write", atomic_write_failed
@ -1600,7 +1600,7 @@ class TestPyCacheDir:
if prefix:
if sys.version_info < (3, 8):
pytest.skip("pycache_prefix not available in py<38")
monkeypatch.setattr(sys, "pycache_prefix", prefix)
monkeypatch.setattr(sys, "pycache_prefix", prefix) # type:ignore
assert get_cache_dir(Path(source)) == Path(expected)

View File

@ -16,6 +16,7 @@ from _pytest.capture import _get_multicapture
from _pytest.capture import CaptureManager
from _pytest.capture import MultiCapture
from _pytest.config import ExitCode
from _pytest.pytester import Testdir
# note: py.io capture tests where copied from
# pylib 1.4.20.dev2 (rev 13d9af95547e)
@ -633,6 +634,34 @@ class TestCaptureFixture:
else:
result.stdout.no_fnmatch_line("*test_normal executed*")
def test_disabled_capture_fixture_twice(self, testdir: Testdir) -> None:
"""Test that an inner disabled() exit doesn't undo an outer disabled().
Issue #7148.
"""
testdir.makepyfile(
"""
def test_disabled(capfd):
print('captured before')
with capfd.disabled():
print('while capture is disabled 1')
with capfd.disabled():
print('while capture is disabled 2')
print('while capture is disabled 1 after')
print('captured after')
assert capfd.readouterr() == ('captured before\\ncaptured after\\n', '')
"""
)
result = testdir.runpytest_subprocess()
result.stdout.fnmatch_lines(
[
"*while capture is disabled 1",
"*while capture is disabled 2",
"*while capture is disabled 1 after",
],
consecutive=True,
)
@pytest.mark.parametrize("fixture", ["capsys", "capfd"])
def test_fixture_use_by_other_fixtures(self, testdir, fixture):
"""

View File

@ -1427,3 +1427,17 @@ class TestImportModeImportlib:
"* 1 failed in *",
]
)
def test_does_not_crash_on_error_from_decorated_function(testdir: Testdir) -> None:
"""Regression test for an issue around bad exception formatting due to
assertion rewriting mangling lineno's (#4984)."""
testdir.makepyfile(
"""
@pytest.fixture
def a(): return 4
"""
)
result = testdir.runpytest()
# Not INTERNAL_ERROR
assert result.ret == ExitCode.INTERRUPTED

View File

@ -362,11 +362,30 @@ class TestParseIni:
testdir.makeini(ini_file_text)
if exception_text:
with pytest.raises(pytest.fail.Exception, match=exception_text):
with pytest.raises(pytest.UsageError, match=exception_text):
testdir.parseconfig()
else:
testdir.parseconfig()
def test_early_config_cmdline(self, testdir, monkeypatch):
"""early_config contains options registered by third-party plugins.
This is a regression involving pytest-cov (and possibly others) introduced in #7700.
"""
testdir.makepyfile(
myplugin="""
def pytest_addoption(parser):
parser.addoption('--foo', default=None, dest='foo')
def pytest_load_initial_conftests(early_config, parser, args):
assert early_config.known_args_namespace.foo == "1"
"""
)
monkeypatch.setenv("PYTEST_PLUGINS", "myplugin")
testdir.syspathinsert()
result = testdir.runpytest("--foo=1")
result.stdout.fnmatch_lines("* no tests ran in *")
class TestConfigCmdlineParsing:
def test_parsing_again_fails(self, testdir):

View File

@ -38,6 +38,41 @@ def test_help(testdir):
)
def test_none_help_param_raises_exception(testdir):
"""Tests a None help param raises a TypeError.
"""
testdir.makeconftest(
"""
def pytest_addoption(parser):
parser.addini("test_ini", None, default=True, type="bool")
"""
)
result = testdir.runpytest("--help")
result.stderr.fnmatch_lines(
["*TypeError: help argument cannot be None for test_ini*"]
)
def test_empty_help_param(testdir):
"""Tests an empty help param is displayed correctly.
"""
testdir.makeconftest(
"""
def pytest_addoption(parser):
parser.addini("test_ini", "", default=True, type="bool")
"""
)
result = testdir.runpytest("--help")
assert result.ret == 0
lines = [
" required_plugins (args):",
" plugins that must be present for pytest to run*",
" test_ini (bool):*",
"environment variables:",
]
result.stdout.fnmatch_lines(lines, consecutive=True)
def test_hookvalidation_unknown(testdir):
testdir.makeconftest(
"""

38
tox.ini
View File

@ -13,6 +13,7 @@ envlist =
pypy3
py37-{pexpect,xdist,unittestextras,numpy,pluggymaster}
doctesting
plugins
py37-freeze
docs
docs-checklinks
@ -114,6 +115,43 @@ commands =
rm -rf {envdir}/.pytest_cache
make regen
[testenv:plugins]
# use latest versions of all plugins, including pre-releases
pip_pre=true
# use latest pip and new dependency resolver (#7783)
download=true
install_command=python -m pip --use-feature=2020-resolver install {opts} {packages}
changedir = testing/plugins_integration
deps =
anyio[curio,trio]
django
pytest-asyncio
pytest-bdd
pytest-cov
pytest-django
pytest-flakes
pytest-html
pytest-mock
pytest-sugar
pytest-trio
pytest-twisted
twisted
pytest-xvfb
setenv =
PYTHONPATH=.
commands =
pip check
pytest bdd_wallet.py
pytest --cov=. simple_integration.py
pytest --ds=django_settings simple_integration.py
pytest --html=simple.html simple_integration.py
pytest pytest_anyio_integration.py
pytest pytest_asyncio_integration.py
pytest pytest_mock_integration.py
pytest pytest_trio_integration.py
pytest pytest_twisted_integration.py
pytest simple_integration.py --force-sugar --flakes
[testenv:py37-freeze]
changedir = testing/freeze
deps =