Skip to content

Commit 5aa8908

Browse files
gh-127750: Restore inspect and pydoc support of singledispatchmethod
The code is still flawed, because it does not recognize class and static methods, and the first argument is not removed from the signature of bound methods, but at least it does not worse than in 3.13 and older.
1 parent b93b7e5 commit 5aa8908

File tree

4 files changed

+79
-1
lines changed

4 files changed

+79
-1
lines changed

Lib/functools.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,10 @@ def __getattr__(self, name):
10751075
raise AttributeError
10761076
return getattr(self._unbound.func, name)
10771077

1078+
@property
1079+
def __wrapped__(self):
1080+
return self._unbound.func
1081+
10781082
@property
10791083
def register(self):
10801084
return self._unbound.register

Lib/inspect.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,8 @@ def isroutine(object):
447447
or isfunction(object)
448448
or ismethod(object)
449449
or ismethoddescriptor(object)
450-
or ismethodwrapper(object))
450+
or ismethodwrapper(object)
451+
or isinstance(object, functools._singledispatchmethod_get))
451452

452453
def isabstract(object):
453454
"""Return true if the object is an abstract base class (ABC)."""

Lib/test/test_functools.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3312,6 +3312,58 @@ def t(self, arg):
33123312
support.gc_collect()
33133313
self.assertIsNone(r())
33143314

3315+
def test_signatures(self):
3316+
@functools.singledispatch
3317+
def func(item, arg: int) -> str:
3318+
return str(item)
3319+
@func.register
3320+
def _(item: int, arg: bytes) -> str:
3321+
return str(item)
3322+
3323+
self.assertEqual(str(Signature.from_callable(func)),
3324+
'(item, arg: int) -> str')
3325+
3326+
def test_method_signatures(self):
3327+
class A:
3328+
def m(self, item, arg: int) -> str:
3329+
return str(item)
3330+
@classmethod
3331+
def cm(cls, item, arg: int) -> str:
3332+
return str(item)
3333+
@functools.singledispatchmethod
3334+
def func(self, item, arg: int) -> str:
3335+
return str(item)
3336+
@func.register
3337+
def _(self, item, arg: bytes) -> str:
3338+
return str(item)
3339+
3340+
@functools.singledispatchmethod
3341+
@classmethod
3342+
def cls_func(cls, item, arg: int) -> str:
3343+
return str(arg)
3344+
@func.register
3345+
@classmethod
3346+
def _(cls, item, arg: bytes) -> str:
3347+
return str(item)
3348+
3349+
@functools.singledispatchmethod
3350+
@staticmethod
3351+
def static_func(item, arg: int) -> str:
3352+
return str(arg)
3353+
@func.register
3354+
@staticmethod
3355+
def _(item, arg: bytes) -> str:
3356+
return str(item)
3357+
3358+
self.assertEqual(str(Signature.from_callable(A.func)),
3359+
'(self, item, arg: int) -> str')
3360+
self.assertEqual(str(Signature.from_callable(A().func)),
3361+
'(self, item, arg: int) -> str')
3362+
self.assertEqual(str(Signature.from_callable(A.cls_func)),
3363+
'(cls, item, arg: int) -> str')
3364+
self.assertEqual(str(Signature.from_callable(A.static_func)),
3365+
'(item, arg: int) -> str')
3366+
33153367

33163368
class CachedCostItem:
33173369
_cost = 1

Lib/test/test_inspect/test_inspect.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,27 @@ def test_isroutine(self):
415415
# partial
416416
self.assertTrue(inspect.isroutine(functools.partial(mod.spam)))
417417

418+
def test_isroutine_singledispatch(self):
419+
self.assertTrue(inspect.isroutine(functools.singledispatch(mod.spam)))
420+
421+
class A:
422+
@functools.singledispatchmethod
423+
def method(self, arg):
424+
pass
425+
@functools.singledispatchmethod
426+
@classmethod
427+
def class_method(cls, arg):
428+
pass
429+
@functools.singledispatchmethod
430+
@staticmethod
431+
def static_method(arg):
432+
pass
433+
434+
self.assertTrue(inspect.isroutine(A.method))
435+
self.assertTrue(inspect.isroutine(A().method))
436+
self.assertTrue(inspect.isroutine(A.static_method))
437+
self.assertTrue(inspect.isroutine(A.class_method))
438+
418439
def test_isclass(self):
419440
self.istest(inspect.isclass, 'mod.StupidGit')
420441
self.assertTrue(inspect.isclass(list))

0 commit comments

Comments
 (0)