Skip to content

Commit 1b83e55

Browse files
picnixzjayaddisonAA-Turner
authored
autodoc: add support for python_display_short_literal (#12003)
Co-authored-by: James Addison <[email protected]> Co-authored-by: Adam Turner <[email protected]>
1 parent 50fb4a9 commit 1b83e55

File tree

8 files changed

+217
-102
lines changed

8 files changed

+217
-102
lines changed

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ Features added
9494
* #8191, #8159: Add :rst:dir:`inheritance-diagram:include-subclasses` option to
9595
the :rst:dir:`inheritance-diagram` directive.
9696
Patch by Walter Dörwald.
97+
* #11995: autodoc: Add support for :confval:`python_display_short_literal_types`.
98+
Patch by Bénédikt Tran and Adam Turner.
9799

98100
Bugs fixed
99101
----------

sphinx/ext/autodoc/__init__.py

Lines changed: 54 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
from sphinx.environment import BuildEnvironment, _CurrentDocument
4545
from sphinx.events import EventManager
4646
from sphinx.ext.autodoc.directive import DocumenterBridge
47-
from sphinx.util.typing import ExtensionMetadata, OptionSpec
47+
from sphinx.util.typing import ExtensionMetadata, OptionSpec, _RestifyMode
4848

4949
_AutodocObjType = Literal[
5050
'module', 'class', 'exception', 'function', 'method', 'attribute'
@@ -76,6 +76,14 @@
7676
special_member_re = re.compile(r'^__\S+__$')
7777

7878

79+
def _get_render_mode(
80+
typehints_format: Literal['fully-qualified', 'short'],
81+
) -> _RestifyMode:
82+
if typehints_format == 'short':
83+
return 'smart'
84+
return 'fully-qualified-except-typing'
85+
86+
7987
def identity(x: Any) -> Any:
8088
return x
8189

@@ -1472,6 +1480,8 @@ def format_args(self, **kwargs: Any) -> str:
14721480
kwargs.setdefault('show_annotation', False)
14731481
if self.config.autodoc_typehints_format == 'short':
14741482
kwargs.setdefault('unqualified_typehints', True)
1483+
if self.config.python_display_short_literal_types:
1484+
kwargs.setdefault('short_literals', True)
14751485

14761486
try:
14771487
self._events.emit('autodoc-before-process-signature', self.object, False)
@@ -1507,6 +1517,8 @@ def add_directive_header(self, sig: str) -> None:
15071517
def format_signature(self, **kwargs: Any) -> str:
15081518
if self.config.autodoc_typehints_format == 'short':
15091519
kwargs.setdefault('unqualified_typehints', True)
1520+
if self.config.python_display_short_literal_types:
1521+
kwargs.setdefault('short_literals', True)
15101522

15111523
sigs = []
15121524
if (
@@ -1794,6 +1806,8 @@ def format_args(self, **kwargs: Any) -> str:
17941806
kwargs.setdefault('show_annotation', False)
17951807
if self.config.autodoc_typehints_format == 'short':
17961808
kwargs.setdefault('unqualified_typehints', True)
1809+
if self.config.python_display_short_literal_types:
1810+
kwargs.setdefault('short_literals', True)
17971811

17981812
try:
17991813
self._signature_class, _signature_method_name, sig = self._get_signature()
@@ -1835,6 +1849,8 @@ def format_signature(self, **kwargs: Any) -> str:
18351849

18361850
if self.config.autodoc_typehints_format == 'short':
18371851
kwargs.setdefault('unqualified_typehints', True)
1852+
if self.config.python_display_short_literal_types:
1853+
kwargs.setdefault('short_literals', True)
18381854

18391855
sig = super().format_signature()
18401856
sigs = []
@@ -1931,10 +1947,8 @@ def add_directive_header(self, sig: str) -> None:
19311947
'autodoc-process-bases', self.fullname, self.object, self.options, bases
19321948
)
19331949

1934-
if self.config.autodoc_typehints_format == 'short':
1935-
base_classes = [restify(cls, 'smart') for cls in bases]
1936-
else:
1937-
base_classes = [restify(cls) for cls in bases]
1950+
mode = _get_render_mode(self.config.autodoc_typehints_format)
1951+
base_classes = [restify(cls, mode=mode) for cls in bases]
19381952

19391953
sourcename = self.get_sourcename()
19401954
self.add_line('', sourcename)
@@ -2047,25 +2061,21 @@ def get_variable_comment(self) -> list[str] | None:
20472061
return None
20482062

20492063
def add_content(self, more_content: StringList | None) -> None:
2064+
mode = _get_render_mode(self.config.autodoc_typehints_format)
2065+
short_literals = self.config.python_display_short_literal_types
2066+
20502067
if isinstance(self.object, NewType):
2051-
if self.config.autodoc_typehints_format == 'short':
2052-
supertype = restify(self.object.__supertype__, 'smart')
2053-
else:
2054-
supertype = restify(self.object.__supertype__)
2068+
supertype = restify(self.object.__supertype__, mode=mode)
20552069

20562070
more_content = StringList([_('alias of %s') % supertype, ''], source='')
20572071
if isinstance(self.object, TypeVar):
20582072
attrs = [repr(self.object.__name__)]
2059-
for constraint in self.object.__constraints__:
2060-
if self.config.autodoc_typehints_format == 'short':
2061-
attrs.append(stringify_annotation(constraint, 'smart'))
2062-
else:
2063-
attrs.append(stringify_annotation(constraint))
2073+
attrs.extend(
2074+
stringify_annotation(constraint, mode, short_literals=short_literals)
2075+
for constraint in self.object.__constraints__
2076+
)
20642077
if self.object.__bound__:
2065-
if self.config.autodoc_typehints_format == 'short':
2066-
bound = restify(self.object.__bound__, 'smart')
2067-
else:
2068-
bound = restify(self.object.__bound__)
2078+
bound = restify(self.object.__bound__, mode=mode)
20692079
attrs.append(r'bound=\ ' + bound)
20702080
if self.object.__covariant__:
20712081
attrs.append('covariant=True')
@@ -2085,10 +2095,7 @@ def add_content(self, more_content: StringList | None) -> None:
20852095

20862096
if self.doc_as_attr and not self.get_variable_comment():
20872097
try:
2088-
if self.config.autodoc_typehints_format == 'short':
2089-
alias = restify(self.object, 'smart')
2090-
else:
2091-
alias = restify(self.object)
2098+
alias = restify(self.object, mode=mode)
20922099
more_content = StringList([_('alias of %s') % alias], source='')
20932100
except AttributeError:
20942101
pass # Invalid class object is passed.
@@ -2180,10 +2187,8 @@ def should_suppress_directive_header(self) -> bool:
21802187

21812188
def update_content(self, more_content: StringList) -> None:
21822189
if inspect.isgenericalias(self.object):
2183-
if self.config.autodoc_typehints_format == 'short':
2184-
alias = restify(self.object, 'smart')
2185-
else:
2186-
alias = restify(self.object)
2190+
mode = _get_render_mode(self.config.autodoc_typehints_format)
2191+
alias = restify(self.object, mode=mode)
21872192

21882193
more_content.append(_('alias of %s') % alias, '')
21892194
more_content.append('', '')
@@ -2307,15 +2312,13 @@ def add_directive_header(self, sig: str) -> None:
23072312
include_extras=True,
23082313
)
23092314
if self.objpath[-1] in annotations:
2310-
if self.config.autodoc_typehints_format == 'short':
2311-
objrepr = stringify_annotation(
2312-
annotations.get(self.objpath[-1]), 'smart'
2313-
)
2314-
else:
2315-
objrepr = stringify_annotation(
2316-
annotations.get(self.objpath[-1]),
2317-
'fully-qualified-except-typing',
2318-
)
2315+
mode = _get_render_mode(self.config.autodoc_typehints_format)
2316+
short_literals = self.config.python_display_short_literal_types
2317+
objrepr = stringify_annotation(
2318+
annotations.get(self.objpath[-1]),
2319+
mode,
2320+
short_literals=short_literals,
2321+
)
23192322
self.add_line(' :type: ' + objrepr, sourcename)
23202323

23212324
try:
@@ -2405,6 +2408,8 @@ def format_args(self, **kwargs: Any) -> str:
24052408
kwargs.setdefault('show_annotation', False)
24062409
if self.config.autodoc_typehints_format == 'short':
24072410
kwargs.setdefault('unqualified_typehints', True)
2411+
if self.config.python_display_short_literal_types:
2412+
kwargs.setdefault('short_literals', True)
24082413

24092414
try:
24102415
if self.object == object.__init__ and self.parent != object: # NoQA: E721
@@ -2474,6 +2479,8 @@ def document_members(self, all_members: bool = False) -> None:
24742479
def format_signature(self, **kwargs: Any) -> str:
24752480
if self.config.autodoc_typehints_format == 'short':
24762481
kwargs.setdefault('unqualified_typehints', True)
2482+
if self.config.python_display_short_literal_types:
2483+
kwargs.setdefault('short_literals', True)
24772484

24782485
sigs = []
24792486
if (
@@ -2957,15 +2964,13 @@ def add_directive_header(self, sig: str) -> None:
29572964
include_extras=True,
29582965
)
29592966
if self.objpath[-1] in annotations:
2960-
if self.config.autodoc_typehints_format == 'short':
2961-
objrepr = stringify_annotation(
2962-
annotations.get(self.objpath[-1]), 'smart'
2963-
)
2964-
else:
2965-
objrepr = stringify_annotation(
2966-
annotations.get(self.objpath[-1]),
2967-
'fully-qualified-except-typing',
2968-
)
2967+
mode = _get_render_mode(self.config.autodoc_typehints_format)
2968+
short_literals = self.config.python_display_short_literal_types
2969+
objrepr = stringify_annotation(
2970+
annotations.get(self.objpath[-1]),
2971+
mode,
2972+
short_literals=short_literals,
2973+
)
29692974
self.add_line(' :type: ' + objrepr, sourcename)
29702975

29712976
try:
@@ -3100,12 +3105,11 @@ def add_directive_header(self, sig: str) -> None:
31003105
func, type_aliases=self.config.autodoc_type_aliases
31013106
)
31023107
if signature.return_annotation is not Parameter.empty:
3103-
if self.config.autodoc_typehints_format == 'short':
3104-
objrepr = stringify_annotation(signature.return_annotation, 'smart')
3105-
else:
3106-
objrepr = stringify_annotation(
3107-
signature.return_annotation, 'fully-qualified-except-typing'
3108-
)
3108+
mode = _get_render_mode(self.config.autodoc_typehints_format)
3109+
short_literals = self.config.python_display_short_literal_types
3110+
objrepr = stringify_annotation(
3111+
signature.return_annotation, mode, short_literals=short_literals
3112+
)
31093113
self.add_line(' :type: ' + objrepr, sourcename)
31103114
except TypeError as exc:
31113115
logger.warning(

sphinx/ext/autodoc/typehints.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
from sphinx.application import Sphinx
2222
from sphinx.ext.autodoc import Options
23-
from sphinx.util.typing import ExtensionMetadata
23+
from sphinx.util.typing import ExtensionMetadata, _StringifyMode
2424

2525

2626
def record_typehints(
@@ -33,11 +33,14 @@ def record_typehints(
3333
retann: str,
3434
) -> None:
3535
"""Record type hints to env object."""
36+
mode: _StringifyMode
3637
if app.config.autodoc_typehints_format == 'short':
3738
mode = 'smart'
3839
else:
3940
mode = 'fully-qualified'
4041

42+
short_literals = app.config.python_display_short_literal_types
43+
4144
try:
4245
if callable(obj):
4346
current_document = app.env.current_document
@@ -46,11 +49,12 @@ def record_typehints(
4649
for param in sig.parameters.values():
4750
if param.annotation is not param.empty:
4851
annotation[param.name] = stringify_annotation(
49-
param.annotation,
50-
mode, # type: ignore[arg-type]
52+
param.annotation, mode, short_literals=short_literals
5153
)
5254
if sig.return_annotation is not sig.empty:
53-
annotation['return'] = stringify_annotation(sig.return_annotation, mode) # type: ignore[arg-type]
55+
annotation['return'] = stringify_annotation(
56+
sig.return_annotation, mode, short_literals=short_literals
57+
)
5458
except (TypeError, ValueError):
5559
pass
5660

sphinx/ext/napoleon/docstring.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1095,8 +1095,13 @@ def _lookup_annotation(self, _name: str) -> str:
10951095
)
10961096
self._annotations = get_type_hints(self._obj, None, localns)
10971097
if _name in self._annotations:
1098+
short_literals = getattr(
1099+
self._config, 'python_display_short_literal_types', False
1100+
)
10981101
return stringify_annotation(
1099-
self._annotations[_name], 'fully-qualified-except-typing'
1102+
self._annotations[_name],
1103+
mode='fully-qualified-except-typing',
1104+
short_literals=short_literals,
11001105
)
11011106
# No annotation found
11021107
return ''

sphinx/util/inspect.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131

3232
from typing_extensions import TypeIs
3333

34+
from sphinx.util.typing import _StringifyMode
35+
3436
class _SupportsGet(Protocol):
3537
def __get__(self, instance: Any, owner: type | None = ..., /) -> Any: ...
3638

@@ -842,14 +844,17 @@ def stringify_signature(
842844
show_annotation: bool = True,
843845
show_return_annotation: bool = True,
844846
unqualified_typehints: bool = False,
847+
short_literals: bool = False,
845848
) -> str:
846849
"""Stringify a :class:`~inspect.Signature` object.
847850
848851
:param show_annotation: If enabled, show annotations on the signature
849852
:param show_return_annotation: If enabled, show annotation of the return value
850853
:param unqualified_typehints: If enabled, show annotations as unqualified
851854
(ex. io.StringIO -> StringIO)
855+
:param short_literals: If enabled, use short literal types.
852856
"""
857+
mode: _StringifyMode
853858
if unqualified_typehints:
854859
mode = 'smart'
855860
else:
@@ -884,7 +889,11 @@ def stringify_signature(
884889

885890
if show_annotation and param.annotation is not EMPTY:
886891
arg.write(': ')
887-
arg.write(stringify_annotation(param.annotation, mode)) # type: ignore[arg-type]
892+
arg.write(
893+
stringify_annotation(
894+
param.annotation, mode, short_literals=short_literals
895+
)
896+
)
888897
if param.default is not EMPTY:
889898
if show_annotation and param.annotation is not EMPTY:
890899
arg.write(' = ')
@@ -907,7 +916,9 @@ def stringify_signature(
907916
):
908917
return f'({concatenated_args})'
909918
else:
910-
retann = stringify_annotation(sig.return_annotation, mode) # type: ignore[arg-type]
919+
retann = stringify_annotation(
920+
sig.return_annotation, mode, short_literals=short_literals
921+
)
911922
return f'({concatenated_args}) -> {retann}'
912923

913924

0 commit comments

Comments
 (0)