Message362434
I tried to apply this change but it didn't work, failing with this error
$ ~/.pyenv/versions/3.8.1/bin/python -m bad_classmethod_as_documented
Traceback (most recent call last):
File "/home/viktor/.pyenv/versions/3.8.1/lib/python3.8/runpy.py", line 193, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/home/viktor/.pyenv/versions/3.8.1/lib/python3.8/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/home/viktor/scratch/bad_classmethod_as_documented.py", line 4, in <module>
class Negator:
File "/home/viktor/scratch/bad_classmethod_as_documented.py", line 12, in Negator
def _(cls, arg: int):
File "/home/viktor/.pyenv/versions/3.8.1/lib/python3.8/functools.py", line 1006, in register
return self.dispatcher.register(cls, func=method)
File "/home/viktor/.pyenv/versions/3.8.1/lib/python3.8/functools.py", line 959, in register
argname, cls = next(iter(get_type_hints(func).items()))
File "/home/viktor/.pyenv/versions/3.8.1/lib/python3.8/typing.py", line 1252, in get_type_hints
raise TypeError('{!r} is not a module, class, method, '
TypeError: <classmethod object at 0x7f84e1e69c40> is not a module, class, method, or function.
After digging around a bit, this diff seems to work (not sure if there's a better way to do it) (also this one doesn't seem to care whether @staticmethod is applied to the implementation methods):
$ diff -u functools-orig.py functools.py
--- functools-orig.py 2020-02-21 16:14:56.141934001 -0500
+++ functools.py 2020-02-21 16:17:19.959905849 -0500
@@ -843,14 +843,18 @@
if func is None:
if isinstance(cls, type):
return lambda f: register(cls, f)
- ann = getattr(cls, '__annotations__', {})
+ if isinstance(cls, (classmethod, staticmethod)):
+ ann = getattr(cls.__func__, '__annotations__', {})
+ func = cls.__func__
+ else:
+ ann = getattr(cls, '__annotations__', {})
+ func = cls
if not ann:
raise TypeError(
f"Invalid first argument to `register()`: {cls!r}. "
f"Use either `@register(some_class)` or plain `@register` "
f"on an annotated function."
)
- func = cls
# only import typing if annotation parsing is necessary
from typing import get_type_hints
@@ -908,6 +912,8 @@
def __get__(self, obj, cls=None):
def _method(*args, **kwargs):
method = self.dispatcher.dispatch(args[0].__class__)
+ if isinstance(self.func, classmethod):
+ return method.__get__(obj, cls)(cls, *args, **kwargs)
return method.__get__(obj, cls)(*args, **kwargs)
_method.__isabstractmethod__ = self.__isabstractmethod__ |
|
Date |
User |
Action |
Args |
2020-02-21 21:21:43 | Viktor Roytman | set | recipients:
+ Viktor Roytman, ncoghlan, lukasz.langa, levkivskyi, xtreak |
2020-02-21 21:21:43 | Viktor Roytman | set | messageid: <1582320103.6.0.588155685636.issue39679@roundup.psfhosted.org> |
2020-02-21 21:21:43 | Viktor Roytman | link | issue39679 messages |
2020-02-21 21:21:43 | Viktor Roytman | create | |
|