|
7 | 7 | import typing |
8 | 8 | from collections.abc import Sequence |
9 | 9 | from contextvars import Context, ContextVar, Token |
| 10 | +from functools import partial as _partial |
10 | 11 | from struct import Struct |
11 | 12 | from typing import TYPE_CHECKING, Any, Callable, ForwardRef, TypedDict, TypeVar, Union |
12 | 13 |
|
|
15 | 16 |
|
16 | 17 | if TYPE_CHECKING: |
17 | 18 | from collections.abc import Mapping |
| 19 | + from collections.abc import Set as AbstractSet |
18 | 20 | from typing import Final |
19 | 21 |
|
20 | 22 | from sphinx.application import Sphinx |
@@ -166,6 +168,8 @@ def restify(cls: type | None, mode: str = 'fully-qualified-except-typing') -> st |
166 | 168 | from sphinx.ext.autodoc.mock import ismock, ismockmodule # lazy loading |
167 | 169 | from sphinx.util import inspect # lazy loading |
168 | 170 |
|
| 171 | + mode = _validate_restify_mode(mode) |
| 172 | + |
169 | 173 | if mode == 'smart': |
170 | 174 | modprefix = '~' |
171 | 175 | else: |
@@ -292,11 +296,7 @@ def stringify_annotation( |
292 | 296 | from sphinx.ext.autodoc.mock import ismock, ismockmodule # lazy loading |
293 | 297 | from sphinx.util.inspect import isNewType # lazy loading |
294 | 298 |
|
295 | | - allowed_modes = {'fully-qualified-except-typing', 'fully-qualified', 'smart'} |
296 | | - if mode not in allowed_modes: |
297 | | - allowed = ', '.join(map(repr, sorted(allowed_modes))) |
298 | | - msg = f'%r must be one of %s; got {mode!r}' % ('mode', allowed) |
299 | | - raise ValueError(msg) |
| 299 | + mode = _validate_stringify_mode(mode) |
300 | 300 |
|
301 | 301 | if mode == 'smart': |
302 | 302 | module_prefix = '~' |
@@ -410,29 +410,48 @@ def stringify_annotation( |
410 | 410 | return f'{module_prefix}{qualname}' |
411 | 411 |
|
412 | 412 |
|
413 | | -def _stringify_literal_arg(arg: Any, mode: str) -> str: |
| 413 | +def _restify_literal_arg(arg: Any, mode: str) -> str: |
414 | 414 | from sphinx.util.inspect import isenumattribute # lazy loading |
415 | 415 |
|
416 | 416 | if isenumattribute(arg): |
417 | | - enumcls = arg.__class__ |
418 | | - if mode == 'smart': |
419 | | - # MyEnum.member |
420 | | - return f'{enumcls.__qualname__}.{arg.name}' |
421 | | - # module.MyEnum.member |
422 | | - return f'{enumcls.__module__}.{enumcls.__qualname__}.{arg.name}' |
| 417 | + enum_cls = arg.__class__ |
| 418 | + prefix = '~' if mode == 'smart' or enum_cls.__module__ == 'typing' else '' |
| 419 | + return f':py:attr:`{prefix}{enum_cls.__module__}.{enum_cls.__qualname__}.{arg.name}`' |
423 | 420 | return repr(arg) |
424 | 421 |
|
425 | 422 |
|
426 | | -def _restify_literal_arg(arg: Any, mode: str) -> str: |
| 423 | +def _stringify_literal_arg(arg: Any, mode: str) -> str: |
427 | 424 | from sphinx.util.inspect import isenumattribute # lazy loading |
428 | 425 |
|
429 | 426 | if isenumattribute(arg): |
430 | 427 | enum_cls = arg.__class__ |
431 | | - prefix = '~' if mode == 'smart' or enum_cls.__module__ == 'typing' else '' |
432 | | - return f':py:attr:`{prefix}{enum_cls.__module__}.{enum_cls.__qualname__}.{arg.name}`' |
| 428 | + # 'MyEnum.member' in 'smart' mode, otherwise 'module.MyEnum.member' |
| 429 | + prefix = '' if mode == 'smart' else enum_cls.__module__ |
| 430 | + return f'{prefix}.{enum_cls.__qualname__}.{arg.name}' |
433 | 431 | return repr(arg) |
434 | 432 |
|
435 | 433 |
|
| 434 | +# validations functions (keep them as separate functions to handle enumerations |
| 435 | +# values instead of plain strings in the future and to be able to add better |
| 436 | +# type annotations using literal values) |
| 437 | +def _validate_mode(mode: str, allowed_modes: AbstractSet[str]) -> str: |
| 438 | + if mode not in allowed_modes: |
| 439 | + allowed = ', '.join(map(repr, sorted(allowed_modes))) |
| 440 | + msg = f'%r must be one of %s; got {mode!r}' % ('mode', allowed) |
| 441 | + raise ValueError(msg) |
| 442 | + return mode |
| 443 | + |
| 444 | + |
| 445 | +_RESTIFY_ALLOWED_MODES: Final[AbstractSet[str]] = {'fully-qualified-except-typing', 'smart'} |
| 446 | +_validate_restify_mode = _partial(_validate_mode, allowed_modes=_RESTIFY_ALLOWED_MODES) |
| 447 | + |
| 448 | +_STRINGIFY_ALLOWED_MODES: Final[AbstractSet[str]] = { |
| 449 | + 'fully-qualified-except-typing', |
| 450 | + 'fully-qualified', |
| 451 | + 'smart', |
| 452 | +} |
| 453 | +_validate_stringify_mode = _partial(_validate_mode, allowed_modes=_STRINGIFY_ALLOWED_MODES) |
| 454 | + |
436 | 455 | # deprecated name -> (object to return, canonical path or empty string, removal version) |
437 | 456 | _DEPRECATED_OBJECTS: dict[str, tuple[Any, str, tuple[int, int]]] = { |
438 | 457 | 'stringify': (stringify_annotation, 'sphinx.util.typing.stringify_annotation', (8, 0)), |
|
0 commit comments