Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple return types aren't hyperlinked #9394

Open
mhostetter opened this issue Jul 1, 2021 · 12 comments
Open

Multiple return types aren't hyperlinked #9394

mhostetter opened this issue Jul 1, 2021 · 12 comments

Comments

@mhostetter
Copy link

Using multiple return values, sphinx/napoleon doesn't hyperlink the return types as it does with parameters. I tried with and without explicitly naming the return values.

  • OS: Ubuntu 20.04
  • Python version: 3.8.10
  • Sphinx version: 4.0.2
  • Sphinx extensions: ['sphinx.ext.napoleon', 'sphinx.ext.mathjax']
    r"""
    Parameters
    ----------
    n : int
        A positive integer.
    B : int, optional
        The max divisor in the trial division. The default is `None` which corresponds to :math:`B = \sqrt{n}`.
        If :math:`B > \sqrt{n}`, the algorithm will only search up to :math:`\sqrt{n}`, since a factor of :math:`n`
        cannot be larger than :math:`\sqrt{n}`.

    Returns
    -------
    list
        The discovered prime factors :math:`\{p_1, \dots, p_k\}`.
    list
        The corresponding prime exponents :math:`\{e_1, \dots, e_k\}`.
    int
        The residual factor :math:`n_r`.
    """

renders like this

image

And when naming the return values

    r"""
    Parameters
    ----------
    n : int
        A positive integer.
    B : int, optional
        The max divisor in the trial division. The default is `None` which corresponds to :math:`B = \sqrt{n}`.
        If :math:`B > \sqrt{n}`, the algorithm will only search up to :math:`\sqrt{n}`, since a factor of :math:`n`
        cannot be larger than :math:`\sqrt{n}`.

    Returns
    -------
    p : list
        The discovered prime factors :math:`\{p_1, \dots, p_k\}`.
    e : list
        The corresponding prime exponents :math:`\{e_1, \dots, e_k\}`.
    n_r : int
        The residual factor :math:`n_r`.
    """

it renders like this

image

However, when using a single return value, the hyperlinks work as expected.

image

FYI, I am using intershpinx_mapping to link to the python docs, which correctly works for the Parameters section.

# File: conf.py
intersphinx_mapping = {
    'python': ('https://docs.python.org/3', None),
    'numpy': ('https://numpy.org/doc/stable/', None),
    'numba': ('https://numba.pydata.org/numba-doc/latest/', None)
}
@astrojuanlu
Copy link
Contributor

On one hand, I have been a victim of this myself and your markup looks correct to me, but on the other hand I just checked that for example the Astropy folks got it working https://docs.astropy.org/en/latest/api/astropy.coordinates.Attribute.html#astropy.coordinates.Attribute.convert_input so I'm not sure what is happening here 🤔

@mhostetter
Copy link
Author

FWIW, from my example, this is the project, conf.py, example function, and the rendered docs.

I'm using sphinx_rtd_theme and astropy isn't. I don't know if that makes a difference.

@tk0miya
Copy link
Member

tk0miya commented Jul 3, 2021

Could you try napoleon_preprocess_types = True, please?

@mhostetter
Copy link
Author

Thanks for the suggestion. It does now hyperlink, however the hyperlink styling has changed. I'm using sphinx_rtd_theme.

Before:
image

After adding napoleon_preprocess_types = True:
image

@astrojuanlu
Copy link
Contributor

@mhostetter Please open an issue about this on https://github.com/readthedocs/sphinx_rtd_theme/, and if you have a Read the Docs build URL, attach it too so we can easily have a look. I guess napoleon_preprocess_types = True generates different HTML (which is then styled differently).

@mhostetter
Copy link
Author

I can open a new issue there. I would note, though, that the default theme in sphinx manifests the same error. So I wonder if the issue is in sphinx itself and not necessarily sphinx_rtd_theme.

Without setting napoleon_preprocess_types:
image

After setting napoleon_preprocess_types = True:
image

When you asked for a "build URL" do you mean a link to the public docs generated from sphinx or a link to the build output from readthedocs website? Let me know how else I can help in the debugging.

@astrojuanlu
Copy link
Contributor

Interesting. If the issue is not specific to the theme, then definitely let's continue the conversation here.

I guess this is the function you're talking about: https://galois.readthedocs.io/en/latest/api/galois.trial_division.html#galois.trial_division

The generated HTML is <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.9)"><em>int</em></a>. What happens if napoleon_preprocess_types = True then?

@mhostetter
Copy link
Author

Without setting napoleon_preprocess_types, the html is

<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>n</strong> (<a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.9)"><em>int</em></a>) – A positive integer.</p></li>
<li><p><strong>B</strong> (<a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.9)"><em>int</em></a><em>, </em><em>optional</em>) – The max divisor in the trial division. The default is <code class="samp docutils literal notranslate"><span class="pre">None</span></code> which corresponds to <span class="math notranslate nohighlight">\(B = \sqrt{n}\)</span>.
If <span class="math notranslate nohighlight">\(B &gt; \sqrt{n}\)</span>, the algorithm will only search up to <span class="math notranslate nohighlight">\(\sqrt{n}\)</span>, since a factor of <span class="math notranslate nohighlight">\(n\)</span>
cannot be larger than <span class="math notranslate nohighlight">\(\sqrt{n}\)</span>.</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p><ul class="simple">
<li><p><em>list</em> – The discovered prime factors <span class="math notranslate nohighlight">\(\{p_1, \dots, p_k\}\)</span>.</p></li>
<li><p><em>list</em> – The corresponding prime exponents <span class="math notranslate nohighlight">\(\{e_1, \dots, e_k\}\)</span>.</p></li>
<li><p><em>int</em> – The residual factor <span class="math notranslate nohighlight">\(n_r\)</span>.</p></li>
</ul>

and renders like

image

After setting napoleon_preprocess_types = True, the html is

<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>n</strong> (<a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a>) – A positive integer.</p></li>
<li><p><strong>B</strong> (<a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a>, <em>optional</em>) – The max divisor in the trial division. The default is <code class="samp docutils literal notranslate"><span class="pre">None</span></code> which corresponds to <span class="math notranslate nohighlight">\(B = \sqrt{n}\)</span>.
If <span class="math notranslate nohighlight">\(B &gt; \sqrt{n}\)</span>, the algorithm will only search up to <span class="math notranslate nohighlight">\(\sqrt{n}\)</span>, since a factor of <span class="math notranslate nohighlight">\(n\)</span>
cannot be larger than <span class="math notranslate nohighlight">\(\sqrt{n}\)</span>.</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p><ul class="simple">
<li><p><a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#list" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">list</span></code></a> – The discovered prime factors <span class="math notranslate nohighlight">\(\{p_1, \dots, p_k\}\)</span>.</p></li>
<li><p><a class="reference external" href="https://docs.python.org/3/library/stdtypes.html#list" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">list</span></code></a> – The corresponding prime exponents <span class="math notranslate nohighlight">\(\{e_1, \dots, e_k\}\)</span>.</p></li>
<li><p><a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.9)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> – The residual factor <span class="math notranslate nohighlight">\(n_r\)</span>.</p></li>
</ul>

and renders like

image

@mhostetter
Copy link
Author

For completeness, I verified the HTML is the same when using the default theme.

@astrojuanlu
Copy link
Contributor

Thanks @mhostetter. I think there are two things here:

  1. With the default value of napoleon_preprocess_types, which is False, multiple return types aren't hyperlinked. Given that "when using a single return value, the hyperlinks work as expected", this looks like a bug rather than a feature, but I'm not sure.
  2. With napoleon_preprocess_types = True, extra HTML is being generated. I have no idea whether this makes sense or not.
    • With that extra HTML, I think it's correct that the different themes style it differently.

@mhostetter
Copy link
Author

FWIW, I agree with your assessment.

@ain-soph
Copy link

ain-soph commented Oct 28, 2021

Have you guys checked the nested type (e.g., dict[float])?

It seems the hyperlinks for dict and float work correctly in Parameters when napoleon_preprocess_types = False, but will not work at True case. This is for both Parameters and Returns.

It seems impossible to get everything hyperlinked very well. I wish everything could be linked as the case of Parameters with napoleon_preprocess_types = False.

From my understanding, when napoleon_preprocess_types = False, parameter types are translated into :type:. According to the docs, the links are created if possible. But multiple return type won't be translated into :rtype: and there's no link for them.
When napoleon_preprocess_types = True, all types won't get translated into :type: nor :rtype:, but using something like :any: to get the link, which makes the nested types not work.

False

image

True

image

Alternatives

From #9119, @fzalkow proposes an alternative, seems promising:

napoleon_custom_sections = [('Returns', 'params_style')]

But currently, it seems not generating any hyperlink (the same output as False image above).
Is this method not generating :param: and :type:, even though using params_style?
That might be a question to the author @SolidifiedRay of PR #8658 .

It seems _parse_custom_params_style_section is calling _format_fields, while _parse_parameters_section is calling _format_docutils_params. Is that the difference? Or it might because of multiple=True or False in _consume_fields?

def _parse_custom_params_style_section(self, section: str) -> List[str]:
return self._format_fields(section, self._consume_fields())

def _parse_parameters_section(self, section: str) -> List[str]:
if self._config.napoleon_use_param:
# Allow to declare multiple parameters at once (ex: x, y: int)
fields = self._consume_fields(multiple=True)
return self._format_docutils_params(fields)
else:
fields = self._consume_fields()
return self._format_fields(_('Parameters'), fields)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants