Repository navigation
Closed
Milestone
Description
Describe the bug
When using sphinx.ext.napoleon with Numpy-format docstrings and nitpicky mode, a warning is emitted about optional.
To Reproduce
Create an empty directory and add the following files:
conf.py:
import sys
sys.path.insert(0, '.')
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx.ext.intersphinx']
napoleon_google_docstring = False
intersphinx_mapping = {'python': ('https://docs.python.org/3.7', None)}
nitpicky = Truemycode.py:
def my_func(arg1, arg2):
"""
Parameters
----------
arg1 : str
Description of `arg1`
arg2 : int, optional
Description of `arg2`, defaults to 0
"""
passindex.rst:
.. autofunction:: mycode.my_funcThen run:
sphinx-build -b html -d _build/doctrees . _build/html
The output includes a warning about the optional string which should not be interpreted as a type:
Running Sphinx v2.2.1
making output directory... done
loading intersphinx inventory from https://docs.python.org/3.7/objects.inv...
building [mo]: targets for 0 po files that are out of date
building [html]: targets for 1 source files that are out of date
updating environment: [new config] 1 added, 0 changed, 0 removed
reading sources... [100%] index
looking for now-outdated files... none found
pickling environment... done
checking consistency... done
preparing documents... done
writing output... [100%] index
/home/tom/tmp/debug/mycode.py:docstring of mycode.my_func:: WARNING: py:class reference target not found: optional
generating indices... genindexdone
writing additional pages... searchdone
copying static files... ... done
copying extra files... done
dumping search index in English (code: en)... done
dumping object inventory... done
build succeeded, 1 warning.
The HTML pages are in _build/html.
Expected behavior
No warning should be emitted since adding , optional is valid by the numpy doc spec.
Environment info
- OS: Ubuntu 19.04
- Python version: 3.7.3
- Sphinx version: 2.2.1
- Sphinx extensions: sphinx.ext.napoleon, sphinx.ext.autodoc, sphinx.ext.intersphinx
Reacted by E. M. Bray
Activity
astrofrog commentedon Nov 25, 2019
I noticed that doing:
works fine, but the example I provided above is lifted straight from the sphinx.ext.napoleon docs, and many projects don't write
:obj:and instead rely on it being interpreted as obj by default. I think the bug here is that if:objor:class:etc is not specified,:objis then applied to all items includingoptional.astrofrog commentedon Nov 26, 2019
I also get warnings about
array_likewhich is a valid type according to the numpydoc specastrofrog commentedon Nov 26, 2019
And I also get warnings for the following syntax which is valid:
tk0miya commentedon Nov 26, 2019
The docstring is expanded to following reST document inside napoleon:
But
py:functiondirective expects arguments of:type:field is a list of types. So it considers "optional" is also kind of type. I think this is interface mismatch between napoleon and python domain. I understand "optional" is a special keyword for numpydoc. So it should be treated not as reference. But I don't understand how to fix this...tk0miya commentedon Nov 26, 2019
I don't think numpydoc says "array_like" is a valid type. It does not mention about validity. It seems it takes free formatted text. It also uses "data-type" and "iterable object" for example. But it is hard to resolve these type-like text. I think no-nitpicky mode is used for such ambiguous types. -1 for supporting these types.
On the other hand, it would be better to suppress warnings for set of values like
{'auto', 'ascii', 'latex'}if possible.astrofrog commentedon Nov 26, 2019
Regarding array_like, here's the text I was referring to:
So I think that is also a special term we should allow without reference.
astrofrog commentedon Nov 26, 2019
And I'm on board with not trying to allow things like data-type and iterable object - for those one can always add nitpick exceptions if really needed.
The biggest blocker for me at the moment is the set of values, because everything else can be worked around with exceptions.
keewis commentedon Dec 15, 2019
I think this has to be fixed in
NumpyDocstring._consume_field: we'd need to create a function that parses numpydoc type specifications and converts something liketo the python domain:
which I believe should silence any nit-picky warnings?
embray commentedon Mar 26, 2020
I had a look into this, and while
NumpyDocstring._consume_fieldmight be part of the picture, it certainly isn't the whole picture.The main problem, as @tk0miya pointed out, is that Napoleon will output something like:
At this point, rendering of the
py:functiondirective and how it handles:type <param>:fields is totally given over to the default renderer for that directive, and it no longer has any connection to Google docstrings or Numpy docstrings, etc.The second problem is that the available Info field options do not have an option for specifying if a parameter is optional, or what its default value is. I'm picturing that a possible solution could involve adding something like this. For example, for a function
my_func(arg1, arg2=1):Perhaps this would be redundant, since the fact that an argument is optional, and its default, are already reflected in the function signature line. But an explicit
:default <arg>:option could indicate explicitly that you want the default value documented in the parameter description list as well. Currently we usually do this manually by adding something like "(default: 1") at the end of the parameter description. But this could take care of doing that automatically. Optionally, a:default arg1:without specifying a value would be shorthand for just marking the parameter "(optional)".Then, on the Napoleon,
NumpyDocstringend of things, it could detect "optional" at the end of a type list, remove that from the type list, and instead output:default <argname>:for that field.embray commentedon Mar 26, 2020
Digging a little deeper, it seems that Napoleon does already monkeypatch the Python domain to add a distinct "Keyword Arguments" field to the docs, and keyword arguments can be added to it by marking them
:keyword <argname>:,:kwarg <argname>:, or:kwparam <argname>:instead of `:param :, etc.However, it only really creates
:kwparam:s when parsing a "keyword arguments" section in the docstring, which is used in Google docstrings but not numpydoc docstrings. At the very least, for numpydoc, it could detect "optional" in a field's type list, and mark that field as a:kwparam:instead of a plain:param:. I'm going to attempt that.keewis commentedon Mar 26, 2020
Thanks for working on this, @embray.
Just for reference,
numpydocaccepts a mapping that translates between type entries – so we could mapmappingto the standard library'sdict-liketerm orarray-like/array_liketo whatever it officially points to innumpy– and a list that allows ignoring certain words (likeof,andand maybe alsoor?).That would push most of the issue to the user but we'd still need to find a way to support sets of values. However, at least for
optional/defaultthe fix you described sounds cleaner to me.embray commentedon Mar 26, 2020
Here's what I came up with, which seems to work fine for my own case. Of course, if others on this issue agree to a fix like this, it should be merged in directly. For now I am just monkey-patching in my
conf.py:I think that, now that this adds all keyword arguments to a separate section, keeping the "(optional)" text is a bit redundant. But I keep it anyways, in the original spirit of the numpydoc format.
For example, here is an actual docstring from my project, and the resulting output:
tk0miya commentedon Jul 25, 2020
Now, this is fixed by @keewis via #7690. Thanks a lot!