From afaaa7e411b65ea3e89776f0db22dec775dca605 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 13 Feb 2019 18:49:35 +0100 Subject: [PATCH 01/15] Travis: test py38-dev only with cron builds The master and features branches are tested daily. --- .travis.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 66d06fccd..317b46484 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,8 @@ stages: if: repo = pytest-dev/pytest AND tag IS NOT present - name: deploy if: repo = pytest-dev/pytest AND tag IS present +- name: cron_only + if: type = cron python: - '3.7' install: @@ -40,8 +42,6 @@ jobs: python: '3.5' - env: TOXENV=py36 python: '3.6' - - env: TOXENV=py38 - python: '3.8-dev' - env: TOXENV=py37 - &test-macos language: generic @@ -65,6 +65,10 @@ jobs: - env: TOXENV=linting,docs,doctesting python: '3.7' + - stage: cron_only + env: TOXENV=py38 + python: '3.8-dev' + - stage: deploy python: '3.6' env: PYTEST_NO_COVERAGE=1 From 407d4a0cf09061806d3cb5604fe42c142bb132f0 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 13 Feb 2019 17:32:04 +0100 Subject: [PATCH 02/15] collect: python: fix `AssertionError` with broken symlinks Fixes https://github.com/pytest-dev/pytest/issues/4782. --- changelog/4782.bugfix.rst | 1 + src/_pytest/main.py | 7 ++++++- src/_pytest/python.py | 20 ++++++++++++++------ testing/test_collection.py | 27 +++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 changelog/4782.bugfix.rst diff --git a/changelog/4782.bugfix.rst b/changelog/4782.bugfix.rst new file mode 100644 index 000000000..12e08d00c --- /dev/null +++ b/changelog/4782.bugfix.rst @@ -0,0 +1 @@ +Fix ``AssertionError`` with collection of broken symlinks with packages. diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 81a597985..cb2c6cfe4 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -597,7 +597,12 @@ class Session(nodes.FSCollector): yield y def _collectfile(self, path, handle_dupes=True): - assert path.isfile() + assert path.isfile(), "%r is not a file (isdir=%r, exists=%r, islink=%r)" % ( + path, + path.isdir(), + path.exists(), + path.islink(), + ) ihook = self.gethookproxy(path) if not self.isinitpath(path): if ihook.pytest_ignore_collect(path=path, config=self.config): diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 48962d137..215015d27 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -599,7 +599,12 @@ class Package(Module): return proxy def _collectfile(self, path, handle_dupes=True): - assert path.isfile() + assert path.isfile(), "%r is not a file (isdir=%r, exists=%r, islink=%r)" % ( + path, + path.isdir(), + path.exists(), + path.islink(), + ) ihook = self.gethookproxy(path) if not self.isinitpath(path): if ihook.pytest_ignore_collect(path=path, config=self.config): @@ -632,7 +637,8 @@ class Package(Module): pkg_prefixes = set() for path in this_path.visit(rec=self._recurse, bf=True, sort=True): # We will visit our own __init__.py file, in which case we skip it. - if path.isfile(): + is_file = path.isfile() + if is_file: if path.basename == "__init__.py" and path.dirpath() == this_path: continue @@ -643,12 +649,14 @@ class Package(Module): ): continue - if path.isdir(): - if path.join("__init__.py").check(file=1): - pkg_prefixes.add(path) - else: + if is_file: for x in self._collectfile(path): yield x + elif not path.isdir(): + # Broken symlink or invalid/missing file. + continue + elif path.join("__init__.py").check(file=1): + pkg_prefixes.add(path) def _get_xunit_setup_teardown(holder, attr_name, param_obj=None): diff --git a/testing/test_collection.py b/testing/test_collection.py index 5fe313f98..d78c21f63 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -1186,3 +1186,30 @@ def test_collect_pkg_init_and_file_in_args(testdir): "*2 passed in*", ] ) + + +@pytest.mark.skipif( + not hasattr(py.path.local, "mksymlinkto"), + reason="symlink not available on this platform", +) +@pytest.mark.parametrize("use_pkg", (True, False)) +def test_collect_sub_with_symlinks(use_pkg, testdir): + sub = testdir.mkdir("sub") + if use_pkg: + sub.ensure("__init__.py") + sub.ensure("test_file.py").write("def test_file(): pass") + + # Create a broken symlink. + sub.join("test_broken.py").mksymlinkto("test_doesnotexist.py") + + # Symlink that gets collected. + sub.join("test_symlink.py").mksymlinkto("test_file.py") + + result = testdir.runpytest("-v", str(sub)) + result.stdout.fnmatch_lines( + [ + "sub/test_file.py::test_file PASSED*", + "sub/test_symlink.py::test_file PASSED*", + "*2 passed in*", + ] + ) From 40cec637d7b9faf7f3794cd6c71517f98704c817 Mon Sep 17 00:00:00 2001 From: "R. Alex Matevish" Date: Thu, 14 Feb 2019 00:03:41 -0800 Subject: [PATCH 03/15] Update kwarg for attr.ib to use 'converter' as 'convert' is due to be deprecated --- src/_pytest/tmpdir.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_pytest/tmpdir.py b/src/_pytest/tmpdir.py index 843c8ca37..4d109cc2b 100644 --- a/src/_pytest/tmpdir.py +++ b/src/_pytest/tmpdir.py @@ -31,7 +31,7 @@ class TempPathFactory(object): # using os.path.abspath() to get absolute path instead of resolve() as it # does not work the same in all platforms (see #4427) # Path.absolute() exists, but it is not public (see https://bugs.python.org/issue25012) - convert=attr.converters.optional( + converter=attr.converters.optional( lambda p: Path(os.path.abspath(six.text_type(p))) ) ) From 0e4750d8377a832236feab0f189339e6e0870065 Mon Sep 17 00:00:00 2001 From: cclauss Date: Thu, 14 Feb 2019 09:40:00 +0100 Subject: [PATCH 04/15] Travis CI: The 'sudo' tag is now deprecated [Travis are now recommending removing the __sudo__ tag](https://blog.travis-ci.com/2018-11-19-required-linux-infrastructure-migration). --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 317b46484..2f361aec0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,3 @@ -sudo: false language: python dist: xenial stages: From 4bc2f96c93e90910b70f5e58ce0de822084b0752 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 14 Feb 2019 08:32:49 -0200 Subject: [PATCH 05/15] Remove 'message' parameter docs from assert.rst As per: https://github.com/pytest-dev/pytest/issues/3974#issuecomment-463462732 Also made the 'match' parameter more prominent --- doc/en/assert.rst | 46 ++++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/doc/en/assert.rst b/doc/en/assert.rst index 186e12853..b119adcf0 100644 --- a/doc/en/assert.rst +++ b/doc/en/assert.rst @@ -88,23 +88,30 @@ and if you need to have access to the actual exception info you may use:: the actual exception raised. The main attributes of interest are ``.type``, ``.value`` and ``.traceback``. -.. versionchanged:: 3.0 +You can pass a ``match`` keyword parameter to the context-manager to test +that a regular expression matches on the string representation of an exception +(similar to the ``TestCase.assertRaisesRegexp`` method from ``unittest``):: -In the context manager form you may use the keyword argument -``message`` to specify a custom failure message:: + import pytest - >>> with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"): - ... pass - ... Failed: Expecting ZeroDivisionError + def myfunc(): + raise ValueError("Exception 123 raised") -If you want to write test code that works on Python 2.4 as well, -you may also use two other ways to test for an expected exception:: + def test_match(): + with pytest.raises(ValueError, match=r'.* 123 .*'): + myfunc() + +The regexp parameter of the ``match`` method is matched with the ``re.search`` +function, so in the above example ``match='123'`` would have worked as +well. + +There's an alternate form of the ``pytest.raises`` function where you pass +a function that will be executed with the given ``*args`` and ``**kwargs`` and +assert that the given exception is raised:: pytest.raises(ExpectedException, func, *args, **kwargs) -which will execute the specified function with args and kwargs and -assert that the given ``ExpectedException`` is raised. The reporter will -provide you with helpful output in case of failures such as *no +The reporter will provide you with helpful output in case of failures such as *no exception* or *wrong exception*. Note that it is also possible to specify a "raises" argument to @@ -121,23 +128,6 @@ exceptions your own code is deliberately raising, whereas using like documenting unfixed bugs (where the test describes what "should" happen) or bugs in dependencies. -Also, the context manager form accepts a ``match`` keyword parameter to test -that a regular expression matches on the string representation of an exception -(like the ``TestCase.assertRaisesRegexp`` method from ``unittest``):: - - import pytest - - def myfunc(): - raise ValueError("Exception 123 raised") - - def test_match(): - with pytest.raises(ValueError, match=r'.* 123 .*'): - myfunc() - -The regexp parameter of the ``match`` method is matched with the ``re.search`` -function. So in the above example ``match='123'`` would have worked as -well. - .. _`assertwarns`: From 59f69dd9e7e1ada1e56d63b1a288c9e2d5c6ce97 Mon Sep 17 00:00:00 2001 From: Grygorii Iermolenko Date: Fri, 15 Feb 2019 15:31:11 +0200 Subject: [PATCH 06/15] Add good talk by Andrew Svetlov --- doc/en/talks.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/en/talks.rst b/doc/en/talks.rst index aa1fb00e7..be0c6fb9f 100644 --- a/doc/en/talks.rst +++ b/doc/en/talks.rst @@ -25,6 +25,9 @@ Talks and blog postings - pytest: recommendations, basic packages for testing in Python and Django, Andreu Vallbona, PyconES 2017 (`slides in english `_, `video in spanish `_) +- `pytest advanced, Andrew Svetlov (Russian, PyCon Russia, 2016) + `_. + - `Pythonic testing, Igor Starikov (Russian, PyNsk, November 2016) `_. From 80ad4485908be67e300ef370922cea5936964e00 Mon Sep 17 00:00:00 2001 From: Grygorii Iermolenko Date: Fri, 15 Feb 2019 16:12:10 +0200 Subject: [PATCH 07/15] Fix code-block in Node docstring --- src/_pytest/nodes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index 00ec80894..ce02e70cd 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -113,11 +113,12 @@ class Node(object): :raise ValueError: if ``warning`` instance is not a subclass of PytestWarning. - Example usage:: + Example usage: .. code-block:: python node.warn(PytestWarning("some message")) + """ from _pytest.warning_types import PytestWarning From 3460105def126c1b5a0f10581ca8704758b8c43f Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 13 Feb 2019 18:40:53 +0100 Subject: [PATCH 08/15] Travis: use xdist for py?? envs, keeping py27/py37 --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2f361aec0..d42400844 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ env: matrix: allow_failures: - python: '3.8-dev' - env: TOXENV=py38 + env: TOXENV=py38-xdist jobs: include: @@ -35,11 +35,11 @@ jobs: - env: TOXENV=pypy PYTEST_NO_COVERAGE=1 python: 'pypy-5.4' dist: trusty - - env: TOXENV=py34 + - env: TOXENV=py34-xdist python: '3.4' - - env: TOXENV=py35 + - env: TOXENV=py35-xdist python: '3.5' - - env: TOXENV=py36 + - env: TOXENV=py36-xdist python: '3.6' - env: TOXENV=py37 - &test-macos @@ -49,9 +49,9 @@ jobs: sudo: required install: - python -m pip install --pre tox - env: TOXENV=py27 + env: TOXENV=py27-xdist - <<: *test-macos - env: TOXENV=py37 + env: TOXENV=py37-xdist before_install: - brew update - brew upgrade python @@ -65,7 +65,7 @@ jobs: python: '3.7' - stage: cron_only - env: TOXENV=py38 + env: TOXENV=py38-xdist python: '3.8-dev' - stage: deploy From 6fb7269979f80c04920e7ad793e7df772ca09db0 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Wed, 13 Feb 2019 22:42:04 +0100 Subject: [PATCH 09/15] terminal: write_fspath_result: work around py bug --- src/_pytest/terminal.py | 4 +++- testing/test_assertrewrite.py | 13 ++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index 33b76ec9c..f0834d870 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -280,7 +280,9 @@ class TerminalReporter(object): def write_fspath_result(self, nodeid, res, **markup): fspath = self.config.rootdir.join(nodeid.split("::")[0]) - if fspath != self.currentfspath: + # NOTE: explicitly check for None to work around py bug, and for less + # overhead in general (https://github.com/pytest-dev/py/pull/207). + if self.currentfspath is None or fspath != self.currentfspath: if self.currentfspath is not None and self._show_progress_info: self._write_progress_information_filling_space() self.currentfspath = fspath diff --git a/testing/test_assertrewrite.py b/testing/test_assertrewrite.py index a852277cc..bfb6acfab 100644 --- a/testing/test_assertrewrite.py +++ b/testing/test_assertrewrite.py @@ -1308,10 +1308,17 @@ class TestEarlyRewriteBailout(object): @pytest.mark.skipif( sys.platform.startswith("win32"), reason="cannot remove cwd on Windows" ) - def test_cwd_changed(self, testdir): + def test_cwd_changed(self, testdir, monkeypatch): + # Setup conditions for py's fspath trying to import pathlib on py34 + # always (previously triggered via xdist only). + # Ref: https://github.com/pytest-dev/py/pull/207 + monkeypatch.setattr(sys, "path", [""] + sys.path) + if "pathlib" in sys.modules: + del sys.modules["pathlib"] + testdir.makepyfile( **{ - "test_bar.py": """ + "test_setup_nonexisting_cwd.py": """ import os import shutil import tempfile @@ -1320,7 +1327,7 @@ class TestEarlyRewriteBailout(object): os.chdir(d) shutil.rmtree(d) """, - "test_foo.py": """ + "test_test.py": """ def test(): pass """, From 71373b04b057e7d40fe8d88f901bc4988e38a87a Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 8 Feb 2019 23:53:19 +0100 Subject: [PATCH 10/15] tox: add generic xdist factor Cherry-picked from features. Conflicts: tox.ini --- tox.ini | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/tox.ini b/tox.ini index 8041abb07..87d419890 100644 --- a/tox.ini +++ b/tox.ini @@ -20,19 +20,22 @@ envlist = [testenv] commands = - {env:_PYTEST_TOX_COVERAGE_RUN:} pytest --lsof {posargs} + {env:_PYTEST_TOX_COVERAGE_RUN:} pytest {env:_PYTEST_TOX_ARGS:} {posargs} coverage: coverage combine coverage: coverage report passenv = USER USERNAME COVERAGE_* TRAVIS PYTEST_ADDOPTS setenv = + _PYTEST_TOX_ARGS=--lsof # Configuration to run with coverage similar to Travis/Appveyor, e.g. # "tox -e py37-coverage". coverage: _PYTEST_TOX_COVERAGE_RUN=coverage run -m coverage: _PYTEST_TOX_EXTRA_DEP=coverage-enable-subprocess coverage: COVERAGE_FILE={toxinidir}/.coverage coverage: COVERAGE_PROCESS_START={toxinidir}/.coveragerc + xdist: _PYTEST_TOX_ARGS={env:_PYTEST_TOX_ARGS:-n auto} extras = testing deps = + xdist: pytest-xdist>=1.13 {env:_PYTEST_TOX_EXTRA_DEP:} [testenv:py27-subprocess] @@ -50,22 +53,6 @@ basepython = python3 deps = pre-commit>=1.11.0 commands = pre-commit run --all-files --show-diff-on-failure -[testenv:py27-xdist] -extras = testing -deps = - {[testenv]deps} - pytest-xdist>=1.13 -commands = - {env:_PYTEST_TOX_COVERAGE_RUN:} pytest -n auto {posargs} - -[testenv:py37-xdist] -# NOTE: copied from above due to https://github.com/tox-dev/tox/issues/706. -extras = testing -deps = - {[testenv]deps} - pytest-xdist>=1.13 -commands = {[testenv:py27-xdist]commands} - [testenv:py27-pexpect] platform = linux|darwin deps = From 40eef6da0c1df818f7479430c6b8ce88dc0d9a8d Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 11 Feb 2019 23:40:40 +0100 Subject: [PATCH 11/15] AppVeyor: use xdist for py?? envs, drop py27/py37 --- appveyor.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 2dea0180f..773e16b1b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,12 +2,10 @@ environment: matrix: - TOXENV: "py37-xdist" - TOXENV: "py27-xdist" - - TOXENV: "py27" - - TOXENV: "py37" - TOXENV: "linting,docs,doctesting" - - TOXENV: "py36" - - TOXENV: "py35" - - TOXENV: "py34" + - TOXENV: "py34-xdist" + - TOXENV: "py35-xdist" + - TOXENV: "py36-xdist" - TOXENV: "pypy" PYTEST_NO_COVERAGE: "1" # Specialized factors for py27. From 4f9e835472a70678012610201d24de4eecbeed0a Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Fri, 15 Feb 2019 18:51:42 +0100 Subject: [PATCH 12/15] Travis: remove cron_only stage, use conditional job Ref: https://github.com/pytest-dev/pytest/pull/4789#issuecomment-464135675 --- .travis.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index d42400844..9010ae1c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,6 @@ stages: if: repo = pytest-dev/pytest AND tag IS NOT present - name: deploy if: repo = pytest-dev/pytest AND tag IS present -- name: cron_only - if: type = cron python: - '3.7' install: @@ -58,16 +56,17 @@ jobs: - brew unlink python - brew link python + # Jobs only run via Travis cron jobs (currently daily). + - env: TOXENV=py38-xdist + python: '3.8-dev' + if: type = cron + - stage: baseline env: TOXENV=py27-pexpect,py27-trial,py27-numpy - env: TOXENV=py37-xdist - env: TOXENV=linting,docs,doctesting python: '3.7' - - stage: cron_only - env: TOXENV=py38-xdist - python: '3.8-dev' - - stage: deploy python: '3.6' env: PYTEST_NO_COVERAGE=1 From 31c869b4c49a999dee8c93eee3c8e2115cef0feb Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Sat, 16 Feb 2019 14:11:58 +0000 Subject: [PATCH 13/15] Preparing release version 4.3.0 --- CHANGELOG.rst | 42 +++++++++++++++ changelog/2753.feature.rst | 1 - changelog/3711.feature.rst | 2 - changelog/4651.bugfix.rst | 1 - changelog/4698.feature.rst | 5 -- changelog/4707.feature.rst | 1 - changelog/4724.deprecation.rst | 3 -- changelog/4782.bugfix.rst | 1 - doc/en/announce/index.rst | 1 + doc/en/announce/release-4.3.0.rst | 36 +++++++++++++ doc/en/cache.rst | 86 +++++++++++++++++++++++++++++-- 11 files changed, 161 insertions(+), 18 deletions(-) delete mode 100644 changelog/2753.feature.rst delete mode 100644 changelog/3711.feature.rst delete mode 100644 changelog/4651.bugfix.rst delete mode 100644 changelog/4698.feature.rst delete mode 100644 changelog/4707.feature.rst delete mode 100644 changelog/4724.deprecation.rst delete mode 100644 changelog/4782.bugfix.rst create mode 100644 doc/en/announce/release-4.3.0.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b1791a6b9..9f98f6408 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,6 +18,48 @@ with advance notice in the **Deprecations** section of releases. .. towncrier release notes start +pytest 4.3.0 (2019-02-16) +========================= + +Deprecations +------------ + +- `#4724 `_: ``pytest.warns()`` now emits a warning when it receives unknown keyword arguments. + + This will be changed into an error in the future. + + + +Features +-------- + +- `#2753 `_: Usage errors from argparse are mapped to pytest's ``UsageError``. + + +- `#3711 `_: Add the ``--ignore-glob`` parameter to exclude test-modules with Unix shell-style wildcards. + Add the ``collect_ignore_glob`` for ``conftest.py`` to exclude test-modules with Unix shell-style wildcards. + + +- `#4698 `_: The warning about Python 2.7 and 3.4 not being supported in pytest 5.0 has been removed. + + In the end it was considered to be more + of a nuisance than actual utility and users of those Python versions shouldn't have problems as ``pip`` will not + install pytest 5.0 on those interpreters. + + +- `#4707 `_: With the help of new ``set_log_path()`` method there is a way to set ``log_file`` paths from hooks. + + + +Bug Fixes +--------- + +- `#4651 `_: ``--help`` and ``--version`` are handled with ``UsageError``. + + +- `#4782 `_: Fix ``AssertionError`` with collection of broken symlinks with packages. + + pytest 4.2.1 (2019-02-12) ========================= diff --git a/changelog/2753.feature.rst b/changelog/2753.feature.rst deleted file mode 100644 index 067e0cad7..000000000 --- a/changelog/2753.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Usage errors from argparse are mapped to pytest's ``UsageError``. diff --git a/changelog/3711.feature.rst b/changelog/3711.feature.rst deleted file mode 100644 index 1503bac60..000000000 --- a/changelog/3711.feature.rst +++ /dev/null @@ -1,2 +0,0 @@ -Add the ``--ignore-glob`` parameter to exclude test-modules with Unix shell-style wildcards. -Add the ``collect_ignore_glob`` for ``conftest.py`` to exclude test-modules with Unix shell-style wildcards. diff --git a/changelog/4651.bugfix.rst b/changelog/4651.bugfix.rst deleted file mode 100644 index f9c639f3e..000000000 --- a/changelog/4651.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -``--help`` and ``--version`` are handled with ``UsageError``. diff --git a/changelog/4698.feature.rst b/changelog/4698.feature.rst deleted file mode 100644 index 18d4c0216..000000000 --- a/changelog/4698.feature.rst +++ /dev/null @@ -1,5 +0,0 @@ -The warning about Python 2.7 and 3.4 not being supported in pytest 5.0 has been removed. - -In the end it was considered to be more -of a nuisance than actual utility and users of those Python versions shouldn't have problems as ``pip`` will not -install pytest 5.0 on those interpreters. diff --git a/changelog/4707.feature.rst b/changelog/4707.feature.rst deleted file mode 100644 index 20c387eb9..000000000 --- a/changelog/4707.feature.rst +++ /dev/null @@ -1 +0,0 @@ -With the help of new ``set_log_path()`` method there is a way to set ``log_file`` paths from hooks. diff --git a/changelog/4724.deprecation.rst b/changelog/4724.deprecation.rst deleted file mode 100644 index 6dc2fe98c..000000000 --- a/changelog/4724.deprecation.rst +++ /dev/null @@ -1,3 +0,0 @@ -``pytest.warns()`` now emits a warning when it receives unknown keyword arguments. - -This will be changed into an error in the future. diff --git a/changelog/4782.bugfix.rst b/changelog/4782.bugfix.rst deleted file mode 100644 index 12e08d00c..000000000 --- a/changelog/4782.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``AssertionError`` with collection of broken symlinks with packages. diff --git a/doc/en/announce/index.rst b/doc/en/announce/index.rst index 62cf5c783..9574229d0 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,7 @@ Release announcements :maxdepth: 2 + release-4.3.0 release-4.2.1 release-4.2.0 release-4.1.1 diff --git a/doc/en/announce/release-4.3.0.rst b/doc/en/announce/release-4.3.0.rst new file mode 100644 index 000000000..593938148 --- /dev/null +++ b/doc/en/announce/release-4.3.0.rst @@ -0,0 +1,36 @@ +pytest-4.3.0 +======================================= + +The pytest team is proud to announce the 4.3.0 release! + +pytest is a mature Python testing tool with more than a 2000 tests +against itself, passing on many different interpreters and platforms. + +This release contains a number of bugs fixes and improvements, so users are encouraged +to take a look at the CHANGELOG: + + https://docs.pytest.org/en/latest/changelog.html + +For complete documentation, please visit: + + https://docs.pytest.org/en/latest/ + +As usual, you can upgrade from pypi via: + + pip install -U pytest + +Thanks to all who contributed to this release, among them: + +* Andras Mitzki +* Anthony Sottile +* Bruno Oliveira +* Christian Fetzer +* Daniel Hahler +* Grygorii Iermolenko +* R. Alex Matevish +* Ronny Pfannschmidt +* cclauss + + +Happy testing, +The Pytest Development Team diff --git a/doc/en/cache.rst b/doc/en/cache.rst index 0cb42e6e9..c5a81b13f 100644 --- a/doc/en/cache.rst +++ b/doc/en/cache.rst @@ -220,8 +220,6 @@ If you run this command for the first time, you can see the print statement: E +23 test_caching.py:17: AssertionError - -------------------------- Captured stdout setup --------------------------- - running expensive computation... 1 failed in 0.12 seconds If you run it a second time the value will be retrieved from @@ -264,12 +262,92 @@ You can always peek at the content of the cache using the cachedir: $PYTHON_PREFIX/.pytest_cache ------------------------------- cache values ------------------------------- cache/lastfailed contains: - {'test_50.py::test_num[17]': True, + {'a/test_db.py::test_a1': True, + 'a/test_db2.py::test_a2': True, + 'b/test_error.py::test_root': True, + 'failure_demo.py::TestCustomAssertMsg::test_custom_repr': True, + 'failure_demo.py::TestCustomAssertMsg::test_multiline': True, + 'failure_demo.py::TestCustomAssertMsg::test_single_line': True, + 'failure_demo.py::TestFailing::test_not': True, + 'failure_demo.py::TestFailing::test_simple': True, + 'failure_demo.py::TestFailing::test_simple_multiline': True, + 'failure_demo.py::TestMoreErrors::test_compare': True, + 'failure_demo.py::TestMoreErrors::test_complex_error': True, + 'failure_demo.py::TestMoreErrors::test_global_func': True, + 'failure_demo.py::TestMoreErrors::test_instance': True, + 'failure_demo.py::TestMoreErrors::test_startswith': True, + 'failure_demo.py::TestMoreErrors::test_startswith_nested': True, + 'failure_demo.py::TestMoreErrors::test_try_finally': True, + 'failure_demo.py::TestMoreErrors::test_z1_unpack_error': True, + 'failure_demo.py::TestMoreErrors::test_z2_type_error': True, + 'failure_demo.py::TestRaises::test_raise': True, + 'failure_demo.py::TestRaises::test_raises': True, + 'failure_demo.py::TestRaises::test_raises_doesnt': True, + 'failure_demo.py::TestRaises::test_reinterpret_fails_with_print_for_the_fun_of_it': True, + 'failure_demo.py::TestRaises::test_some_error': True, + 'failure_demo.py::TestRaises::test_tupleerror': True, + 'failure_demo.py::TestSpecialisedExplanations::test_eq_attrs': True, + 'failure_demo.py::TestSpecialisedExplanations::test_eq_dataclass': True, + 'failure_demo.py::TestSpecialisedExplanations::test_eq_dict': True, + 'failure_demo.py::TestSpecialisedExplanations::test_eq_list': True, + 'failure_demo.py::TestSpecialisedExplanations::test_eq_list_long': True, + 'failure_demo.py::TestSpecialisedExplanations::test_eq_long_text': True, + 'failure_demo.py::TestSpecialisedExplanations::test_eq_long_text_multiline': True, + 'failure_demo.py::TestSpecialisedExplanations::test_eq_longer_list': True, + 'failure_demo.py::TestSpecialisedExplanations::test_eq_multiline_text': True, + 'failure_demo.py::TestSpecialisedExplanations::test_eq_set': True, + 'failure_demo.py::TestSpecialisedExplanations::test_eq_similar_text': True, + 'failure_demo.py::TestSpecialisedExplanations::test_eq_text': True, + 'failure_demo.py::TestSpecialisedExplanations::test_in_list': True, + 'failure_demo.py::TestSpecialisedExplanations::test_not_in_text_multiline': True, + 'failure_demo.py::TestSpecialisedExplanations::test_not_in_text_single': True, + 'failure_demo.py::TestSpecialisedExplanations::test_not_in_text_single_long': True, + 'failure_demo.py::TestSpecialisedExplanations::test_not_in_text_single_long_term': True, + 'failure_demo.py::test_attribute': True, + 'failure_demo.py::test_attribute_failure': True, + 'failure_demo.py::test_attribute_instance': True, + 'failure_demo.py::test_attribute_multiple': True, + 'failure_demo.py::test_dynamic_compile_shows_nicely': True, + 'failure_demo.py::test_generative[3-6]': True, + 'test_50.py::test_num[17]': True, 'test_50.py::test_num[25]': True, + 'test_anothersmtp.py::test_showhelo': True, 'test_assert1.py::test_function': True, 'test_assert2.py::test_set_comparison': True, + 'test_backends.py::test_db_initialized[d2]': True, 'test_caching.py::test_function': True, - 'test_foocompare.py::test_compare': True} + 'test_checkconfig.py::test_something': True, + 'test_class.py::TestClass::test_two': True, + 'test_compute.py::test_compute[4]': True, + 'test_example.py::test_error': True, + 'test_example.py::test_fail': True, + 'test_foocompare.py::test_compare': True, + 'test_module.py::test_call_fails': True, + 'test_module.py::test_ehlo': True, + 'test_module.py::test_ehlo[mail.python.org]': True, + 'test_module.py::test_ehlo[smtp.gmail.com]': True, + 'test_module.py::test_event_simple': True, + 'test_module.py::test_fail1': True, + 'test_module.py::test_fail2': True, + 'test_module.py::test_func2': True, + 'test_module.py::test_interface_complex': True, + 'test_module.py::test_interface_simple': True, + 'test_module.py::test_noop': True, + 'test_module.py::test_noop[mail.python.org]': True, + 'test_module.py::test_noop[smtp.gmail.com]': True, + 'test_module.py::test_setup_fails': True, + 'test_parametrize.py::TestClass::test_equals[1-2]': True, + 'test_sample.py::test_answer': True, + 'test_show_warnings.py::test_one': True, + 'test_simple.yml::hello': True, + 'test_smtpsimple.py::test_ehlo': True, + 'test_step.py::TestUserHandling::test_modification': True, + 'test_strings.py::test_valid_string[!]': True, + 'test_tmp_path.py::test_create_file': True, + 'test_tmpdir.py::test_create_file': True, + 'test_tmpdir.py::test_needsfiles': True, + 'test_unittest_db.py::MyTest::test_method1': True, + 'test_unittest_db.py::MyTest::test_method2': True} cache/nodeids contains: ['test_caching.py::test_function'] cache/stepwise contains: From 5505826db921b0e46c30004ea20b6bf6e478e683 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Fri, 15 Feb 2019 17:34:31 -0800 Subject: [PATCH 14/15] Fix python3.8 / pypy failures --- testing/code/test_source.py | 11 ++++++++--- testing/test_skipping.py | 5 ++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/testing/code/test_source.py b/testing/code/test_source.py index 0103acb70..fc5eaed04 100644 --- a/testing/code/test_source.py +++ b/testing/code/test_source.py @@ -560,7 +560,6 @@ def test_oneline_and_comment(): assert str(source) == "raise ValueError" -@pytest.mark.xfail(hasattr(sys, "pypy_version_info"), reason="does not work on pypy") def test_comments(): source = '''def test(): "comment 1" @@ -576,9 +575,15 @@ comment 4 ''' for line in range(2, 6): assert str(getstatement(line, source)) == " x = 1" - for line in range(6, 10): + if sys.version_info >= (3, 8) or hasattr(sys, "pypy_version_info"): + tqs_start = 8 + else: + tqs_start = 10 + assert str(getstatement(10, source)) == '"""' + for line in range(6, tqs_start): assert str(getstatement(line, source)) == " assert False" - assert str(getstatement(10, source)) == '"""' + for line in range(tqs_start, 10): + assert str(getstatement(line, source)) == '"""\ncomment 4\n"""' def test_comment_in_statement(): diff --git a/testing/test_skipping.py b/testing/test_skipping.py index b2a515f11..33878c8f4 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -910,7 +910,6 @@ def test_reportchars_all_error(testdir): result.stdout.fnmatch_lines(["ERROR*test_foo*"]) -@pytest.mark.xfail("hasattr(sys, 'pypy_version_info')") def test_errors_in_xfail_skip_expressions(testdir): testdir.makepyfile( """ @@ -931,6 +930,10 @@ def test_errors_in_xfail_skip_expressions(testdir): if sys.platform.startswith("java"): # XXX report this to java markline = "*" + markline[8:] + elif hasattr(sys, "pypy_version_info") and sys.pypy_version_info < (6,): + markline = markline[5:] + elif sys.version_info >= (3, 8) or hasattr(sys, "pypy_version_info"): + markline = markline[4:] result.stdout.fnmatch_lines( [ "*ERROR*test_nameerror*", From ff015f630851927a39899b35b175a39945dd6c74 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 18 Feb 2019 18:46:03 +0100 Subject: [PATCH 15/15] Fix docs (tox -e regen, plus pre-commit) --- doc/en/cache.rst | 86 ++-------------------------------- doc/en/example/parametrize.rst | 6 +-- 2 files changed, 6 insertions(+), 86 deletions(-) diff --git a/doc/en/cache.rst b/doc/en/cache.rst index c5a81b13f..0cb42e6e9 100644 --- a/doc/en/cache.rst +++ b/doc/en/cache.rst @@ -220,6 +220,8 @@ If you run this command for the first time, you can see the print statement: E +23 test_caching.py:17: AssertionError + -------------------------- Captured stdout setup --------------------------- + running expensive computation... 1 failed in 0.12 seconds If you run it a second time the value will be retrieved from @@ -262,92 +264,12 @@ You can always peek at the content of the cache using the cachedir: $PYTHON_PREFIX/.pytest_cache ------------------------------- cache values ------------------------------- cache/lastfailed contains: - {'a/test_db.py::test_a1': True, - 'a/test_db2.py::test_a2': True, - 'b/test_error.py::test_root': True, - 'failure_demo.py::TestCustomAssertMsg::test_custom_repr': True, - 'failure_demo.py::TestCustomAssertMsg::test_multiline': True, - 'failure_demo.py::TestCustomAssertMsg::test_single_line': True, - 'failure_demo.py::TestFailing::test_not': True, - 'failure_demo.py::TestFailing::test_simple': True, - 'failure_demo.py::TestFailing::test_simple_multiline': True, - 'failure_demo.py::TestMoreErrors::test_compare': True, - 'failure_demo.py::TestMoreErrors::test_complex_error': True, - 'failure_demo.py::TestMoreErrors::test_global_func': True, - 'failure_demo.py::TestMoreErrors::test_instance': True, - 'failure_demo.py::TestMoreErrors::test_startswith': True, - 'failure_demo.py::TestMoreErrors::test_startswith_nested': True, - 'failure_demo.py::TestMoreErrors::test_try_finally': True, - 'failure_demo.py::TestMoreErrors::test_z1_unpack_error': True, - 'failure_demo.py::TestMoreErrors::test_z2_type_error': True, - 'failure_demo.py::TestRaises::test_raise': True, - 'failure_demo.py::TestRaises::test_raises': True, - 'failure_demo.py::TestRaises::test_raises_doesnt': True, - 'failure_demo.py::TestRaises::test_reinterpret_fails_with_print_for_the_fun_of_it': True, - 'failure_demo.py::TestRaises::test_some_error': True, - 'failure_demo.py::TestRaises::test_tupleerror': True, - 'failure_demo.py::TestSpecialisedExplanations::test_eq_attrs': True, - 'failure_demo.py::TestSpecialisedExplanations::test_eq_dataclass': True, - 'failure_demo.py::TestSpecialisedExplanations::test_eq_dict': True, - 'failure_demo.py::TestSpecialisedExplanations::test_eq_list': True, - 'failure_demo.py::TestSpecialisedExplanations::test_eq_list_long': True, - 'failure_demo.py::TestSpecialisedExplanations::test_eq_long_text': True, - 'failure_demo.py::TestSpecialisedExplanations::test_eq_long_text_multiline': True, - 'failure_demo.py::TestSpecialisedExplanations::test_eq_longer_list': True, - 'failure_demo.py::TestSpecialisedExplanations::test_eq_multiline_text': True, - 'failure_demo.py::TestSpecialisedExplanations::test_eq_set': True, - 'failure_demo.py::TestSpecialisedExplanations::test_eq_similar_text': True, - 'failure_demo.py::TestSpecialisedExplanations::test_eq_text': True, - 'failure_demo.py::TestSpecialisedExplanations::test_in_list': True, - 'failure_demo.py::TestSpecialisedExplanations::test_not_in_text_multiline': True, - 'failure_demo.py::TestSpecialisedExplanations::test_not_in_text_single': True, - 'failure_demo.py::TestSpecialisedExplanations::test_not_in_text_single_long': True, - 'failure_demo.py::TestSpecialisedExplanations::test_not_in_text_single_long_term': True, - 'failure_demo.py::test_attribute': True, - 'failure_demo.py::test_attribute_failure': True, - 'failure_demo.py::test_attribute_instance': True, - 'failure_demo.py::test_attribute_multiple': True, - 'failure_demo.py::test_dynamic_compile_shows_nicely': True, - 'failure_demo.py::test_generative[3-6]': True, - 'test_50.py::test_num[17]': True, + {'test_50.py::test_num[17]': True, 'test_50.py::test_num[25]': True, - 'test_anothersmtp.py::test_showhelo': True, 'test_assert1.py::test_function': True, 'test_assert2.py::test_set_comparison': True, - 'test_backends.py::test_db_initialized[d2]': True, 'test_caching.py::test_function': True, - 'test_checkconfig.py::test_something': True, - 'test_class.py::TestClass::test_two': True, - 'test_compute.py::test_compute[4]': True, - 'test_example.py::test_error': True, - 'test_example.py::test_fail': True, - 'test_foocompare.py::test_compare': True, - 'test_module.py::test_call_fails': True, - 'test_module.py::test_ehlo': True, - 'test_module.py::test_ehlo[mail.python.org]': True, - 'test_module.py::test_ehlo[smtp.gmail.com]': True, - 'test_module.py::test_event_simple': True, - 'test_module.py::test_fail1': True, - 'test_module.py::test_fail2': True, - 'test_module.py::test_func2': True, - 'test_module.py::test_interface_complex': True, - 'test_module.py::test_interface_simple': True, - 'test_module.py::test_noop': True, - 'test_module.py::test_noop[mail.python.org]': True, - 'test_module.py::test_noop[smtp.gmail.com]': True, - 'test_module.py::test_setup_fails': True, - 'test_parametrize.py::TestClass::test_equals[1-2]': True, - 'test_sample.py::test_answer': True, - 'test_show_warnings.py::test_one': True, - 'test_simple.yml::hello': True, - 'test_smtpsimple.py::test_ehlo': True, - 'test_step.py::TestUserHandling::test_modification': True, - 'test_strings.py::test_valid_string[!]': True, - 'test_tmp_path.py::test_create_file': True, - 'test_tmpdir.py::test_create_file': True, - 'test_tmpdir.py::test_needsfiles': True, - 'test_unittest_db.py::MyTest::test_method1': True, - 'test_unittest_db.py::MyTest::test_method2': True} + 'test_foocompare.py::test_compare': True} cache/nodeids contains: ['test_caching.py::test_function'] cache/stepwise contains: diff --git a/doc/en/example/parametrize.rst b/doc/en/example/parametrize.rst index b5d4693ad..05932d164 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -436,10 +436,8 @@ Running it results in some skips if we don't have all the python interpreters in .. code-block:: pytest . $ pytest -rs -q multipython.py - ...sss...sssssssss...sss... [100%] - ========================= short test summary info ========================== - SKIPPED [15] $REGENDOC_TMPDIR/CWD/multipython.py:30: 'python3.4' not found - 12 passed, 15 skipped in 0.12 seconds + ........................... [100%] + 27 passed in 0.12 seconds Indirect parametrization of optional implementations/imports --------------------------------------------------------------------