Compare commits
40 Commits
Author | SHA1 | Date |
---|---|---|
|
e886b170dd | |
|
45a645db86 | |
|
f5b1f44317 | |
|
89d03b2999 | |
|
5e14e7d9c1 | |
|
5819cb611e | |
|
687146e3f1 | |
|
ae61fa4040 | |
|
d7d089469e | |
|
6933bf6b4d | |
|
819fef87a7 | |
|
604047ee1a | |
|
52363fe560 | |
|
c923dbc96f | |
|
2d680da78b | |
|
b3c444ddc1 | |
|
fe69bd5baf | |
|
09b1d7cc99 | |
|
ea65ea877e | |
|
f4f30d7073 | |
|
309810ac2c | |
|
e63fac3aec | |
|
cb91c5033e | |
|
9a879ee23e | |
|
e9d18bd8ac | |
|
912870d33e | |
|
0115b716c0 | |
|
9a91b67eeb | |
|
79d0d3eff4 | |
|
834f55eddb | |
|
6110f84f78 | |
|
5a339f0d74 | |
|
022bff27a7 | |
|
92af2e22d2 | |
|
0307213254 | |
|
df7b26704d | |
|
1516780829 | |
|
b945b39b0b | |
|
2d5b8a85c2 | |
|
8963644da3 |
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -1,2 +0,0 @@
|
|||
Fix pylint ``not-callable`` lint on ``pytest.mark.parametrize()`` and the other builtin marks:
|
||||
``skip``, ``skipif``, ``xfail``, ``usefixtures``, ``filterwarnings``.
|
|
@ -1 +0,0 @@
|
|||
Fix regression in plugins using ``TestReport.longreprtext`` (such as ``pytest-html``) when ``TestReport.longrepr`` is not a string.
|
|
@ -0,0 +1 @@
|
|||
When a plugin listed in ``required_plugins`` is missing, a simple error message is now shown instead of a stacktrace.
|
|
@ -0,0 +1 @@
|
|||
Fix INTERNALERROR when accessing locals / globals with faulty ``exec``.
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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__``.
|
||||
|
|
|
@ -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).
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -28,7 +28,7 @@ Install ``pytest``
|
|||
.. code-block:: bash
|
||||
|
||||
$ pytest --version
|
||||
pytest 6.0.0
|
||||
pytest 6.0.2
|
||||
|
||||
.. _`simpletest`:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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".
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 = [
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,9 +193,10 @@ def showhelp(config: Config) -> None:
|
|||
tw.write(" " * (indent_len - spec_len - 2))
|
||||
wrapped = textwrap.wrap(help, columns - indent_len, break_on_hyphens=False)
|
||||
|
||||
tw.line(wrapped[0])
|
||||
for line in wrapped[1:]:
|
||||
tw.line(indent + line)
|
||||
if wrapped:
|
||||
tw.line(wrapped[0])
|
||||
for line in wrapped[1:]:
|
||||
tw.line(indent + line)
|
||||
|
||||
tw.line()
|
||||
tw.line("environment variables:")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -437,7 +437,8 @@ 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)
|
||||
self._initial_handler_level = self.handler.level
|
||||
if self._initial_handler_level is None:
|
||||
self._initial_handler_level = self.handler.level
|
||||
self.handler.setLevel(level)
|
||||
|
||||
@contextmanager
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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",
|
||||
[
|
||||
{
|
||||
"style": style,
|
||||
"showlocals": showlocals,
|
||||
"funcargs": funcargs,
|
||||
"tbfilter": tbfilter,
|
||||
}
|
||||
for style in ("long", "short", "no")
|
||||
pytest.param(
|
||||
{
|
||||
"style": style,
|
||||
"showlocals": showlocals,
|
||||
"funcargs": funcargs,
|
||||
"tbfilter": tbfilter,
|
||||
},
|
||||
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"])
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
*.html
|
||||
assets/
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
SECRET_KEY = "mysecret"
|
|
@ -0,0 +1,4 @@
|
|||
[pytest]
|
||||
addopts = --strict-markers
|
||||
filterwarnings =
|
||||
error::pytest.PytestWarning
|
|
@ -0,0 +1,8 @@
|
|||
import anyio
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.anyio
|
||||
async def test_sleep():
|
||||
await anyio.sleep(0)
|
|
@ -0,0 +1,8 @@
|
|||
import asyncio
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sleep():
|
||||
await asyncio.sleep(0)
|
|
@ -0,0 +1,2 @@
|
|||
def test_mocker(mocker):
|
||||
mocker.MagicMock()
|
|
@ -0,0 +1,8 @@
|
|||
import trio
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_sleep():
|
||||
await trio.sleep(0)
|
|
@ -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()
|
|
@ -0,0 +1,10 @@
|
|||
import pytest
|
||||
|
||||
|
||||
def test_foo():
|
||||
assert True
|
||||
|
||||
|
||||
@pytest.mark.parametrize("i", range(3))
|
||||
def test_bar(i):
|
||||
assert True
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
38
tox.ini
|
@ -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 =
|
||||
|
|
Loading…
Reference in New Issue