11import inspect
2+ from typing import Any
23
34from _pytest .config import Config
45from _pytest .nodes import Item
@@ -11,7 +12,9 @@ def pytest_configure(config: Config) -> None:
1112 node IDs (without parameterization suffixes) have already had
1213 their docstrings printed.
1314 """
14- config ._printed_docstrings = set () # type: ignore[attr-defined]
15+ # use getattr/setattr to avoid static-type warnings about unknown attrs
16+ if getattr (config , "_printed_docstrings" , None ) is None :
17+ setattr (config , "_printed_docstrings" , set ())
1518
1619
1720def pytest_runtest_setup (item : Item ) -> None :
@@ -30,16 +33,33 @@ def pytest_runtest_setup(item: Item) -> None:
3033 # "path/to/test.py::test_func[param]" → keep the part before "["
3134 base_nodeid = item .nodeid .split ("[" , 1 )[0 ]
3235
33- if base_nodeid in item .config ._printed_docstrings : # type: ignore[attr-defined]
36+ printed = getattr (item .config , "_printed_docstrings" , set ())
37+ if base_nodeid in printed :
3438 return
3539
36- doc = inspect .getdoc (item .obj ) or ""
40+ # obtain the underlying Python object for the test in a safe way
41+ # different pytest versions / stubs expose different attributes; try common ones
42+ obj : Any = getattr (item , "obj" , None ) or getattr (item , "function" , None ) or item
43+
44+ doc = inspect .getdoc (obj ) or ""
3745 if not doc .strip ():
38- item .config ._printed_docstrings .add (base_nodeid ) # type: ignore[attr-defined]
46+ printed .add (base_nodeid )
47+ setattr (item .config , "_printed_docstrings" , printed )
3948 return
4049
41- for line in doc .splitlines ():
42- tr .write_line (" " + line )
43- tr .write_line ("" )
50+ # call write_line if available; otherwise fall back to a write() if present
51+ write_line = getattr (tr , "write_line" , None )
52+ if callable (write_line ):
53+ for line in doc .splitlines ():
54+ write_line (" " + line )
55+ write_line ("" )
56+ else :
57+ write = getattr (tr , "write" , None )
58+ if callable (write ):
59+ # write() often expects raw text including newline
60+ for line in doc .splitlines ():
61+ write (" " + line + "\n " )
62+ write ("\n " )
4463
45- item .config ._printed_docstrings .add (base_nodeid ) # type: ignore[attr-defined]
64+ printed .add (base_nodeid )
65+ setattr (item .config , "_printed_docstrings" , printed )
0 commit comments