-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
improvement: show return type annotations in fixtures #13680
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
base: main
Are you sure you want to change the base?
Changes from 6 commits
3687117
3387532
ce68932
536c8d2
c3e0a48
ebe8c9c
79ce682
eb16715
776560e
b7c7827
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Added return type annotations in ``fixtures`` and ``fixtures-per-test``. | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1915,6 +1915,9 @@ def write_fixture(fixture_def: FixtureDef[object]) -> None: | |
return | ||
prettypath = _pretty_fixture_path(invocation_dir, fixture_def.func) | ||
tw.write(f"{argname}", green=True) | ||
ret_annotation = get_return_annotation(fixture_def.func) | ||
if ret_annotation: | ||
tw.write(f" -> {ret_annotation}", cyan=True) | ||
tw.write(f" -- {prettypath}", yellow=True) | ||
tw.write("\n") | ||
fixture_doc = inspect.getdoc(fixture_def.func) | ||
|
@@ -1999,6 +2002,9 @@ def _showfixtures_main(config: Config, session: Session) -> None: | |
if verbose <= 0 and argname.startswith("_"): | ||
continue | ||
tw.write(f"{argname}", green=True) | ||
ret_annotation = get_return_annotation(fixturedef.func) | ||
if ret_annotation: | ||
tw.write(f" -> {ret_annotation}", cyan=True) | ||
if fixturedef.scope != "function": | ||
tw.write(f" [{fixturedef.scope} scope]", cyan=True) | ||
tw.write(f" -- {prettypath}", yellow=True) | ||
|
@@ -2013,6 +2019,17 @@ def _showfixtures_main(config: Config, session: Session) -> None: | |
tw.line() | ||
|
||
|
||
def get_return_annotation(fixture_func: Callable[..., Any]) -> str: | ||
try: | ||
sig = signature(fixture_func) | ||
annotation = sig.return_annotation | ||
if annotation is not sig.empty and annotation != inspect._empty: | ||
return inspect.formatannotation(annotation).replace("'", "") | ||
|
||
except (ValueError, TypeError): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why would That being said, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TypeError happens when the argument is not a callable (e.g. a number). I doubt this case happens. ValueError happens when the passed argument is a callable but a signature can't be obtained (e.g. |
||
pass | ||
return "" | ||
|
||
|
||
def write_docstring(tw: TerminalWriter, doc: str, indent: str = " ") -> None: | ||
for line in doc.split("\n"): | ||
tw.line(indent + line) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
from _pytest.compat import getfuncargnames | ||
from _pytest.config import ExitCode | ||
from _pytest.fixtures import deduplicate_names | ||
from _pytest.fixtures import get_return_annotation | ||
from _pytest.fixtures import TopRequest | ||
from _pytest.monkeypatch import MonkeyPatch | ||
from _pytest.pytester import get_public_names | ||
|
@@ -3581,9 +3582,9 @@ def test_show_fixtures(self, pytester: Pytester) -> None: | |
result = pytester.runpytest("--fixtures") | ||
result.stdout.fnmatch_lines( | ||
[ | ||
"tmp_path_factory [[]session scope[]] -- .../_pytest/tmpdir.py:*", | ||
"tmp_path_factory* [[]session scope[]] -- .../_pytest/tmpdir.py:*", | ||
"*for the test session*", | ||
"tmp_path -- .../_pytest/tmpdir.py:*", | ||
"tmp_path* -- .../_pytest/tmpdir.py:*", | ||
"*temporary directory*", | ||
] | ||
) | ||
|
@@ -3592,9 +3593,9 @@ def test_show_fixtures_verbose(self, pytester: Pytester) -> None: | |
result = pytester.runpytest("--fixtures", "-v") | ||
result.stdout.fnmatch_lines( | ||
[ | ||
"tmp_path_factory [[]session scope[]] -- .../_pytest/tmpdir.py:*", | ||
"tmp_path_factory* [[]session scope[]] -- .../_pytest/tmpdir.py:*", | ||
"*for the test session*", | ||
"tmp_path -- .../_pytest/tmpdir.py:*", | ||
"tmp_path* -- .../_pytest/tmpdir.py:*", | ||
"*temporary directory*", | ||
] | ||
) | ||
|
@@ -3614,14 +3615,31 @@ def arg1(): | |
result = pytester.runpytest("--fixtures", p) | ||
result.stdout.fnmatch_lines( | ||
""" | ||
*tmp_path -- * | ||
*tmp_path* -- * | ||
*fixtures defined from* | ||
*arg1 -- test_show_fixtures_testmodule.py:6* | ||
*hello world* | ||
""" | ||
) | ||
result.stdout.no_fnmatch_line("*arg0*") | ||
|
||
def test_show_fixtures_return_annotation(self, pytester: Pytester) -> None: | ||
p = pytester.makepyfile( | ||
""" | ||
import pytest | ||
@pytest.fixture | ||
def six() -> int: | ||
return 6 | ||
""" | ||
) | ||
result = pytester.runpytest("--fixtures", p) | ||
result.stdout.fnmatch_lines( | ||
""" | ||
*fixtures defined from* | ||
*six -> int -- test_show_fixtures_return_annotation.py:3* | ||
""" | ||
) | ||
|
||
@pytest.mark.parametrize("testmod", [True, False]) | ||
def test_show_fixtures_conftest(self, pytester: Pytester, testmod) -> None: | ||
pytester.makeconftest( | ||
|
@@ -5068,3 +5086,27 @@ def test_method(self, /, fix): | |
) | ||
result = pytester.runpytest() | ||
result.assert_outcomes(passed=1) | ||
|
||
|
||
def test_get_return_annotation() -> None: | ||
|
||
def six() -> int: | ||
return 6 | ||
|
||
assert get_return_annotation(six) == "int" | ||
|
||
def two_sixes() -> tuple[int, str]: | ||
return (6, "six") | ||
|
||
assert get_return_annotation(two_sixes) == "tuple[int, str]" | ||
|
||
def no_annot(): | ||
return 6 | ||
|
||
assert get_return_annotation(no_annot) == "" | ||
|
||
def none_return() -> None: | ||
|
||
pass | ||
|
||
assert get_return_annotation(none_return) == "None" | ||
|
||
assert get_return_annotation(range) == "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.