From 609c7951bd36ea9a772456a0e9f1d2ae5a2ce041 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sun, 9 Oct 2022 14:26:49 +0300 Subject: [PATCH] gh-97959: [pydoc] now `help()` does not show extra notes for `classmethod`s --- Lib/pydoc.py | 14 ++++++- Lib/test/pydoc_mod.py | 3 ++ Lib/test/test_pydoc.py | 39 +++++++++++++++++-- ...2-10-09-14-26-14.gh-issue-97959.tbJfPO.rst | 2 + 4 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2022-10-09-14-26-14.gh-issue-97959.tbJfPO.rst diff --git a/Lib/pydoc.py b/Lib/pydoc.py index a4dc910c8a8e89..574e72466c2e90 100755 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -243,6 +243,14 @@ def _is_bound_method(fn): return not (inspect.ismodule(self) or (self is None)) return False +def _is_bound_classmethod(method): + """Returns True for bound classmethods.""" + return ( + inspect.isclass(method.__self__) and + (getattr(getattr(method.__self__, method.__name__, None), '__func__', None) + is method.__func__) + ) + def allmethods(cl): methods = {} @@ -1032,7 +1040,8 @@ def docroutine(self, object, name=None, mod=None, if _is_bound_method(object): imclass = object.__self__.__class__ if cl: - if imclass is not cl: + if imclass is not cl and not _is_bound_classmethod(object): + # We ignore `from builtins.type` note for classmethods. note = ' from ' + self.classlink(imclass, mod) else: if object.__self__ is not None: @@ -1465,7 +1474,8 @@ def docroutine(self, object, name=None, mod=None, cl=None): if _is_bound_method(object): imclass = object.__self__.__class__ if cl: - if imclass is not cl: + if imclass is not cl and not _is_bound_classmethod(object): + # We ignore `from builtins.type` note for classmethods. note = ' from ' + classname(imclass, mod) else: if object.__self__ is not None: diff --git a/Lib/test/pydoc_mod.py b/Lib/test/pydoc_mod.py index 80c287fb10c31e..326d6971853e6b 100644 --- a/Lib/test/pydoc_mod.py +++ b/Lib/test/pydoc_mod.py @@ -31,6 +31,9 @@ def is_it_true(self): return self.get_answer() def __class_getitem__(self, item): return types.GenericAlias(self, item) + @classmethod + def regular(cls, arg): + """Doc for class method.""" def doc_func(): """ diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py index cefc71cb5a7f54..f68103bda18225 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -98,7 +98,10 @@ class C(builtins.object) | ---------------------------------------------------------------------- | Class methods defined here: | - | __class_getitem__(item) from builtins.type + | __class_getitem__(item) + | + | regular(arg) + | Doc for class method. | | ---------------------------------------------------------------------- | Data descriptors defined here: @@ -188,7 +191,9 @@ class C(builtins.object) Return self.get_answer() say_no(self) Class methods defined here: - __class_getitem__(item) from builtins.type + __class_getitem__(item) + regular(arg) + Doc for class method. Data descriptors defined here: __dict__ dictionary for instance variables (if defined) @@ -1202,10 +1207,38 @@ def cm(cls, x): self.assertIn(""" | Class methods defined here: | - | cm(x) from builtins.type + | cm(x) | A class method """, pydoc.plain(pydoc.render_doc(X))) + @requires_docstrings + def test_classmethod_builtins(self): + self.assertIn(""" + | Class methods defined here: + | + | from_bytes = + | Return the integer represented by the given array of bytes. + | +""", pydoc.plain(pydoc.render_doc(int))) + + @requires_docstrings + def test_types_method_type(self): + from types import MethodType + + def some(*args, **kwargs): + """Doc1.""" + + class X: + name = MethodType(some, 1) + + self.assertIn(""" + | Methods defined here: + | + | name = some(*args, **kwargs) from builtins.int + | Doc1. + | +""", pydoc.plain(pydoc.render_doc(X))) + @requires_docstrings def test_getset_descriptor(self): # Currently these attributes are implemented as getset descriptors diff --git a/Misc/NEWS.d/next/Library/2022-10-09-14-26-14.gh-issue-97959.tbJfPO.rst b/Misc/NEWS.d/next/Library/2022-10-09-14-26-14.gh-issue-97959.tbJfPO.rst new file mode 100644 index 00000000000000..ea158e695b1c67 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-09-14-26-14.gh-issue-97959.tbJfPO.rst @@ -0,0 +1,2 @@ +Now ``help()`` does not show ``from builtins.type`` note for ``classmethod`` +definitions.