Imported Upstream version 6.0.1 upstream/6.0.1
authorDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 18 Mar 2021 02:33:14 +0000 (11:33 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Thu, 18 Mar 2021 02:33:14 +0000 (11:33 +0900)
12 files changed:
doc/en/announce/index.rst
doc/en/announce/release-6.0.1.rst [new file with mode: 0644]
doc/en/changelog.rst
doc/en/getting-started.rst
doc/en/tmpdir.rst
src/_pytest/helpconfig.py
src/_pytest/logging.py
src/_pytest/mark/structures.py
src/_pytest/reports.py
testing/logging/test_fixture.py
testing/test_helpconfig.py
testing/test_runner.py

index 7d176aa..49d7a04 100644 (file)
@@ -6,6 +6,7 @@ Release announcements
    :maxdepth: 2
 
 
+   release-6.0.1
    release-6.0.0
    release-6.0.0rc1
    release-5.4.3
diff --git a/doc/en/announce/release-6.0.1.rst b/doc/en/announce/release-6.0.1.rst
new file mode 100644 (file)
index 0000000..33fdbed
--- /dev/null
@@ -0,0 +1,21 @@
+pytest-6.0.1
+=======================================
+
+pytest 6.0.1 has just been released to PyPI.
+
+This is a bug-fix release, being a drop-in replacement. To upgrade::
+
+  pip install --upgrade pytest
+
+The full changelog is available at https://docs.pytest.org/en/latest/changelog.html.
+
+Thanks to all who contributed to this release, among them:
+
+* Bruno Oliveira
+* Mattreex
+* Ran Benita
+* hp310780
+
+
+Happy testing,
+The pytest Development Team
index 2ad8de2..7516b53 100644 (file)
@@ -28,6 +28,26 @@ with advance notice in the **Deprecations** section of releases.
 
 .. towncrier release notes start
 
+pytest 6.0.1 (2020-07-30)
+=========================
+
+Bug Fixes
+---------
+
+- `#7394 <https://github.com/pytest-dev/pytest/issues/7394>`_: Passing an empty ``help`` value to ``Parser.add_option`` is now accepted instead of crashing when running ``pytest --help``.
+  Passing ``None`` raises a more informative ``TypeError``.
+
+
+- `#7558 <https://github.com/pytest-dev/pytest/issues/7558>`_: Fix pylint ``not-callable`` lint on ``pytest.mark.parametrize()`` and the other builtin marks:
+  ``skip``, ``skipif``, ``xfail``, ``usefixtures``, ``filterwarnings``.
+
+
+- `#7559 <https://github.com/pytest-dev/pytest/issues/7559>`_: Fix regression in plugins using ``TestReport.longreprtext`` (such as ``pytest-html``) when ``TestReport.longrepr`` is not a string.
+
+
+- `#7569 <https://github.com/pytest-dev/pytest/issues/7569>`_: Fix logging capture handler's level not reset on teardown after a call to ``caplog.set_level()``.
+
+
 pytest 6.0.0 (2020-07-28)
 =========================
 
index a2f6daa..c160191 100644 (file)
@@ -28,7 +28,7 @@ Install ``pytest``
 .. code-block:: bash
 
     $ pytest --version
-    pytest 6.0.0
+    pytest 6.0.1
 
 .. _`simpletest`:
 
index a3749d8..5f882b1 100644 (file)
@@ -192,8 +192,13 @@ You can override the default temporary directory setting like this:
 
     pytest --basetemp=mydir
 
-When distributing tests on the local machine, ``pytest`` takes care to
-configure a basetemp directory for the sub processes such that all temporary
+.. warning::
+
+    The contents of ``mydir`` will be completely removed, so make sure to use a directory
+    for that purpose only.
+
+When distributing tests on the local machine using ``pytest-xdist``, care is taken to
+automatically configure a basetemp directory for the sub processes such that all temporary
 data lands below a single per-test run basetemp directory.
 
 .. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
index 2495285..f3623b8 100644 (file)
@@ -170,6 +170,8 @@ def showhelp(config: Config) -> None:
         help, type, default = config._parser._inidict[name]
         if type is None:
             type = "string"
+        if help is None:
+            raise TypeError("help argument cannot be None for {}".format(name))
         spec = "{} ({}):".format(name, type)
         tw.write("  %s" % spec)
         spec_len = len(spec)
@@ -191,9 +193,10 @@ def showhelp(config: Config) -> None:
             tw.write(" " * (indent_len - spec_len - 2))
             wrapped = textwrap.wrap(help, columns - indent_len, break_on_hyphens=False)
 
-            tw.line(wrapped[0])
-            for line in wrapped[1:]:
-                tw.line(indent + line)
+            if wrapped:
+                tw.line(wrapped[0])
+                for line in wrapped[1:]:
+                    tw.line(indent + line)
 
     tw.line()
     tw.line("environment variables:")
index 11031f2..0ee9457 100644 (file)
@@ -345,6 +345,7 @@ class LogCaptureFixture:
         """Creates a new funcarg."""
         self._item = item
         # dict of log name -> log level
+        self._initial_handler_level = None  # type: Optional[int]
         self._initial_logger_levels = {}  # type: Dict[Optional[str], int]
 
     def _finalize(self) -> None:
@@ -353,6 +354,8 @@ class LogCaptureFixture:
         This restores the log levels changed by :meth:`set_level`.
         """
         # restore log levels
+        if self._initial_handler_level is not None:
+            self.handler.setLevel(self._initial_handler_level)
         for logger_name, level in self._initial_logger_levels.items():
             logger = logging.getLogger(logger_name)
             logger.setLevel(level)
@@ -434,6 +437,7 @@ class LogCaptureFixture:
         # save the original log-level to restore it during teardown
         self._initial_logger_levels.setdefault(logger, logger_obj.level)
         logger_obj.setLevel(level)
+        self._initial_handler_level = self.handler.level
         self.handler.setLevel(level)
 
     @contextmanager
index 5edeecd..6567822 100644 (file)
@@ -4,7 +4,6 @@ import typing
 import warnings
 from typing import Any
 from typing import Callable
-from typing import cast
 from typing import Iterable
 from typing import List
 from typing import Mapping
@@ -473,14 +472,13 @@ class MarkGenerator:
 
     # See TYPE_CHECKING above.
     if TYPE_CHECKING:
-        # Using casts instead of type comments intentionally - issue #7473.
         # TODO(py36): Change to builtin annotation syntax.
-        skip = cast(_SkipMarkDecorator, None)
-        skipif = cast(_SkipifMarkDecorator, None)
-        xfail = cast(_XfailMarkDecorator, None)
-        parametrize = cast(_ParametrizeMarkDecorator, None)
-        usefixtures = cast(_UsefixturesMarkDecorator, None)
-        filterwarnings = cast(_FilterwarningsMarkDecorator, None)
+        skip = _SkipMarkDecorator(Mark("skip", (), {}))
+        skipif = _SkipifMarkDecorator(Mark("skipif", (), {}))
+        xfail = _XfailMarkDecorator(Mark("xfail", (), {}))
+        parametrize = _ParametrizeMarkDecorator(Mark("parametrize", (), {}))
+        usefixtures = _UsefixturesMarkDecorator(Mark("usefixtures", (), {}))
+        filterwarnings = _FilterwarningsMarkDecorator(Mark("filterwarnings", (), {}))
 
     def __getattr__(self, name: str) -> MarkDecorator:
         if name[0] == "_":
index 186c53e..cbd9ae1 100644 (file)
@@ -82,9 +82,10 @@ class BaseReport:
             longrepr.toterminal(out)
         else:
             try:
-                out.line(longrepr)
+                s = str(longrepr)
             except UnicodeEncodeError:
-                out.line("<unprintable longrepr>")
+                s = "<unprintable longrepr>"
+            out.line(s)
 
     def get_sections(self, prefix: str) -> Iterator[Tuple[str, str]]:
         for name, content in self.sections:
index da53033..6e5e9c2 100644 (file)
@@ -2,6 +2,7 @@ import logging
 
 import pytest
 from _pytest.logging import caplog_records_key
+from _pytest.pytester import Testdir
 
 logger = logging.getLogger(__name__)
 sublogger = logging.getLogger(__name__ + ".baz")
@@ -27,8 +28,11 @@ def test_change_level(caplog):
     assert "CRITICAL" in caplog.text
 
 
-def test_change_level_undo(testdir):
-    """Ensure that 'set_level' is undone after the end of the test"""
+def test_change_level_undo(testdir: Testdir) -> None:
+    """Ensure that 'set_level' is undone after the end of the test.
+
+    Tests the logging output themselves (affacted both by logger and handler levels).
+    """
     testdir.makepyfile(
         """
         import logging
@@ -50,6 +54,33 @@ def test_change_level_undo(testdir):
     result.stdout.no_fnmatch_line("*log from test2*")
 
 
+def test_change_level_undos_handler_level(testdir: Testdir) -> None:
+    """Ensure that 'set_level' is undone after the end of the test (handler).
+
+    Issue #7569. Tests the handler level specifically.
+    """
+    testdir.makepyfile(
+        """
+        import logging
+
+        def test1(caplog):
+            assert caplog.handler.level == 0
+            caplog.set_level(41)
+            assert caplog.handler.level == 41
+
+        def test2(caplog):
+            assert caplog.handler.level == 0
+
+        def test3(caplog):
+            assert caplog.handler.level == 0
+            caplog.set_level(43)
+            assert caplog.handler.level == 43
+    """
+    )
+    result = testdir.runpytest()
+    result.assert_outcomes(passed=3)
+
+
 def test_with_statement(caplog):
     with caplog.at_level(logging.INFO):
         logger.debug("handler DEBUG level")
index 24590dd..a33273a 100644 (file)
@@ -38,6 +38,41 @@ def test_help(testdir):
     )
 
 
+def test_none_help_param_raises_exception(testdir):
+    """Tests a None help param raises a TypeError.
+    """
+    testdir.makeconftest(
+        """
+        def pytest_addoption(parser):
+            parser.addini("test_ini", None, default=True, type="bool")
+    """
+    )
+    result = testdir.runpytest("--help")
+    result.stderr.fnmatch_lines(
+        ["*TypeError: help argument cannot be None for test_ini*"]
+    )
+
+
+def test_empty_help_param(testdir):
+    """Tests an empty help param is displayed correctly.
+    """
+    testdir.makeconftest(
+        """
+        def pytest_addoption(parser):
+            parser.addini("test_ini", "", default=True, type="bool")
+    """
+    )
+    result = testdir.runpytest("--help")
+    assert result.ret == 0
+    lines = [
+        "  required_plugins (args):",
+        "                        plugins that must be present for pytest to run*",
+        "  test_ini (bool):*",
+        "environment variables:",
+    ]
+    result.stdout.fnmatch_lines(lines, consecutive=True)
+
+
 def test_hookvalidation_unknown(testdir):
     testdir.makeconftest(
         """
index def3f91..b207ccc 100644 (file)
@@ -951,6 +951,33 @@ class TestReportContents:
         rep = reports[1]
         assert rep.longreprtext == ""
 
+    def test_longreprtext_skip(self, testdir) -> None:
+        """TestReport.longreprtext can handle non-str ``longrepr`` attributes (#7559)"""
+        reports = testdir.runitem(
+            """
+            import pytest
+            def test_func():
+                pytest.skip()
+            """
+        )
+        _, call_rep, _ = reports
+        assert isinstance(call_rep.longrepr, tuple)
+        assert "Skipped" in call_rep.longreprtext
+
+    def test_longreprtext_collect_skip(self, testdir) -> None:
+        """CollectReport.longreprtext can handle non-str ``longrepr`` attributes (#7559)"""
+        testdir.makepyfile(
+            """
+            import pytest
+            pytest.skip(allow_module_level=True)
+            """
+        )
+        rec = testdir.inline_run()
+        calls = rec.getcalls("pytest_collectreport")
+        _, call = calls
+        assert isinstance(call.report.longrepr, tuple)
+        assert "Skipped" in call.report.longreprtext
+
     def test_longreprtext_failure(self, testdir) -> None:
         reports = testdir.runitem(
             """