would require parsing Python code directly (which is what Sphinx has to do
to support these).
+`Documenting enum values`_
+--------------------------
+
+Python supplies an implicit docstrings for enums derived from :py:`enum.Enum`
+and enum values implicitly inherit the docstring of the enum class. If either
+is detected to be the case, docstring of the enum or the value is ignored.
+While it's possible to document enum classes the usual way, there's a
+non-obvious way to document enum values as well.
+
+.. code:: py
+
+ import enum
+
+ class MyEnum(enum.Enum):
+ """My enum"""
+
+ ZERO = 0
+ TWO = 3
+ CONSISTENCY = -73
+
+ MyEnum.ZERO.__doc__ = "Zero value"
+ MyEnum.TWO.__doc__ = "Three, but named TWO for compatibility"
+
+The documentation output for enums includes enum value values and the class it
+was derived from, so it's possible to know whether it's an enum or a flag.
+
`Command-line options`_
=======================
======================================= =======================================
Property Description
======================================= =======================================
+:py:`page.prefix_wbr` Fully-qualified symbol prefix for given
+ compound with trailing ``.`` with
+ :html:`<wbr/>` tag after every ``.``.
:py:`page.modules` List of inner modules. See
`Module properties`_ for details.
:py:`page.classes` List of classes. See
`Class properties`_ for details.
+:py:`page.enums` List of enums. See
+ `Enum properties`_ for details.
:py:`page.functions` List of module-level functions. See
`Function properties`_ for details.
:py:`page.data` List of module-level data. See
`Data properties`_ for details.
+:py:`page.has_enum_details` If there is at least one enum with full
+ description block [2]_
======================================= =======================================
Each class page has the following additional properties:
======================================= =======================================
Property Description
======================================= =======================================
+:py:`page.prefix_wbr` Fully-qualified symbol prefix for given
+ compound with trailing ``.`` with
+ :html:`<wbr/>` tag after every ``.``.
:py:`page.classes` List of classes. See
`Class properties`_ for details.
+:py:`page.enums` List of enums. See
+ `Enum properties`_ for details.
:py:`page.classmethods` List of class methods (annotated with
:py:`@classmethod`). See
`Function properties`_ for details.
`Property properties`_ for details.
:py:`page.data` List of data. See `Data properties`_
for details.
+:py:`page.has_enum_details` If there is at least one enum with full
+ description block [2]_
======================================= =======================================
`Module properties`_
:py:`class_.brief` Brief docs
======================================= =======================================
+`Enum properties`_
+```````````````````
+
+.. class:: m-table m-fullwidth
+
+======================================= =======================================
+Property Description
+======================================= =======================================
+:py:`enum.name` Enum name
+:py:`enum.brief` Brief docs
+:py:`enum.base` Base class from which the enum is
+ derived
+:py:`enum.values` List of enum values
+:py:`enum.has_details` If there is enough content for the full
+ description block. [2]_
+:py:`enum.has_value_details` If the enum values have description.
+ Impies :py:`enum.has_details`.
+======================================= =======================================
+
+Every item of :py:`enum.values` has the following properties:
+
+.. class:: m-table m-fullwidth
+
+=========================== ===================================================
+Property Description
+=========================== ===================================================
+:py:`value.name` Value name
+:py:`value.value` Value value. Set to :py:`None` if no value is
+ available.
+:py:`value.brief` Value brief docs
+=========================== ===================================================
+
`Function properties`_
``````````````````````
import argparse
import copy
+import enum
import urllib.parse
import html
import importlib
out.brief = extract_brief(class_.__doc__)
return out
+def extract_enum_doc(path: List[str], enum_):
+ assert issubclass(enum_, enum.Enum)
+
+ out = Empty()
+ out.name = path[-1]
+
+ # Enum doc is by default set to a generic value. That's useless as well.
+ if enum_.__doc__ == 'An enumeration.':
+ out.brief = ''
+ else:
+ out.brief = extract_brief(enum_.__doc__)
+
+ out.base = extract_type(enum_.__base__)
+ out.values = []
+ out.has_details = False
+ out.has_value_details = False
+
+ for i in enum_:
+ value = Empty()
+ value.name = i.name
+ value.value = html.escape(repr(i.value))
+
+ # Value doc gets by default inherited from the enum, that's useless
+ if i.__doc__ == enum_.__doc__:
+ value.brief = ''
+ else:
+ value.brief = extract_brief(i.__doc__)
+
+ if value.brief:
+ out.has_details = True
+ out.has_value_details = True
+ out.values += [value]
+
+ return out
+
def extract_function_doc(path: List[str], function):
assert inspect.isfunction(function) or inspect.ismethod(function) or inspect.isroutine(function)
page.brief = extract_brief(module.__doc__)
page.url = breadcrumb[-1][1]
page.breadcrumb = breadcrumb
+ page.prefix_wbr = '.<wbr />'.join(path + [''])
page.modules = []
page.classes = []
+ page.enums = []
page.functions = []
page.data = []
+ page.has_enum_details = False
# This is actually complicated -- if the module defines __all__, use that.
# The __all__ is meant to expose the public API, so we don't filter out
if inspect.ismodule(object):
page.modules += [extract_module_doc(subpath, object)]
render_module(config, subpath, object, env)
- elif inspect.isclass(object):
+ elif inspect.isclass(object) and not issubclass(object, enum.Enum):
page.classes += [extract_class_doc(subpath, object)]
render_class(config, subpath, object, env)
+ elif inspect.isclass(object) and issubclass(object, enum.Enum):
+ enum_ = extract_enum_doc(subpath, object)
+ page.enums += [enum_]
+ if enum_.has_details: page.has_enum_details = True
elif inspect.isfunction(object) or inspect.isbuiltin(object):
page.functions += [extract_function_doc(subpath, object)]
# Assume everything else is data. The builtin help help() (from
render_module(config, subpath, object, env)
# Get (and render) inner classes
- for name, object in inspect.getmembers(module, inspect.isclass):
+ for name, object in inspect.getmembers(module, lambda o: inspect.isclass(o) and not issubclass(o, enum.Enum)):
if is_internal_or_imported_module_member(module, path, name, object): continue
subpath = path + [name]
page.classes += [extract_class_doc(subpath, object)]
render_class(config, subpath, object, env)
+ # Get enums
+ for name, object in inspect.getmembers(module, lambda o: inspect.isclass(o) and issubclass(o, enum.Enum)):
+ if is_internal_or_imported_module_member(module, path, name, object): continue
+
+ subpath = path + [name]
+ if not object.__doc__: logging.warning("%s is undocumented", '.'.join(subpath))
+
+ enum_ = extract_enum_doc(subpath, object)
+ page.enums += [enum_]
+ if enum_.has_details: page.has_enum_details = True
+
# Get inner functions
for name, object in inspect.getmembers(module, lambda o: inspect.isfunction(o) or inspect.isbuiltin(o)):
if is_internal_or_imported_module_member(module, path, name, object): continue
page.brief = extract_brief(class_.__doc__)
page.url = breadcrumb[-1][1]
page.breadcrumb = breadcrumb
+ page.prefix_wbr = '.<wbr />'.join(path + [''])
page.classes = []
+ page.enums = []
page.classmethods = []
page.staticmethods = []
page.dunder_methods = []
page.methods = []
page.properties = []
page.data = []
+ page.has_enum_details = False
# Get inner classes
- for name, object in inspect.getmembers(class_, inspect.isclass):
+ for name, object in inspect.getmembers(class_, lambda o: inspect.isclass(o) and not issubclass(o, enum.Enum)):
if name in ['__base__', '__class__']: continue # TODO
if name.startswith('_'): continue
page.classes += [extract_class_doc(subpath, object)]
render_class(config, subpath, object, env)
+ # Get enums
+ for name, object in inspect.getmembers(class_, lambda o: inspect.isclass(o) and issubclass(o, enum.Enum)):
+ if name.startswith('_'): continue
+
+ subpath = path + [name]
+ if not object.__doc__: logging.warning("%s is undocumented", '.'.join(subpath))
+
+ enum_ = extract_enum_doc(subpath, object)
+ page.enums += [enum_]
+ if enum_.has_details: page.has_enum_details = True
+
# Get methods
for name, object in inspect.getmembers(class_, inspect.isroutine):
# Filter out underscored methods (but not dunder methods)
{% extends 'base.html' %}
{% macro entry_class(class) %}{% include 'entry-class.html' %}{% endmacro %}
+{% macro entry_enum(enum) %}{% include 'entry-enum.html' %}{% endmacro %}
{% macro entry_function(function) %}{% include 'entry-function.html' %}{% endmacro %}
{% macro entry_property(property) %}{% include 'entry-property.html' %}{% endmacro %}
{% macro entry_data(data) %}{% include 'entry-data.html' %}{% endmacro %}
+{% macro details_enum(enum, prefix) %}{% include 'details-enum.html' %}{% endmacro %}
+
{% block title %}{% set j = joiner('.') %}{% for name, _ in page.breadcrumb %}{{ j() }}{{ name }}{% endfor %} | {{ super() }}{% endblock %}
{% block main %}
{% if page.classes %}
<li><a href="#classes">Classes</a></li>
{% endif %}
+ {% if page.enums %}
+ <li><a href="#enums">Enums</a></li>
+ {% endif %}
{% if page.classmethods %}
<li><a href="#classmethods">Class methods</a></li>
{% endif %}
</dl>
</section>
{% endif %}
+ {% if page.enums %}
+ <section id="enums">
+ <h2><a href="#enums">Enums</a></h2>
+ <dl class="m-doc">
+ {% for enum in page.enums %}
+{{ entry_enum(enum) }}
+ {% endfor %}
+ </dl>
+ </section>
+ {% endif %}
{% if page.classmethods %}
<section id="classmethods">
<h2><a href="#classmethods">Class methods</a></h2>
</dl>
</section>
{% endif %}
+ {% if page.has_enum_details %}
+ <section>
+ <h2>Enum documentation</h2>
+ {% for enum in page.enums %}
+ {% if enum.has_details %}
+{{ details_enum(enum, page.prefix_wbr) }}
+ {% endif %}
+ {% endfor %}
+ </section>
+ {% endif %}
{% endblock %}
--- /dev/null
+ <section class="m-doc-details"><div>
+ <h3>
+ class {{ prefix }}<a href="" class="m-doc-self">{{ enum.name }}</a>({{ enum.base }})
+ </h3>
+ {% if enum.brief %}
+ <p>{{ enum.brief }}</p>
+ {% endif %}
+ {% if enum.has_value_details %}
+ <table class="m-table m-fullwidth m-flat m-doc">
+ <thead><tr><th style="width: 1%">Enumerators</th><th></th></tr></thead>
+ <tbody>
+ {% for value in enum.values %}
+ <tr>
+ <td><a href="" class="m-doc-self">{{ value.name }}</a></td>
+ <td>
+ {% if value.brief %}
+ <p>{{ value.brief }}</p>
+ {% endif %}
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ {% endif %}
+ </div></section>
--- /dev/null
+ <dt>
+ {% set j = joiner('\n ') %}
+ <span class="m-doc-wrap-bumper">class <a href="" class="m-doc{% if not enum.has_details %}-self{% endif %}">{{ enum.name }}</a>({{ enum.base }}): </span><span class="m-doc-wrap">{% for value in enum.values %}{{ j() }}<a href="" class="m-doc{% if not enum.has_details %}-self{% endif %}">{{ value.name }}</a>{% if value.value is not none %} = {{ value.value }}{% endif %}{% endfor %}</span>
+ </dt>
+ <dd>{{ enum.brief }}</dd>
{% macro entry_module(module) %}{% include 'entry-module.html' %}{% endmacro %}
{% macro entry_class(class) %}{% include 'entry-class.html' %}{% endmacro %}
+{% macro entry_enum(enum) %}{% include 'entry-enum.html' %}{% endmacro %}
{% macro entry_function(function) %}{% include 'entry-function.html' %}{% endmacro %}
{% macro entry_data(data) %}{% include 'entry-data.html' %}{% endmacro %}
+{% macro details_enum(enum, prefix) %}{% include 'details-enum.html' %}{% endmacro %}
+
{% block title %}{% set j = joiner('.') %}{% for name, _ in page.breadcrumb %}{{ j() }}{{ name }}{% endfor %} | {{ super() }}{% endblock %}
{% block main %}
{% if page.classes %}
<li><a href="#classes">Classes</a></li>
{% endif %}
+ {% if page.enums %}
+ <li><a href="#enums">Enums</a></li>
+ {% endif %}
{% if page.functions %}
<li><a href="#functions">Functions</a></li>
{% endif %}
</dl>
</section>
{% endif %}
+ {% if page.enums %}
+ <section id="enums">
+ <h2><a href="#enums">Enums</a></h2>
+ <dl class="m-doc">
+ {% for enum in page.enums %}
+{{ entry_enum(enum) }}
+ {% endfor %}
+ </dl>
+ </section>
+ {% endif %}
{% if page.functions %}
<section id="functions">
<h2><a href="#functions">Functions</a></h2>
</dl>
</section>
{% endif %}
+ {% if page.has_enum_details %}
+ <section>
+ <h2>Enum documentation</h2>
+ {% for enum in page.enums %}
+ {% if enum.has_details %}
+{{ details_enum(enum, page.prefix_wbr) }}
+ {% endif %}
+ {% endfor %}
+ </section>
+ {% endif %}
{% endblock %}
<ul>
<li><a href="#packages">Modules</a></li>
<li><a href="#classes">Classes</a></li>
+ <li><a href="#enums">Enums</a></li>
<li><a href="#functions">Functions</a></li>
<li><a href="#data">Data</a></li>
</ul>
<dd></dd>
</dl>
</section>
+ <section id="enums">
+ <h2><a href="#enums">Enums</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">class <a href="" class="m-doc">_MyPrivateEnum</a>(enum.Enum): </span><span class="m-doc-wrap"><a href="" class="m-doc">VALUE</a> = 1
+ <a href="" class="m-doc">ANOTHER</a> = 2
+ <a href="" class="m-doc">YAY</a> = 3</span>
+ </dt>
+ <dd></dd>
+ <dt>
+ <span class="m-doc-wrap-bumper">class <a href="" class="m-doc-self">UndocumentedEnum</a>(enum.IntFlag): </span><span class="m-doc-wrap"><a href="" class="m-doc-self">FLAG_ONE</a> = 1
+ <a href="" class="m-doc-self">FLAG_SEVENTEEN</a> = 17</span>
+ </dt>
+ <dd></dd>
+ </dl>
+ </section>
<section id="functions">
<h2><a href="#functions">Functions</a></h2>
<dl class="m-doc">
<dd></dd>
</dl>
</section>
+ <section>
+ <h2>Enum documentation</h2>
+ <section class="m-doc-details"><div>
+ <h3>
+ class inspect_all_property.<wbr /><a href="" class="m-doc-self">_MyPrivateEnum</a>(enum.Enum)
+ </h3>
+ <table class="m-table m-fullwidth m-flat m-doc">
+ <thead><tr><th style="width: 1%">Enumerators</th><th></th></tr></thead>
+ <tbody>
+ <tr>
+ <td><a href="" class="m-doc-self">VALUE</a></td>
+ <td>
+ <p>A value</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="" class="m-doc-self">ANOTHER</a></td>
+ <td>
+ <p>Another value</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="" class="m-doc-self">YAY</a></td>
+ <td>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div></section>
+ </section>
</div>
</div>
</div>
+import enum
+
from . import hidden
from . import _private_but_exposed
_private_data = 'Hey!'
-__all__ = ['_private_but_exposed', '_PrivateButExposedClass', '_private_but_exposed_func', '_private_data']
+class _MyPrivateEnum(enum.Enum):
+ VALUE = 1
+ ANOTHER = 2
+ YAY = 3
+
+_MyPrivateEnum.VALUE.__doc__ = "A value"
+_MyPrivateEnum.ANOTHER.__doc__ = "Another value"
+
+class UndocumentedEnum(enum.IntFlag):
+ FLAG_ONE = 1
+ FLAG_SEVENTEEN = 17
+
+class HiddenEnum(enum.Flag):
+ pass
+
+__all__ = ['_private_but_exposed', '_PrivateButExposedClass', '_private_but_exposed_func', '_private_data', '_MyPrivateEnum', 'UndocumentedEnum']
Reference
<ul>
<li><a href="#classes">Classes</a></li>
+ <li><a href="#enums">Enums</a></li>
<li><a href="#classmethods">Class methods</a></li>
<li><a href="#staticmethods">Static methods</a></li>
<li><a href="#methods">Methods</a></li>
<dd>A subclass of Foo</dd>
</dl>
</section>
+ <section id="enums">
+ <h2><a href="#enums">Enums</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">class <a href="" class="m-doc">InnerEnum</a>(enum.Enum): </span><span class="m-doc-wrap"><a href="" class="m-doc">VALUE</a> = 0
+ <a href="" class="m-doc">ANOTHER</a> = 1
+ <a href="" class="m-doc">YAY</a> = 2</span>
+ </dt>
+ <dd>Inner enum</dd>
+ <dt>
+ <span class="m-doc-wrap-bumper">class <a href="" class="m-doc-self">UndocumentedInnerEnum</a>(enum.IntFlag): </span><span class="m-doc-wrap"><a href="" class="m-doc-self">FLAG_ONE</a> = 1
+ <a href="" class="m-doc-self">FLAG_SEVENTEEN</a> = 17</span>
+ </dt>
+ <dd></dd>
+ </dl>
+ </section>
<section id="classmethods">
<h2><a href="#classmethods">Class methods</a></h2>
<dl class="m-doc">
<dd></dd>
</dl>
</section>
+ <section>
+ <h2>Enum documentation</h2>
+ <section class="m-doc-details"><div>
+ <h3>
+ class inspect_string.<wbr />Foo.<wbr /><a href="" class="m-doc-self">InnerEnum</a>(enum.Enum)
+ </h3>
+ <p>Inner enum</p>
+ <table class="m-table m-fullwidth m-flat m-doc">
+ <thead><tr><th style="width: 1%">Enumerators</th><th></th></tr></thead>
+ <tbody>
+ <tr>
+ <td><a href="" class="m-doc-self">VALUE</a></td>
+ <td>
+ <p>A value</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="" class="m-doc-self">ANOTHER</a></td>
+ <td>
+ <p>Another value</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="" class="m-doc-self">YAY</a></td>
+ <td>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div></section>
+ </section>
</div>
</div>
</div>
<ul>
<li><a href="#packages">Modules</a></li>
<li><a href="#classes">Classes</a></li>
+ <li><a href="#enums">Enums</a></li>
<li><a href="#functions">Functions</a></li>
<li><a href="#data">Data</a></li>
</ul>
<dd>Special class members</dd>
</dl>
</section>
+ <section id="enums">
+ <h2><a href="#enums">Enums</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">class <a href="" class="m-doc">MyEnum</a>(enum.Enum): </span><span class="m-doc-wrap"><a href="" class="m-doc">VALUE</a> = 0
+ <a href="" class="m-doc">ANOTHER</a> = 1
+ <a href="" class="m-doc">YAY</a> = 2</span>
+ </dt>
+ <dd>An enum</dd>
+ <dt>
+ <span class="m-doc-wrap-bumper">class <a href="" class="m-doc-self">UndocumentedEnum</a>(enum.IntFlag): </span><span class="m-doc-wrap"><a href="" class="m-doc-self">FLAG_ONE</a> = 1
+ <a href="" class="m-doc-self">FLAG_SEVENTEEN</a> = 17</span>
+ </dt>
+ <dd></dd>
+ </dl>
+ </section>
<section id="functions">
<h2><a href="#functions">Functions</a></h2>
<dl class="m-doc">
<a href="" class="m-doc-self">A_CONSTANT</a> = 3.24
</dt>
<dd></dd>
+ <dt>
+ <a href="" class="m-doc-self">ENUM_THING</a>
+ </dt>
+ <dd></dd>
<dt>
<a href="" class="m-doc-self">foo</a>
</dt>
<dd></dd>
</dl>
</section>
+ <section>
+ <h2>Enum documentation</h2>
+ <section class="m-doc-details"><div>
+ <h3>
+ class inspect_string.<wbr /><a href="" class="m-doc-self">MyEnum</a>(enum.Enum)
+ </h3>
+ <p>An enum</p>
+ <table class="m-table m-fullwidth m-flat m-doc">
+ <thead><tr><th style="width: 1%">Enumerators</th><th></th></tr></thead>
+ <tbody>
+ <tr>
+ <td><a href="" class="m-doc-self">VALUE</a></td>
+ <td>
+ <p>A value</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="" class="m-doc-self">ANOTHER</a></td>
+ <td>
+ <p>Another value</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="" class="m-doc-self">YAY</a></td>
+ <td>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div></section>
+ </section>
</div>
</div>
</div>
A_DATA = 'BOO'
+ class InnerEnum(enum.Enum):
+ """Inner enum"""
+
+ VALUE = 0
+ ANOTHER = 1
+ YAY = 2
+
+ InnerEnum.VALUE.__doc__ = "A value"
+ InnerEnum.ANOTHER.__doc__ = "Another value"
+
+ class UndocumentedInnerEnum(enum.IntFlag):
+ FLAG_ONE = 1
+ FLAG_SEVENTEEN = 17
+
class Subclass:
"""A subclass of Foo"""
pass
# Undocumented, but should be present
pass
+class MyEnum(enum.Enum):
+ """An enum"""
+
+ VALUE = 0
+ ANOTHER = 1
+ YAY = 2
+
+MyEnum.VALUE.__doc__ = "A value"
+MyEnum.ANOTHER.__doc__ = "Another value"
+
+class UndocumentedEnum(enum.IntFlag):
+ FLAG_ONE = 1
+ FLAG_SEVENTEEN = 17
+
class _PrivateClass:
"""Private class"""
pass
A_CONSTANT = 3.24
+ENUM_THING = MyEnum.YAY
+
_PRIVATE_CONSTANT = -3
foo = Foo()