From a323cdcb33c8c856e5668acfb2c67ab5198672c4 Mon Sep 17 00:00:00 2001 From: Sanyam Khurana <8039608+CuriousLearner@users.noreply.github.com> Date: Sun, 21 Oct 2018 00:22:02 -0700 Subject: 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. --- Lib/pydoc.py | 18 ++++ Lib/test/test_pydoc.py | 118 +++++++++++++++++++++ .../2018-01-01-00-16-59.bpo-8525.Dq8s63.rst | 4 + 3 files changed, 140 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2018-01-01-00-16-59.bpo-8525.Dq8s63.rst diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 8a6b27b..3a46171 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -1254,6 +1254,24 @@ location listed above. 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 06f8729..6cd81ec 100644 --- a/Lib/test/test_pydoc.py +++ b/Lib/test/test_pydoc.py @@ -517,6 +517,124 @@ class PydocDocTest(unittest.TestCase): self.assertEqual(stripid(""), "") + 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 0000000..d8af500 --- /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. -- cgit v0.12