Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling of ellipsis in traceback comparisons for doctests #13039

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/2574.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix handling of ellipsis (...) in traceback comparisons for doctests
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Fix handling of ellipsis (...) in traceback comparisons for doctests
Fix handling of ellipsis (``...``) in traceback comparisons for doctests.

2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,9 @@ markers = [
"slow",
# experimental mark for all tests using pexpect
"uses_pexpect",
"doctest: mark tests related to doctests",
]
doctest_optionflags = [ "ELLIPSIS" ]

[tool.towncrier]
package = "pytest"
Expand Down
7 changes: 7 additions & 0 deletions src/_pytest/doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,13 @@
if allow_number:
got = self._remove_unwanted_precision(want, got)

if "..." in want:
want_regex = re.escape(want).replace(r"\.\.\.", ".*")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit simplistic in the sense that it will replace any ... found in the docstring, even if they are used in places where we don't want this replacement to happen, say inside a string literal.

Perhaps we can limit our replacement to lines containing a single ... (minus spaces)?

Here is how the stdlib does this: https://github.com/python/cpython/blob/1503fc8f88d4903e61f76a78a30bcd581b0ee0cd/Lib/doctest.py#L295-L342

I'm OK with copying that code over pytest.

print(f"Transformed WANT: {want_regex}") # Debugging output
print(f"GOT: {got}") # Debugging output

Check warning on line 655 in src/_pytest/doctest.py

View check run for this annotation

Codecov / codecov/patch

src/_pytest/doctest.py#L653-L655

Added lines #L653 - L655 were not covered by tests
Comment on lines +654 to +655
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like those are left-overs.

Suggested change
print(f"Transformed WANT: {want_regex}") # Debugging output
print(f"GOT: {got}") # Debugging output

if re.fullmatch(want_regex, got, re.DOTALL):
return True

Check warning on line 657 in src/_pytest/doctest.py

View check run for this annotation

Codecov / codecov/patch

src/_pytest/doctest.py#L657

Added line #L657 was not covered by tests

return super().check_output(want, got, optionflags)

def _remove_unwanted_precision(self, want: str, got: str) -> str:
Expand Down
25 changes: 25 additions & 0 deletions testing/test_doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1642,3 +1642,28 @@ def test_is_setup_py_different_encoding(tmp_path: Path, mod: str) -> None:
def test_is_main_py(tmp_path: Path, name: str, expected: bool) -> None:
dunder_main = tmp_path.joinpath(name)
assert _is_main_py(dunder_main) == expected


def test_doctest_wildcard(pytester):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_doctest_wildcard(pytester):
def test_doctest_wildcard(pytester: Pytester) -> None:

"""
Test that doctests with wildcards in tracebacks are handled correctly.
"""
# Create a Python file with a function that raises a ValueError and includes a doctest.
pytester.makepyfile(
"""
def _test_doctest_wildcard():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def _test_doctest_wildcard():
def doctest_wildcard():

'''
>>> _test_doctest_wildcard()
Traceback (most recent call last):
...
ValueError: An error occurred
'''
raise ValueError("An error occurred")
"""
)

# Run pytest with doctest support enabled.
result = pytester.runpytest("--doctest-modules")

# Check that the test passed without failures.
result.assert_outcomes(passed=1, failed=0)
Loading