Skip to content

Commit

Permalink
Fix :paramtype: reference targets (#11964)
Browse files Browse the repository at this point in the history
  • Loading branch information
picnixz authored Feb 13, 2024
1 parent a408ec5 commit b587eb2
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ Bugs fixed
* #11925: Blacklist the ``sphinxprettysearchresults`` extension; the functionality
it provides was merged into Sphinx v2.0.0.
Patch by James Addison.
* #11962: Fix target resolution when using ``:paramtype:`` fields.
Patch by Bénédikt Tran.

Testing
-------
Expand Down
2 changes: 1 addition & 1 deletion sphinx/ext/napoleon/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ def _patch_python_domain() -> None:
PyObject.doc_field_types.append(
PyTypedField('keyword', label=_('Keyword Arguments'),
names=('keyword', 'kwarg', 'kwparam'),
typerolename='obj', typenames=('paramtype', 'kwtype'),
typerolename='class', typenames=('paramtype', 'kwtype'),
can_collapse=True))


Expand Down
15 changes: 15 additions & 0 deletions tests/roots/test-ext-napoleon-paramtype/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import os
import sys

sys.path.insert(0, os.path.abspath('.'))
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.napoleon',
'sphinx.ext.intersphinx'
]

# Python inventory is manually created in the test
# in order to avoid creating a real HTTP connection
intersphinx_mapping = {}
intersphinx_cache_limit = 0
intersphinx_disabled_reftypes = []
8 changes: 8 additions & 0 deletions tests/roots/test-ext-napoleon-paramtype/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
test-ext-napoleon
=================

.. automodule:: pkg.bar
:members:

.. automodule:: pkg.foo
:members:
Empty file.
10 changes: 10 additions & 0 deletions tests/roots/test-ext-napoleon-paramtype/pkg/bar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class Bar:
"""The bar."""
def list(self) -> None:
"""A list method."""

@staticmethod
def int() -> float:
"""An int method."""
return 1.0

27 changes: 27 additions & 0 deletions tests/roots/test-ext-napoleon-paramtype/pkg/foo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class Foo:
"""The foo."""
def do(
self,
*,
keyword_paramtype,
keyword_kwtype,
kwarg_paramtype,
kwarg_kwtype,
kwparam_paramtype,
kwparam_kwtype,
):
"""Some method.
:keyword keyword_paramtype: some param
:paramtype keyword_paramtype: list[int]
:keyword keyword_kwtype: some param
:kwtype keyword_kwtype: list[int]
:kwarg kwarg_paramtype: some param
:paramtype kwarg_paramtype: list[int]
:kwarg kwarg_kwtype: some param
:kwtype kwarg_kwtype: list[int]
:kwparam kwparam_paramtype: some param
:paramtype kwparam_paramtype: list[int]
:kwparam kwparam_kwtype: some param
:kwtype kwparam_kwtype: list[int]
"""
43 changes: 43 additions & 0 deletions tests/test_extensions/test_ext_napoleon_docstring.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
"""Tests for :mod:`sphinx.ext.napoleon.docstring` module."""

import re
import zlib
from collections import namedtuple
from inspect import cleandoc
from itertools import product
from textwrap import dedent
from unittest import mock

import pytest
from html5lib import HTMLParser

from sphinx.ext.intersphinx import load_mappings, normalize_intersphinx_mapping
from sphinx.ext.napoleon import Config
from sphinx.ext.napoleon.docstring import (
GoogleDocstring,
Expand Down Expand Up @@ -2659,3 +2663,42 @@ def test_napoleon_and_autodoc_typehints_description_documented_params(app, statu
'\n'
' * ****kwargs** (*int*) -- Extra arguments.\n'
)


@pytest.mark.sphinx('html', testroot='ext-napoleon-paramtype', freshenv=True)
def test_napoleon_keyword_and_paramtype(app, tmp_path):
inv_file = tmp_path / 'objects.inv'
inv_file.write_bytes(b'''\
# Sphinx inventory version 2
# Project: Intersphinx Test
# Version: 42
# The remainder of this file is compressed using zlib.
''' + zlib.compress(b'''\
None py:data 1 none.html -
list py:class 1 list.html -
int py:class 1 int.html -
''')) # NoQA: W291
app.config.intersphinx_mapping = {'python': ('127.0.0.1:5555', str(inv_file))}
normalize_intersphinx_mapping(app, app.config)
load_mappings(app)

app.build(force_all=True)

buffer = (app.outdir / 'index.html').read_bytes()
etree = HTMLParser(namespaceHTMLElements=False).parse(buffer)

for name, typename in product(('keyword', 'kwarg', 'kwparam'), ('paramtype', 'kwtype')):
param = f'{name}_{typename}'
li_ = list(etree.findall(f'.//li/p/strong[.="{param}"]/../..'))
assert len(li_) == 1
li = li_[0]

text = li.text or ''.join(li.itertext())
assert text == f'{param} (list[int]) \u2013 some param'

a_ = list(li.findall('.//a[@class="reference external"]'))

assert len(a_) == 2
for a, uri in zip(a_, ('list.html', 'int.html')):
assert a.attrib['href'] == f'127.0.0.1:5555/{uri}'
assert a.attrib['title'] == '(in Intersphinx Test v42)'

0 comments on commit b587eb2

Please sign in to comment.