Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Oct 21, 2018
18 changes: 18 additions & 0 deletions Lib/pydoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
118 changes: 118 additions & 0 deletions Lib/test/test_pydoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
Original file line number Diff line number Diff line change
@@ -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.