]> granicus.if.org Git - python/commitdiff
Issue #20710: The pydoc summary line no longer displays the "self" parameter
authorLarry Hastings <larry@hastings.org>
Fri, 21 Feb 2014 07:34:46 +0000 (23:34 -0800)
committerLarry Hastings <larry@hastings.org>
Fri, 21 Feb 2014 07:34:46 +0000 (23:34 -0800)
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.

Lib/pydoc.py
Lib/test/test_pydoc.py
Misc/NEWS

index 3873d5554acf4753e4405a115415970f402491c7..505b7cbd58da9ca20bf8be1f0a57be1e09a72359 100755 (executable)
@@ -137,6 +137,19 @@ def _is_some_method(obj):
             inspect.isbuiltin(obj) or
             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):
     methods = {}
     for key, value in inspect.getmembers(cl, _is_some_method):
@@ -898,7 +911,7 @@ class HTMLDoc(Doc):
         anchor = (cl and cl.__name__ or '') + '-' + name
         note = ''
         skipdocs = 0
-        if inspect.ismethod(object):
+        if _is_bound_method(object):
             imclass = object.__self__.__class__
             if cl:
                 if imclass is not cl:
@@ -909,7 +922,6 @@ class HTMLDoc(Doc):
                         object.__self__.__class__, mod)
                 else:
                     note = ' unbound %s method' % self.classlink(imclass,mod)
-            object = object.__func__
 
         if name == 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' % (
                 anchor, name, reallink)
         argspec = None
-        if inspect.isfunction(object) or inspect.isbuiltin(object):
+        if inspect.isroutine(object):
             try:
                 signature = inspect.signature(object)
             except (ValueError, TypeError):
@@ -1304,7 +1316,7 @@ location listed above.
         name = name or realname
         note = ''
         skipdocs = 0
-        if inspect.ismethod(object):
+        if _is_bound_method(object):
             imclass = object.__self__.__class__
             if cl:
                 if imclass is not cl:
@@ -1315,7 +1327,6 @@ location listed above.
                         object.__self__.__class__, mod)
                 else:
                     note = ' unbound %s method' % classname(imclass,mod)
-            object = object.__func__
 
         if name == realname:
             title = self.bold(realname)
index 9909b9ae535387c7d3ed5c8848cce326b839ae56..96b923077fb0a74caf6aea7d0b826dde127c5479 100644 (file)
@@ -6,6 +6,7 @@ import difflib
 import inspect
 import pydoc
 import keyword
+import _pickle
 import pkgutil
 import re
 import string
@@ -699,12 +700,41 @@ class TestDescriptions(unittest.TestCase):
             self.assertIsNone(pydoc.locate(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
+    def test_unbound_builtin_method(self):
+        self.assertEqual(self._get_summary_line(_pickle.Pickler.dump),
+            "dump(self, obj, /)")
+
+    # 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_builtin_signatures(self):
-        # test producing signatures from builtins
-        stat_sig = pydoc.render_doc(os.stat)
-        self.assertEqual(pydoc.plain(stat_sig).splitlines()[2],
-            'stat(path, *, dir_fd=None, follow_symlinks=True)')
+    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.')
index edb5f717511e02a95fd0420389aef8c68988e11e..b4374cc4879747cea5f869cd3b90247de2381062 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -28,6 +28,9 @@ Core and Builtins
 Library
 -------
 
+- Issue #20710: The pydoc summary line no longer displays the "self" parameter
+  for bound methods.
+
 - Issue #20654: Fixed pydoc for enums with zero value.  Patch by Vajrasky Kok.
 
 - Issue #20635: Fixed grid_columnconfigure() and grid_rowconfigure() methods of