From 64ee1ee81b634ea5a1d4dc1914a18347973ee882 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Sun, 9 Dec 2018 11:53:41 +0100 Subject: [PATCH 1/9] tests: fix tests that require PYTEST_DISABLE_PLUGIN_AUTOLOAD to be unset Fix pytest's own tests with PYTEST_DISABLE_PLUGIN_AUTOLOAD=1. --- testing/test_assertion.py | 3 ++- testing/test_config.py | 3 +++ testing/test_junitxml.py | 3 ++- testing/test_terminal.py | 12 ++++++++---- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/testing/test_assertion.py b/testing/test_assertion.py index b6c31aba2..6f5852e54 100644 --- a/testing/test_assertion.py +++ b/testing/test_assertion.py @@ -153,7 +153,8 @@ class TestImportHookInstallation(object): @pytest.mark.parametrize("mode", ["plain", "rewrite"]) @pytest.mark.parametrize("plugin_state", ["development", "installed"]) - def test_installed_plugin_rewrite(self, testdir, mode, plugin_state): + def test_installed_plugin_rewrite(self, testdir, mode, plugin_state, monkeypatch): + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) # Make sure the hook is installed early enough so that plugins # installed via setuptools are rewritten. testdir.tmpdir.join("hampkg").ensure(dir=1) diff --git a/testing/test_config.py b/testing/test_config.py index 605d28aa0..185c7d396 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -511,6 +511,7 @@ def test_options_on_small_file_do_not_blow_up(testdir): def test_preparse_ordering_with_setuptools(testdir, monkeypatch): pkg_resources = pytest.importorskip("pkg_resources") + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) def my_iter(name): assert name == "pytest11" @@ -548,6 +549,7 @@ def test_preparse_ordering_with_setuptools(testdir, monkeypatch): def test_setuptools_importerror_issue1479(testdir, monkeypatch): pkg_resources = pytest.importorskip("pkg_resources") + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) def my_iter(name): assert name == "pytest11" @@ -576,6 +578,7 @@ def test_setuptools_importerror_issue1479(testdir, monkeypatch): @pytest.mark.parametrize("block_it", [True, False]) def test_plugin_preparse_prevents_setuptools_loading(testdir, monkeypatch, block_it): pkg_resources = pytest.importorskip("pkg_resources") + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) plugin_module_placeholder = object() diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index c9dc39f82..e04af1ec3 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -1032,12 +1032,13 @@ def test_record_attribute(testdir): ) -def test_random_report_log_xdist(testdir): +def test_random_report_log_xdist(testdir, monkeypatch): """xdist calls pytest_runtest_logreport as they are executed by the slaves, with nodes from several nodes overlapping, so junitxml must cope with that to produce correct reports. #1064 """ pytest.importorskip("xdist") + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) testdir.makepyfile( """ import pytest, time diff --git a/testing/test_terminal.py b/testing/test_terminal.py index 86ec1cd07..019dd66f4 100644 --- a/testing/test_terminal.py +++ b/testing/test_terminal.py @@ -1331,13 +1331,15 @@ class TestProgressOutputStyle(object): ] ) - def test_xdist_normal(self, many_tests_files, testdir): + def test_xdist_normal(self, many_tests_files, testdir, monkeypatch): pytest.importorskip("xdist") + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) output = testdir.runpytest("-n2") output.stdout.re_match_lines([r"\.{20} \s+ \[100%\]"]) - def test_xdist_normal_count(self, many_tests_files, testdir): + def test_xdist_normal_count(self, many_tests_files, testdir, monkeypatch): pytest.importorskip("xdist") + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) testdir.makeini( """ [pytest] @@ -1347,8 +1349,9 @@ class TestProgressOutputStyle(object): output = testdir.runpytest("-n2") output.stdout.re_match_lines([r"\.{20} \s+ \[20/20\]"]) - def test_xdist_verbose(self, many_tests_files, testdir): + def test_xdist_verbose(self, many_tests_files, testdir, monkeypatch): pytest.importorskip("xdist") + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) output = testdir.runpytest("-n2", "-v") output.stdout.re_match_lines_random( [ @@ -1442,7 +1445,8 @@ class TestProgressWithTeardown(object): ] ) - def test_xdist_normal(self, many_files, testdir): + def test_xdist_normal(self, many_files, testdir, monkeypatch): pytest.importorskip("xdist") + monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD", raising=False) output = testdir.runpytest("-n2") output.stdout.re_match_lines([r"[\.E]{40} \s+ \[100%\]"]) From a254ad0436a922cb180015cdaec1bfe1cef8eb07 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 12 Dec 2018 14:58:48 -0800 Subject: [PATCH 2/9] Raise `TypeError` for `with raises(..., match=)`. --- changelog/4538.bugfix.rst | 1 + src/_pytest/python_api.py | 2 +- testing/python/raises.py | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 changelog/4538.bugfix.rst diff --git a/changelog/4538.bugfix.rst b/changelog/4538.bugfix.rst new file mode 100644 index 000000000..0ecfb5be0 --- /dev/null +++ b/changelog/4538.bugfix.rst @@ -0,0 +1 @@ +Raise ``TypeError`` for ``with raises(..., match=)``. diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index 7de8e154c..37eafa7f0 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -716,6 +716,6 @@ class RaisesContext(object): suppress_exception = issubclass(self.excinfo.type, self.expected_exception) if sys.version_info[0] == 2 and suppress_exception: sys.exc_clear() - if self.match_expr and suppress_exception: + if self.match_expr is not None and suppress_exception: self.excinfo.match(self.match_expr) return suppress_exception diff --git a/testing/python/raises.py b/testing/python/raises.py index 912d34673..2ee18b173 100644 --- a/testing/python/raises.py +++ b/testing/python/raises.py @@ -37,6 +37,11 @@ class TestRaises(object): except pytest.raises.Exception: pass + def test_raises_falsey_type_error(self): + with pytest.raises(TypeError): + with pytest.raises(AssertionError, match=0): + raise AssertionError("ohai") + def test_raises_repr_inflight(self): """Ensure repr() on an exception info inside a pytest.raises with block works (#4386)""" From 6c5a1150d46f0392e84d6c9f28ace48d5199ca22 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 13 Dec 2018 23:37:51 +0000 Subject: [PATCH 3/9] Preparing release version 4.0.2 --- CHANGELOG.rst | 25 +++++++++++++++++++++++++ changelog/1495.doc.rst | 1 - changelog/4265.bugfix.rst | 1 - changelog/4435.bugfix.rst | 1 - changelog/4500.bugfix.rst | 1 - changelog/4538.bugfix.rst | 1 - doc/en/announce/index.rst | 1 + doc/en/announce/release-4.0.2.rst | 24 ++++++++++++++++++++++++ doc/en/example/parametrize.rst | 2 +- 9 files changed, 51 insertions(+), 6 deletions(-) delete mode 100644 changelog/1495.doc.rst delete mode 100644 changelog/4265.bugfix.rst delete mode 100644 changelog/4435.bugfix.rst delete mode 100644 changelog/4500.bugfix.rst delete mode 100644 changelog/4538.bugfix.rst create mode 100644 doc/en/announce/release-4.0.2.rst diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8e0ba82e4..22f3ac862 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,6 +18,31 @@ with advance notice in the **Deprecations** section of releases. .. towncrier release notes start +pytest 4.0.2 (2018-12-13) +========================= + +Bug Fixes +--------- + +- `#4265 `_: Validate arguments from the ``PYTEST_ADDOPTS`` environment variable and the ``addopts`` ini option separately. + + +- `#4435 `_: Fix ``raises(..., 'code(string)')`` frame filename. + + +- `#4500 `_: When a fixture yields and a log call is made after the test runs, and, if the test is interrupted, capture attributes are ``None``. + + +- `#4538 `_: Raise ``TypeError`` for ``with raises(..., match=)``. + + + +Improved Documentation +---------------------- + +- `#1495 `_: Document common doctest fixture directory tree structure pitfalls + + pytest 4.0.1 (2018-11-23) ========================= diff --git a/changelog/1495.doc.rst b/changelog/1495.doc.rst deleted file mode 100644 index ab7231333..000000000 --- a/changelog/1495.doc.rst +++ /dev/null @@ -1 +0,0 @@ -Document common doctest fixture directory tree structure pitfalls diff --git a/changelog/4265.bugfix.rst b/changelog/4265.bugfix.rst deleted file mode 100644 index 7b40737c3..000000000 --- a/changelog/4265.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Validate arguments from the ``PYTEST_ADDOPTS`` environment variable and the ``addopts`` ini option separately. diff --git a/changelog/4435.bugfix.rst b/changelog/4435.bugfix.rst deleted file mode 100644 index de60b5e62..000000000 --- a/changelog/4435.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fix ``raises(..., 'code(string)')`` frame filename. diff --git a/changelog/4500.bugfix.rst b/changelog/4500.bugfix.rst deleted file mode 100644 index b84b6b117..000000000 --- a/changelog/4500.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -When a fixture yields and a log call is made after the test runs, and, if the test is interrupted, capture attributes are ``None``. diff --git a/changelog/4538.bugfix.rst b/changelog/4538.bugfix.rst deleted file mode 100644 index 0ecfb5be0..000000000 --- a/changelog/4538.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Raise ``TypeError`` for ``with raises(..., match=)``. diff --git a/doc/en/announce/index.rst b/doc/en/announce/index.rst index 4120ccfc9..d6379f1b3 100644 --- a/doc/en/announce/index.rst +++ b/doc/en/announce/index.rst @@ -6,6 +6,7 @@ Release announcements :maxdepth: 2 + release-4.0.2 release-4.0.1 release-4.0.0 release-3.10.1 diff --git a/doc/en/announce/release-4.0.2.rst b/doc/en/announce/release-4.0.2.rst new file mode 100644 index 000000000..3b6e4be71 --- /dev/null +++ b/doc/en/announce/release-4.0.2.rst @@ -0,0 +1,24 @@ +pytest-4.0.2 +======================================= + +pytest 4.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/latest/changelog.html. + +Thanks to all who contributed to this release, among them: + +* Anthony Sottile +* Bruno Oliveira +* Daniel Hahler +* Pedro Algarvio +* Ronny Pfannschmidt +* Tomer Keren +* Yash Todi + + +Happy testing, +The pytest Development Team diff --git a/doc/en/example/parametrize.rst b/doc/en/example/parametrize.rst index 488f6e310..16e48878c 100644 --- a/doc/en/example/parametrize.rst +++ b/doc/en/example/parametrize.rst @@ -537,7 +537,7 @@ Then run ``pytest`` with verbose mode and with only the ``basic`` marker: $ pytest -v -m basic =========================== test session starts ============================ - platform linux -- Python 3.x.y, pytest-4.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python + platform linux -- Python 3.x.y, pytest-4.x.y, py-1.x.y, pluggy-0.x.y -- $PYTHON_PREFIX/bin/python3.6 cachedir: .pytest_cache rootdir: $REGENDOC_TMPDIR, inifile: collecting ... collected 17 items / 14 deselected From 1e80a9cb34c73066cc8fa232be9b20fe284b8ae9 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Thu, 13 Dec 2018 21:14:41 -0200 Subject: [PATCH 4/9] Remove pytest_funcarg__ prefix support for defining fixtures Fix #4543 --- changelog/4543.removal.rst | 3 +++ doc/en/deprecations.rst | 41 +++++++++++++++++----------------- src/_pytest/config/__init__.py | 4 ++-- src/_pytest/deprecated.py | 6 ----- src/_pytest/fixtures.py | 31 ++++--------------------- testing/deprecated_test.py | 22 ------------------ testing/python/fixture.py | 19 ---------------- 7 files changed, 30 insertions(+), 96 deletions(-) create mode 100644 changelog/4543.removal.rst diff --git a/changelog/4543.removal.rst b/changelog/4543.removal.rst new file mode 100644 index 000000000..f810b5bad --- /dev/null +++ b/changelog/4543.removal.rst @@ -0,0 +1,3 @@ +Remove support to define fixtures using the ``pytest_funcarg__`` prefix. Use the ``@pytest.fixture`` decorator instead. + +See our `docs `__ on information on how to update your code. diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index a2f16d974..37cffb1fb 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -237,26 +237,6 @@ By passing a string, users expect that pytest will interpret that command-line u on (for example ``bash`` or ``Powershell``), but this is very hard/impossible to do in a portable way. -``pytest_funcarg__`` prefix -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. deprecated:: 3.0 - -In very early pytest versions fixtures could be defined using the ``pytest_funcarg__`` prefix: - -.. code-block:: python - - def pytest_funcarg__data(): - return SomeData() - -Switch over to the ``@pytest.fixture`` decorator: - -.. code-block:: python - - @pytest.fixture - def data(): - return SomeData() - [pytest] section in setup.cfg files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -295,6 +275,27 @@ collection. This issue should affect only advanced plugins who create new collection types, so if you see this warning message please contact the authors so they can change the code. +``pytest_funcarg__`` prefix +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +*Removed in version 4.0.* + +In very early pytest versions fixtures could be defined using the ``pytest_funcarg__`` prefix: + +.. code-block:: python + + def pytest_funcarg__data(): + return SomeData() + +Switch over to the ``@pytest.fixture`` decorator: + +.. code-block:: python + + @pytest.fixture + def data(): + return SomeData() + + Metafunc.addcall ~~~~~~~~~~~~~~~~ diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index fafd8c930..3ed82694b 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -261,8 +261,8 @@ class PytestPluginManager(PluginManager): # (see issue #1073) if not name.startswith("pytest_"): return - # ignore some historic special names which can not be hooks anyway - if name == "pytest_plugins" or name.startswith("pytest_funcarg__"): + # ignore names which can not be hooks + if name == "pytest_plugins": return method = getattr(plugin, name) diff --git a/src/_pytest/deprecated.py b/src/_pytest/deprecated.py index 426533a0c..67f0d534f 100644 --- a/src/_pytest/deprecated.py +++ b/src/_pytest/deprecated.py @@ -24,12 +24,6 @@ MAIN_STR_ARGS = RemovedInPytest4Warning( YIELD_TESTS = "yield tests were removed in pytest 4.0 - {name} will be ignored" -FUNCARG_PREFIX = UnformattedWarning( - RemovedInPytest4Warning, - '{name}: declaring fixtures using "pytest_funcarg__" prefix is deprecated ' - "and scheduled to be removed in pytest 4.0. " - "Please remove the prefix and use the @pytest.fixture decorator instead.", -) FIXTURE_FUNCTION_CALL = UnformattedWarning( RemovedInPytest4Warning, diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 3e5ad5f73..0136dea09 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -38,8 +38,6 @@ from _pytest.deprecated import FIXTURE_NAMED_REQUEST from _pytest.outcomes import fail from _pytest.outcomes import TEST_OUTCOME -FIXTURE_MSG = 'fixtures cannot have "pytest_funcarg__" prefix and be decorated with @pytest.fixture:\n{}' - @attr.s(frozen=True) class PseudoFixtureDef(object): @@ -1117,7 +1115,6 @@ class FixtureManager(object): by a lookup of their FuncFixtureInfo. """ - _argprefix = "pytest_funcarg__" FixtureLookupError = FixtureLookupError FixtureLookupErrorRepr = FixtureLookupErrorRepr @@ -1255,8 +1252,6 @@ class FixtureManager(object): items[:] = reorder_items(items) def parsefactories(self, node_or_obj, nodeid=NOTSET, unittest=False): - from _pytest import deprecated - if nodeid is not NOTSET: holderobj = node_or_obj else: @@ -1272,31 +1267,13 @@ class FixtureManager(object): # access below can raise. safe_getatt() ignores such exceptions. obj = safe_getattr(holderobj, name, None) marker = getfixturemarker(obj) - # fixture functions have a pytest_funcarg__ prefix (pre-2.3 style) - # or are "@pytest.fixture" marked - if marker is None: - if not name.startswith(self._argprefix): - continue - if not callable(obj): - continue - marker = defaultfuncargprefixmarker - - filename, lineno = getfslineno(obj) - warnings.warn_explicit( - deprecated.FUNCARG_PREFIX.format(name=name), - category=None, - filename=str(filename), - lineno=lineno + 1, - ) - name = name[len(self._argprefix) :] - elif not isinstance(marker, FixtureFunctionMarker): + if not isinstance(marker, FixtureFunctionMarker): # magic globals with __getattr__ might have got us a wrong # fixture attribute continue - else: - if marker.name: - name = marker.name - assert not name.startswith(self._argprefix), FIXTURE_MSG.format(name) + + if marker.name: + name = marker.name # during fixture definition we wrap the original fixture function # to issue a warning if called directly, so here we unwrap it in order to not emit the warning diff --git a/testing/deprecated_test.py b/testing/deprecated_test.py index 4353ec2be..b971a9d2e 100644 --- a/testing/deprecated_test.py +++ b/testing/deprecated_test.py @@ -10,28 +10,6 @@ from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG pytestmark = pytest.mark.pytester_example_path("deprecated") -def test_funcarg_prefix_deprecation(testdir): - testdir.makepyfile( - """ - def pytest_funcarg__value(): - return 10 - - def test_funcarg_prefix(value): - assert value == 10 - """ - ) - result = testdir.runpytest("-ra", SHOW_PYTEST_WARNINGS_ARG) - result.stdout.fnmatch_lines( - [ - ( - "*test_funcarg_prefix_deprecation.py:1: *pytest_funcarg__value: " - 'declaring fixtures using "pytest_funcarg__" prefix is deprecated*' - ), - "*1 passed*", - ] - ) - - @pytest.mark.filterwarnings("default") def test_pytest_setup_cfg_deprecated(testdir): testdir.makefile( diff --git a/testing/python/fixture.py b/testing/python/fixture.py index 2cc4122b4..a4ef5af87 100644 --- a/testing/python/fixture.py +++ b/testing/python/fixture.py @@ -627,25 +627,6 @@ class TestRequestBasic(object): print(ss.stack) assert teardownlist == [1] - def test_mark_as_fixture_with_prefix_and_decorator_fails(self, testdir): - testdir.makeconftest( - """ - import pytest - - @pytest.fixture - def pytest_funcarg__marked_with_prefix_and_decorator(): - pass - """ - ) - result = testdir.runpytest_subprocess() - assert result.ret != 0 - result.stdout.fnmatch_lines( - [ - "*AssertionError: fixtures cannot have*@pytest.fixture*", - "*pytest_funcarg__marked_with_prefix_and_decorator*", - ] - ) - def test_request_addfinalizer_failing_setup(self, testdir): testdir.makepyfile( """ From 98987177a082944135ea2b208b38ec7d32b02d39 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 14 Dec 2018 11:17:24 -0200 Subject: [PATCH 5/9] Review changelog entries for features branch I used `towncrier --draft` to see the full changelog, and decided to "nitpick" it so it reads better as a whole. --- changelog/3050.deprecation.rst | 4 +++- changelog/3079.removal.rst | 2 +- changelog/3083.removal.rst | 2 +- changelog/3191.feature.rst | 16 +++++++++++----- changelog/3616.removal.rst | 2 +- changelog/4278.feature.rst | 4 ++++ changelog/4278.trivial.rst | 1 - changelog/4292.feature.rst | 2 +- changelog/4386.feature.rst | 2 +- changelog/4416.feature.rst | 2 +- changelog/4421.removal.rst | 2 +- changelog/4435.bugfix.rst | 2 +- changelog/4435.deprecation.rst | 4 +++- changelog/4483.feature.rst | 11 +++++++++-- changelog/4535.removal.rst | 2 +- changelog/4543.removal.rst | 2 +- 16 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 changelog/4278.feature.rst delete mode 100644 changelog/4278.trivial.rst diff --git a/changelog/3050.deprecation.rst b/changelog/3050.deprecation.rst index 2da417c85..fce5979d6 100644 --- a/changelog/3050.deprecation.rst +++ b/changelog/3050.deprecation.rst @@ -1 +1,3 @@ -Deprecate ``pytest.config`` global. See https://docs.pytest.org/en/latest/deprecations.html#pytest-config-global +Deprecated the ``pytest.config`` global. + +See https://docs.pytest.org/en/latest/deprecations.html#pytest-config-global for rationale. diff --git a/changelog/3079.removal.rst b/changelog/3079.removal.rst index 19a8612f0..cb2265ff3 100644 --- a/changelog/3079.removal.rst +++ b/changelog/3079.removal.rst @@ -1,3 +1,3 @@ -Remove support for yield tests - they are fundamentally broken because they don't support fixtures properly since collection and test execution were separated. +Removed support for yield tests - they are fundamentally broken because they don't support fixtures properly since collection and test execution were separated. See our `docs `__ on information on how to update your code. diff --git a/changelog/3083.removal.rst b/changelog/3083.removal.rst index ce689b94a..74d268a4e 100644 --- a/changelog/3083.removal.rst +++ b/changelog/3083.removal.rst @@ -1,3 +1,3 @@ -Remove ``Metafunc.addcall``. This was the predecessor mechanism to ``@pytest.mark.parametrize``. +Removed ``Metafunc.addcall``. This was the predecessor mechanism to ``@pytest.mark.parametrize``. See our `docs `__ on information on how to update your code. diff --git a/changelog/3191.feature.rst b/changelog/3191.feature.rst index 7eb4c3a15..dbf1c8304 100644 --- a/changelog/3191.feature.rst +++ b/changelog/3191.feature.rst @@ -1,16 +1,22 @@ A warning is now issued when assertions are made for ``None``. -This is a common source of confusion among new users, which write:: +This is a common source of confusion among new users, which write: - assert mocked_object.assert_called_with(3, 4, 5, key='value') +.. code-block:: python -When they should write:: + assert mocked_object.assert_called_with(3, 4, 5, key="value") - mocked_object.assert_called_with(3, 4, 5, key='value') +When they should write: + +.. code-block:: python + + mocked_object.assert_called_with(3, 4, 5, key="value") Because the ``assert_called_with`` method of mock objects already executes an assertion. -This warning will not be issued when ``None`` is explicitly checked. An assertion like:: +This warning will not be issued when ``None`` is explicitly checked. An assertion like: + +.. code-block:: python assert variable is None diff --git a/changelog/3616.removal.rst b/changelog/3616.removal.rst index a8f2f1c92..5d8c9134e 100644 --- a/changelog/3616.removal.rst +++ b/changelog/3616.removal.rst @@ -1,3 +1,3 @@ -Remove the deprecated compat properties for ``node.Class/Function/Module`` - use ``pytest.Class/Function/Module`` now. +Removed the deprecated compat properties for ``node.Class/Function/Module`` - use ``pytest.Class/Function/Module`` now. See our `docs `__ on information on how to update your code. diff --git a/changelog/4278.feature.rst b/changelog/4278.feature.rst new file mode 100644 index 000000000..332e64572 --- /dev/null +++ b/changelog/4278.feature.rst @@ -0,0 +1,4 @@ +``CACHEDIR.TAG`` files are now created inside cache directories. + +Those files are part of the `Cache Directory Tagging Standard `__, and can +be used by backup or synchronization programs to identify pytest's cache directory as such. diff --git a/changelog/4278.trivial.rst b/changelog/4278.trivial.rst deleted file mode 100644 index 126cabea8..000000000 --- a/changelog/4278.trivial.rst +++ /dev/null @@ -1 +0,0 @@ -A CACHEDIR.TAG file gets added to the cache directory. diff --git a/changelog/4292.feature.rst b/changelog/4292.feature.rst index 27d113ba0..760a27783 100644 --- a/changelog/4292.feature.rst +++ b/changelog/4292.feature.rst @@ -1 +1 @@ -``pytest.outcomes.Exit`` is derived from ``SystemExit`` instead of ``KeyboardInterrupt``. +``pytest.outcomes.Exit`` is derived from ``SystemExit`` instead of ``KeyboardInterrupt``. This allows us to better handle ``pdb`` exiting. diff --git a/changelog/4386.feature.rst b/changelog/4386.feature.rst index fe827cc23..5133a39a7 100644 --- a/changelog/4386.feature.rst +++ b/changelog/4386.feature.rst @@ -1 +1 @@ -Restructure ExceptionInfo object construction and ensure incomplete instances have a ``repr``/``str``. +Restructured ``ExceptionInfo`` object construction and ensure incomplete instances have a ``repr``/``str``. diff --git a/changelog/4416.feature.rst b/changelog/4416.feature.rst index 89c0a84b1..949e7c25a 100644 --- a/changelog/4416.feature.rst +++ b/changelog/4416.feature.rst @@ -1,4 +1,4 @@ -pdb: support keyword arguments with ``pdb.set_trace`` +pdb: added support for keyword arguments with ``pdb.set_trace``. It handles ``header`` similar to Python 3.7 does it, and forwards any other keyword arguments to the ``Pdb`` constructor. diff --git a/changelog/4421.removal.rst b/changelog/4421.removal.rst index 279587d06..4bebd5c19 100644 --- a/changelog/4421.removal.rst +++ b/changelog/4421.removal.rst @@ -1,3 +1,3 @@ -Remove the implementation of the ``pytest_namespace`` hook. +Removed the implementation of the ``pytest_namespace`` hook. See our `docs `__ on information on how to update your code. diff --git a/changelog/4435.bugfix.rst b/changelog/4435.bugfix.rst index de60b5e62..36ace1fab 100644 --- a/changelog/4435.bugfix.rst +++ b/changelog/4435.bugfix.rst @@ -1 +1 @@ -Fix ``raises(..., 'code(string)')`` frame filename. +Fixed ``raises(..., 'code(string)')`` frame filename. diff --git a/changelog/4435.deprecation.rst b/changelog/4435.deprecation.rst index f12f0bc6c..6815c1776 100644 --- a/changelog/4435.deprecation.rst +++ b/changelog/4435.deprecation.rst @@ -1 +1,3 @@ -Deprecate ``raises(..., 'code(as_a_string)')`` and ``warns(..., 'code(as_a_string)')``. See https://docs.pytest.org/en/latest/deprecations.html#raises-warns-exec +Deprecated ``raises(..., 'code(as_a_string)')`` and ``warns(..., 'code(as_a_string)')``. + +See https://docs.pytest.org/en/latest/deprecations.html#raises-warns-exec for rationale and examples. diff --git a/changelog/4483.feature.rst b/changelog/4483.feature.rst index d9bd4c717..e70db2979 100644 --- a/changelog/4483.feature.rst +++ b/changelog/4483.feature.rst @@ -1,2 +1,9 @@ -Add ini parameter ``junit_time`` to optionally report test call -durations less setup and teardown times. +Added ini parameter ``junit_time`` to optionally report test call durations, excluding setup and teardown times. + +The JUnit XML specification and the default pytest behavior is to include setup and teardown times in the test duration +report. You can include just the call durations instead (excluding setup and teardown) by adding this to your ``pytest.ini`` file: + +.. code-block:: ini + + [pytest] + junit_time = call diff --git a/changelog/4535.removal.rst b/changelog/4535.removal.rst index f89900587..89de6b744 100644 --- a/changelog/4535.removal.rst +++ b/changelog/4535.removal.rst @@ -1 +1 @@ -Removed deprecated ``PyCollector.makeitem`` method. This method was made public by mistake a long time ago. +Removed the deprecated ``PyCollector.makeitem`` method. This method was made public by mistake a long time ago. diff --git a/changelog/4543.removal.rst b/changelog/4543.removal.rst index f810b5bad..0a2b615f9 100644 --- a/changelog/4543.removal.rst +++ b/changelog/4543.removal.rst @@ -1,3 +1,3 @@ -Remove support to define fixtures using the ``pytest_funcarg__`` prefix. Use the ``@pytest.fixture`` decorator instead. +Removed support to define fixtures using the ``pytest_funcarg__`` prefix. Use the ``@pytest.fixture`` decorator instead. See our `docs `__ on information on how to update your code. From 231863b1337b708b2c95db975f7f2d9f6d0ef086 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 14 Dec 2018 12:56:26 -0200 Subject: [PATCH 6/9] Rename "junit_time" to "junit_duration_report" option Just realized while reading the changelog that "junit_time" is not a very good name, so I decided to open this PR renaming it to "junit_duration_report" which I believe conveys the meaning of the option better --- changelog/4483.feature.rst | 4 ++-- doc/en/usage.rst | 4 ++-- src/_pytest/junitxml.py | 6 ++++-- testing/test_junitxml.py | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/changelog/4483.feature.rst b/changelog/4483.feature.rst index e70db2979..9b3018707 100644 --- a/changelog/4483.feature.rst +++ b/changelog/4483.feature.rst @@ -1,4 +1,4 @@ -Added ini parameter ``junit_time`` to optionally report test call durations, excluding setup and teardown times. +Added ini parameter ``junit_duration_report`` to optionally report test call durations, excluding setup and teardown times. The JUnit XML specification and the default pytest behavior is to include setup and teardown times in the test duration report. You can include just the call durations instead (excluding setup and teardown) by adding this to your ``pytest.ini`` file: @@ -6,4 +6,4 @@ report. You can include just the call durations instead (excluding setup and tea .. code-block:: ini [pytest] - junit_time = call + junit_duration_report = call diff --git a/doc/en/usage.rst b/doc/en/usage.rst index 7c3ef19fb..865e007f5 100644 --- a/doc/en/usage.rst +++ b/doc/en/usage.rst @@ -301,12 +301,12 @@ should report total test execution times, including setup and teardown (`1 `_, `2 `_). It is the default pytest behavior. To report just call durations -instead, configure the ``junit_time`` option like this: +instead, configure the ``junit_duration_report`` option like this: .. code-block:: ini [pytest] - junit_time = call + junit_duration_report = call .. _record_property example: diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index 696deb6e9..672fde5d5 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -324,7 +324,9 @@ def pytest_addoption(parser): default="no", ) # choices=['no', 'stdout', 'stderr']) parser.addini( - "junit_time", "Duration time to report: one of total|call", default="total" + "junit_duration_report", + "Duration time to report: one of total|call", + default="total", ) # choices=['total', 'call']) @@ -337,7 +339,7 @@ def pytest_configure(config): config.option.junitprefix, config.getini("junit_suite_name"), config.getini("junit_logging"), - config.getini("junit_time"), + config.getini("junit_duration_report"), ) config.pluginmanager.register(config._xml) diff --git a/testing/test_junitxml.py b/testing/test_junitxml.py index aafbb8da9..d3e9542f8 100644 --- a/testing/test_junitxml.py +++ b/testing/test_junitxml.py @@ -153,7 +153,7 @@ class TestPython(object): val = tnode["time"] assert round(float(val), 2) >= 0.03 - def test_call_time(self, testdir): + def test_junit_duration_report(self, testdir): testdir.makepyfile( """ import time, pytest @@ -165,7 +165,7 @@ class TestPython(object): time.sleep(0.1) """ ) - result, dom = runandparse(testdir, "-o", "junit_time=call") + result, dom = runandparse(testdir, "-o", "junit_duration_report=call") node = dom.find_first_by_tag("testsuite") tnode = node.find_first_by_tag("testcase") val = tnode["time"] From 6e1b1abfa7ec8816c289df29c5bc8fdfae5e6bff Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 14 Dec 2018 15:10:08 -0200 Subject: [PATCH 7/9] Remove deprecated record_xml_property Fix #4547 --- changelog/4547.removal.rst | 3 +++ doc/en/deprecations.rst | 44 +++++++++++++++++++------------------- src/_pytest/deprecated.py | 6 ------ src/_pytest/junitxml.py | 10 --------- 4 files changed, 25 insertions(+), 38 deletions(-) create mode 100644 changelog/4547.removal.rst diff --git a/changelog/4547.removal.rst b/changelog/4547.removal.rst new file mode 100644 index 000000000..a30d5d7bd --- /dev/null +++ b/changelog/4547.removal.rst @@ -0,0 +1,3 @@ +The deprecated ``record_xml_property`` fixture has been removed, use the more generic ``record_property`` instead. + +See our `docs `__ for more information. diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index 37cffb1fb..d814b0bee 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -149,28 +149,6 @@ As part of a large :ref:`marker-revamp`, :meth:`_pytest.nodes.Node.get_marker` i :ref:`the documentation ` on tips on how to update your code. -record_xml_property -~~~~~~~~~~~~~~~~~~~ - -.. deprecated:: 3.5 - -The ``record_xml_property`` fixture is now deprecated in favor of the more generic ``record_property``, which -can be used by other consumers (for example ``pytest-html``) to obtain custom information about the test run. - -This is just a matter of renaming the fixture as the API is the same: - -.. code-block:: python - - def test_foo(record_xml_property): - ... - -Change to: - -.. code-block:: python - - def test_foo(record_property): - ... - pytest_plugins in non-top-level conftest files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -353,6 +331,28 @@ more information. This has been documented as deprecated for years, but only now we are actually emitting deprecation warnings. +record_xml_property +~~~~~~~~~~~~~~~~~~~ + +*Removed in version 4.0.* + +The ``record_xml_property`` fixture is now deprecated in favor of the more generic ``record_property``, which +can be used by other consumers (for example ``pytest-html``) to obtain custom information about the test run. + +This is just a matter of renaming the fixture as the API is the same: + +.. code-block:: python + + def test_foo(record_xml_property): + ... + +Change to: + +.. code-block:: python + + def test_foo(record_property): + ... + ``yield`` tests ~~~~~~~~~~~~~~~ diff --git a/src/_pytest/deprecated.py b/src/_pytest/deprecated.py index 67f0d534f..1de42924d 100644 --- a/src/_pytest/deprecated.py +++ b/src/_pytest/deprecated.py @@ -82,12 +82,6 @@ WARNS_EXEC = PytestDeprecationWarning( "See https://docs.pytest.org/en/latest/deprecations.html#raises-warns-exec" ) -RECORD_XML_PROPERTY = RemovedInPytest4Warning( - 'Fixture renamed from "record_xml_property" to "record_property" as user ' - "properties are now available to all reporters.\n" - '"record_xml_property" is now deprecated.' -) - PYTEST_PLUGINS_FROM_NON_TOP_LEVEL_CONFTEST = RemovedInPytest4Warning( "Defining pytest_plugins in a non-top-level conftest is deprecated, " diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index 696deb6e9..73adb179c 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -263,16 +263,6 @@ def record_property(request): return append_property -@pytest.fixture -def record_xml_property(record_property, request): - """(Deprecated) use record_property.""" - from _pytest import deprecated - - request.node.warn(deprecated.RECORD_XML_PROPERTY) - - return record_property - - @pytest.fixture def record_xml_attribute(request): """Add extra xml attributes to the tag for the calling test. From a7e401656eca66fb1ecee7c5e55ea24598d87f45 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 14 Dec 2018 15:19:48 -0200 Subject: [PATCH 8/9] Remove support to pass strings to pytest.main() Fix #3085 --- changelog/3085.removal.rst | 3 +++ doc/en/deprecations.rst | 45 ++++++++++++++++++---------------- src/_pytest/config/__init__.py | 7 ++---- src/_pytest/deprecated.py | 5 ---- testing/acceptance_test.py | 11 ++++----- testing/deprecated_test.py | 19 -------------- 6 files changed, 34 insertions(+), 56 deletions(-) create mode 100644 changelog/3085.removal.rst diff --git a/changelog/3085.removal.rst b/changelog/3085.removal.rst new file mode 100644 index 000000000..67ba04c28 --- /dev/null +++ b/changelog/3085.removal.rst @@ -0,0 +1,3 @@ +Removed support for passing strings to ``pytest.main``. Now, always pass a list of strings instead. + +See our `docs `__ on information on how to update your code. diff --git a/doc/en/deprecations.rst b/doc/en/deprecations.rst index d814b0bee..6ec80cbe8 100644 --- a/doc/en/deprecations.rst +++ b/doc/en/deprecations.rst @@ -193,27 +193,6 @@ To update the code, use ``pytest.param``: -Passing command-line string to ``pytest.main()`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. deprecated:: 3.0 - -Passing a command-line string to ``pytest.main()`` is deprecated: - -.. code-block:: python - - pytest.main("-v -s") - -Pass a list instead: - -.. code-block:: python - - pytest.main(["-v", "-s"]) - - -By passing a string, users expect that pytest will interpret that command-line using the shell rules they are working -on (for example ``bash`` or ``Powershell``), but this is very hard/impossible to do in a portable way. - [pytest] section in setup.cfg files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -353,6 +332,30 @@ Change to: def test_foo(record_property): ... + +Passing command-line string to ``pytest.main()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +*Removed in version 4.0.* + +Passing a command-line string to ``pytest.main()`` is deprecated: + +.. code-block:: python + + pytest.main("-v -s") + +Pass a list instead: + +.. code-block:: python + + pytest.main(["-v", "-s"]) + + +By passing a string, users expect that pytest will interpret that command-line using the shell rules they are working +on (for example ``bash`` or ``Powershell``), but this is very hard/impossible to do in a portable way. + + + ``yield`` tests ~~~~~~~~~~~~~~~ diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 3ed82694b..d68b1249e 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -173,12 +173,9 @@ def _prepareconfig(args=None, plugins=None): elif isinstance(args, py.path.local): args = [str(args)] elif not isinstance(args, (tuple, list)): - if not isinstance(args, str): - raise ValueError("not a string or argument list: %r" % (args,)) - args = shlex.split(args, posix=sys.platform != "win32") - from _pytest import deprecated + msg = "`args` parameter expected to be a list or tuple of strings, got: {!r} (type: {})" + raise TypeError(msg.format(args, type(args))) - warning = deprecated.MAIN_STR_ARGS config = get_config() pluginmanager = config.pluginmanager try: diff --git a/src/_pytest/deprecated.py b/src/_pytest/deprecated.py index 1de42924d..8b2fbf3f9 100644 --- a/src/_pytest/deprecated.py +++ b/src/_pytest/deprecated.py @@ -17,11 +17,6 @@ from _pytest.warning_types import RemovedInPytest4Warning from _pytest.warning_types import UnformattedWarning -MAIN_STR_ARGS = RemovedInPytest4Warning( - "passing a string to pytest.main() is deprecated, " - "pass a list of arguments instead." -) - YIELD_TESTS = "yield tests were removed in pytest 4.0 - {name} will be ignored" diff --git a/testing/acceptance_test.py b/testing/acceptance_test.py index 0b7af5338..7276445ac 100644 --- a/testing/acceptance_test.py +++ b/testing/acceptance_test.py @@ -559,12 +559,11 @@ class TestInvocationVariants(object): def test_equivalence_pytest_pytest(self): assert pytest.main == py.test.cmdline.main - def test_invoke_with_string(self, capsys): - retcode = pytest.main("-h") - assert not retcode - out, err = capsys.readouterr() - assert "--help" in out - pytest.raises(ValueError, lambda: pytest.main(0)) + def test_invoke_with_invalid_type(self, capsys): + with pytest.raises( + TypeError, match="expected to be a list or tuple of strings, got: '-h'" + ): + pytest.main("-h") def test_invoke_with_path(self, tmpdir, capsys): retcode = pytest.main(tmpdir) diff --git a/testing/deprecated_test.py b/testing/deprecated_test.py index b971a9d2e..5f5b78032 100644 --- a/testing/deprecated_test.py +++ b/testing/deprecated_test.py @@ -40,25 +40,6 @@ def test_pytest_custom_cfg_deprecated(testdir): ) -def test_str_args_deprecated(tmpdir): - """Deprecate passing strings to pytest.main(). Scheduled for removal in pytest-4.0.""" - from _pytest.main import EXIT_NOTESTSCOLLECTED - - warnings = [] - - class Collect(object): - def pytest_warning_captured(self, warning_message): - warnings.append(str(warning_message.message)) - - ret = pytest.main("%s -x" % tmpdir, plugins=[Collect()]) - msg = ( - "passing a string to pytest.main() is deprecated, " - "pass a list of arguments instead." - ) - assert msg in warnings - assert ret == EXIT_NOTESTSCOLLECTED - - def test_getfuncargvalue_is_deprecated(request): pytest.deprecated_call(request.getfuncargvalue, "tmpdir") From 1499778d5ea0f02f690cd50462c4061dad8cb9d7 Mon Sep 17 00:00:00 2001 From: Bruno Oliveira Date: Fri, 14 Dec 2018 17:09:27 -0200 Subject: [PATCH 9/9] Errors in parametrize id functions now propagate the error instead of issuing a warning Fix #2169 --- changelog/2169.removal.rst | 1 + src/_pytest/python.py | 11 ++++------- testing/python/metafunc.py | 10 +++------- 3 files changed, 8 insertions(+), 14 deletions(-) create mode 100644 changelog/2169.removal.rst diff --git a/changelog/2169.removal.rst b/changelog/2169.removal.rst new file mode 100644 index 000000000..272ddbdfb --- /dev/null +++ b/changelog/2169.removal.rst @@ -0,0 +1 @@ +``pytest.mark.parametrize``: in previous versions, errors raised by id functions were suppressed and changed into warnings. Now the exceptions are propagated, along with a pytest message informing the node, parameter value and index where the exception occurred. diff --git a/src/_pytest/python.py b/src/_pytest/python.py index a872a86ed..5a77b09ad 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -45,7 +45,6 @@ from _pytest.mark.structures import transfer_markers from _pytest.outcomes import fail from _pytest.pathlib import parts from _pytest.warning_types import PytestWarning -from _pytest.warning_types import RemovedInPytest4Warning def pyobj_property(name): @@ -1059,13 +1058,11 @@ def _idval(val, argname, idx, idfn, item, config): s = idfn(val) except Exception as e: # See issue https://github.com/pytest-dev/pytest/issues/2169 - msg = ( - "While trying to determine id of parameter {} at position " - "{} the following exception was raised:\n".format(argname, idx) - ) + msg = "{}: error raised while trying to determine id of parameter '{}' at position {}\n" + msg = msg.format(item.nodeid, argname, idx) + # we only append the exception type and message because on Python 2 reraise does nothing msg += " {}: {}\n".format(type(e).__name__, e) - msg += "This warning will be an error error in pytest-4.0." - item.warn(RemovedInPytest4Warning(msg)) + six.raise_from(ValueError(msg), e) if s: return ascii_escaped(s) diff --git a/testing/python/metafunc.py b/testing/python/metafunc.py index 7f9cdb5cc..0b05a7c5e 100644 --- a/testing/python/metafunc.py +++ b/testing/python/metafunc.py @@ -393,7 +393,6 @@ class TestMetafunc(object): ) assert result == ["a-a0", "a-a1", "a-a2"] - @pytest.mark.filterwarnings("default") def test_parametrize_ids_exception(self, testdir): """ :param testdir: the instance of Testdir class, a temporary @@ -411,14 +410,11 @@ class TestMetafunc(object): pass """ ) - result = testdir.runpytest("--collect-only", SHOW_PYTEST_WARNINGS_ARG) + result = testdir.runpytest() result.stdout.fnmatch_lines( [ - "", - " ", - " ", - "*test_parametrize_ids_exception.py:6: *parameter arg at position 0*", - "*test_parametrize_ids_exception.py:6: *parameter arg at position 1*", + "*test_foo: error raised while trying to determine id of parameter 'arg' at position 0", + "*Exception: bad ids", ] )