mirror of
https://github.com/python/cpython.git
synced 2025-07-29 14:15:07 +00:00
Issue #20710: The pydoc summary line no longer displays the "self" parameter
for bound methods. Previous to this change, it displayed "self" for methods implemented in Python but not methods implemented in C; it is now both internally consistent and consistent with inspect.Signature.
This commit is contained in:
parent
d224b6a796
commit
13da6a1a9c
3 changed files with 54 additions and 10 deletions
21
Lib/pydoc.py
21
Lib/pydoc.py
|
@ -137,6 +137,19 @@ def _is_some_method(obj):
|
||||||
inspect.isbuiltin(obj) or
|
inspect.isbuiltin(obj) or
|
||||||
inspect.ismethoddescriptor(obj))
|
inspect.ismethoddescriptor(obj))
|
||||||
|
|
||||||
|
def _is_bound_method(fn):
|
||||||
|
"""
|
||||||
|
Returns True if fn is a bound method, regardless of whether
|
||||||
|
fn was implemented in Python or in C.
|
||||||
|
"""
|
||||||
|
if inspect.ismethod(fn):
|
||||||
|
return True
|
||||||
|
if inspect.isbuiltin(fn):
|
||||||
|
self = getattr(fn, '__self__', None)
|
||||||
|
return not (inspect.ismodule(self) or (self is None))
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def allmethods(cl):
|
def allmethods(cl):
|
||||||
methods = {}
|
methods = {}
|
||||||
for key, value in inspect.getmembers(cl, _is_some_method):
|
for key, value in inspect.getmembers(cl, _is_some_method):
|
||||||
|
@ -898,7 +911,7 @@ class HTMLDoc(Doc):
|
||||||
anchor = (cl and cl.__name__ or '') + '-' + name
|
anchor = (cl and cl.__name__ or '') + '-' + name
|
||||||
note = ''
|
note = ''
|
||||||
skipdocs = 0
|
skipdocs = 0
|
||||||
if inspect.ismethod(object):
|
if _is_bound_method(object):
|
||||||
imclass = object.__self__.__class__
|
imclass = object.__self__.__class__
|
||||||
if cl:
|
if cl:
|
||||||
if imclass is not cl:
|
if imclass is not cl:
|
||||||
|
@ -909,7 +922,6 @@ class HTMLDoc(Doc):
|
||||||
object.__self__.__class__, mod)
|
object.__self__.__class__, mod)
|
||||||
else:
|
else:
|
||||||
note = ' unbound %s method' % self.classlink(imclass,mod)
|
note = ' unbound %s method' % self.classlink(imclass,mod)
|
||||||
object = object.__func__
|
|
||||||
|
|
||||||
if name == realname:
|
if name == realname:
|
||||||
title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
|
title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
|
||||||
|
@ -924,7 +936,7 @@ class HTMLDoc(Doc):
|
||||||
title = '<a name="%s"><strong>%s</strong></a> = %s' % (
|
title = '<a name="%s"><strong>%s</strong></a> = %s' % (
|
||||||
anchor, name, reallink)
|
anchor, name, reallink)
|
||||||
argspec = None
|
argspec = None
|
||||||
if inspect.isfunction(object) or inspect.isbuiltin(object):
|
if inspect.isroutine(object):
|
||||||
try:
|
try:
|
||||||
signature = inspect.signature(object)
|
signature = inspect.signature(object)
|
||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
|
@ -1301,7 +1313,7 @@ location listed above.
|
||||||
name = name or realname
|
name = name or realname
|
||||||
note = ''
|
note = ''
|
||||||
skipdocs = 0
|
skipdocs = 0
|
||||||
if inspect.ismethod(object):
|
if _is_bound_method(object):
|
||||||
imclass = object.__self__.__class__
|
imclass = object.__self__.__class__
|
||||||
if cl:
|
if cl:
|
||||||
if imclass is not cl:
|
if imclass is not cl:
|
||||||
|
@ -1312,7 +1324,6 @@ location listed above.
|
||||||
object.__self__.__class__, mod)
|
object.__self__.__class__, mod)
|
||||||
else:
|
else:
|
||||||
note = ' unbound %s method' % classname(imclass,mod)
|
note = ' unbound %s method' % classname(imclass,mod)
|
||||||
object = object.__func__
|
|
||||||
|
|
||||||
if name == realname:
|
if name == realname:
|
||||||
title = self.bold(realname)
|
title = self.bold(realname)
|
||||||
|
|
|
@ -6,6 +6,7 @@ import difflib
|
||||||
import inspect
|
import inspect
|
||||||
import pydoc
|
import pydoc
|
||||||
import keyword
|
import keyword
|
||||||
|
import _pickle
|
||||||
import pkgutil
|
import pkgutil
|
||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
|
@ -689,12 +690,41 @@ class TestDescriptions(unittest.TestCase):
|
||||||
self.assertIsNone(pydoc.locate(name))
|
self.assertIsNone(pydoc.locate(name))
|
||||||
self.assertRaises(ImportError, pydoc.render_doc, name)
|
self.assertRaises(ImportError, pydoc.render_doc, name)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_summary_line(o):
|
||||||
|
text = pydoc.plain(pydoc.render_doc(o))
|
||||||
|
lines = text.split('\n')
|
||||||
|
assert len(lines) >= 2
|
||||||
|
return lines[2]
|
||||||
|
|
||||||
|
# these should include "self"
|
||||||
|
def test_unbound_python_method(self):
|
||||||
|
self.assertEqual(self._get_summary_line(textwrap.TextWrapper.wrap),
|
||||||
|
"wrap(self, text)")
|
||||||
|
|
||||||
@requires_docstrings
|
@requires_docstrings
|
||||||
def test_builtin_signatures(self):
|
def test_unbound_builtin_method(self):
|
||||||
# test producing signatures from builtins
|
self.assertEqual(self._get_summary_line(_pickle.Pickler.dump),
|
||||||
stat_sig = pydoc.render_doc(os.stat)
|
"dump(self, obj, /)")
|
||||||
self.assertEqual(pydoc.plain(stat_sig).splitlines()[2],
|
|
||||||
'stat(path, *, dir_fd=None, follow_symlinks=True)')
|
# these no longer include "self"
|
||||||
|
def test_bound_python_method(self):
|
||||||
|
t = textwrap.TextWrapper()
|
||||||
|
self.assertEqual(self._get_summary_line(t.wrap),
|
||||||
|
"wrap(text) method of textwrap.TextWrapper instance")
|
||||||
|
|
||||||
|
@requires_docstrings
|
||||||
|
def test_bound_builtin_method(self):
|
||||||
|
s = StringIO()
|
||||||
|
p = _pickle.Pickler(s)
|
||||||
|
self.assertEqual(self._get_summary_line(p.dump),
|
||||||
|
"dump(obj, /) method of _pickle.Pickler instance")
|
||||||
|
|
||||||
|
# this should *never* include self!
|
||||||
|
@requires_docstrings
|
||||||
|
def test_module_level_callable(self):
|
||||||
|
self.assertEqual(self._get_summary_line(os.stat),
|
||||||
|
"stat(path, *, dir_fd=None, follow_symlinks=True)")
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(threading, 'Threading required for this test.')
|
@unittest.skipUnless(threading, 'Threading required for this test.')
|
||||||
|
|
|
@ -26,6 +26,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #20710: The pydoc summary line no longer displays the "self" parameter
|
||||||
|
for bound methods.
|
||||||
|
|
||||||
- Issue #20566: Change asyncio.as_completed() to use a Queue, to
|
- Issue #20566: Change asyncio.as_completed() to use a Queue, to
|
||||||
avoid O(N**2) behavior.
|
avoid O(N**2) behavior.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue