Support positional-only parameters in classmethods #11635
Support positional-only parameters in classmethods #11635AA-Turner merged 4 commits intosphinx-doc:masterfrom
Conversation
|
@AA-Turner The patch works well for the projects I use sphinx in 👍, but I added some comments to code sections that could be problematic in some edge cases regardless. |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
|
|
||
| if args.defaults or args.kw_defaults: | ||
| sig = inspect.signature(obj) | ||
| is_classmethod = bound_method and inspect.ismethod(obj) |
There was a problem hiding this comment.
Is it clear that this catches classmethod and classmethod only? (and not any otherwise decorated things?)
Possibly it would be better to make a helper function.
There was a problem hiding this comment.
Good point, this captures all bound methods.
| if is_classmethod and hasattr(obj, '__func__'): | ||
| sig = inspect.signature(obj.__func__) |
There was a problem hiding this comment.
If the is_classmethod is correct, then __func__ should always exist, so I'd rather do
if is_classmethod:
assert hasattr(obj, '__func__')
sig = inspect.signature(obj.__func__)Which would help to find bugs if there are any in is_classmethod.
There was a problem hiding this comment.
As I'd like this to go in to 7.2.3 I don't want to introduce a new assert.
| if is_classmethod: | ||
| # classmethods can't be assigned __signature__ attribute. | ||
| obj.__dict__['__signature__'] = sig |
There was a problem hiding this comment.
This is problematic since obj might not have __dict__. This can happen if it is decorated with a class that uses __slots__. It's a pretty cursed example/edge-case...
from functools import wraps
def make_cursed_decorator(func):
class CursedDecorator:
__slots__ = ()
@staticmethod
@wraps(func)
def __call__(*args, **kwargs):
return func(*args, **kwargs)
return CursedDecorator()
class A:
@classmethod
@make_cursed_decorator
def foo(cls, x: int, /, *, y: int = 0) -> int:
return x + y
A.foo(1, y=2)
A.foo.__dict__ # AttributeErrorThere was a problem hiding this comment.
The outer except (AttributeError, TypeError): would catch this, but it isn't very clear -- I've added a note to capture this case.
cc: @randolf-scholz -- please could you check that this works for you?
A