Skip to content

Commit 49db522

Browse files
committed
Support tuples
1 parent f2e1488 commit 49db522

File tree

4 files changed

+55
-10
lines changed

4 files changed

+55
-10
lines changed

.editorconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
root = true
2+
3+
[*.py]
4+
charset = utf-8
5+
indent_size = 4
6+
indent_style = space
7+
insert_final_newline = true
8+
max_line_length = 88

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,3 @@ doc = [
3838
[tool.black]
3939
py36 = false
4040
exclude = '3.5'
41-

scanpydoc/elegant_typehints.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,12 @@ def _format_full(annotation: Type[Any], fully_qualified: bool = False):
7373
return _format_orig(annotation, fully_qualified)
7474
annotation_cls = annotation if inspect.isclass(annotation) else type(annotation)
7575
if annotation_cls.__module__ == "typing":
76-
return _format_orig(annotation, fully_qualified)
76+
formatted = _format_orig(annotation, fully_qualified)
77+
# work around https://github.com/agronholm/sphinx-autodoc-typehints/issues/94
78+
formatted = formatted.replace(
79+
":py:class:`typing.Tuple`", ":py:data:`typing.Tuple`"
80+
)
81+
return formatted
7782

7883
# Only if this is a real class we override sphinx_autodoc_typehints
7984
if inspect.isclass(annotation) or inspect.isclass(

tests/test_elegant_typehints.py

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Mapping, Any, Dict, Union
1+
import typing as t
22

33
import pytest
44
from sphinx.application import Sphinx
@@ -29,8 +29,8 @@ def process_docstring(a):
2929

3030

3131
def test_mapping(app):
32-
assert _format_terse(Mapping[str, Any]) == ":py:class:`~typing.Mapping`"
33-
assert _format_full(Mapping[str, Any]) == (
32+
assert _format_terse(t.Mapping[str, t.Any]) == ":py:class:`~typing.Mapping`"
33+
assert _format_full(t.Mapping[str, t.Any]) == (
3434
r":py:class:`~typing.Mapping`\["
3535
r":py:class:`str`, "
3636
r":py:data:`~typing.Any`"
@@ -39,7 +39,9 @@ def test_mapping(app):
3939

4040

4141
def test_dict(app):
42-
assert _format_terse(Dict[str, Any]) == "{:py:class:`str`: :py:data:`~typing.Any`}"
42+
assert _format_terse(t.Dict[str, t.Any]) == (
43+
"{:py:class:`str`: :py:data:`~typing.Any`}"
44+
)
4345

4446

4547
def test_qualname_overrides(app):
@@ -52,10 +54,10 @@ def test_qualname_overrides(app):
5254
def test_qualname_overrides_recursive(app):
5355
sparse = pytest.importorskip("scipy.sparse")
5456

55-
assert _format_terse(Union[sparse.spmatrix, str]) == (
57+
assert _format_terse(t.Union[sparse.spmatrix, str]) == (
5658
r":py:class:`~scipy.sparse.spmatrix`, :py:class:`str`"
5759
)
58-
assert _format_full(Union[sparse.spmatrix, str]) == (
60+
assert _format_full(t.Union[sparse.spmatrix, str]) == (
5961
r":py:data:`~typing.Union`\["
6062
r":py:class:`~scipy.sparse.spmatrix`, "
6163
r":py:class:`str`"
@@ -66,10 +68,10 @@ def test_qualname_overrides_recursive(app):
6668
def test_fully_qualified(app):
6769
sparse = pytest.importorskip("scipy.sparse")
6870

69-
assert _format_terse(Union[sparse.spmatrix, str], True) == (
71+
assert _format_terse(t.Union[sparse.spmatrix, str], True) == (
7072
r":py:class:`scipy.sparse.spmatrix`, :py:class:`str`"
7173
)
72-
assert _format_full(Union[sparse.spmatrix, str], True) == (
74+
assert _format_full(t.Union[sparse.spmatrix, str], True) == (
7375
r":py:data:`typing.Union`\["
7476
r":py:class:`scipy.sparse.spmatrix`, "
7577
r":py:class:`str`"
@@ -83,3 +85,34 @@ def test_classes_get_added(app, parse):
8385
assert doc[0][0].tagname == "inline"
8486
assert doc[0][0]["classes"] == ["annotation", "full"]
8587
# print(doc.asdom().toprettyxml())
88+
89+
90+
@pytest.mark.parametrize("formatter", [_format_terse, _format_full], ids="tf")
91+
# These guys aren’t listed as classes in Python’s intersphinx index:
92+
@pytest.mark.parametrize(
93+
"annotation",
94+
[
95+
t.Any,
96+
t.AnyStr,
97+
# t.NoReturn,
98+
t.Callable[[int], None],
99+
# t.ClassVar[t.Any],
100+
t.Optional[int],
101+
t.Tuple[int, str],
102+
t.Tuple[float, ...],
103+
t.Union[int, str],
104+
],
105+
ids=lambda p: str(p).replace("typing.", ""),
106+
)
107+
def test_typing_classes(app, annotation, formatter):
108+
name = (
109+
getattr(annotation, "_name", None)
110+
or getattr(annotation, "__name__", None)
111+
or annotation.__origin__._name
112+
)
113+
if name == "Union":
114+
if formatter is _format_terse:
115+
pytest.skip("Tested elsewhere")
116+
elif len(annotation.__args__) == 2 and type(None) in annotation.__args__:
117+
name = "Optional"
118+
assert formatter(annotation, True).startswith(f":py:data:`typing.{name}")

0 commit comments

Comments
 (0)