[Python-checkins] bpo-8525: help() on a type now shows builtin subclasses (GH-5066)

Nick Coghlan webhook-mailer at python.org
Sun Oct 21 03:22:05 EDT 2018


https://github.com/python/cpython/commit/a323cdcb33c8c856e5668acfb2c67ab5198672c4
commit: a323cdcb33c8c856e5668acfb2c67ab5198672c4
branch: master
author: Sanyam Khurana <8039608+CuriousLearner at users.noreply.github.com>
committer: Nick Coghlan <ncoghlan at gmail.com>
date: 2018-10-21T17:22:02+10:00
summary:

bpo-8525: help() on a type now shows builtin subclasses (GH-5066)

For builtin types with builtin subclasses, help() on the type now shows up
to 4 of the subclasses. This partially replaces the exception hierarchy
information previously displayed in Python 2.7.

files:
A Misc/NEWS.d/next/Library/2018-01-01-00-16-59.bpo-8525.Dq8s63.rst
M Lib/pydoc.py
M Lib/test/test_pydoc.py

diff --git a/Lib/pydoc.py b/Lib/pydoc.py
index 8a6b27b16e52..3a461714821d 100644
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -1254,6 +1254,24 @@ def makename(c, m=object.__module__):
                 push('    ' + makename(base))
             push('')
 
+        # List the built-in subclasses, if any:
+        subclasses = sorted(
+            (str(cls.__name__) for cls in object.__subclasses__()
+             if not cls.__name__.startswith("_") and cls.__module__ == "builtins"),
+            key=str.lower
+        )
+        no_of_subclasses = len(subclasses)
+        MAX_SUBCLASSES_TO_DISPLAY = 4
+        if subclasses:
+            push("Built-in subclasses:")
+            for subclassname in subclasses[:MAX_SUBCLASSES_TO_DISPLAY]:
+                push('    ' + subclassname)
+            if no_of_subclasses > MAX_SUBCLASSES_TO_DISPLAY:
+                push('    ... and ' +
+                     str(no_of_subclasses - MAX_SUBCLASSES_TO_DISPLAY) +
+                     ' other subclasses')
+            push('')
+
         # Cute little class to pump out a horizontal rule between sections.
         class HorizontalRule:
             def __init__(self):
diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py
index 06f872999515..6cd81ec5c334 100644
--- a/Lib/test/test_pydoc.py
+++ b/Lib/test/test_pydoc.py
@@ -517,6 +517,124 @@ def test_stripid(self):
         self.assertEqual(stripid("<type 'exceptions.Exception'>"),
                          "<type 'exceptions.Exception'>")
 
+    def test_builtin_with_more_than_four_children(self):
+        """Tests help on builtin object which have more than four child classes.
+
+        When running help() on a builtin class which has child classes, it
+        should contain a "Built-in subclasses" section and only 4 classes
+        should be displayed with a hint on how many more subclasses are present.
+        For example:
+
+        >>> help(object)
+        Help on class object in module builtins:
+
+        class object
+         |  The most base type
+         |
+         |  Built-in subclasses:
+         |      async_generator
+         |      BaseException
+         |      builtin_function_or_method
+         |      bytearray
+         |      ... and 82 other subclasses
+        """
+        doc = pydoc.TextDoc()
+        text = doc.docclass(object)
+        snip = (" |  Built-in subclasses:\n"
+                " |      async_generator\n"
+                " |      BaseException\n"
+                " |      builtin_function_or_method\n"
+                " |      bytearray\n"
+                " |      ... and \\d+ other subclasses")
+        self.assertRegex(text, snip)
+
+    def test_builtin_with_child(self):
+        """Tests help on builtin object which have only child classes.
+
+        When running help() on a builtin class which has child classes, it
+        should contain a "Built-in subclasses" section. For example:
+
+        >>> help(ArithmeticError)
+        Help on class ArithmeticError in module builtins:
+
+        class ArithmeticError(Exception)
+         |  Base class for arithmetic errors.
+         |
+         ...
+         |
+         |  Built-in subclasses:
+         |      FloatingPointError
+         |      OverflowError
+         |      ZeroDivisionError
+        """
+        doc = pydoc.TextDoc()
+        text = doc.docclass(ArithmeticError)
+        snip = (" |  Built-in subclasses:\n"
+                " |      FloatingPointError\n"
+                " |      OverflowError\n"
+                " |      ZeroDivisionError")
+        self.assertIn(snip, text)
+
+    def test_builtin_with_grandchild(self):
+        """Tests help on builtin classes which have grandchild classes.
+
+        When running help() on a builtin class which has child classes, it
+        should contain a "Built-in subclasses" section. However, if it also has
+        grandchildren, these should not show up on the subclasses section.
+        For example:
+
+        >>> help(Exception)
+        Help on class Exception in module builtins:
+
+        class Exception(BaseException)
+         |  Common base class for all non-exit exceptions.
+         |
+         ...
+         |
+         |  Built-in subclasses:
+         |      ArithmeticError
+         |      AssertionError
+         |      AttributeError
+         ...
+        """
+        doc = pydoc.TextDoc()
+        text = doc.docclass(Exception)
+        snip = (" |  Built-in subclasses:\n"
+                " |      ArithmeticError\n"
+                " |      AssertionError\n"
+                " |      AttributeError")
+        self.assertIn(snip, text)
+        # Testing that the grandchild ZeroDivisionError does not show up
+        self.assertNotIn('ZeroDivisionError', text)
+
+    def test_builtin_no_child(self):
+        """Tests help on builtin object which have no child classes.
+
+        When running help() on a builtin class which has no child classes, it
+        should not contain any "Built-in subclasses" section. For example:
+
+        >>> help(ZeroDivisionError)
+
+        Help on class ZeroDivisionError in module builtins:
+
+        class ZeroDivisionError(ArithmeticError)
+         |  Second argument to a division or modulo operation was zero.
+         |
+         |  Method resolution order:
+         |      ZeroDivisionError
+         |      ArithmeticError
+         |      Exception
+         |      BaseException
+         |      object
+         |
+         |  Methods defined here:
+         ...
+        """
+        doc = pydoc.TextDoc()
+        text = doc.docclass(ZeroDivisionError)
+        # Testing that the subclasses section does not appear
+        self.assertNotIn('Built-in subclasses', text)
+
     @unittest.skipIf(sys.flags.optimize >= 2,
                      'Docstrings are omitted with -O2 and above')
     @unittest.skipIf(hasattr(sys, 'gettrace') and sys.gettrace(),
diff --git a/Misc/NEWS.d/next/Library/2018-01-01-00-16-59.bpo-8525.Dq8s63.rst b/Misc/NEWS.d/next/Library/2018-01-01-00-16-59.bpo-8525.Dq8s63.rst
new file mode 100644
index 000000000000..d8af500ab63c
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2018-01-01-00-16-59.bpo-8525.Dq8s63.rst
@@ -0,0 +1,4 @@
+help() on a type now displays builtin subclasses. This is intended primarily
+to help with notification of more specific exception subclasses.
+
+Patch by Sanyam Khurana.



More information about the Python-checkins mailing list