Skip to content

Commit 8275f4e

Browse files
authored
Merge pull request #295 from rossbar/xref_conf
ENH: Add configuration option for parameter cross-referencing
2 parents 4210060 + f2f1867 commit 8275f4e

File tree

4 files changed

+144
-10
lines changed

4 files changed

+144
-10
lines changed

doc/install.rst

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,26 @@ numpydoc_xref_aliases : dict
7676

7777
This option depends on the ``numpydoc_xref_param_type`` option
7878
being ``True``.
79-
numpydoc_xref_ignore : set
80-
Words not to cross-reference. Most likely, these are common words
79+
numpydoc_xref_ignore : set or ``"all"``
80+
How to handle terms not in ``numpydoc_xref_aliases`` when
81+
``numpydoc_xref_aliases=True``. The value can either be a ``set``
82+
containing terms to ignore, or ``"all"``. In the former case, the set
83+
contains words not to cross-reference. Most likely, these are common words
8184
used in parameter type descriptions that may be confused for
8285
classes of the same name. For example::
8386

8487
numpydoc_xref_ignore = {'type', 'optional', 'default'}
8588

8689
The default is an empty set.
90+
91+
If the ``numpydoc_xref_ignore="all"``, then all unrecognized terms are
92+
ignored, i.e. terms not in ``numpydoc_xref_aliases`` are *not* wrapped in
93+
``:obj:`` roles.
94+
This configuration parameter may be useful if you only want create
95+
cross references for a small number of terms. In this case, including the
96+
desired cross reference mappings in ``numpydoc_xref_aliases`` and setting
97+
``numpydoc_xref_ignore="all"`` is more convenient than explicitly listing
98+
terms to ignore in a set.
8799
numpydoc_edit_link : bool
88100
.. deprecated:: edit your HTML template instead
89101

numpydoc/docscrape_sphinx.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ def _str_returns(self, name='Returns'):
7373
param_type = make_xref(
7474
param_type,
7575
self.xref_aliases,
76-
self.xref_ignore)
76+
self.xref_ignore
77+
)
7778
if param.name:
7879
out += self._str_indent([named_fmt % (param.name.strip(),
7980
param_type)])
@@ -213,7 +214,8 @@ def _str_param_list(self, name, fake_autosummary=False):
213214
param_type = make_xref(
214215
param_type,
215216
self.xref_aliases,
216-
self.xref_ignore)
217+
self.xref_ignore
218+
)
217219
parts.append(param_type)
218220
out += self._str_indent([' : '.join(parts)])
219221

numpydoc/tests/test_xref.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,101 @@
102102
:class:`python:dict`\[:class:`python:tuple`\(:class:`python:str`, :class:`python:str`), :class:`python:int`]
103103
""" # noqa: E501
104104

105+
data_ignore_obj = r"""
106+
(...) array_like, float, optional
107+
(...) :term:`numpy:array_like`, :class:`python:float`, optional
108+
109+
(2,) ndarray
110+
(2,) :obj:`ndarray <numpy.ndarray>`
111+
112+
(...,M,N) array_like
113+
(...,M,N) :term:`numpy:array_like`
114+
115+
(..., M, N) array_like
116+
(..., M, N) :term:`numpy:array_like`
117+
118+
(float, float), optional
119+
(:class:`python:float`, :class:`python:float`), optional
120+
121+
1-D array or sequence
122+
1-D :obj:`array <numpy.ndarray>` or :term:`python:sequence`
123+
124+
array of str or unicode-like
125+
:obj:`array <numpy.ndarray>` of :class:`python:str` or unicode-like
126+
127+
array_like of float
128+
:term:`numpy:array_like` of :class:`python:float`
129+
130+
bool or callable
131+
:ref:`bool <python:bltin-boolean-values>` or :func:`python:callable`
132+
133+
int in [0, 255]
134+
:class:`python:int` in [0, 255]
135+
136+
int or None, optional
137+
:class:`python:int` or :data:`python:None`, optional
138+
139+
list of str or array_like
140+
:class:`python:list` of :class:`python:str` or :term:`numpy:array_like`
141+
142+
sequence of array_like
143+
:term:`python:sequence` of :term:`numpy:array_like`
144+
145+
str or pathlib.Path
146+
:class:`python:str` or pathlib.Path
147+
148+
{'', string}, optional
149+
{'', :class:`python:str`}, optional
150+
151+
{'C', 'F', 'A', or 'K'}, optional
152+
{'C', 'F', 'A', or 'K'}, optional
153+
154+
{'linear', 'lower', 'higher', 'midpoint', 'nearest'}
155+
{'linear', 'lower', 'higher', 'midpoint', 'nearest'}
156+
157+
{False, True, 'greedy', 'optimal'}
158+
{:data:`python:False`, :data:`python:True`, 'greedy', 'optimal'}
159+
160+
{{'begin', 1}, {'end', 0}}, {string, int}
161+
{{'begin', 1}, {'end', 0}}, {:class:`python:str`, :class:`python:int`}
162+
163+
callable f'(x,*args)
164+
:func:`python:callable` f'(x,*args)
165+
166+
callable ``fhess(x, *args)``, optional
167+
:func:`python:callable` ``fhess(x, *args)``, optional
168+
169+
spmatrix (format: ``csr``, ``bsr``, ``dia`` or coo``)
170+
spmatrix (format: ``csr``, ``bsr``, ``dia`` or coo``)
171+
172+
:ref:`strftime <strftime-strptime-behavior>`
173+
:ref:`strftime <strftime-strptime-behavior>`
174+
175+
callable or :ref:`strftime <strftime-strptime-behavior>`
176+
:func:`python:callable` or :ref:`strftime <strftime-strptime-behavior>`
177+
178+
callable or :ref:`strftime behavior <strftime-strptime-behavior>`
179+
:func:`python:callable` or :ref:`strftime behavior <strftime-strptime-behavior>`
180+
181+
list(int)
182+
:class:`python:list`\(:class:`python:int`)
183+
184+
list[int]
185+
:class:`python:list`\[:class:`python:int`]
186+
187+
dict(str, int)
188+
:class:`python:dict`\(:class:`python:str`, :class:`python:int`)
189+
190+
dict[str, int]
191+
:class:`python:dict`\[:class:`python:str`, :class:`python:int`]
192+
193+
tuple(float, float)
194+
:class:`python:tuple`\(:class:`python:float`, :class:`python:float`)
195+
196+
dict[tuple(str, str), int]
197+
:class:`python:dict`\[:class:`python:tuple`\(:class:`python:str`, :class:`python:str`), :class:`python:int`]
198+
""" # noqa: E501
199+
105200
xref_ignore = {'or', 'in', 'of', 'default', 'optional'}
106201

107202

@@ -111,3 +206,14 @@
111206
)
112207
def test_make_xref(param_type, expected_result):
113208
assert make_xref(param_type, xref_aliases, xref_ignore) == expected_result
209+
210+
@pytest.mark.parametrize(
211+
('param_type', 'expected_result'),
212+
[tuple(s.split('\n')) for s in data_ignore_obj.strip().split('\n\n')]
213+
)
214+
def test_make_xref_ignore_unknown(param_type, expected_result):
215+
assert make_xref(param_type, xref_aliases, xref_ignore="all") == expected_result
216+
217+
def test_xref_ignore_is_all():
218+
with pytest.raises(TypeError, match="must be a set or 'all'"):
219+
make_xref("array_like", xref_aliases, xref_ignore="foo")

numpydoc/xref.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,26 +106,41 @@ def make_xref(param_type, xref_aliases, xref_ignore):
106106
xref_aliases : dict
107107
Mapping used to resolve common abbreviations and aliases
108108
to fully qualified names that can be cross-referenced.
109-
xref_ignore : set
110-
Words not to cross-reference.
109+
xref_ignore : set or "all"
110+
A set containing words not to cross-reference. Instead of a set, the
111+
string 'all' can be given to ignore all unrecognized terms.
112+
Unrecognized terms include those that are not in `xref_aliases` and
113+
are not already wrapped in a reST role.
111114
112115
Returns
113116
-------
114117
out : str
115118
Text with fully-qualified names and terms that may be wrapped in a
116119
``:obj:`` role.
117120
"""
121+
ignore_set = xref_ignore
122+
wrap_unknown = True
123+
if isinstance(xref_ignore, str):
124+
if xref_ignore.lower() == "all":
125+
wrap_unknown = False
126+
ignore_set = set()
127+
else:
128+
raise TypeError(
129+
"xref_ignore must be a set or 'all', got {}".format(xref_ignore)
130+
)
131+
118132
if param_type in xref_aliases:
119133
link, title = xref_aliases[param_type], param_type
120134
param_type = link
121135
else:
122136
link = title = param_type
123137

124-
if QUALIFIED_NAME_RE.match(link) and link not in xref_ignore:
138+
if QUALIFIED_NAME_RE.match(link) and link not in ignore_set:
125139
if link != title:
126140
return ':obj:`%s <%s>`' % (title, link)
127-
else:
141+
if wrap_unknown:
128142
return ':obj:`%s`' % link
143+
return link
129144

130145
def _split_and_apply_re(s, pattern):
131146
"""
@@ -141,8 +156,7 @@ def _split_and_apply_re(s, pattern):
141156
if pattern.match(tok):
142157
results.append(tok)
143158
else:
144-
res = make_xref(
145-
tok, xref_aliases, xref_ignore)
159+
res = make_xref(tok, xref_aliases, xref_ignore)
146160
# Opening brackets immediately after a role is
147161
# bad markup. Detect that and add backslash.
148162
# :role:`type`( to :role:`type`\(

0 commit comments

Comments
 (0)