diff --git a/CHANGELOG.rst b/CHANGELOG.rst index afa4b4f7c..30574f574 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -67,7 +67,7 @@ Features rather than implicitly. -- `#5914 `_: ``pytester`` learned two new functions, `no_fnmatch_line `_ and +- `#5914 `_: `testdir `__ learned two new functions, `no_fnmatch_line `_ and `no_re_match_line `_. The functions are used to ensure the captured text *does not* match the given @@ -77,12 +77,14 @@ Features .. code-block:: python + result = testdir.runpytest() assert re.match(pat, result.stdout.str()) is None Or the ``in`` operator: .. code-block:: python + result = testdir.runpytest() assert text in result.stdout.str() But the new functions produce best output on failure. diff --git a/changelog/6082.bugfix.rst b/changelog/6082.bugfix.rst new file mode 100644 index 000000000..24d389257 --- /dev/null +++ b/changelog/6082.bugfix.rst @@ -0,0 +1 @@ +Fix line detection for doctest samples inside ``property`` docstrings, as a workaround to `bpo-17446 `__. diff --git a/changelog/6254.bugfix.rst b/changelog/6254.bugfix.rst new file mode 100644 index 000000000..a278a85ed --- /dev/null +++ b/changelog/6254.bugfix.rst @@ -0,0 +1 @@ +Fix compatibility with pytest-parallel (regression in pytest 5.3.0). diff --git a/doc/en/reference.rst b/doc/en/reference.rst index 9986d1129..b24ca5e5a 100644 --- a/doc/en/reference.rst +++ b/doc/en/reference.rst @@ -1215,6 +1215,15 @@ passed multiple times. The expected format is ``name=value``. For example:: a specific entry in the log. ``extra`` kwarg overrides the value specified on the command line or in the config. +.. confval:: log_cli + + Enable log display during test run (also known as :ref:`"live logging" `). + The default is ``False``. + + .. code-block:: ini + + [pytest] + log_cli = True .. confval:: log_cli_date_format diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 1c98f0266..eecb29365 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -784,7 +784,7 @@ class Config: @classmethod def fromdictargs(cls, option_dict, args): - """ constructor useable for subprocesses. """ + """ constructor usable for subprocesses. """ config = get_config(args) config.option.__dict__.update(option_dict) config.parse(args, addopts=False) diff --git a/src/_pytest/doctest.py b/src/_pytest/doctest.py index f7d96257e..c81f0bfd4 100644 --- a/src/_pytest/doctest.py +++ b/src/_pytest/doctest.py @@ -435,6 +435,16 @@ class DoctestModule(pytest.Module): https://bugs.python.org/issue25532 """ + def _find_lineno(self, obj, source_lines): + """ + Doctest code does not take into account `@property`, this is a hackish way to fix it. + + https://bugs.python.org/issue17446 + """ + if isinstance(obj, property): + obj = getattr(obj, "fget", obj) + return doctest.DocTestFinder._find_lineno(self, obj, source_lines) + def _find(self, tests, obj, name, module, source_lines, globs, seen): if _is_mocked(obj): return diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index 40e12e406..e88545eca 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -1099,7 +1099,7 @@ def _get_main_color(stats) -> Tuple[str, List[str]]: "failed passed skipped deselected xfailed xpassed warnings error".split() ) unknown_type_seen = False - for found_type in stats: + for found_type in stats.keys(): if found_type not in known_types: if found_type: # setup/teardown reports have an empty key, ignore them known_types.append(found_type) diff --git a/testing/test_doctest.py b/testing/test_doctest.py index 79095e3e7..bd214e3de 100644 --- a/testing/test_doctest.py +++ b/testing/test_doctest.py @@ -287,13 +287,68 @@ class TestDoctests: ) ) result = testdir.runpytest("--doctest-modules") + result.stdout.fnmatch_lines( + ["*hello*", "006*>>> 1/0*", "*UNEXPECTED*ZeroDivision*", "*1 failed*"] + ) + + def test_doctest_linedata_on_property(self, testdir): + testdir.makepyfile( + """ + class Sample(object): + @property + def some_property(self): + ''' + >>> Sample().some_property + 'another thing' + ''' + return 'something' + """ + ) + result = testdir.runpytest("--doctest-modules") result.stdout.fnmatch_lines( [ - "*hello*", - "*EXAMPLE LOCATION UNKNOWN, not showing all tests of that example*", - "*1/0*", - "*UNEXPECTED*ZeroDivision*", - "*1 failed*", + "*= FAILURES =*", + "*_ [[]doctest[]] test_doctest_linedata_on_property.Sample.some_property _*", + "004 ", + "005 >>> Sample().some_property", + "Expected:", + " 'another thing'", + "Got:", + " 'something'", + "", + "*/test_doctest_linedata_on_property.py:5: DocTestFailure", + "*= 1 failed in *", + ] + ) + + def test_doctest_no_linedata_on_overriden_property(self, testdir): + testdir.makepyfile( + """ + class Sample(object): + @property + def some_property(self): + ''' + >>> Sample().some_property + 'another thing' + ''' + return 'something' + some_property = property(some_property.__get__, None, None, some_property.__doc__) + """ + ) + result = testdir.runpytest("--doctest-modules") + result.stdout.fnmatch_lines( + [ + "*= FAILURES =*", + "*_ [[]doctest[]] test_doctest_no_linedata_on_overriden_property.Sample.some_property _*", + "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example", + "[?][?][?] >>> Sample().some_property", + "Expected:", + " 'another thing'", + "Got:", + " 'something'", + "", + "*/test_doctest_no_linedata_on_overriden_property.py:None: DocTestFailure", + "*= 1 failed in *", ] ) diff --git a/tox.ini b/tox.ini index afb5cb36b..5e0817258 100644 --- a/tox.ini +++ b/tox.ini @@ -60,9 +60,8 @@ basepython = python3 usedevelop = True changedir = doc/en deps = -r{toxinidir}/doc/en/requirements.txt - commands = - sphinx-build -W -b html . _build + sphinx-build -W --keep-going -b html . _build {posargs:} [testenv:docs-checklinks] basepython = python3