Skip to content

Commit b587eb2

Browse files
authored
Fix :paramtype: reference targets (#11964)
1 parent a408ec5 commit b587eb2

File tree

8 files changed

+106
-1
lines changed

8 files changed

+106
-1
lines changed

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ Bugs fixed
7777
* #11925: Blacklist the ``sphinxprettysearchresults`` extension; the functionality
7878
it provides was merged into Sphinx v2.0.0.
7979
Patch by James Addison.
80+
* #11962: Fix target resolution when using ``:paramtype:`` fields.
81+
Patch by Bénédikt Tran.
8082

8183
Testing
8284
-------

sphinx/ext/napoleon/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ def _patch_python_domain() -> None:
339339
PyObject.doc_field_types.append(
340340
PyTypedField('keyword', label=_('Keyword Arguments'),
341341
names=('keyword', 'kwarg', 'kwparam'),
342-
typerolename='obj', typenames=('paramtype', 'kwtype'),
342+
typerolename='class', typenames=('paramtype', 'kwtype'),
343343
can_collapse=True))
344344

345345

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import os
2+
import sys
3+
4+
sys.path.insert(0, os.path.abspath('.'))
5+
extensions = [
6+
'sphinx.ext.autodoc',
7+
'sphinx.ext.napoleon',
8+
'sphinx.ext.intersphinx'
9+
]
10+
11+
# Python inventory is manually created in the test
12+
# in order to avoid creating a real HTTP connection
13+
intersphinx_mapping = {}
14+
intersphinx_cache_limit = 0
15+
intersphinx_disabled_reftypes = []
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
test-ext-napoleon
2+
=================
3+
4+
.. automodule:: pkg.bar
5+
:members:
6+
7+
.. automodule:: pkg.foo
8+
:members:

tests/roots/test-ext-napoleon-paramtype/pkg/__init__.py

Whitespace-only changes.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class Bar:
2+
"""The bar."""
3+
def list(self) -> None:
4+
"""A list method."""
5+
6+
@staticmethod
7+
def int() -> float:
8+
"""An int method."""
9+
return 1.0
10+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class Foo:
2+
"""The foo."""
3+
def do(
4+
self,
5+
*,
6+
keyword_paramtype,
7+
keyword_kwtype,
8+
kwarg_paramtype,
9+
kwarg_kwtype,
10+
kwparam_paramtype,
11+
kwparam_kwtype,
12+
):
13+
"""Some method.
14+
15+
:keyword keyword_paramtype: some param
16+
:paramtype keyword_paramtype: list[int]
17+
:keyword keyword_kwtype: some param
18+
:kwtype keyword_kwtype: list[int]
19+
:kwarg kwarg_paramtype: some param
20+
:paramtype kwarg_paramtype: list[int]
21+
:kwarg kwarg_kwtype: some param
22+
:kwtype kwarg_kwtype: list[int]
23+
:kwparam kwparam_paramtype: some param
24+
:paramtype kwparam_paramtype: list[int]
25+
:kwparam kwparam_kwtype: some param
26+
:kwtype kwparam_kwtype: list[int]
27+
"""

tests/test_extensions/test_ext_napoleon_docstring.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
"""Tests for :mod:`sphinx.ext.napoleon.docstring` module."""
22

33
import re
4+
import zlib
45
from collections import namedtuple
56
from inspect import cleandoc
7+
from itertools import product
68
from textwrap import dedent
79
from unittest import mock
810

911
import pytest
12+
from html5lib import HTMLParser
1013

14+
from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping
1115
from sphinx.ext.napoleon import Config
1216
from sphinx.ext.napoleon.docstring import (
1317
GoogleDocstring,
@@ -2659,3 +2663,42 @@ def test_napoleon_and_autodoc_typehints_description_documented_params(app, statu
26592663
'\n'
26602664
' * ****kwargs** (*int*) -- Extra arguments.\n'
26612665
)
2666+
2667+
2668+
@pytest.mark.sphinx('html', testroot='ext-napoleon-paramtype', freshenv=True)
2669+
def test_napoleon_keyword_and_paramtype(app, tmp_path):
2670+
inv_file = tmp_path / 'objects.inv'
2671+
inv_file.write_bytes(b'''\
2672+
# Sphinx inventory version 2
2673+
# Project: Intersphinx Test
2674+
# Version: 42
2675+
# The remainder of this file is compressed using zlib.
2676+
''' + zlib.compress(b'''\
2677+
None py:data 1 none.html -
2678+
list py:class 1 list.html -
2679+
int py:class 1 int.html -
2680+
''')) # NoQA: W291
2681+
app.config.intersphinx_mapping = {'python': ('127.0.0.1:5555', str(inv_file))}
2682+
normalize_intersphinx_mapping(app, app.config)
2683+
load_mappings(app)
2684+
2685+
app.build(force_all=True)
2686+
2687+
buffer = (app.outdir / 'index.html').read_bytes()
2688+
etree = HTMLParser(namespaceHTMLElements=False).parse(buffer)
2689+
2690+
for name, typename in product(('keyword', 'kwarg', 'kwparam'), ('paramtype', 'kwtype')):
2691+
param = f'{name}_{typename}'
2692+
li_ = list(etree.findall(f'.//li/p/strong[.="{param}"]/../..'))
2693+
assert len(li_) == 1
2694+
li = li_[0]
2695+
2696+
text = li.text or ''.join(li.itertext())
2697+
assert text == f'{param} (list[int]) \u2013 some param'
2698+
2699+
a_ = list(li.findall('.//a[@class="reference external"]'))
2700+
2701+
assert len(a_) == 2
2702+
for a, uri in zip(a_, ('list.html', 'int.html')):
2703+
assert a.attrib['href'] == f'127.0.0.1:5555/{uri}'
2704+
assert a.attrib['title'] == '(in Intersphinx Test v42)'

0 commit comments

Comments
 (0)