2021-02-28
The majority of Python code I write uses the scientific/PyData ecosystem. This leads to reading and writing a lot of NumPy style docstrings. If you've read some of my other posts you've undoubtedly noticed my editor of choice is GNU Emacs. Docstring-generating Emacs Lisp packages for Python do exist: sphinx-doc.el and docstr. The former does not support the NumPy docstring style, while the latter isn't quite as plug-and-play as I wanted (docstr supports many programming languages and it's very programmable).
I wrote numpydoc.el to support the features I was looking for. Simply
call numpydoc-generate
from the body of the function of interest to
create a docstring. The function signature and body are parsed to
determine argument names, types, default values, return type and what
exceptions (if any) can be raised. That information is used to
generate the Parameters
block and the Returns
block for the
docstring. If exceptions are found the Raises
block is also added.
The default behavior prompts the user to enter a short and long
function description along with descriptions for the individual
components of the function. You can also configure the package to use
yasnippet. The git repository README includes a gif with some example
usage. Who doesn't want to turn this:
def func(number: int = 5, label: str | None = None) -> str:
if number > 42:
raise ValueError("Illegal number")
if label is not None:
return label * number
return "None" * number
into this:
def func(number: int = 5, label: str | None = None) -> str:
"""FIXME: Short description.
FIXME: Long description.
Parameters
----------
number : int
FIXME: Add docs.
label : str, optional
FIXME: Add docs.
Returns
-------
str
FIXME: Add docs.
Raises
------
ValueError
FIXME: Add docs.
Examples
--------
FIXME: Add docs.
"""
if number > 42:
raise ValueError("Illegal number")
if label is not None:
return label * number
return "None" * number
with one M-x
execution? The package is available on MELPA. Just add
to your (use-package
leveraging) init.el
:
(use-package numpydoc
:ensure t
:after python)
Perhaps you can bind it to C-c C-n
(it's a vacant binding, unused by
python.el
as of writing this post):
(use-package numpydoc
:ensure t
:after python
:bind (:map python-mode-map
("C-c C-n" . numpydoc-generate)))