mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Support positional-only parameters in classmethods (#11635)
This commit is contained in:
parent
02cb02ccfb
commit
a73fb59a71
2
CHANGES
2
CHANGES
@ -5,6 +5,8 @@ Dependencies
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
* #11576: Require sphinxcontrib-serializinghtml 1.1.9.
|
* #11576: Require sphinxcontrib-serializinghtml 1.1.9.
|
||||||
|
* #11543: autodoc: Support positional-only parameters in ``classmethod`` methods
|
||||||
|
when ``autodoc_preserve_defaults`` is ``True``.
|
||||||
|
|
||||||
Bugs fixed
|
Bugs fixed
|
||||||
----------
|
----------
|
||||||
|
@ -135,51 +135,57 @@ def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
args = _get_arguments(obj)
|
args = _get_arguments(obj)
|
||||||
if args is None:
|
except SyntaxError:
|
||||||
# If the object is a built-in, we won't be always able to recover
|
return
|
||||||
# the function definition and its arguments. This happens if *obj*
|
if args is None:
|
||||||
# is the `__init__` method generated automatically for dataclasses.
|
# If the object is a built-in, we won't be always able to recover
|
||||||
return
|
# the function definition and its arguments. This happens if *obj*
|
||||||
|
# is the `__init__` method generated automatically for dataclasses.
|
||||||
|
return
|
||||||
|
|
||||||
if args.defaults or args.kw_defaults:
|
if not args.defaults and not args.kw_defaults:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
if bound_method and inspect.ismethod(obj) and hasattr(obj, '__func__'):
|
||||||
|
sig = inspect.signature(obj.__func__)
|
||||||
|
else:
|
||||||
sig = inspect.signature(obj)
|
sig = inspect.signature(obj)
|
||||||
defaults = list(args.defaults)
|
defaults = list(args.defaults)
|
||||||
kw_defaults = list(args.kw_defaults)
|
kw_defaults = list(args.kw_defaults)
|
||||||
parameters = list(sig.parameters.values())
|
parameters = list(sig.parameters.values())
|
||||||
for i, param in enumerate(parameters):
|
for i, param in enumerate(parameters):
|
||||||
if param.default is param.empty:
|
if param.default is param.empty:
|
||||||
if param.kind == param.KEYWORD_ONLY:
|
if param.kind == param.KEYWORD_ONLY:
|
||||||
# Consume kw_defaults for kwonly args
|
# Consume kw_defaults for kwonly args
|
||||||
kw_defaults.pop(0)
|
kw_defaults.pop(0)
|
||||||
else:
|
|
||||||
if param.kind in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD):
|
|
||||||
default = defaults.pop(0)
|
|
||||||
value = get_default_value(lines, default)
|
|
||||||
if value is None:
|
|
||||||
value = ast_unparse(default)
|
|
||||||
parameters[i] = param.replace(default=DefaultValue(value))
|
|
||||||
else:
|
|
||||||
default = kw_defaults.pop(0) # type: ignore[assignment]
|
|
||||||
value = get_default_value(lines, default)
|
|
||||||
if value is None:
|
|
||||||
value = ast_unparse(default)
|
|
||||||
parameters[i] = param.replace(default=DefaultValue(value))
|
|
||||||
|
|
||||||
if bound_method and inspect.ismethod(obj):
|
|
||||||
# classmethods
|
|
||||||
cls = inspect.Parameter('cls', inspect.Parameter.POSITIONAL_OR_KEYWORD)
|
|
||||||
parameters.insert(0, cls)
|
|
||||||
|
|
||||||
sig = sig.replace(parameters=parameters)
|
|
||||||
if bound_method and inspect.ismethod(obj):
|
|
||||||
# classmethods can't be assigned __signature__ attribute.
|
|
||||||
obj.__dict__['__signature__'] = sig
|
|
||||||
else:
|
else:
|
||||||
obj.__signature__ = sig
|
if param.kind in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD):
|
||||||
|
default = defaults.pop(0)
|
||||||
|
value = get_default_value(lines, default)
|
||||||
|
if value is None:
|
||||||
|
value = ast_unparse(default)
|
||||||
|
parameters[i] = param.replace(default=DefaultValue(value))
|
||||||
|
else:
|
||||||
|
default = kw_defaults.pop(0) # type: ignore[assignment]
|
||||||
|
value = get_default_value(lines, default)
|
||||||
|
if value is None:
|
||||||
|
value = ast_unparse(default)
|
||||||
|
parameters[i] = param.replace(default=DefaultValue(value))
|
||||||
|
|
||||||
|
sig = sig.replace(parameters=parameters)
|
||||||
|
try:
|
||||||
|
obj.__signature__ = sig
|
||||||
|
except AttributeError:
|
||||||
|
# __signature__ can't be set directly on bound methods.
|
||||||
|
obj.__dict__['__signature__'] = sig
|
||||||
except (AttributeError, TypeError):
|
except (AttributeError, TypeError):
|
||||||
# failed to update signature (ex. built-in or extension types)
|
# Failed to update signature (e.g. built-in or extension types).
|
||||||
pass
|
# For user-defined functions, "obj" may not have __dict__,
|
||||||
except NotImplementedError as exc: # failed to ast.unparse()
|
# e.g. when decorated with a class that defines __slots__.
|
||||||
|
# In this case, we can't set __signature__.
|
||||||
|
return
|
||||||
|
except NotImplementedError as exc: # failed to ast_unparse()
|
||||||
logger.warning(__("Failed to parse a default argument value for %r: %s"), obj, exc)
|
logger.warning(__("Failed to parse a default argument value for %r: %s"), obj, exc)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user