cross-linked types
:py:`function.params` List of function parameters. See below for
details.
+:py:`function.exceptions` List of exceptions raised by this function.
+ See below for details.
:py:`function.has_complex_params` Set to :py:`True` if the parameter list
should be wrapped on several lines for
better readability (for example when it
:py:`False` otherwise.
=================================== ===========================================
-The :py:`func.params` is a list of function parameters and their description.
-Each item has the following properties:
+The :py:`function.params` is a list of function parameters and their
+description. Each item has the following properties:
.. class:: m-table m-fullwidth
introspected. In that case, the parameter list is a single entry with ``name``
set to :py:`"..."` and the rest being empty.
+The :py:`function.exceptions` is a list of exceptions types and descriptions.
+Each item has the following properties:
+
+.. class:: m-table m-fullwidth
+
+=========================== ===================================================
+Property Description
+=========================== ===================================================
+:py:`exception.type` Exception type
+:py:`exception.type_link` Like :py:`exception`, but with a cross-linked type
+:py:`exception.content` Detailed documentation
+=========================== ===================================================
+
`Property properties`_
``````````````````````
cross-linked types
:py:`property.summary` Doc summary
:py:`property.content` Detailed documentation, if any
+:py:`property.exceptions` List of exceptions raised when accessing
+ this property. Same as
+ :py:`function.exceptions` described in
+ `function properties`_.
: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`
------------
The :rst:`.. py:function::` directive supports additional options ---
-:py:`:param <name>:` for documenting parameters and :py:`:return:` for
-documenting the return value. It's allowed to have either none or all
-parameters documented (the ``self`` parameter can be omitted), having them
-documented only partially or documenting parameters that are not present in the
-function signature will cause a warning. Example:
+:rst:`:param name:` for documenting parameters, :rst:`:raise name:` for
+documenting raised exceptions and :rst:`:return:` for documenting the return
+value. It's allowed to have either none or all parameters documented (the
+``self`` parameter can be omitted), having them documented only partially or
+documenting parameters that are not present in the function signature will
+cause a warning. Documenting one parameter multiple times causes a warning, on
+the other hand listing one exception multiple times is a valid use case.
+Example:
.. code:: rst
:param value: Corresponding value
:param overwrite_existing: Overwrite existing value if already present
in the container
+ :raise ValueError: If the key type is not hashable
:return: The inserted tuple or the existing
key/value pair in case :p:`overwrite_existing` is not set
`Properties`_
-------------
-Use :rst:`.. py:property::` for documenting properties. This directive doesn't
-support any additional options besides :rst:`:summary:`. For convenience,
-properties that have just a summary can be also documented directly in the
-enclosing :rst:`.. py:class::` directive `as shown above <#classes>`__.
+Use :rst:`.. py:property::` for documenting properties. This directive supports
+the :rst:`:raise name:` option similarly as for `functions`_, plus the usual
+:rst:`:summary:`. For convenience, properties that have just a summary can be
+also documented directly in the enclosing :rst:`.. py:class::` directive
+`as shown above <#classes>`__.
.. code:: rst
overloads = [out]
- # Common path for parameter / return value docs and search
+ # Common path for parameter / exception / return value docs and search
path_str = '.'.join(entry.path)
for out in overloads:
signature = '({})'.format(', '.join(['{}: {}'.format(param.name, param.type) if param.type else param.name for param in out.params]))
if name not in used_params:
logging.warning("%s%s documents parameter %s, which isn't in the signature", path_str, signature, name)
+ if function_docs.get('raise'):
+ out.exceptions = []
+ for type_, content in function_docs['raise']:
+ exception = Empty()
+ exception.type = type_
+ exception.type_link = make_name_link(state, entry.path, type_)
+ exception.content = render_inline_rst(state, content)
+ out.exceptions += [exception]
+ out.has_details = True
+
if function_docs.get('return'):
try:
out.return_value = render_inline_rst(state, function_docs['return'])
for hook in state.hooks_post_scope:
hook(type=entry.type, path=entry.path)
+ # Exception docs, if any
+ exception_docs = state.property_docs.get('.'.join(entry.path), {}).get('raise')
+ if exception_docs:
+ out.exceptions = []
+ for type_, content in exception_docs:
+ exception = Empty()
+ exception.type = type_
+ exception.type_link = make_name_link(state, entry.path, type_)
+ exception.content = render_inline_rst(state, content)
+ out.exceptions += [exception]
+ out.has_details = True
+
if not state.config['SEARCH_DISABLED']:
result = Empty()
result.flags = ResultFlag.from_type(ResultFlag.NONE, EntryType.PROPERTY)
{% if function.summary %}
<p>{{ function.summary }}</p>
{% endif %}
- {% if function.has_param_details or function.return_value %}
+ {% if function.has_param_details or function.exceptions or function.return_value %}
<table class="m-table m-fullwidth m-flat">
{% if function.has_param_details %}
<thead>
{% endfor %}
</tbody>
{% endif %}
+ {% if function.exceptions %}
+ <thead>
+ <tr><th colspan="2">Exceptions</th></tr>
+ </thead>
+ <tbody>
+ {% for exception in function.exceptions %}
+ <tr>
+ <td{% if loop.index == 1 and not function.has_param_details %} style="width: 1%"{% endif %}>{{ exception.type_link }}</td>
+ <td>{{ exception.content }}</td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ {% endif %}
{% if function.return_value %}
<tfoot>
<tr>
- <th{% if not function.has_param_details %} style="width: 1%"{% endif %}>Returns</th>
+ <th{% if not function.has_param_details and not function.exceptions %} style="width: 1%"{% endif %}>Returns</th>
<td>{{ function.return_value }}</td>
</tr>
</tfoot>
{% if property.summary %}
<p>{{ property.summary }}</p>
{% endif %}
+ {% if property.exceptions %}
+ <table class="m-table m-fullwidth m-flat">
+ <thead>
+ <tr><th colspan="2">Exceptions</th></tr>
+ </thead>
+ <tbody>
+ {% for exception in property.exceptions %}
+ <tr>
+ <td{% if loop.index == 1 %} style="width: 1%"{% endif %}>{{ exception.type_link }}</td>
+ <td>{{ exception.content }}</td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ {% endif %}
{% if property.content %}
{{ property.content }}
{% endif %}
<span class="m-doc-wrap-bumper">def <a href="#method_param_docs" class="m-doc">method_param_docs</a>(</span><span class="m-doc-wrap">self, a, b)</span>
</dt>
<dd>This method gets its params except self documented</dd>
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="#method_param_exception_return_docs" class="m-doc">method_param_exception_return_docs</a>(</span><span class="m-doc-wrap">self, a, b)</span>
+ </dt>
+ <dd>This one documents params and raised exceptions</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>
<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>
+ <dt>
+ <a href="#property_exception_docs" class="m-doc">property_exception_docs</a> <span class="m-label m-flat m-warning">get</span>
+ </dt>
+ <dd>This one documents raised exceptions in an (otherwise unneeded)
+detail view</dd>
</dl>
</section>
<section id="data">
</table>
<p>The <code>self</code> isn't documented and thus also not included in the list.</p>
</div></section>
+ <section class="m-doc-details" id="method_param_exception_return_docs"><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_param_exception_return_docs" class="m-doc-self">method_param_exception_return_docs</a>(</span><span class="m-doc-wrap">self, a, b)</span></span>
+ </h3>
+ <p>This one documents params and raised exceptions</p>
+ <table class="m-table m-fullwidth m-flat">
+ <thead>
+ <tr><th colspan="2">Parameters</th></tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td style="width: 1%">a</td>
+ <td>The first parameter</td>
+ </tr>
+ <tr>
+ <td>b</td>
+ <td>The second parameter</td>
+ </tr>
+ </tbody>
+ <thead>
+ <tr><th colspan="2">Exceptions</th></tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>AttributeError</td>
+ <td>If you do bad things to it</td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <th>Returns</th>
+ <td>If you don't do bad things to it</td>
+ </tr>
+ </tfoot>
+ </table>
+ </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>
<p>This is an annotated property</p>
<p>Annotated property, using summary from the docstring.</p>
</div></section>
+ <section class="m-doc-details" id="property_exception_docs"><div>
+ <h3>
+ content.<wbr />Class.<wbr /><a href="#property_exception_docs" class="m-doc-self">property_exception_docs</a> <span class="m-label m-flat m-warning">get</span>
+ </h3>
+ <p>This one documents raised exceptions in an (otherwise unneeded)
+detail view</p>
+ <table class="m-table m-fullwidth m-flat">
+ <thead>
+ <tr><th colspan="2">Exceptions</th></tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td style="width: 1%">AttributeError</td>
+ <td>If you do bad things to it</td>
+ </tr>
+ </tbody>
+ </table>
+ </div></section>
</section>
<section>
<h2>Data documentation</h2>
<section id="functions">
<h2><a href="#functions">Functions</a></h2>
<dl class="m-doc">
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="#exception_docs" class="m-doc">exception_docs</a>(</span><span class="m-doc-wrap">)</span>
+ </dt>
+ <dd>This one documents raised exceptions in an (otherwise unneeded) detail
+view</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>
</section>
<section>
<h2>Function documentation</h2>
+ <section class="m-doc-details" id="exception_docs"><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="#exception_docs" class="m-doc-self">exception_docs</a>(</span><span class="m-doc-wrap">)</span></span>
+ </h3>
+ <p>This one documents raised exceptions in an (otherwise unneeded) detail
+view</p>
+ <table class="m-table m-fullwidth m-flat">
+ <thead>
+ <tr><th colspan="2">Exceptions</th></tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td style="width: 1%">ValueError</td>
+ <td>This thing fires</td>
+ </tr>
+ <tr>
+ <td>ValueError</td>
+ <td>This <em>same</em> thing fires <em>also</em> for this reason</td>
+ </tr>
+ <tr>
+ <td>RuntimeError</td>
+ <td>This another thing fires too</td>
+ </tr>
+ </tbody>
+ </table>
+ </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>
def method_param_docs(self, a, b):
"""This method gets its params except self documented"""
+ def method_param_exception_return_docs(self, a, b):
+ """This one documents params and raised exceptions"""
+
@property
def a_property(self):
"""This summary is not shown either"""
def annotated_property(self) -> float:
"""This is an annotated property"""
+ @property
+ def property_exception_docs(self):
+ """This one documents raised exceptions in an (otherwise unneeded)
+ detail view"""
+
DATA_WITH_DETAILS: str = 'this blows'
class ClassWithSummary:
Like this.
"""
+def exception_docs():
+ """This one documents raised exceptions in an (otherwise unneeded) detail
+ view
+ """
+
# This should check we handle reST parsing errors in external docs gracefully.
# Will probably look extra weird in the output tho, but that's okay -- it's an
# error after all.
The ``self`` isn't documented and thus also not included in the list.
+.. py:function:: content.Class.method_param_exception_return_docs
+ :param a: The first parameter
+ :param b: The second parameter
+ :raise AttributeError: If you do bad things to it
+ :return: If you don't do bad things to it
+
.. py:property:: content.Class.a_property
:summary: This overwrites the docstring for :ref:`a_property`, but doesn't
add any detailed block.
Annotated property, using summary from the docstring.
+.. py:property:: content.Class.property_exception_docs
+ :raise AttributeError: If you do bad things to it
+
.. py:data:: content.Class.DATA_WITH_DETAILS
Detailed docs for :ref:`DATA_WITH_DETAILS` in a class to check
:param a: First parameter
:param b: Second
+.. py:function:: content.exception_docs
+ :raise ValueError: This thing fires
+ :raise ValueError: This *same* thing fires *also* for this reason
+ :raise RuntimeError: This another thing fires too
+
.. py:data:: content.CONSTANT
:summary: This is finally a docstring for :ref:`CONSTANT`
function we need to say :ref:`inspect_type_links.open()`. If it would be
the other way around, there would be no simple way to link to builtins.
+.. py:function:: inspect_type_links.open
+ :raise ValueError: If this is not a can, crosslinking to :ref:`ValueError`
+ of course.
+
+.. py:property:: inspect_type_links.Foo.prop
+ :raise SystemError: If you look at it wrong, crosslinking to
+ :ref:`SystemError` of course.
+
.. py:module:: inspect_type_links.first
:ref:`Foo`, :ref:`first.Foo` and :ref:`inspect_type_links.first.Foo` should
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8" />
+ <title>inspect_type_links.Foo | 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="inspect_type_links.html">inspect_type_links</a>.<wbr/></span>Foo <span class="m-thin">class</span>
+ </h1>
+ <p>A class in the root module</p>
+ <div class="m-block m-default">
+ <h3>Contents</h3>
+ <ul>
+ <li>
+ Reference
+ <ul>
+ <li><a href="#properties">Properties</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <section id="properties">
+ <h2><a href="#properties">Properties</a></h2>
+ <dl class="m-doc">
+ <dt>
+ <a href="#prop" class="m-doc">prop</a> <span class="m-label m-flat m-warning">get</span>
+ </dt>
+ <dd>Here just to test the raise option</dd>
+ </dl>
+ </section>
+ <section>
+ <h2>Property documentation</h2>
+ <section class="m-doc-details" id="prop"><div>
+ <h3>
+ inspect_type_links.<wbr />Foo.<wbr /><a href="#prop" class="m-doc-self">prop</a> <span class="m-label m-flat m-warning">get</span>
+ </h3>
+ <p>Here just to test the raise option</p>
+ <table class="m-table m-fullwidth m-flat">
+ <thead>
+ <tr><th colspan="2">Exceptions</th></tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td style="width: 1%"><a href="https://docs.python.org/3/library/exceptions.html#SystemError" class="m-doc-external">SystemError</a></td>
+ <td>If you look at it wrong, crosslinking to
+<a class="m-doc-external" href="https://docs.python.org/3/library/exceptions.html#SystemError">SystemError</a> of course.</td>
+ </tr>
+ </tbody>
+ </table>
+ </div></section>
+ </section>
+ </div>
+ </div>
+ </div>
+</article></main>
+</body>
+</html>
<section id="functions">
<h2><a href="#functions">Functions</a></h2>
<dl class="m-doc">
- <dt id="open">
- <span class="m-doc-wrap-bumper">def <a href="#open" class="m-doc-self">open</a>(</span><span class="m-doc-wrap">)</span>
+ <dt>
+ <span class="m-doc-wrap-bumper">def <a href="#open" class="m-doc">open</a>(</span><span class="m-doc-wrap">)</span>
</dt>
<dd>A function that opens cans.</dd>
</dl>
</section>
+ <section>
+ <h2>Function documentation</h2>
+ <section class="m-doc-details" id="open"><div>
+ <h3>
+ <span class="m-doc-wrap-bumper">def inspect_type_links.<wbr /></span><span class="m-doc-wrap"><span class="m-doc-wrap-bumper"><a href="#open" class="m-doc-self">open</a>(</span><span class="m-doc-wrap">)</span></span>
+ </h3>
+ <p>A function that opens cans.</p>
+ <table class="m-table m-fullwidth m-flat">
+ <thead>
+ <tr><th colspan="2">Exceptions</th></tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td style="width: 1%"><a href="https://docs.python.org/3/library/exceptions.html#ValueError" class="m-doc-external">ValueError</a></td>
+ <td>If this is not a can, crosslinking to <a class="m-doc-external" href="https://docs.python.org/3/library/exceptions.html#ValueError">ValueError</a>
+of course.</td>
+ </tr>
+ </tbody>
+ </table>
+ </div></section>
+ </section>
</div>
</div>
</div>
class Foo:
"""A class in the root module"""
+ @property
+ def prop(self):
+ """Here just to test the raise option"""
+
class Bar:
"""Another class in the root module"""
self.assertEqual(*self.actual_expected_contents('index.html'))
self.assertEqual(*self.actual_expected_contents('inspect_type_links.html'))
+ self.assertEqual(*self.actual_expected_contents('inspect_type_links.Foo.html'))
self.assertEqual(*self.actual_expected_contents('inspect_type_links.first.html'))
self.assertEqual(*self.actual_expected_contents('inspect_type_links.first.Foo.html'))
self.assertEqual(*self.actual_expected_contents('inspect_type_links.first.Foo.Foo.html'))
required_arguments = 1
option_spec = {'summary': directives.unchanged,
'param': directives_unchanged_list,
+ 'raise': directives_unchanged_list,
'return': directives.unchanged}
def run(self):
for name, content in self.options.get('param', []):
if name in params: raise KeyError("duplicate param {}".format(name))
params[name] = content
+ # Check that exceptions are parsed properly. This will blow up if the
+ # exception name is not specified. Unlike function params not turning
+ # these into a dict since a single type can be raised for multiple
+ # reasons.
+ raises = []
+ for name, content in self.options.get('raise', []):
+ raises += [(name, content)]
output = function_doc_output.setdefault(self.arguments[0], {})
if self.options.get('summary'):
output['summary'] = self.options['summary']
if params:
output['params'] = params
+ if raises:
+ output['raise'] = raises
if self.options.get('return'):
output['return'] = self.options['return']
if self.content:
final_argument_whitespace = True
has_content = True
required_arguments = 1
- option_spec = {'summary': directives.unchanged}
+ option_spec = {'summary': directives.unchanged,
+ 'raise': directives_unchanged_list}
def run(self):
+ # Check that exceptions are parsed properly. This will blow up if the
+ # exception name is not specified. Unlike function params not turning
+ # these into a dict since a single type can be raised for multiple
+ # reasons.
+ raises = []
+ for name, content in self.options.get('raise', []):
+ raises += [(name, content)]
+
output = property_doc_output.setdefault(self.arguments[0], {})
+ if raises:
+ output['raise'] = raises
if self.options.get('summary'):
output['summary'] = self.options['summary']
if self.content:
# TODO: this will blow up if the above loop is never entered (which is
# unlikely) as EntryType is defined there
(EntryType.CLASS, 'py:class'),
+ # Otherwise we can't link to standard exceptions from :raise:
+ (EntryType.CLASS, 'py:exception'), # TODO: special type for these?
(EntryType.DATA, 'py:data'), # typing.Tuple or typing.Any is data
# Those are custom to m.css, not in Sphinx
(EntryType.ENUM, 'py:enum'),