:param overwrite_existing: Overwrite existing value if already present
in the container
:return: The inserted tuple or the existing
- key/value pair in case ``overwrite_existing`` is not set
+ key/value pair in case :p:`overwrite_existing` is not set
The operation has a :math:`\mathcal{O}(\log{}n)` complexity.
+.. block-success:: Referencing function parameters
+
+ What's also shown in the above snippet is the :rst:`:p:` directive. It
+ looks the same as if you would write just :rst:```overwrite_existing```,
+ but in addition it checks the parameter name against current function signature, emitting a warning in case of a mismatch. This is useful to
+ ensure the documentation doesn't get out of sync with the actual signature.
+
For overloaded functions (such as those coming from pybind11), it's possible to
specify the full signature to distinguish between particular overloads.
Directives with the full signature have a priority, if no signature matches
.. py:function:: content.param_docs
:param a: First parameter
- :param b: The second one
+ :param b: The second one is different from :p:`a`
:param c: And a ``float``
:return: String, of course, it's all *stringly* typed
:param a: First
:param c: Third
- The ``b`` is not documented, while ``c`` isn't in the signature.
+ The :p:`b` is not documented, while :p:`c` isn't in the signature.
.. py:function:: content.full_docstring
:param a: First parameter
# All those initialized in register() or register_mcss()
current_referer_path = None
+current_param_names = None
module_doc_output = None
class_doc_output = None
enum_doc_output = None
node = nodes.literal(rawtext, target, **_options)
return [node], []
-def scope_enter(path, **kwargs):
- global current_referer_path
+def scope_enter(path, param_names=None, **kwargs):
+ global current_referer_path, current_param_names
current_referer_path += [path]
+ current_param_names = param_names
def scope_exit(path, **kwargs):
- global current_referer_path
+ global current_referer_path, current_param_names
assert current_referer_path[-1] == path, "%s %s" % (current_referer_path, path)
current_referer_path = current_referer_path[:-1]
+ current_param_names = None
def check_scope_stack_empty(**kwargs):
global current_referer_path
assert not current_referer_path
+def p(name, rawtext, text, lineno, inliner: Inliner, options={}, content=[]):
+ global current_referer_path, current_param_names
+ if not current_param_names:
+ logging.warning("can't reference parameter %s outside of a function scope", text)
+ elif text not in current_param_names:
+ logging.warning("parameter %s not found in %s(%s) function signature", text, '.'.join(current_referer_path[-1]), ', '.join(current_param_names))
+
+ node = nodes.literal(rawtext, text, **options)
+ return [node], []
+
def consume_docstring(type, path: List[str], signature: Optional[str], doc: str) -> str:
# Create the directive header based on type
if type.name == 'MODULE':
rst.directives.register_directive('py:data', PyData)
rst.roles.register_local_role('ref', ref)
+ rst.roles.register_local_role('p', p)
hooks_pre_scope += [scope_enter]
hooks_post_scope += [scope_exit]