Compare commits
20 Commits
6.2.0.dev0
...
6.1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e8b50ba01 | ||
|
|
cd221df8e2 | ||
|
|
8c1c1ae310 | ||
|
|
a88fe584ad | ||
|
|
cd57271455 | ||
|
|
46195edc3e | ||
|
|
9237b5f633 | ||
|
|
95fd566133 | ||
|
|
c93962c491 | ||
|
|
dc96e485a0 | ||
|
|
7ccfc39f15 | ||
|
|
69d903260d | ||
|
|
0ad20b533f | ||
|
|
9df5267648 | ||
|
|
1521849c87 | ||
|
|
bcb94c4c8b | ||
|
|
0f83df4f55 | ||
|
|
330caac2ca | ||
|
|
08a1ab3a8a | ||
|
|
868bc003ec |
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -16,6 +16,7 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 30
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -187,6 +188,7 @@ jobs:
|
||||
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') && github.repository == 'pytest-dev/pytest'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
|
||||
needs: [build]
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ Release announcements
|
||||
:maxdepth: 2
|
||||
|
||||
|
||||
release-6.1.2
|
||||
release-6.1.1
|
||||
release-6.1.0
|
||||
release-6.0.2
|
||||
release-6.0.1
|
||||
|
||||
18
doc/en/announce/release-6.1.1.rst
Normal file
18
doc/en/announce/release-6.1.1.rst
Normal file
@@ -0,0 +1,18 @@
|
||||
pytest-6.1.1
|
||||
=======================================
|
||||
|
||||
pytest 6.1.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/stable/changelog.html.
|
||||
|
||||
Thanks to all of the contributors to this release:
|
||||
|
||||
* Ran Benita
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
22
doc/en/announce/release-6.1.2.rst
Normal file
22
doc/en/announce/release-6.1.2.rst
Normal file
@@ -0,0 +1,22 @@
|
||||
pytest-6.1.2
|
||||
=======================================
|
||||
|
||||
pytest 6.1.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
|
||||
* Manuel Mariñez
|
||||
* Ran Benita
|
||||
* Vasilis Gerakaris
|
||||
* William Jamir Silva
|
||||
|
||||
|
||||
Happy testing,
|
||||
The pytest Development Team
|
||||
@@ -28,6 +28,37 @@ with advance notice in the **Deprecations** section of releases.
|
||||
|
||||
.. towncrier release notes start
|
||||
|
||||
pytest 6.1.2 (2020-10-28)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#7758 <https://github.com/pytest-dev/pytest/issues/7758>`_: Fixed an issue where some files in packages are getting lost from ``--lf`` even though they contain tests that failed. Regressed in pytest 5.4.0.
|
||||
|
||||
|
||||
- `#7911 <https://github.com/pytest-dev/pytest/issues/7911>`_: Directories created by `tmpdir` are now considered stale after 3 days without modification (previous value was 3 hours) to avoid deleting directories still in use in long running test suites.
|
||||
|
||||
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- `#7815 <https://github.com/pytest-dev/pytest/issues/7815>`_: Improve deprecation warning message for ``pytest._fillfuncargs()``.
|
||||
|
||||
|
||||
pytest 6.1.1 (2020-10-03)
|
||||
=========================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- `#7807 <https://github.com/pytest-dev/pytest/issues/7807>`_: Fixed regression in pytest 6.1.0 causing incorrect rootdir to be determined in some non-trivial cases where parent directories have config files as well.
|
||||
|
||||
|
||||
- `#7814 <https://github.com/pytest-dev/pytest/issues/7814>`_: Fixed crash in header reporting when :confval:`testpaths` is used and contains absolute paths (regression in 6.1.0).
|
||||
|
||||
|
||||
pytest 6.1.0 (2020-09-26)
|
||||
=========================
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ Install ``pytest``
|
||||
.. code-block:: bash
|
||||
|
||||
$ pytest --version
|
||||
pytest 6.1.0
|
||||
pytest 6.1.2
|
||||
|
||||
.. _`simpletest`:
|
||||
|
||||
|
||||
@@ -1236,12 +1236,13 @@ passed multiple times. The expected format is ``name=value``. For example::
|
||||
.. confval:: junit_family
|
||||
|
||||
.. versionadded:: 4.2
|
||||
.. versionchanged:: 6.1
|
||||
Default changed to ``xunit2``.
|
||||
|
||||
Configures the format of the generated JUnit XML file. The possible options are:
|
||||
|
||||
* ``xunit1`` (or ``legacy``): produces old style output, compatible with the xunit 1.0 format. **This is the default**.
|
||||
* ``xunit2``: produces `xunit 2.0 style output <https://github.com/jenkinsci/xunit-plugin/blob/xunit-2.3.2/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd>`__,
|
||||
which should be more compatible with latest Jenkins versions.
|
||||
* ``xunit1`` (or ``legacy``): produces old style output, compatible with the xunit 1.0 format.
|
||||
* ``xunit2``: produces `xunit 2.0 style output <https://github.com/jenkinsci/xunit-plugin/blob/xunit-2.3.2/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd>`__, which should be more compatible with latest Jenkins versions. **This is the default**.
|
||||
|
||||
.. code-block:: ini
|
||||
|
||||
|
||||
@@ -33,26 +33,34 @@ Plugin discovery order at tool startup
|
||||
|
||||
``pytest`` loads plugin modules at tool startup in the following way:
|
||||
|
||||
* by loading all builtin plugins
|
||||
1. by scanning the command line for the ``-p no:name`` option
|
||||
and *blocking* that plugin from being loaded (even builtin plugins can
|
||||
be blocked this way). This happens before normal command-line parsing.
|
||||
|
||||
* by loading all plugins registered through `setuptools entry points`_.
|
||||
2. by loading all builtin plugins.
|
||||
|
||||
* by pre-scanning the command line for the ``-p name`` option
|
||||
and loading the specified plugin before actual command line parsing.
|
||||
3. by scanning the command line for the ``-p name`` option
|
||||
and loading the specified plugin. This happens before normal command-line parsing.
|
||||
|
||||
* by loading all :file:`conftest.py` files as inferred by the command line
|
||||
invocation:
|
||||
4. by loading all plugins registered through `setuptools entry points`_.
|
||||
|
||||
- if no test paths are specified use current dir as a test path
|
||||
- if exists, load ``conftest.py`` and ``test*/conftest.py`` relative
|
||||
to the directory part of the first test path.
|
||||
5. by loading all plugins specified through the :envvar:`PYTEST_PLUGINS` environment variable.
|
||||
|
||||
Note that pytest does not find ``conftest.py`` files in deeper nested
|
||||
sub directories at tool startup. It is usually a good idea to keep
|
||||
your ``conftest.py`` file in the top level test or project root directory.
|
||||
6. by loading all :file:`conftest.py` files as inferred by the command line
|
||||
invocation:
|
||||
|
||||
* by recursively loading all plugins specified by the
|
||||
:globalvar:`pytest_plugins` variable in ``conftest.py`` files
|
||||
- if no test paths are specified, use the current dir as a test path
|
||||
- if exists, load ``conftest.py`` and ``test*/conftest.py`` relative
|
||||
to the directory part of the first test path. After the ``conftest.py``
|
||||
file is loaded, load all plugins specified in its
|
||||
:globalvar:`pytest_plugins` variable if present.
|
||||
|
||||
Note that pytest does not find ``conftest.py`` files in deeper nested
|
||||
sub directories at tool startup. It is usually a good idea to keep
|
||||
your ``conftest.py`` file in the top level test or project root directory.
|
||||
|
||||
7. by recursively loading all plugins specified by the
|
||||
:globalvar:`pytest_plugins` variable in ``conftest.py`` files.
|
||||
|
||||
|
||||
.. _`pytest/plugin`: http://bitbucket.org/pytest-dev/pytest/src/tip/pytest/plugin/
|
||||
|
||||
@@ -29,6 +29,7 @@ from _pytest.config.argparsing import Parser
|
||||
from _pytest.fixtures import FixtureRequest
|
||||
from _pytest.main import Session
|
||||
from _pytest.python import Module
|
||||
from _pytest.python import Package
|
||||
from _pytest.reports import TestReport
|
||||
|
||||
|
||||
@@ -233,7 +234,10 @@ class LFPluginCollSkipfiles:
|
||||
def pytest_make_collect_report(
|
||||
self, collector: nodes.Collector
|
||||
) -> Optional[CollectReport]:
|
||||
if isinstance(collector, Module):
|
||||
# Packages are Modules, but _last_failed_paths only contains
|
||||
# test-bearing paths and doesn't try to include the paths of their
|
||||
# packages, so don't filter them.
|
||||
if isinstance(collector, Module) and not isinstance(collector, Package):
|
||||
if Path(str(collector.fspath)) not in self.lfplugin._last_failed_paths:
|
||||
self.lfplugin._skipped_files += 1
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import itertools
|
||||
import os
|
||||
from typing import Dict
|
||||
from typing import Iterable
|
||||
@@ -100,7 +99,7 @@ def locate_config(
|
||||
args = [Path.cwd()]
|
||||
for arg in args:
|
||||
argpath = absolutepath(arg)
|
||||
for base in itertools.chain((argpath,), reversed(argpath.parents)):
|
||||
for base in (argpath, *argpath.parents):
|
||||
for config_name in config_names:
|
||||
p = base / config_name
|
||||
if p.is_file():
|
||||
@@ -184,9 +183,7 @@ def determine_setup(
|
||||
ancestor = get_common_ancestor(dirs)
|
||||
rootdir, inipath, inicfg = locate_config([ancestor])
|
||||
if rootdir is None and rootdir_cmd_arg is None:
|
||||
for possible_rootdir in itertools.chain(
|
||||
(ancestor,), reversed(ancestor.parents)
|
||||
):
|
||||
for possible_rootdir in (ancestor, *ancestor.parents):
|
||||
if (possible_rootdir / "setup.py").is_file():
|
||||
rootdir = possible_rootdir
|
||||
break
|
||||
|
||||
@@ -20,9 +20,10 @@ DEPRECATED_EXTERNAL_PLUGINS = {
|
||||
}
|
||||
|
||||
|
||||
FILLFUNCARGS = PytestDeprecationWarning(
|
||||
"The `_fillfuncargs` function is deprecated, use "
|
||||
"function._request._fillfixtures() instead if you cannot avoid reaching into internals."
|
||||
FILLFUNCARGS = UnformattedWarning(
|
||||
PytestDeprecationWarning,
|
||||
"{name} is deprecated, use "
|
||||
"function._request._fillfixtures() instead if you cannot avoid reaching into internals.",
|
||||
)
|
||||
|
||||
PYTEST_COLLECT_MODULE = UnformattedWarning(
|
||||
|
||||
@@ -339,9 +339,22 @@ def reorder_items_atscope(
|
||||
return items_done
|
||||
|
||||
|
||||
def _fillfuncargs(function: "Function") -> None:
|
||||
"""Fill missing fixtures for a test function, old public API (deprecated)."""
|
||||
warnings.warn(FILLFUNCARGS.format(name="pytest._fillfuncargs()"), stacklevel=2)
|
||||
_fill_fixtures_impl(function)
|
||||
|
||||
|
||||
def fillfixtures(function: "Function") -> None:
|
||||
"""Fill missing funcargs for a test function."""
|
||||
warnings.warn(FILLFUNCARGS, stacklevel=2)
|
||||
"""Fill missing fixtures for a test function (deprecated)."""
|
||||
warnings.warn(
|
||||
FILLFUNCARGS.format(name="_pytest.fixtures.fillfixtures()"), stacklevel=2
|
||||
)
|
||||
_fill_fixtures_impl(function)
|
||||
|
||||
|
||||
def _fill_fixtures_impl(function: "Function") -> None:
|
||||
"""Internal implementation to fill fixtures on the given function object."""
|
||||
try:
|
||||
request = function._request
|
||||
except AttributeError:
|
||||
|
||||
@@ -38,7 +38,7 @@ else:
|
||||
__all__ = ["Path", "PurePath"]
|
||||
|
||||
|
||||
LOCK_TIMEOUT = 60 * 60 * 3
|
||||
LOCK_TIMEOUT = 60 * 60 * 24 * 3
|
||||
|
||||
|
||||
_AnyPurePath = TypeVar("_AnyPurePath", bound=PurePath)
|
||||
|
||||
@@ -718,10 +718,10 @@ class TerminalReporter:
|
||||
if config.inipath:
|
||||
line += ", configfile: " + bestrelpath(config.rootpath, config.inipath)
|
||||
|
||||
testpaths = config.getini("testpaths")
|
||||
testpaths = config.getini("testpaths") # type: List[str]
|
||||
if testpaths and config.args == testpaths:
|
||||
rel_paths = [bestrelpath(config.rootpath, x) for x in testpaths]
|
||||
line += ", testpaths: {}".format(", ".join(rel_paths))
|
||||
line += ", testpaths: {}".format(", ".join(testpaths))
|
||||
|
||||
result = [line]
|
||||
|
||||
plugininfo = config.pluginmanager.list_plugin_distinfo()
|
||||
|
||||
@@ -11,7 +11,7 @@ from _pytest.config import hookspec
|
||||
from _pytest.config import main
|
||||
from _pytest.config import UsageError
|
||||
from _pytest.debugging import pytestPDB as __pytestPDB
|
||||
from _pytest.fixtures import fillfixtures as _fillfuncargs
|
||||
from _pytest.fixtures import _fillfuncargs
|
||||
from _pytest.fixtures import fixture
|
||||
from _pytest.fixtures import FixtureLookupError
|
||||
from _pytest.fixtures import yield_fixture
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import re
|
||||
import warnings
|
||||
from unittest import mock
|
||||
|
||||
@@ -26,11 +27,27 @@ def test_external_plugins_integrated(testdir, plugin):
|
||||
def test_fillfuncargs_is_deprecated() -> None:
|
||||
with pytest.warns(
|
||||
pytest.PytestDeprecationWarning,
|
||||
match="The `_fillfuncargs` function is deprecated",
|
||||
match=re.escape(
|
||||
"pytest._fillfuncargs() is deprecated, use "
|
||||
"function._request._fillfixtures() instead if you cannot avoid reaching into internals."
|
||||
),
|
||||
):
|
||||
pytest._fillfuncargs(mock.Mock())
|
||||
|
||||
|
||||
def test_fillfixtures_is_deprecated() -> None:
|
||||
import _pytest.fixtures
|
||||
|
||||
with pytest.warns(
|
||||
pytest.PytestDeprecationWarning,
|
||||
match=re.escape(
|
||||
"_pytest.fixtures.fillfixtures() is deprecated, use "
|
||||
"function._request._fillfixtures() instead if you cannot avoid reaching into internals."
|
||||
),
|
||||
):
|
||||
_pytest.fixtures.fillfixtures(mock.Mock())
|
||||
|
||||
|
||||
def test_minus_k_dash_is_deprecated(testdir) -> None:
|
||||
threepass = testdir.makepyfile(
|
||||
test_threepass="""
|
||||
|
||||
@@ -87,7 +87,7 @@ def test_getfuncargnames_staticmethod_partial():
|
||||
class TestFillFixtures:
|
||||
def test_fillfuncargs_exposed(self):
|
||||
# used by oejskit, kept for compatibility
|
||||
assert pytest._fillfuncargs == fixtures.fillfixtures
|
||||
assert pytest._fillfuncargs == fixtures._fillfuncargs
|
||||
|
||||
def test_funcarg_lookupfails(self, testdir):
|
||||
testdir.copy_example()
|
||||
|
||||
@@ -984,6 +984,36 @@ class TestLastFailed:
|
||||
)
|
||||
assert result.ret == 0
|
||||
|
||||
def test_packages(self, testdir: Testdir) -> None:
|
||||
"""Regression test for #7758.
|
||||
|
||||
The particular issue here was that Package nodes were included in the
|
||||
filtering, being themselves Modules for the __init__.py, even if they
|
||||
had failed Modules in them.
|
||||
|
||||
The tests includes a test in an __init__.py file just to make sure the
|
||||
fix doesn't somehow regress that, it is not critical for the issue.
|
||||
"""
|
||||
testdir.makepyfile(
|
||||
**{
|
||||
"__init__.py": "",
|
||||
"a/__init__.py": "def test_a_init(): assert False",
|
||||
"a/test_one.py": "def test_1(): assert False",
|
||||
"b/__init__.py": "",
|
||||
"b/test_two.py": "def test_2(): assert False",
|
||||
},
|
||||
)
|
||||
testdir.makeini(
|
||||
"""
|
||||
[pytest]
|
||||
python_files = *.py
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest()
|
||||
result.assert_outcomes(failed=3)
|
||||
result = testdir.runpytest("--lf")
|
||||
result.assert_outcomes(failed=3)
|
||||
|
||||
|
||||
class TestNewFirst:
|
||||
def test_newfirst_usecase(self, testdir):
|
||||
|
||||
@@ -1375,6 +1375,21 @@ class TestRootdir:
|
||||
assert rootpath == tmp_path
|
||||
assert inipath is None
|
||||
|
||||
def test_with_config_also_in_parent_directory(
|
||||
self, tmp_path: Path, monkeypatch: MonkeyPatch
|
||||
) -> None:
|
||||
"""Regression test for #7807."""
|
||||
(tmp_path / "setup.cfg").write_text("[tool:pytest]\n", "utf-8")
|
||||
(tmp_path / "myproject").mkdir()
|
||||
(tmp_path / "myproject" / "setup.cfg").write_text("[tool:pytest]\n", "utf-8")
|
||||
(tmp_path / "myproject" / "tests").mkdir()
|
||||
monkeypatch.chdir(tmp_path / "myproject")
|
||||
|
||||
rootpath, inipath, _ = determine_setup(None, ["tests/"])
|
||||
|
||||
assert rootpath == tmp_path / "myproject"
|
||||
assert inipath == tmp_path / "myproject" / "setup.cfg"
|
||||
|
||||
|
||||
class TestOverrideIniArgs:
|
||||
@pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split())
|
||||
|
||||
@@ -18,6 +18,7 @@ import pytest
|
||||
from _pytest._io.wcwidth import wcswidth
|
||||
from _pytest.config import Config
|
||||
from _pytest.config import ExitCode
|
||||
from _pytest.monkeypatch import MonkeyPatch
|
||||
from _pytest.pathlib import Path
|
||||
from _pytest.pytester import Testdir
|
||||
from _pytest.reports import BaseReport
|
||||
@@ -749,6 +750,29 @@ class TestTerminalFunctional:
|
||||
result = testdir.runpytest("tests")
|
||||
result.stdout.fnmatch_lines(["rootdir: *test_header0, configfile: tox.ini"])
|
||||
|
||||
def test_header_absolute_testpath(
|
||||
self, testdir: Testdir, monkeypatch: MonkeyPatch
|
||||
) -> None:
|
||||
"""Regresstion test for #7814."""
|
||||
tests = testdir.tmpdir.join("tests")
|
||||
tests.ensure_dir()
|
||||
testdir.makepyprojecttoml(
|
||||
"""
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ['{}']
|
||||
""".format(
|
||||
tests
|
||||
)
|
||||
)
|
||||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"rootdir: *absolute_testpath0, configfile: pyproject.toml, testpaths: {}".format(
|
||||
tests
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
def test_no_header(self, testdir):
|
||||
testdir.tmpdir.join("tests").ensure_dir()
|
||||
testdir.tmpdir.join("gui").ensure_dir()
|
||||
|
||||
Reference in New Issue
Block a user