And also detailed docs for enums, functions, properties and data.
etc.
:py:`module_doc_contents` Module documentation contents
:py:`class_doc_contents` Class documentation contents
+:py:`enum_doc_contents` Enum documentation contents
+:py:`function_doc_contents` Function documentation contents
+:py:`property_doc_contents` Property documentation contents
:py:`data_doc_contents` Data documentation contents
:py:`hooks_pre_page` Hooks to call before each page gets rendered
:py:`hooks_post_run` Hooks to call at the very end of the script run
=========================== ===================================================
-The :py:`module_doc_contents`, :py:`class_doc_contents` and
+The :py:`module_doc_contents`, :py:`class_doc_contents`,
+:py:`function_doc_contents`, :py:`property_doc_contents` and
:py:`data_doc_contents` variables are :py:`Dict[str, Dict[str, str]]`, where
the first level is a name and second level are key/value pairs of the actual
HTML documentation content. Plugins that parse extra documentation inputs (such
`Data properties`_ for details.
:py:`page.has_enum_details` If there is at least one enum with full
description block [2]_
+:py:`page.has_function_details` If there is at least one function (or
+ method, in case of classes) with full
+ description block [2]_
+:py:`page.has_data_details` If there is at least one data with full
+ description block [2]_
======================================= =======================================
Each class page, rendered with ``class.html``, has the following additional
`Function properties`_ for details.
:py:`page.properties` List of properties. See
`Property properties`_ for details.
+:py:`page.has_property_details` If there is at least one property with
+ full description block [2]_
======================================= =======================================
Explicit documentation pages rendered with ``class.html`` have additional
:py:`enum.name` Enum name
:py:`enum.id` Enum ID [4]_
:py:`enum.summary` Doc summary
+:py:`enum.content` Detailed documentation, if any
:py:`enum.base` Base class from which the enum is
derived. Set to :py:`None` if no base
class information is available.
:py:`function.name` Function name
:py:`function.id` Function ID [4]_
:py:`function.summary` Doc summary
+:py:`function.content` Detailed documentation, if any
:py:`function.type` Function return type annotation [1]_
:py:`function.params` List of function parameters. See below for
details.
wrapping on multiple lines would only
occupy too much vertical space.
:py:`function.has_details` If there is enough content for the full
- description block. Currently always set to
- :py:`False`. [2]_
+ description block [2]_
:py:`function.is_classmethod` Set to :py:`True` if the function is
annotated with :py:`@classmethod`,
:py:`False` otherwise.
:py:`property.id` Property ID [4]_
:py:`property.type` Property getter return type annotation [1]_
:py:`property.summary` Doc summary
+:py:`property.content` Detailed documentation, if any
:py:`property.is_gettable` If the property is gettable
:py:`property.is_settable` If the property is settable
:py:`property.is_deletable` If the property is deletable with :py:`del`
:py:`property.has_details` If there is enough content for the full
- description block. Currently always set to
- :py:`False`. [2]_
+ description block [2]_
=================================== ===========================================
`Data properties`_
:py:`data.id` Data ID [4]_
:py:`data.type` Data type
:py:`data.summary` Doc summary
+:py:`data.content` Detailed documentation, if any
:py:`data.value` Data value representation
:py:`data.has_details` If there is enough content for the full
- description block. Currently always set to
- :py:`False`. [2]_
+ description block [2]_
=================================== ===========================================
`Index page templates`_
PLUGINS += ['m.sphinx']
-`Module, class and data docs`_
-==============================
-
-The :rst:`.. py:module::`, :rst:`.. py:class::` and :rst:`.. py:data::`
-directives provide a way to supply module, class and data documentation
-content. Directive option is the name to document, directive contents are
-the actual contents; in addition the :py:`:summary:` option can override the
-docstring extracted using inspection. No restrictions are made on the contents,
-it's possible to make use of any additional plugins in the markup. Example:
+`Module, class, enum, function, property and data docs`_
+========================================================
+
+The :rst:`.. py:module::`, :rst:`.. py:class::`, :rst:`.. py:enum::`,
+:rst:`.. py:function::`, :rst:`.. py:property::` and :rst:`.. py:data::`
+directives provide a way to supply module, class, enum, function / method,
+property and data documentation content. Directive option is the name to
+document, directive contents are the actual contents; in addition the
+:py:`:summary:` option can override the docstring extracted using inspection.
+No restrictions are made on the contents, it's possible to make use of any
+additional plugins in the markup. Example:
.. code:: rst
self.module_mapping: Dict[str, str] = {}
self.module_docs: Dict[str, Dict[str, str]] = {}
self.class_docs: Dict[str, Dict[str, str]] = {}
+ self.enum_docs: Dict[str, Dict[str, str]] = {}
+ self.function_docs: Dict[str, Dict[str, str]] = {}
+ self.property_docs: Dict[str, Dict[str, str]] = {}
self.data_docs: Dict[str, Dict[str, str]] = {}
self.external_data: Set[str] = set()
end = original_signature.find('\n')
logging.warning("cannot parse pybind11 function signature %s", original_signature[:end if end != -1 else None])
if end != -1 and len(original_signature) > end + 1 and original_signature[end + 1] == '\n':
- summary = extract_summary(state, {}, [], original_signature[end + 1:])
+ summary = take_first_paragraph(inspect.cleandoc(original_signature[end + 1:]))
else:
summary = ''
return (name, summary, [('…', None, None, None)], None)
if len(signature) > 1 and signature[1] == '\n':
- summary = extract_summary(state, {}, [], signature[2:])
+ summary = take_first_paragraph(inspect.cleandoc(signature[2:]))
else:
summary = ''
else:
return None
+def take_first_paragraph(doc: str) -> str:
+ end = doc.find('\n\n')
+ return doc if end == -1 else doc [:end]
+
def extract_summary(state: State, external_docs, path: List[str], doc: str) -> str:
# Prefer external docs, if available
path_str = '.'.join(path)
return render_inline_rst(state, external_docs[path_str]['summary'])
if not doc: return '' # some modules (xml.etree) have that :(
- doc = inspect.cleandoc(doc)
- end = doc.find('\n\n')
- return html.escape(doc if end == -1 else doc[:end])
+ # TODO: render as rst (config option for that)
+ return html.escape(take_first_paragraph(inspect.cleandoc(doc)))
+
+def extract_docs(state: State, external_docs, path: List[str], doc: str) -> Tuple[str, str]:
+ path_str = '.'.join(path)
+ if path_str in external_docs:
+ external_doc_entry = external_docs[path_str]
+ else:
+ external_doc_entry = None
+
+ # Summary. Prefer external docs, if available
+ if external_doc_entry and external_doc_entry['summary']:
+ summary = render_inline_rst(state, external_doc_entry['summary'])
+ else:
+ # some modules (xml.etree) have None as a docstring :(
+ # TODO: render as rst (config option for that)
+ summary = html.escape(take_first_paragraph(inspect.cleandoc(doc or '')))
+
+ # Content
+ if external_doc_entry and external_doc_entry['content']:
+ content = render_rst(state, external_doc_entry['content'])
+ else:
+ # TODO: extract more than just a summary from the docstring
+ content = None
+
+ # Mark the docs as used (so it can warn about unused docs at the end)
+ if external_doc_entry: external_doc_entry['used'] = True
+
+ return summary, content
def extract_type(type) -> str:
# For types we concatenate the type name with its module unless it's
out.name = entry.path[-1]
out.id = state.config['ID_FORMATTER'](EntryType.ENUM, entry.path[-1:])
out.values = []
- out.has_details = False
out.has_value_details = False
# The happy case
if issubclass(entry.object, enum.Enum):
# Enum doc is by default set to a generic value. That's useless as well.
if entry.object.__doc__ == 'An enumeration.':
- out.summary = ''
+ docstring = ''
else:
- # TODO: external summary for enums
- out.summary = extract_summary(state, {}, [], entry.object.__doc__)
+ docstring = entry.object.__doc__
+ out.summary, out.content = extract_docs(state, state.enum_docs, entry.path, docstring)
+ out.has_details = bool(out.content)
out.base = extract_type(entry.object.__base__)
if out.base: out.base = make_name_link(state, entry.path, out.base)
elif state.config['PYBIND11_COMPATIBILITY']:
assert hasattr(entry.object, '__members__')
- # TODO: external summary for enums
- out.summary = extract_summary(state, {}, [], entry.object.__doc__)
+ out.summary, out.content = extract_docs(state, state.enum_docs, entry.path, entry.object.__doc__)
+ out.has_details = bool(out.content)
out.base = None
for name, v in entry.object.__members__.items():
out.name = entry.path[-1]
out.params = []
out.has_complex_params = False
- out.has_details = False
- # TODO: external summary for functions
- out.summary = summary
+ out.summary, out.content = extract_docs(state, state.function_docs, entry.path, summary)
+ out.has_details = bool(out.content)
# Don't show None return type for functions w/o a return
out.type = None if type == 'None' else type
out.id = state.config['ID_FORMATTER'](EntryType.FUNCTION, entry.path[-1:])
out.params = []
out.has_complex_params = False
- out.has_details = False
- # TODO: external summary for functions
- out.summary = extract_summary(state, {}, [], entry.object.__doc__)
+ out.summary, out.content = extract_docs(state, state.function_docs, entry.path, entry.object.__doc__)
+ out.has_details = bool(out.content)
# Decide if classmethod or staticmethod in case this is a method
if inspect.isclass(parent):
# gettable and settable (couldn't find any way to make them *inspectably*
# readonly, all solutions involved throwing from __setattr__()) and
# deletable as well (calling del on it seems to simply remove any
- # previously set value). Unfortunately we can't get any docstring for these
- # either.
+ # previously set value).
# TODO: any better way to detect that those are slots?
if entry.object.__class__.__name__ == 'member_descriptor' and entry.object.__class__.__module__ == 'builtins':
out.is_gettable = True
out.is_settable = True
out.is_deletable = True
- # TODO: external summary for properties
- out.summary = ''
- out.has_details = False
+ # Unfortunately we can't get any docstring for these
+ out.summary, out.content = extract_docs(state, state.property_docs, entry.path, '')
+ out.has_details = bool(out.content)
# First try to get fully dereferenced type hints (with strings
# converted to actual annotations). If that fails (e.g. because a type
out.is_gettable = True
out.is_settable = False
out.is_deletable = False
- out.summary = ''
- out.has_details = False
+ # Unfortunately we can't get any docstring for these
+ out.summary, out.content = extract_docs(state, state.property_docs, entry.path, '')
+ out.has_details = bool(out.content)
out.type = None
return out
- # TODO: external summary for properties
out.is_gettable = entry.object.fget is not None
if entry.object.fget or (entry.object.fset and entry.object.__doc__):
- out.summary = extract_summary(state, {}, [], entry.object.__doc__)
+ docstring = entry.object.__doc__
else:
assert entry.object.fset
- out.summary = extract_summary(state, {}, [], entry.object.fset.__doc__)
+ docstring = entry.object.fset.__doc__
+ out.summary, out.content = extract_docs(state, state.property_docs, entry.path, docstring)
out.is_settable = entry.object.fset is not None
out.is_deletable = entry.object.fdel is not None
- out.has_details = False
+ out.has_details = bool(out.content)
# For the type, if the property is gettable, get it from getters's return
# type. For write-only properties get it from setter's second argument
out.name = entry.path[-1]
out.id = state.config['ID_FORMATTER'](EntryType.DATA, entry.path[-1:])
# Welp. https://stackoverflow.com/questions/8820276/docstring-for-variable
- out.summary = extract_summary(state, state.data_docs, entry.path, '')
- out.has_details = False
+ out.summary, out.content = extract_docs(state, state.data_docs, entry.path, '')
+ out.has_details = bool(out.content)
# First try to get fully dereferenced type hints (with strings converted to
# actual annotations). If that fails (e.g. because a type doesn't exist),
for hook in state.hooks_pre_page: hook()
page = Empty()
- page.summary = extract_summary(state, state.module_docs, path, module.__doc__)
+ page.summary, page.content = extract_docs(state, state.module_docs, path, module.__doc__)
page.filename = filename
page.url = url
page.breadcrumb = breadcrumb
page.functions = []
page.data = []
page.has_enum_details = False
-
- # External page content, if provided
- path_str = '.'.join(path)
- if path_str in state.module_docs:
- page.content = render_rst(state, state.module_docs[path_str]['content'])
- state.module_docs[path_str]['used'] = True
+ page.has_function_details = False
+ page.has_data_details = False
# Find itself in the global map, save the summary back there for index
- module_entry = state.name_map[path_str]
+ module_entry = state.name_map['.'.join(path)]
module_entry.summary = page.summary
# Extract docs for all members
page.enums += [enum_]
if enum_.has_details: page.has_enum_details = True
elif member_entry.type == EntryType.FUNCTION:
- page.functions += extract_function_doc(state, module, member_entry)
+ functions = extract_function_doc(state, module, member_entry)
+ page.functions += functions
+ for function in functions:
+ if function.has_details: page.has_function_details = True
elif member_entry.type == EntryType.DATA:
- page.data += [extract_data_doc(state, module, member_entry)]
+ data = extract_data_doc(state, module, member_entry)
+ page.data += [data]
+ if data.has_details: page.has_data_details = True
else: # pragma: no cover
assert False
for hook in state.hooks_pre_page: hook()
page = Empty()
- page.summary = extract_summary(state, state.class_docs, path, class_.__doc__)
+ page.summary, page.content = extract_docs(state, state.class_docs, path, class_.__doc__)
page.filename = filename
page.url = url
page.breadcrumb = breadcrumb
page.properties = []
page.data = []
page.has_enum_details = False
-
- # External page content, if provided
- path_str = '.'.join(path)
- if path_str in state.class_docs:
- page.content = render_rst(state, state.class_docs[path_str]['content'])
- state.class_docs[path_str]['used'] = True
+ page.has_function_details = False
+ page.has_property_details = False
+ page.has_data_details = False
# Find itself in the global map, save the summary back there for index
- module_entry = state.name_map[path_str]
+ module_entry = state.name_map['.'.join(path)]
module_entry.summary = page.summary
# Extract docs for all members
page.staticmethods += [function]
else:
page.methods += [function]
+ if function.has_details: page.has_function_details = True
elif member_entry.type == EntryType.PROPERTY:
- page.properties += [extract_property_doc(state, class_, member_entry)]
+ property = extract_property_doc(state, class_, member_entry)
+ page.properties += [property]
+ if property.has_details: page.has_property_details = True
elif member_entry.type == EntryType.DATA:
- page.data += [extract_data_doc(state, class_, member_entry)]
+ data = extract_data_doc(state, class_, member_entry)
+ page.data += [data]
+ if data.has_details: page.has_data_details = True
else: # pragma: no cover
assert False
jinja_environment=env,
module_doc_contents=state.module_docs,
class_doc_contents=state.class_docs,
+ enum_doc_contents=state.enum_docs,
+ function_doc_contents=state.function_docs,
+ property_doc_contents=state.property_docs,
data_doc_contents=state.data_docs,
hooks_pre_page=state.hooks_pre_page,
hooks_post_run=state.hooks_post_run)
render_page(state, entry.path, entry.filename, env)
# Warn if there are any unused contents left after processing everything
- unused_module_docs = [key for key, value in state.module_docs.items() if not 'used' in value]
- unused_class_docs = [key for key, value in state.class_docs.items() if not 'used' in value]
- unused_data_docs = [key for key, value in state.data_docs.items() if not 'used' in value]
- if unused_module_docs:
- logging.warning("The following module doc contents were unused: %s", unused_module_docs)
- if unused_class_docs:
- logging.warning("The following class doc contents were unused: %s", unused_class_docs)
- if unused_data_docs:
- logging.warning("The following data doc contents were unused: %s", unused_data_docs)
+ for docs in ['module', 'class', 'enum', 'function', 'property', 'data']:
+ unused_docs = [key for key, value in getattr(state, f'{docs}_docs').items() if not 'used' in value]
+ if unused_docs:
+ logging.warning("The following %s doc contents were unused: %s", docs, unused_docs)
# Create module and class index from the toplevel name list. Recursively go
# from the top-level index list and gather all class/module children.
{% macro entry_data(data) %}{% include 'entry-data.html' %}{% endmacro %}
{% macro details_enum(enum, prefix) %}{% include 'details-enum.html' %}{% endmacro %}
+{% macro details_function(function, prefix) %}{% include 'details-function.html' %}{% endmacro %}
+{% macro details_property(property, prefix) %}{% include 'details-property.html' %}{% endmacro %}
+{% macro details_data(data, prefix) %}{% include 'details-data.html' %}{% endmacro %}
{% block title %}{% set j = joiner('.') %}{% for name, _ in page.breadcrumb %}{{ j() }}{{ name }}{% endfor %} | {{ super() }}{% endblock %}
{% endfor %}
</section>
{% endif %}
+ {% if page.has_function_details %}
+ <section>
+ <h2>Method documentation</h2>
+ {% for function in page.classmethods %}
+ {% if function.has_details %}
+{{ details_function(function, page.prefix_wbr) }}
+ {% endif %}
+ {% endfor %}
+ {% for function in page.staticmethods %}
+ {% if function.has_details %}
+{{ details_function(function, page.prefix_wbr) }}
+ {% endif %}
+ {% endfor %}
+ {% for function in page.methods %}
+ {% if function.has_details %}
+{{ details_function(function, page.prefix_wbr) }}
+ {% endif %}
+ {% endfor %}
+ {% for function in page.dunder_methods %}
+ {% if function.has_details %}
+{{ details_function(function, page.prefix_wbr) }}
+ {% endif %}
+ {% endfor %}
+ </section>
+ {% endif %}
+ {% if page.has_property_details %}
+ <section>
+ <h2>Property documentation</h2>
+ {% for property in page.properties %}
+ {% if property.has_details %}
+{{ details_property(property, page.prefix_wbr) }}
+ {% endif %}
+ {% endfor %}
+ </section>
+ {% endif %}
+ {% if page.has_data_details %}
+ <section>
+ <h2>Data documentation</h2>
+ {% for data in page.data %}
+ {% if data.has_details %}
+{{ details_data(data, page.prefix_wbr) }}
+ {% endif %}
+ {% endfor %}
+ </section>
+ {% endif %}
{% endblock %}
--- /dev/null
+ <section class="m-doc-details" id="{{ data.id }}"><div>
+ <h3>
+ {{ prefix }}<a href="#{{ data.id }}" class="m-doc-self">{{ data.name }}</a>{% if data.type %}: {{ data.type }}{% endif %}
+ {# the empty line needs to be here to prevent the lines from merging #}
+
+ </h3>
+ {% if data.summary %}
+ <p>{{ data.summary }}</p>
+ {% endif %}
+ {% if data.content %}
+{{ data.content }}
+ {% endif %}
+ </div></section>
--- /dev/null
+ <section class="m-doc-details" id="{{ function.id }}"><div>
+ <h3>
+ {% set j = joiner('\n ' if function.has_complex_params else ' ') %}
+ <span class="m-doc-wrap-bumper">def {{ prefix }}</span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#{{ function.id }}" class="m-doc-self">{{ function.name }}</a>(</span><span class="m-doc-wrap">{% for param in function.params %}{% if loop.index0 %}{% if function.params[loop.index0 - 1].kind == 'POSITIONAL_OR_KEYWORD' and param.kind == 'KEYWORD_ONLY' %},<span class="m-text m-dim"> *,</span>{% else %},{% endif %}{% endif %}{{ j() }}{% if param.kind == 'VAR_POSITIONAL' %}*{% elif param.kind == 'VAR_KEYWORD' %}**{% endif %}{{ param.name }}{% if param.type %}: {{ param.type }}{% endif %}{% if param.default %} = {{ param.default }}{% endif %}{% if param.kind == 'POSITIONAL_ONLY' and (loop.last or function.params[loop.index0 + 1].kind != 'POSITIONAL_ONLY') %}<span class="m-text m-dim">, /</span>{% endif %}{% endfor %}){% if function.type %} -> {{ function.type }}{% endif %}{% if function.is_classmethod %} <span class="m-label m-success">classmethod</span>{% elif function.is_staticmethod %} <span class="m-label m-info">staticmethod</span>{% endif %}</span></span>
+ </h3>
+ {% if function.summary %}
+ <p>{{ function.summary }}</p>
+ {% endif %}
+ {% if function.has_param_details or function.return_value %}
+ <table class="m-table m-fullwidth m-flat">
+ {% if function.has_param_details %}
+ <thead>
+ <tr><th colspan="2">Parameters</th></tr>
+ </thead>
+ <tbody>
+ {% for param in function.params %}
+ <tr>
+ <td{% if loop.index == 1 %} style="width: 1%"{% endif %}>{{ param.name }}</td>
+ <td>{{ param.description }}</td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ {% endif %}
+ {% if function.return_value %}
+ <tfoot>
+ <tr>
+ <th{% if not function.has_param_details %} style="width: 1%"{% endif %}>Returns</th>
+ <td>{{ function.return_value }}</td>
+ </tr>
+ </tfoot>
+ {% endif %}
+ </table>
+ {% endif %}
+ {% if function.content %}
+{{ function.content }}
+ {% endif %}
+ </div></section>
--- /dev/null
+ <section class="m-doc-details" id="{{ property.id }}"><div>
+ <h3>
+ {{ prefix }}<a href="#{{ property.id }}" class="m-doc-self">{{ property.name }}</a>{% if property.type %}: {{ property.type }}{% endif %} <span class="m-label m-flat {% if property.is_gettable and property.is_settable %}m-success{% elif property.is_gettable %}m-warning{% else %}m-danger{% endif %}">{% if property.is_gettable and property.is_settable %}get set{% elif property.is_gettable %}get{% else %}set{% endif %}{% if property.is_deletable %} del{% endif %}</span>
+ </h3>
+ {% if property.summary %}
+ <p>{{ property.summary }}</p>
+ {% endif %}
+ {% if property.content %}
+{{ property.content }}
+ {% endif %}
+ </div></section>
{% macro entry_data(data) %}{% include 'entry-data.html' %}{% endmacro %}
{% macro details_enum(enum, prefix) %}{% include 'details-enum.html' %}{% endmacro %}
+{% macro details_function(function, prefix) %}{% include 'details-function.html' %}{% endmacro %}
+{% macro details_data(data, prefix) %}{% include 'details-data.html' %}{% endmacro %}
{% block title %}{% set j = joiner('.') %}{% for name, _ in page.breadcrumb %}{{ j() }}{{ name }}{% endfor %} | {{ super() }}{% endblock %}
{% endfor %}
</section>
{% endif %}
+ {% if page.has_function_details %}
+ <section>
+ <h2>Function documentation</h2>
+ {% for function in page.functions %}
+ {% if function.has_details %}
+{{ details_function(function, page.prefix_wbr) }}
+ {% endif %}
+ {% endfor %}
+ </section>
+ {% endif %}
+ {% if page.has_data_details %}
+ <section>
+ <h2>Data documentation</h2>
+ {% for data in page.data %}
+ {% if data.has_details %}
+{{ details_data(data, page.prefix_wbr) }}
+ {% endif %}
+ {% endfor %}
+ </section>
+ {% endif %}
{% endblock %}
<li class="m-doc-collapsible">
<a href="#" onclick="return toggle(this)">module</a> <a href="content.html" class="m-doc">content</a> <span class="m-doc">This overwrites the docstring for <code>content</code>.</span>
<ul class="m-doc">
- <li>class <a href="content.AnotherClass.html" class="m-doc">AnotherClass</a> <span class="m-doc">This class has summary from the docstring</span></li>
+ <li>module <a href="content.docstring_summary.html" class="m-doc">docstring_summary</a> <span class="m-doc">This module retains summary from the docstring</span></li>
<li>class <a href="content.Class.html" class="m-doc">Class</a> <span class="m-doc">This overwrites the docstring for <code>content.Class</code>.</span></li>
+ <li>class <a href="content.ClassWithSummary.html" class="m-doc">ClassWithSummary</a> <span class="m-doc">This class has summary from the docstring</span></li>
</ul>
</li>
</ul>
<span class="m-breadcrumb"><a href="content.html">content</a>.<wbr/></span>Class <span class="m-thin">class</span>
</h1>
<p>This overwrites the docstring for <code>content.Class</code>.</p>
+ <div class="m-block m-default">
+ <h3>Contents</h3>
+ <ul>
+ <li>
+ Reference
+ <ul>
+ <li><a href="#classmethods">Class methods</a></li>
+ <li><a href="#staticmethods">Static methods</a></li>
+ <li><a href="#methods">Methods</a></li>
+ <li><a href="#dunder-methods">Special methods</a></li>
+ <li><a href="#properties">Properties</a></li>
+ <li><a href="#data">Data</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
<p>This is detailed class docs. Here I <em>also</em> hate how it needs to be
indented.</p>
+ <section id="classmethods">
+ <h2><a href="#classmethods">Class methods</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="#class_method" class="m-doc">class_method</a>(</span><span class="m-doc-wrap">b)</span>
+ </dt>
+ <dd>This function is a class method</dd>
+ </dl>
+ </section>
+ <section id="staticmethods">
+ <h2><a href="#staticmethods">Static methods</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="#static_method" class="m-doc">static_method</a>(</span><span class="m-doc-wrap">cls, a)</span>
+ </dt>
+ <dd>This function is a static method</dd>
+ </dl>
+ </section>
+ <section id="methods">
+ <h2><a href="#methods">Methods</a></h2>
+ <dl class="m-doc">
+ <dt id="method">
+ <span class="m-doc-wrap-bumper">def <a href="#method" class="m-doc-self">method</a>(</span><span class="m-doc-wrap">self)</span>
+ </dt>
+ <dd>This overwrites the docstring for <code>content.Class.method</code>, but
+doesn't add any detailed block.</dd>
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="#method_with_details" class="m-doc">method_with_details</a>(</span><span class="m-doc-wrap">self)</span>
+ </dt>
+ <dd></dd>
+ </dl>
+ </section>
+ <section id="dunder-methods">
+ <h2><a href="#dunder-methods">Special methods</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="#__init__" class="m-doc">__init__</a>(</span><span class="m-doc-wrap">self)</span>
+ </dt>
+ <dd>A dunder method</dd>
+ </dl>
+ </section>
+ <section id="properties">
+ <h2><a href="#properties">Properties</a></h2>
+ <dl class="m-doc">
+ <dt id="a_property">
+ <a href="#a_property" class="m-doc-self">a_property</a> <span class="m-label m-flat m-warning">get</span>
+ </dt>
+ <dd>This overwrites the docstring for <code>content.Class.a_property</code>,
+but doesn't add any detailed block.</dd>
+ <dt>
+ <a href="#a_property_with_details" class="m-doc">a_property_with_details</a> <span class="m-label m-flat m-warning">get</span>
+ </dt>
+ <dd>This overwrites the docstring for <code>content.Class.a_property_with_details</code>.</dd>
+ <dt>
+ <a href="#annotated_property" class="m-doc">annotated_property</a>: float <span class="m-label m-flat m-warning">get</span>
+ </dt>
+ <dd>This is an annotated property</dd>
+ </dl>
+ </section>
+ <section id="data">
+ <h2><a href="#data">Data</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <a href="#DATA_WITH_DETAILS" class="m-doc">DATA_WITH_DETAILS</a>: str = 'this blows'
+ </dt>
+ <dd></dd>
+ </dl>
+ </section>
+ <section>
+ <h2>Method documentation</h2>
+ <section class="m-doc-details" id="class_method"><div>
+ <h3>
+ <span class="m-doc-wrap-bumper">def content.<wbr />Class.<wbr /></span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#class_method" class="m-doc-self">class_method</a>(</span><span class="m-doc-wrap">b) <span class="m-label m-success">classmethod</span></span></span>
+ </h3>
+ <p>This function is a class method</p>
+<p>The <span class="m-label m-success">classmethod</span> should be shown here.</p>
+ </div></section>
+ <section class="m-doc-details" id="static_method"><div>
+ <h3>
+ <span class="m-doc-wrap-bumper">def content.<wbr />Class.<wbr /></span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#static_method" class="m-doc-self">static_method</a>(</span><span class="m-doc-wrap">cls, a) <span class="m-label m-info">staticmethod</span></span></span>
+ </h3>
+ <p>This function is a static method</p>
+<p>The <span class="m-label m-info">staticmethod</span> should be shown here.</p>
+ </div></section>
+ <section class="m-doc-details" id="method_with_details"><div>
+ <h3>
+ <span class="m-doc-wrap-bumper">def content.<wbr />Class.<wbr /></span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#method_with_details" class="m-doc-self">method_with_details</a>(</span><span class="m-doc-wrap">self)</span></span>
+ </h3>
+<p>This one has a detailed block without any summary.</p>
+ </div></section>
+ <section class="m-doc-details" id="__init__"><div>
+ <h3>
+ <span class="m-doc-wrap-bumper">def content.<wbr />Class.<wbr /></span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#__init__" class="m-doc-self">__init__</a>(</span><span class="m-doc-wrap">self)</span></span>
+ </h3>
+ <p>A dunder method</p>
+<p>A dunder method shown in the detailed view.</p>
+ </div></section>
+ </section>
+ <section>
+ <h2>Property documentation</h2>
+ <section class="m-doc-details" id="a_property_with_details"><div>
+ <h3>
+ content.<wbr />Class.<wbr /><a href="#a_property_with_details" class="m-doc-self">a_property_with_details</a> <span class="m-label m-flat m-warning">get</span>
+ </h3>
+ <p>This overwrites the docstring for <code>content.Class.a_property_with_details</code>.</p>
+<p>Detailed property docs.</p>
+ </div></section>
+ <section class="m-doc-details" id="annotated_property"><div>
+ <h3>
+ content.<wbr />Class.<wbr /><a href="#annotated_property" class="m-doc-self">annotated_property</a>: float <span class="m-label m-flat m-warning">get</span>
+ </h3>
+ <p>This is an annotated property</p>
+<p>Annotated property, using summary from the docstring.</p>
+ </div></section>
+ </section>
+ <section>
+ <h2>Data documentation</h2>
+ <section class="m-doc-details" id="DATA_WITH_DETAILS"><div>
+ <h3>
+ content.<wbr />Class.<wbr /><a href="#DATA_WITH_DETAILS" class="m-doc-self">DATA_WITH_DETAILS</a>: str
+ </h3>
+<p>Detailed docs for <code>data</code> in a class to check rendering.</p>
+ </div></section>
+ </section>
</div>
</div>
</div>
<html lang="en">
<head>
<meta charset="UTF-8" />
- <title>content.AnotherClass | My Python Project</title>
+ <title>content.ClassWithSummary | My Python Project</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
<link rel="stylesheet" href="m-dark+documentation.compiled.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<div class="m-row">
<div class="m-col-l-10 m-push-l-1">
<h1>
- <span class="m-breadcrumb"><a href="content.html">content</a>.<wbr/></span>AnotherClass <span class="m-thin">class</span>
+ <span class="m-breadcrumb"><a href="content.html">content</a>.<wbr/></span>ClassWithSummary <span class="m-thin">class</span>
</h1>
<p>This class has summary from the docstring</p>
<p>This class has external details but summary from the docstring.</p>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>content.docstring_summary | My Python Project</title>
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
+ <link rel="stylesheet" href="m-dark+documentation.compiled.css" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+</head>
+<body>
+<header><nav id="navigation">
+ <div class="m-container">
+ <div class="m-row">
+ <a href="index.html" id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">My Python Project</a>
+ </div>
+ </div>
+</nav></header>
+<main><article>
+ <div class="m-container m-container-inflatable">
+ <div class="m-row">
+ <div class="m-col-l-10 m-push-l-1">
+ <h1>
+ <span class="m-breadcrumb"><a href="content.html">content</a>.<wbr/></span>docstring_summary <span class="m-thin">module</span>
+ </h1>
+ <p>This module retains summary from the docstring</p>
+<p>And adds detailed docs.</p>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
<li>
Reference
<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>
</li>
</div>
<p>This is detailed module docs. I kinda <em>hate</em> how it needs to be indented,
tho.</p>
+ <section id="namespaces">
+ <h2><a href="#namespaces">Modules</a></h2>
+ <dl class="m-doc">
+ <dt>module <a href="content.docstring_summary.html" class="m-doc">docstring_summary</a></dt>
+ <dd>This module retains summary from the docstring</dd>
+ </dl>
+ </section>
<section id="classes">
<h2><a href="#classes">Classes</a></h2>
<dl class="m-doc">
- <dt>class <a href="content.AnotherClass.html" class="m-doc">AnotherClass</a></dt>
- <dd>This class has summary from the docstring</dd>
<dt>class <a href="content.Class.html" class="m-doc">Class</a></dt>
<dd>This overwrites the docstring for <code>content.Class</code>.</dd>
+ <dt>class <a href="content.ClassWithSummary.html" class="m-doc">ClassWithSummary</a></dt>
+ <dd>This class has summary from the docstring</dd>
+ </dl>
+ </section>
+ <section id="enums">
+ <h2><a href="#enums">Enums</a></h2>
+ <dl class="m-doc">
+ <dt id="Enum">
+ <span class="m-doc-wrap-bumper">class <a href="#Enum" class="m-doc-self">Enum</a>(enum.Enum): </span><span class="m-doc-wrap"></span>
+ </dt>
+ <dd>This overwrites the docstring for <code>content.Enum</code>, but
+doesn't add any detailed block.</dd>
+ <dt>
+ <span class="m-doc-wrap-bumper">class <a href="#EnumWithSummary" class="m-doc">EnumWithSummary</a>(enum.Enum): </span><span class="m-doc-wrap"><a href="#EnumWithSummary-VALUE" class="m-doc">VALUE</a> = 0
+ <a href="#EnumWithSummary-ANOTHER" class="m-doc">ANOTHER</a> = 1</span>
+ </dt>
+ <dd>This summary is preserved</dd>
+ </dl>
+ </section>
+ <section id="functions">
+ <h2><a href="#functions">Functions</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="#annotations" class="m-doc">annotations</a>(</span><span class="m-doc-wrap">a: int,
+ b,
+ c: float) -> str</span>
+ </dt>
+ <dd>No annotations shown for this</dd>
+ <dt id="foo">
+ <span class="m-doc-wrap-bumper">def <a href="#foo" class="m-doc-self">foo</a>(</span><span class="m-doc-wrap">a, b)</span>
+ </dt>
+ <dd>This overwrites the docstring for <code>content.foo</code>, but
+doesn't add any detailed block.</dd>
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="#foo_with_details" class="m-doc">foo_with_details</a>(</span><span class="m-doc-wrap">a, b)</span>
+ </dt>
+ <dd>This overwrites the docstring for <code>content.foo_with_details()</code>.</dd>
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="#function_with_summary" class="m-doc">function_with_summary</a>(</span><span class="m-doc-wrap">)</span>
+ </dt>
+ <dd>This function has summary from the docstring</dd>
</dl>
</section>
<section id="data">
<a href="#CONSTANT" class="m-doc-self">CONSTANT</a>: float = 3.14
</dt>
<dd>This is finally a docstring for <code>content.CONSTANT</code></dd>
+ <dt>
+ <a href="#DATA_WITH_DETAILS" class="m-doc">DATA_WITH_DETAILS</a>: str = 'heyoo'
+ </dt>
+ <dd>This is finally a docstring for <code>content.CONSTANT</code></dd>
+ <dt>
+ <a href="#DATA_WITH_DETAILS_BUT_NO_SUMMARY_NEITHER_TYPE" class="m-doc">DATA_WITH_DETAILS_BUT_NO_SUMMARY_NEITHER_TYPE</a> = None
+ </dt>
+ <dd></dd>
</dl>
</section>
+ <section>
+ <h2>Enum documentation</h2>
+ <section class="m-doc-details" id="EnumWithSummary"><div>
+ <h3>
+ class content.<wbr /><a href="#EnumWithSummary" class="m-doc-self">EnumWithSummary</a>(enum.Enum)
+ </h3>
+ <p>This summary is preserved</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="#EnumWithSummary-VALUE" id="EnumWithSummary-VALUE" class="m-doc-self">VALUE</a></td>
+ <td>
+ <p>A value</p>
+ </td>
+ </tr>
+ <tr>
+ <td><a href="#EnumWithSummary-ANOTHER" id="EnumWithSummary-ANOTHER" class="m-doc-self">ANOTHER</a></td>
+ <td>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div></section>
+ </section>
+ <section>
+ <h2>Function documentation</h2>
+ <section class="m-doc-details" id="annotations"><div>
+ <h3>
+ <span class="m-doc-wrap-bumper">def content.<wbr /></span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#annotations" class="m-doc-self">annotations</a>(</span><span class="m-doc-wrap">a: int,
+ b,
+ c: float) -> str</span></span>
+ </h3>
+ <p>No annotations shown for this</p>
+<p>Type annotations in detailed docs.</p>
+ </div></section>
+ <section class="m-doc-details" id="foo_with_details"><div>
+ <h3>
+ <span class="m-doc-wrap-bumper">def content.<wbr /></span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#foo_with_details" class="m-doc-self">foo_with_details</a>(</span><span class="m-doc-wrap">a, b)</span></span>
+ </h3>
+ <p>This overwrites the docstring for <code>content.foo_with_details()</code>.</p>
+<div class="m-note m-info">
+Detailed docs for this function</div>
+ </div></section>
+ <section class="m-doc-details" id="function_with_summary"><div>
+ <h3>
+ <span class="m-doc-wrap-bumper">def content.<wbr /></span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#function_with_summary" class="m-doc-self">function_with_summary</a>(</span><span class="m-doc-wrap">)</span></span>
+ </h3>
+ <p>This function has summary from the docstring</p>
+<p>This function has external details but summary from the docstring.</p>
+ </div></section>
+ </section>
+ <section>
+ <h2>Data documentation</h2>
+ <section class="m-doc-details" id="DATA_WITH_DETAILS"><div>
+ <h3>
+ content.<wbr /><a href="#DATA_WITH_DETAILS" class="m-doc-self">DATA_WITH_DETAILS</a>: str
+ </h3>
+ <p>This is finally a docstring for <code>content.CONSTANT</code></p>
+<p>Detailed docs for the data. <strong>YAY.</strong></p>
+ </div></section>
+ <section class="m-doc-details" id="DATA_WITH_DETAILS_BUT_NO_SUMMARY_NEITHER_TYPE"><div>
+ <h3>
+ content.<wbr /><a href="#DATA_WITH_DETAILS_BUT_NO_SUMMARY_NEITHER_TYPE" class="m-doc-self">DATA_WITH_DETAILS_BUT_NO_SUMMARY_NEITHER_TYPE</a>
+ </h3>
+<p>Why it has to be yelling?!</p>
+ </div></section>
+ </section>
</div>
</div>
</div>
+++ /dev/null
-"""Yes so this is module summary, not shown in the output"""
-
-class Class:
- """And this class summary, not shown either"""
-
-class AnotherClass:
- """This class has summary from the docstring"""
-
-CONSTANT: float = 3.14
--- /dev/null
+"""Yes so this is module summary, not shown in the output"""
+
+import enum
+from . import docstring_summary
+
+class Class:
+ """And this class summary, not shown either"""
+
+ @classmethod
+ def class_method(a, b):
+ """This function is a class method"""
+
+ @staticmethod
+ def static_method(cls, a):
+ """This function is a static method"""
+
+ def __init__(self):
+ """A dunder method"""
+
+ def method(self):
+ """This summary will get overriden from the docs"""
+
+ def method_with_details(self):
+ pass
+
+ @property
+ def a_property(self):
+ """This summary is not shown either"""
+
+ @property
+ def a_property_with_details(self):
+ """This summary is not shown either"""
+
+ @property
+ def annotated_property(self) -> float:
+ """This is an annotated property"""
+
+ DATA_WITH_DETAILS: str = 'this blows'
+
+class ClassWithSummary:
+ """This class has summary from the docstring"""
+
+class Enum(enum.Enum):
+ """This summary gets ignored"""
+
+class EnumWithSummary(enum.Enum):
+ """This summary is preserved"""
+
+ VALUE = 0
+ ANOTHER = 1
+
+EnumWithSummary.VALUE.__doc__ = "A value"
+
+def foo(a, b):
+ """This summary is not shown either"""
+
+def foo_with_details(a, b):
+ """This summary is not shown either"""
+
+def function_with_summary():
+ """This function has summary from the docstring"""
+
+def annotations(a: int, b, c: float) -> str:
+ """No annotations shown for this"""
+
+CONSTANT: float = 3.14
+
+DATA_WITH_DETAILS: str = 'heyoo'
+
+DATA_WITH_DETAILS_BUT_NO_SUMMARY_NEITHER_TYPE = None
--- /dev/null
+"""This module retains summary from the docstring"""
+.. role:: label-success
+ :class: m-label m-success
+.. role:: label-info
+ :class: m-label m-info
+
.. py:module:: content
:summary: This overwrites the docstring for ``content``.
This is detailed module docs. I kinda *hate* how it needs to be indented,
tho.
+.. py:module:: content.docstring_summary
+
+ And adds detailed docs.
+
.. py:class:: content.Class
:summary: This overwrites the docstring for ``content.Class``.
This is detailed class docs. Here I *also* hate how it needs to be
indented.
-.. py:class:: content.AnotherClass
+.. py:function:: content.Class.class_method
+
+ The :label-success:`classmethod` should be shown here.
+
+.. py:function:: content.Class.static_method
+
+ The :label-info:`staticmethod` should be shown here.
+
+.. py:function:: content.Class.__init__
+
+ A dunder method shown in the detailed view.
+
+.. py:function:: content.Class.method
+ :summary: This overwrites the docstring for ``content.Class.method``, but
+ doesn't add any detailed block.
+
+.. py:function:: content.Class.method_with_details
+
+ This one has a detailed block without any summary.
+
+.. py:property:: content.Class.a_property
+ :summary: This overwrites the docstring for ``content.Class.a_property``,
+ but doesn't add any detailed block.
+
+.. py:property:: content.Class.a_property_with_details
+ :summary: This overwrites the docstring for ``content.Class.a_property_with_details``.
+
+ Detailed property docs.
+
+.. py:property:: content.Class.annotated_property
+
+ Annotated property, using summary from the docstring.
+
+.. py:data:: content.Class.DATA_WITH_DETAILS
+
+ Detailed docs for ``data`` in a class to check rendering.
+
+.. py:class:: content.ClassWithSummary
This class has external details but summary from the docstring.
+.. py:enum:: content.Enum
+ :summary: This overwrites the docstring for ``content.Enum``, but
+ doesn't add any detailed block.
+
+.. py:enum:: content.EnumWithSummary
+
+ And this is detailed docs added to the docstring summary.
+
+.. py:function:: content.foo
+ :summary: This overwrites the docstring for ``content.foo``, but
+ doesn't add any detailed block.
+
+.. py:function:: content.foo_with_details
+ :summary: This overwrites the docstring for ``content.foo_with_details()``.
+
+ .. container:: m-note m-info
+
+ Detailed docs for this function
+
+.. py:function:: content.function_with_summary
+
+ This function has external details but summary from the docstring.
+
+.. py:function:: content.annotations
+
+ Type annotations in detailed docs.
+
.. py:data:: content.CONSTANT
:summary: This is finally a docstring for ``content.CONSTANT``
+.. py:data:: content.DATA_WITH_DETAILS
+ :summary: This is finally a docstring for ``content.CONSTANT``
+
+ Detailed docs for the data. **YAY.**
+
+.. py:data:: content.DATA_WITH_DETAILS_BUT_NO_SUMMARY_NEITHER_TYPE
+
+ Why it has to be yelling?!
+
+.. py:function: content.foo
+
+ Details for this function
+
.. py:module:: thismoduledoesnotexist
:summary: This docs get unused and produce a warning
.. py:class:: content.ThisDoesNotExist
:summary: This docs get unused and produce a warning
+.. py:enum:: content.ThisEnumDoesNotExist
+ :summary: This docs get unused and produce a warning
+
+.. py:function:: content.this_function_does_not_exist
+ :summary: This docs get unused and produce a warning
+
+.. py:property:: content.Class.this_property_does_not_exist
+ :summary: This docs get unused and produce a warning
+
.. py:data:: content.THIS_DOES_NOT_EXIST
:summary: This docs get unused and produce a warning
})
self.assertEqual(*self.actual_expected_contents('classes.html'))
self.assertEqual(*self.actual_expected_contents('content.html'))
+ self.assertEqual(*self.actual_expected_contents('content.docstring_summary.html'))
self.assertEqual(*self.actual_expected_contents('content.Class.html'))
- self.assertEqual(*self.actual_expected_contents('content.AnotherClass.html'))
+ self.assertEqual(*self.actual_expected_contents('content.ClassWithSummary.html'))
module_doc_output = None
class_doc_output = None
+enum_doc_output = None
+function_doc_output = None
+property_doc_output = None
data_doc_output = None
class PyModule(rst.Directive):
}
return []
+class PyEnum(rst.Directive):
+ final_argument_whitespace = True
+ has_content = True
+ required_arguments = 1
+ option_spec = {'summary': directives.unchanged}
+
+ def run(self):
+ enum_doc_output[self.arguments[0]] = {
+ 'summary': self.options.get('summary', ''),
+ 'content': '\n'.join(self.content)
+ }
+ return []
+
+class PyFunction(rst.Directive):
+ final_argument_whitespace = True
+ has_content = True
+ required_arguments = 1
+ option_spec = {'summary': directives.unchanged}
+
+ def run(self):
+ function_doc_output[self.arguments[0]] = {
+ 'summary': self.options.get('summary', ''),
+ 'content': '\n'.join(self.content)
+ }
+ return []
+
+class PyProperty(rst.Directive):
+ final_argument_whitespace = True
+ has_content = True
+ required_arguments = 1
+ option_spec = {'summary': directives.unchanged}
+
+ def run(self):
+ property_doc_output[self.arguments[0]] = {
+ 'summary': self.options.get('summary', ''),
+ 'content': '\n'.join(self.content)
+ }
+ return []
+
class PyData(rst.Directive):
final_argument_whitespace = True
has_content = True
}
return []
-def register_mcss(module_doc_contents, class_doc_contents, data_doc_contents, **kwargs):
- global module_doc_output, class_doc_output, data_doc_output
+def register_mcss(module_doc_contents, class_doc_contents, enum_doc_contents, function_doc_contents, property_doc_contents, data_doc_contents, **kwargs):
+ global module_doc_output, class_doc_output, enum_doc_output, function_doc_output, property_doc_output, data_doc_output
module_doc_output = module_doc_contents
class_doc_output = class_doc_contents
+ enum_doc_output = enum_doc_contents
+ function_doc_output = function_doc_contents
+ property_doc_output = property_doc_contents
data_doc_output = data_doc_contents
rst.directives.register_directive('py:module', PyModule)
rst.directives.register_directive('py:class', PyClass)
+ rst.directives.register_directive('py:enum', PyEnum)
+ rst.directives.register_directive('py:function', PyFunction)
+ rst.directives.register_directive('py:property', PyProperty)
rst.directives.register_directive('py:data', PyData)
def register(): # for Pelican