Skip to content

Commit aceb328

Browse files
authored
Fix roles for types module (#516)
Fixes #498 Also apparently the emitted role for FunctionType used to be wrong, so fixes that as well.
1 parent 3af8fb6 commit aceb328

File tree

2 files changed

+25
-5
lines changed

2 files changed

+25
-5
lines changed

src/sphinx_autodoc_typehints/__init__.py

+18-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,23 @@
3636
from sphinx.ext.autodoc import Options
3737

3838
_LOGGER = logging.getLogger(__name__)
39-
_PYDATA_ANNOTATIONS = {"Any", "AnyStr", "Callable", "ClassVar", "Literal", "NoReturn", "Optional", "Tuple", "Union"}
39+
_PYDATA_ANNOTS_TYPING = {"Any", "AnyStr", "Callable", "ClassVar", "Literal", "NoReturn", "Optional", "Tuple", "Union"}
40+
_PYDATA_ANNOTS_TYPES = {
41+
*("AsyncGeneratorType", "BuiltinFunctionType", "BuiltinMethodType"),
42+
*("CellType", "ClassMethodDescriptorType", "CoroutineType"),
43+
"EllipsisType",
44+
*("FrameType", "FunctionType"),
45+
*("GeneratorType", "GetSetDescriptorType"),
46+
"LambdaType",
47+
*("MemberDescriptorType", "MethodDescriptorType", "MethodType", "MethodWrapperType"),
48+
# NoneType is special, but included here for completeness' sake
49+
*("NoneType", "NotImplementedType"),
50+
"WrapperDescriptorType",
51+
}
52+
_PYDATA_ANNOTATIONS = {
53+
*(("typing", n) for n in _PYDATA_ANNOTS_TYPING),
54+
*(("types", n) for n in _PYDATA_ANNOTS_TYPES),
55+
}
4056

4157
# types has a bunch of things like ModuleType where ModuleType.__module__ is
4258
# "builtins" and ModuleType.__name__ is "module", so we have to check for this.
@@ -219,7 +235,7 @@ def format_annotation(annotation: Any, config: Config) -> str: # noqa: C901, PL
219235
full_name = f"{module}.{class_name}" if module != "builtins" else class_name
220236
fully_qualified: bool = getattr(config, "typehints_fully_qualified", False)
221237
prefix = "" if fully_qualified or full_name == class_name else "~"
222-
role = "data" if module == "typing" and class_name in _PYDATA_ANNOTATIONS else "class"
238+
role = "data" if (module, class_name) in _PYDATA_ANNOTATIONS else "class"
223239
args_format = "\\[{}]"
224240
formatted_args: str | None = ""
225241

tests/test_sphinx_autodoc_typehints.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from io import StringIO
1010
from pathlib import Path
1111
from textwrap import dedent, indent
12-
from types import FunctionType, ModuleType
12+
from types import EllipsisType, FrameType, FunctionType, ModuleType, NotImplementedType, TracebackType
1313
from typing import ( # noqa: UP035
1414
IO,
1515
Any,
@@ -168,8 +168,12 @@ def test_parse_annotation(annotation: Any, module: str, class_name: str, args: t
168168
pytest.param(str, ":py:class:`str`", id="str"),
169169
pytest.param(int, ":py:class:`int`", id="int"),
170170
pytest.param(StringIO, ":py:class:`~io.StringIO`", id="StringIO"),
171-
pytest.param(FunctionType, ":py:class:`~types.FunctionType`", id="FunctionType"),
171+
pytest.param(EllipsisType, ":py:data:`~types.EllipsisType`", id="EllipsisType"),
172+
pytest.param(FunctionType, ":py:data:`~types.FunctionType`", id="FunctionType"),
173+
pytest.param(FrameType, ":py:data:`~types.FrameType`", id="FrameType"),
172174
pytest.param(ModuleType, ":py:class:`~types.ModuleType`", id="ModuleType"),
175+
pytest.param(NotImplementedType, ":py:data:`~types.NotImplementedType`", id="NotImplementedType"),
176+
pytest.param(TracebackType, ":py:class:`~types.TracebackType`", id="TracebackType"),
173177
pytest.param(type(None), ":py:obj:`None`", id="type None"),
174178
pytest.param(type, ":py:class:`type`", id="type"),
175179
pytest.param(Callable, ":py:class:`~collections.abc.Callable`", id="abc-Callable"),
@@ -414,7 +418,7 @@ def test_format_annotation(inv: Inventory, annotation: Any, expected_result: str
414418
assert format_annotation(annotation, conf) == expected_result
415419

416420
# Test for the correct role (class vs data) using the official Sphinx inventory
417-
if "typing" in expected_result:
421+
if any(modname in expected_result for modname in ("typing", "types")):
418422
m = re.match(r"^:py:(?P<role>class|data|func):`~(?P<name>[^`]+)`", result)
419423
assert m, "No match"
420424
name = m.group("name")

0 commit comments

Comments
 (0)