gh-127750: Improve repr of functools.singledispatchmethod (GH-130220)

This commit is contained in:
Serhiy Storchaka 2025-03-05 13:10:05 +02:00 committed by GitHub
parent 67a942d427
commit f33d21e24f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 85 additions and 0 deletions

View file

@ -1033,6 +1033,15 @@ class singledispatchmethod:
def __isabstractmethod__(self): def __isabstractmethod__(self):
return getattr(self.func, '__isabstractmethod__', False) return getattr(self.func, '__isabstractmethod__', False)
def __repr__(self):
try:
name = self.func.__qualname__
except AttributeError:
try:
name = self.func.__name__
except AttributeError:
name = '?'
return f'<single dispatch method descriptor {name}>'
class _singledispatchmethod_get: class _singledispatchmethod_get:
def __init__(self, unbound, obj, cls): def __init__(self, unbound, obj, cls):
@ -1052,6 +1061,19 @@ class _singledispatchmethod_get:
except AttributeError: except AttributeError:
pass pass
def __repr__(self):
try:
name = self.__qualname__
except AttributeError:
try:
name = self.__name__
except AttributeError:
name = '?'
if self._obj is not None:
return f'<bound single dispatch method {name} of {self._obj!r}>'
else:
return f'<single dispatch method {name}>'
def __call__(self, /, *args, **kwargs): def __call__(self, /, *args, **kwargs):
if not args: if not args:
funcname = getattr(self._unbound.func, '__name__', funcname = getattr(self._unbound.func, '__name__',

View file

@ -2934,6 +2934,67 @@ class TestSingleDispatch(unittest.TestCase):
self.assertEqual(A.static_func.__name__, 'static_func') self.assertEqual(A.static_func.__name__, 'static_func')
self.assertEqual(A().static_func.__name__, 'static_func') self.assertEqual(A().static_func.__name__, 'static_func')
def test_method_repr(self):
class Callable:
def __call__(self, *args):
pass
class CallableWithName:
__name__ = 'NOQUALNAME'
def __call__(self, *args):
pass
class A:
@functools.singledispatchmethod
def func(self, arg):
pass
@functools.singledispatchmethod
@classmethod
def cls_func(cls, arg):
pass
@functools.singledispatchmethod
@staticmethod
def static_func(arg):
pass
# No __qualname__, only __name__
no_qualname = functools.singledispatchmethod(CallableWithName())
# No __qualname__, no __name__
no_name = functools.singledispatchmethod(Callable())
self.assertEqual(repr(A.__dict__['func']),
f'<single dispatch method descriptor {A.__qualname__}.func>')
self.assertEqual(repr(A.__dict__['cls_func']),
f'<single dispatch method descriptor {A.__qualname__}.cls_func>')
self.assertEqual(repr(A.__dict__['static_func']),
f'<single dispatch method descriptor {A.__qualname__}.static_func>')
self.assertEqual(repr(A.__dict__['no_qualname']),
f'<single dispatch method descriptor NOQUALNAME>')
self.assertEqual(repr(A.__dict__['no_name']),
f'<single dispatch method descriptor ?>')
self.assertEqual(repr(A.func),
f'<single dispatch method {A.__qualname__}.func>')
self.assertEqual(repr(A.cls_func),
f'<single dispatch method {A.__qualname__}.cls_func>')
self.assertEqual(repr(A.static_func),
f'<single dispatch method {A.__qualname__}.static_func>')
self.assertEqual(repr(A.no_qualname),
f'<single dispatch method NOQUALNAME>')
self.assertEqual(repr(A.no_name),
f'<single dispatch method ?>')
a = A()
self.assertEqual(repr(a.func),
f'<bound single dispatch method {A.__qualname__}.func of {a!r}>')
self.assertEqual(repr(a.cls_func),
f'<bound single dispatch method {A.__qualname__}.cls_func of {a!r}>')
self.assertEqual(repr(a.static_func),
f'<bound single dispatch method {A.__qualname__}.static_func of {a!r}>')
self.assertEqual(repr(a.no_qualname),
f'<bound single dispatch method NOQUALNAME of {a!r}>')
self.assertEqual(repr(a.no_name),
f'<bound single dispatch method ? of {a!r}>')
def test_double_wrapped_methods(self): def test_double_wrapped_methods(self):
def classmethod_friendly_decorator(func): def classmethod_friendly_decorator(func):
wrapped = func.__func__ wrapped = func.__func__

View file

@ -0,0 +1,2 @@
Improve repr of :class:`functools.singledispatchmethod` methods and
descriptors.