Skip to content

Commit 0f5c33c

Browse files
committed
Changes after review
- Also changed the role used to create links from `obj` to `class`.
1 parent 616c4b9 commit 0f5c33c

File tree

2 files changed

+49
-65
lines changed

2 files changed

+49
-65
lines changed

numpydoc/tests/test_xref.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
(2,) :xref_param_type:`~numpy.ndarray`
2828
2929
(...,M,N) array_like
30-
(...,M,N) :term:`numpy:array_like`
30+
(...,:xref_param_type:`M`,:xref_param_type:`N`) :term:`numpy:array_like`
3131
3232
(float, float), optional
3333
(:xref_param_type:`float`, :xref_param_type:`float`), optional
@@ -72,17 +72,26 @@
7272
{:xref_param_type:`False`, :xref_param_type:`True`, 'greedy', 'optimal'}
7373
7474
{{'begin', 1}, {'end', 0}}, {string, int}
75-
{{'begin', 1}, {'end', 0}}, {string, :xref_param_type:`int`}
75+
{{'begin', 1}, {'end', 0}}, {:xref_param_type:`str`, :xref_param_type:`int`}
7676
7777
callable f'(x,*args)
78-
:xref_param_type:`callable` f'(x,*args)
78+
:xref_param_type:`callable` f'(:xref_param_type:`x`,*args)
7979
8080
callable ``fhess(x, *args)``, optional
8181
:xref_param_type:`callable` ``fhess(x, *args)``, optional
8282
8383
spmatrix (format: ``csr``, ``bsr``, ``dia`` or coo``)
8484
:xref_param_type:`spmatrix` (format: ``csr``, ``bsr``, ``dia`` or coo``)
8585
86+
:ref:`strftime <strftime-strptime-behavior>`
87+
:ref:`strftime <strftime-strptime-behavior>`
88+
89+
callable or :ref:`strftime <strftime-strptime-behavior>`
90+
:xref_param_type:`callable` or :ref:`strftime <strftime-strptime-behavior>`
91+
92+
callable or :ref:`strftime behavior <strftime-strptime-behavior>`
93+
:xref_param_type:`callable` or :ref:`strftime behavior <strftime-strptime-behavior>`
94+
8695
list(int)
8796
:xref_param_type:`list`(:xref_param_type:`int`)
8897

numpydoc/xref.py

Lines changed: 37 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,33 @@
11
import re
22
from sphinx import addnodes
33

4+
# When sphinx (including the napoleon extension) parses the parameters
5+
# section of a docstring, it converts the information into field lists.
6+
# Some items in the list are for the parameter type. When the type fields
7+
# are processed, the text is split and some tokens are turned into
8+
# pending_xref nodes. These nodes are responsible for creating links.
9+
#
10+
# numpydoc does not create field lists, so the type information is
11+
# not placed into fields that can be processed to make links. Instead,
12+
# when parsing the type information we identify tokens that are link
13+
# worthy and wrap them around a special role (xref_param_type_role).
14+
# When the role is processed, we create pending_xref nodes which are
15+
# later turned into links.
16+
417

518
QUALIFIED_NAME_RE = re.compile(
6-
# e.g int, numpy.array, ~numpy.array
19+
# e.g int, numpy.array, ~numpy.array, .class_in_current_module
720
r'^'
821
r'[~\.]?'
922
r'[a-zA-Z_]\w*'
1023
r'(?:\.[a-zA-Z_]\w*)*'
1124
r'$'
1225
)
1326

14-
CONTAINER_TYPE_RE = re.compile(
15-
# e.g.
16-
# - list[int]
17-
# - dict(str, int)
18-
# - dict[str, int]'
19-
# - tuple(float, float)
20-
# - dict[tuple(str, str), int]'
21-
r'^'
22-
r'(dict|list|tuple)'
23-
r'[\[\(]'
24-
r'(.+?(?:,\s*)?)+'
25-
r'[\]\)]'
26-
r'$'
27-
)
28-
2927
CONTAINER_SPLIT_RE = re.compile(
3028
# splits dict(str, int) into
3129
# ['dict', '[', 'str', ', ', 'int', ']', '']
32-
r'(\s*[\[\]\(\),]\s*)'
30+
r'(\s*[\[\]\(\)\{\},]\s*)'
3331
)
3432

3533
DOUBLE_QUOTE_SPLIT_RE = re.compile(
@@ -38,27 +36,34 @@
3836
r'(``.+?``)'
3937
)
4038

41-
IGNORE = {'of', ' of ', 'either', 'or', 'with', 'in', 'default'}
39+
ROLE_SPLIT_RE = re.compile(
40+
# splits to preserve ReST roles
41+
r'(:\w+:`.+?(?<!\\)`)'
42+
)
43+
44+
TEXT_SPLIT_RE = re.compile(
45+
# splits on ' or ', ' | ', ', ' and ' '
46+
r'(\s+or\s+|\s+\|\s+|,\s+|\s+)'
47+
)
48+
49+
IGNORE = {'of', 'either', 'or', 'with', 'in', 'default', 'optional'}
4250
CONTAINER_CHARS = set('[](){}')
4351

4452

4553
def make_xref_param_type(param_type, xref_aliases):
4654
"""
4755
Enclose str in a role that creates a cross-reference
48-
4956
The role ``xref_param_type`` *may be* added to any token
5057
that looks like type information and no other. The
5158
function tries to be clever and catch type information
5259
in different disguises.
53-
5460
Parameters
5561
----------
5662
param_type : str
5763
text
5864
xref_aliases : dict
5965
Mapping used to resolve common abbreviations and aliases
6066
to fully qualified names that can be cross-referenced.
61-
6267
Returns
6368
-------
6469
out : str
@@ -72,9 +77,6 @@ def make_xref_param_type(param_type, xref_aliases):
7277
param_type not in IGNORE):
7378
return ':xref_param_type:`%s`' % param_type
7479

75-
# Clever stuff below (except the last return)
76-
# can be removed without affecting the basic functionality.
77-
7880
def _split_and_apply_re(s, pattern):
7981
"""
8082
Split string using the regex pattern,
@@ -94,16 +96,6 @@ def _split_and_apply_re(s, pattern):
9496
return ''.join(results)
9597
return s
9698

97-
def _split_and_apply_str(s, on):
98-
"""
99-
Split string s, at the substring on,
100-
apply main function to the splits,
101-
combine the results
102-
"""
103-
return on.join(
104-
make_xref_param_type(s, xref_aliases)
105-
for s in s.split(on))
106-
10799
# The cases are dealt with in an order the prevents
108100
# conflict.
109101
# Then the strategy is:
@@ -112,37 +104,20 @@ def _split_and_apply_str(s, on):
112104
# - re-apply the function to the other parts
113105
# - join the results with the pattern
114106

115-
# endswith ', optional'
116-
if param_type.endswith(', optional'):
117-
return '%s, optional' % make_xref_param_type(
118-
param_type[:-10],
119-
xref_aliases)
120-
121-
# Any sort of bracket '[](){}'
122-
has_container = any(c in CONTAINER_CHARS for c in param_type)
123-
if has_container:
124-
# of the form 'dict[int, float]'
125-
if CONTAINER_TYPE_RE.match(param_type):
126-
return _split_and_apply_re(param_type, CONTAINER_SPLIT_RE)
127-
else:
128-
# of the form '[int, float]'
129-
for start, end in ['[]', '()', '{}']:
130-
if param_type.startswith(start) and param_type.endswith(end):
131-
return '%s%s%s' % (
132-
start,
133-
make_xref_param_type(param_type[1:-1], xref_aliases),
134-
end)
135-
136-
# May have an unsplittable literal
107+
# Unsplittable literal
137108
if '``' in param_type:
138109
return _split_and_apply_re(param_type, DOUBLE_QUOTE_SPLIT_RE)
139110

140-
# Is splittable
141-
for splitter in [' or ', ', ', ' ']:
142-
if splitter in param_type:
143-
return _split_and_apply_str(param_type, splitter)
111+
# Any roles
112+
if ':`' in param_type:
113+
return _split_and_apply_re(param_type, ROLE_SPLIT_RE)
114+
115+
# Any sort of bracket '[](){}'
116+
if any(c in CONTAINER_CHARS for c in param_type):
117+
return _split_and_apply_re(param_type, CONTAINER_SPLIT_RE)
144118

145-
return param_type
119+
# Common splitter tokens
120+
return _split_and_apply_re(param_type, TEXT_SPLIT_RE)
146121

147122

148123
def xref_param_type_role(role, rawtext, text, lineno, inliner,
@@ -164,6 +139,6 @@ def xref_param_type_role(role, rawtext, text, lineno, inliner,
164139

165140
contnode = addnodes.literal_emphasis(text, text)
166141
node = addnodes.pending_xref('', refdomain='py', refexplicit=False,
167-
reftype='obj', reftarget=target)
142+
reftype='class', reftarget=target)
168143
node += contnode
169144
return [node], []

0 commit comments

Comments
 (0)