Post-process docstring output

This commit is contained in:
Griatch 2020-07-10 14:14:34 +02:00
parent 09c602dd69
commit 29fc31bb01
5 changed files with 140 additions and 97 deletions

View file

@ -260,6 +260,16 @@ li > p {
margin-bottom: 0px;
}
/* The indents of kwarg - lists in api docs */
dl.field-list.simple > dd.field-odd > ul.simple > li > ul {
margin-left: 24px;
}
dd.field-odd > ul.simple > li > ul > li > dl.simple {
margin-bottom: -8px;
}
.admonition.important {
background-color: #fbf7c3;
border: 1px solid #c8c59b;

View file

@ -6,6 +6,7 @@
import os
import sys
import re
import sphinx_theme
from recommonmark.transform import AutoStructify
from sphinx.util.osutil import cd
@ -233,12 +234,40 @@ def autodoc_skip_member(app, what, name, obj, skip, options):
return False
def autodoc_clean_docstring(app, what, name, obj, options, lines):
"""Clean docstring of ansi. Must modify lines list in-place"""
def autodoc_post_process_docstring(app, what, name, obj, options, lines):
"""
Post-process docstring in various ways. Must modify lines-list in-place.
"""
try:
# clean out ANSI colors
if ansi_clean:
for il, line in enumerate(lines):
lines[il] = ansi_clean(line)
# post-parse docstrings to convert any remaining
# markdown -> reST since napoleon doesn't know Markdown
def _sub_codeblock(match):
code = match.group(1)
return "::\n\n {}".format(
"\n ".join(lne for lne in code.split("\n")))
doc = "\n".join(lines)
doc = re.sub(r"```python\s*\n+(.*?)```", _sub_codeblock, doc,
flags=re.MULTILINE + re.DOTALL)
doc = re.sub(r"```", "", doc, flags=re.MULTILINE)
doc = re.sub(r"`{1}", "**", doc, flags=re.MULTILINE)
newlines = doc.split("\n")
# we must modify lines in-place
lines[:] = newlines[:]
except Exception as err:
# if we don't print here we won't see what the error actually is
print(f"Post-process docstring exception: {err}")
raise
# Napoleon Google-style docstring parser for autodocs
@ -247,7 +276,7 @@ napoleon_numpy_docstring = False
napoleon_include_init_with_doc = False
napoleon_include_private_with_doc = False
napoleon_include_special_with_doc = False
napoleon_use_admonition_for_examples = True
napoleon_use_admonition_for_examples = False
napoleon_use_admonition_for_notes = False
napoleon_use_admonition_for_references = False
napoleon_use_ivar = False
@ -262,7 +291,7 @@ napoleon_use_rtype = False
def setup(app):
app.connect("autodoc-skip-member", autodoc_skip_member)
app.connect("autodoc-process-docstring", autodoc_clean_docstring)
app.connect("autodoc-process-docstring", autodoc_post_process_docstring)
app.add_transform(AutoStructify)
# build toctree file

View file

@ -76,6 +76,7 @@ class PortalSessionHandler(SessionHandler):
Returns:
sessid
"""
self.latest_sessid += 1
if self.latest_sessid in self:
@ -247,7 +248,7 @@ class PortalSessionHandler(SessionHandler):
for the protocol used, eg
'evennia.server.portal.irc.IRCClientFactory'
config (dict): Dictionary of configuration options, fed as
**kwarg to protocol class' __init__ method.
`**kwargs` to protocol class' __init__ method.
Raises:
RuntimeError: If The correct factory class is not found.

View file

@ -415,9 +415,7 @@ class EvMenu(object):
by default in all nodes of the menu. This will print out the current state of
the menu. Deactivate for production use! When the debug flag is active, the
`persistent` flag is deactivated.
Kwargs:
any (any): All kwargs will become initialization variables on `caller.ndb._menutree`,
**kwargs: All kwargs will become initialization variables on `caller.ndb._menutree`,
to be available at run.
Raises:
@ -789,8 +787,7 @@ class EvMenu(object):
raw_string (str): The raw default string entered on the
previous node (only used if the node accepts it as an
argument)
Kwargs:
any: Extra arguments to goto callables.
**kwargs: Extra arguments to goto callables.
"""

View file

@ -356,7 +356,7 @@ def list_to_string(inlist, endsep="and", addquote=False):
Returns:
liststr (str): The list represented as a string.
Examples:
Example:
```python
# no endsep:
@ -839,7 +839,7 @@ def to_bytes(text, session=None):
the text with "?" in place of problematic characters. If the specified encoding cannot
be found, the protocol flag is reset to utf-8. In any case, returns bytes.
Note:
Notes:
If `text` is already bytes, return it as is.
"""
@ -879,7 +879,7 @@ def to_str(text, session=None):
Returns:
decoded_text (str): The decoded text.
Note:
Notes:
If `text` is already str, return it as is.
"""
if isinstance(text, str):
@ -977,18 +977,17 @@ def inherits_from(obj, parent):
distance from parent.
Args:
obj (any): Object to analyze. This may be either an instance
or a class.
parent (any): Can be either instance, class or python path to class.
obj (any): Object to analyze. This may be either an instance or
a class.
parent (any): Can be either an instance, a class or the python
path to the class.
Returns:
inherits_from (bool): If `parent` is a parent to `obj` or not.
Notes:
What differs this function from e.g. `isinstance()` is that `obj`
may be both an instance and a class, and parent may be an
instance, a class, or the python path to a class (counting from
the evennia root directory).
What differentiates this function from Python's `isinstance()` is the
flexibility in the types allowed for the object and parent being compared.
"""
@ -1036,8 +1035,7 @@ def uses_database(name="sqlite3"):
shortcut to having to use the full backend name.
Args:
name (str): One of 'sqlite3', 'mysql', 'postgresql'
or 'oracle'.
name (str): One of 'sqlite3', 'mysql', 'postgresql' or 'oracle'.
Returns:
uses (bool): If the given database is used or not.
@ -1061,20 +1059,19 @@ def delay(timedelay, callback, *args, **kwargs):
timedelay (int or float): The delay in seconds
callback (callable): Will be called as `callback(*args, **kwargs)`
after `timedelay` seconds.
args (any, optional): Will be used as arguments to callback
Kwargs:
persistent (bool, optional): should make the delay persistent
over a reboot or reload
any (any): Will be used as keyword arguments to callback.
*args: Will be used as arguments to callback
Keyword args:
persistent (bool): Make the delay persistent over a reboot or reload.
any: Any other keywords will be use as keyword arguments to callback.
Returns:
deferred (deferred): Will fire with callback after
`timedelay` seconds. Note that if `timedelay()` is used in the
deferred: Will fire with callback after `timedelay` seconds. Note that
if `timedelay()` is used in the
commandhandler callback chain, the callback chain can be
defined directly in the command body and don't need to be
specified here.
Note:
Notes:
The task handler (`evennia.scripts.taskhandler.TASK_HANDLER`) will
be called for persistent or non-persistent tasks.
If persistent is set to True, the callback, its arguments
@ -1102,11 +1099,10 @@ def run_async(to_execute, *args, **kwargs):
Args:
to_execute (callable): If this is a callable, it will be
executed with *args and non-reserved *kwargs as arguments.
executed with `*args` and non-reserved `**kwargs` as arguments.
The callable will be executed using ProcPool, or in a thread
if ProcPool is not available.
Kwargs:
Keyword args:
at_return (callable): Should point to a callable with one
argument. It will be called with the return value from
to_execute.
@ -1638,11 +1634,9 @@ def string_partial_matching(alternatives, inp, ret_index=True):
def format_table(table, extra_space=1):
"""
Note: `evennia.utils.evtable` is more powerful than this, but this
function can be useful when the number of columns and rows are
unknown and must be calculated on the fly.
Format a 2D array of strings into a multi-column table.
Args.
Args:
table (list): A list of lists to represent columns in the
table: `[[val,val,val,...], [val,val,val,...], ...]`, where
each val will be placed on a separate row in the
@ -1652,14 +1646,17 @@ def format_table(table, extra_space=1):
padding (in characters) should be left between columns.
Returns:
table (list): A list of lists representing the rows to print
out one by one.
list: A list of lists representing the rows to print out one by one.
Notes:
The function formats the columns to be as wide as the widest member
of each column.
Examples:
`evennia.utils.evtable` is more powerful than this, but this
function can be useful when the number of columns and rows are
unknown and must be calculated on the fly.
Example:
```python
ftable = format_table([[...], [...], ...])
@ -1671,7 +1668,9 @@ def format_table(table, extra_space=1):
string += "\n" + "".join(row)
print string
```
"""
if not table:
return [[]]
@ -1703,12 +1702,10 @@ def percent(value, minval, maxval, formatting="{:3.1f}%"):
current value as a percentage. If None, the
raw float will be returned instead.
Returns:
str or float: The formatted value or the raw percentage
as a float.
str or float: The formatted value or the raw percentage as a float.
Notes:
We try to handle a weird interval gracefully.
- If either maxval or minval is None (open interval),
we (aribtrarily) assume 100%.
- If either maxval or minval is None (open interval), we (aribtrarily) assume 100%.
- If minval > maxval, we return 0%.
- If minval == maxval == value we are looking at a single value match
and return 100%.
@ -1759,7 +1756,9 @@ def percentile(iterable, percent, key=lambda x: x):
percent (float): A value from 0.0 to 1.0.
key (callable, optional). Function to compute value from each element of N.
@return - the percentile of the values
Returns:
float: The percentile of the values
"""
if not iterable:
return None
@ -1792,7 +1791,7 @@ def format_grid(elements, width=78, sep=" ", verbatim_elements=None):
decorations in the grid, such as horizontal bars.
Returns:
gridstr (list): The grid as a list of ready-formatted rows. We return it
gridstr: The grid as a list of ready-formatted rows. We return it
like this to make it easier to insert decorations between rows, such
as horizontal bars.
"""
@ -1883,13 +1882,13 @@ def get_evennia_pids():
Examples:
This can be used to determine if we are in a subprocess by
something like:
```python
self_pid = os.getpid()
server_pid, portal_pid = get_evennia_pids()
is_subprocess = self_pid not in (server_pid, portal_pid)
```
"""
server_pidfile = os.path.join(settings.GAME_DIR, "server.pid")
portal_pidfile = os.path.join(settings.GAME_DIR, "portal.pid")
@ -2078,8 +2077,7 @@ def at_search_result(matches, caller, query="", quiet=False, **kwargs):
query (str, optional): The search query used to produce `matches`.
quiet (bool, optional): If `True`, no messages will be echoed to caller
on errors.
Kwargs:
Keyword args:
nofound_string (str): Replacement string to echo on a notfound error.
multimatch_string (str): Replacement string to echo on a multimatch error.
@ -2138,7 +2136,7 @@ class LimitedSizeOrderedDict(OrderedDict):
"""
Limited-size ordered dict.
Kwargs:
Keyword args:
size_limit (int): Use this to limit the number of elements
alloweds to be in this list. By default the overshooting elements
will be removed in FIFO order.
@ -2210,10 +2208,10 @@ def get_all_typeclasses(parent=None):
from this parent.
Returns:
typeclasses (dict): On the form {"typeclass.path": typeclass, ...}
dict: On the form `{"typeclass.path": typeclass, ...}`
Notes:
This will dynamicall retrieve all abstract django models inheriting at any distance
This will dynamically retrieve all abstract django models inheriting at any distance
from the TypedObject base (aka a Typeclass) so it will work fine with any custom
classes being added.
@ -2236,15 +2234,19 @@ def get_all_typeclasses(parent=None):
def interactive(func):
"""
Decorator to make a method pausable with yield(seconds)
and able to ask for user-input with response=yield(question).
For the question-asking to work, 'caller' must the name
of an argument or kwarg to the decorated function.
Decorator to make a method pausable with `yield(seconds)`
and able to ask for user-input with `response=yield(question)`.
For the question-asking to work, one of the args or kwargs to the
decorated function must be named 'caller'.
Note that this turns the method into a generator.
Raises:
ValueError: If asking an interactive question but the decorated
function has no arg or kwarg named 'caller'.
ValueError: If passing non int/float to yield using for pausing.
Example usage:
Example:
```python
@interactive
def myfunc(caller):
caller.msg("This is a test")
@ -2256,6 +2258,10 @@ def interactive(func):
yield(5)
else:
# ...
```
Notes:
This turns the decorated function or method into a generator.
"""
from evennia.utils.evmenu import get_input