Skip to content

Commit d82c8a7

Browse files
authored
Merge pull request #9131 from RuRo/feature/glob-nitpick-ignore
Ignore nitpick warnings with regular expressions using `nitpick_ignore_regex`
2 parents d006c66 + afa80df commit d82c8a7

File tree

6 files changed

+112
-1
lines changed

6 files changed

+112
-1
lines changed

doc/usage/configuration.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,20 @@ General configuration
419419

420420
.. versionadded:: 1.1
421421

422+
.. confval:: nitpick_ignore_regex
423+
424+
An extended version of :confval:`nitpick_ignore`, which instead interprets
425+
the ``type`` and ``target`` strings as regular expressions. Note, that the
426+
regular expression must match the whole string (as if the ``^`` and ``$``
427+
markers were inserted).
428+
429+
For example, ``(r'py:.*', r'foo.*bar\.B.*')`` will ignore nitpicky warnings
430+
for all python entities that start with ``'foo'`` and have ``'bar.B'`` in
431+
them, such as ``('py:const', 'foo_package.bar.BAZ_VALUE')`` or
432+
``('py:class', 'food.bar.Barman')``.
433+
434+
.. versionadded:: 4.1
435+
422436
.. confval:: numfig
423437

424438
If true, figures, tables and code-blocks are automatically numbered if they

sphinx/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class Config:
131131
'manpages_url': (None, 'env', []),
132132
'nitpicky': (False, None, []),
133133
'nitpick_ignore': ([], None, []),
134+
'nitpick_ignore_regex': ([], None, []),
134135
'numfig': (False, 'env', []),
135136
'numfig_secnum_depth': (1, 'env', []),
136137
'numfig_format': ({}, 'env', []), # will be initialized in init_numfig_format()

sphinx/transforms/post_transforms/__init__.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
:license: BSD, see LICENSE for details.
99
"""
1010

11+
import re
1112
from typing import Any, Dict, List, Optional, Tuple, Type, cast
1213

1314
from docutils import nodes
@@ -171,14 +172,27 @@ def warn_missing_reference(self, refdoc: str, typ: str, target: str,
171172
warn = node.get('refwarn')
172173
if self.config.nitpicky:
173174
warn = True
175+
dtype = '%s:%s' % (domain.name, typ) if domain else typ
174176
if self.config.nitpick_ignore:
175-
dtype = '%s:%s' % (domain.name, typ) if domain else typ
176177
if (dtype, target) in self.config.nitpick_ignore:
177178
warn = False
178179
# for "std" types also try without domain name
179180
if (not domain or domain.name == 'std') and \
180181
(typ, target) in self.config.nitpick_ignore:
181182
warn = False
183+
if self.config.nitpick_ignore_regex:
184+
def matches_ignore(entry_type: str, entry_target: str) -> bool:
185+
for ignore_type, ignore_target in self.config.nitpick_ignore_regex:
186+
if re.fullmatch(ignore_type, entry_type) and \
187+
re.fullmatch(ignore_target, entry_target):
188+
return True
189+
return False
190+
if matches_ignore(dtype, target):
191+
warn = False
192+
# for "std" types also try without domain name
193+
if (not domain or domain.name == 'std') and \
194+
matches_ignore(typ, target):
195+
warn = False
182196
if not warn:
183197
return
184198

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nitpicky = True
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
test-nitpicky-warnings
2+
======================
3+
4+
:py:const:`prefix.anything.postfix`
5+
:py:class:`prefix.anything`
6+
:py:class:`anything.postfix`
7+
:js:class:`prefix.anything.postfix`

tests/test_config.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,77 @@ def test_check_enum_for_list_failed(logger):
311311
config.init_values()
312312
check_confval_types(None, config)
313313
assert logger.warning.called
314+
315+
316+
nitpick_warnings = [
317+
"WARNING: py:const reference target not found: prefix.anything.postfix",
318+
"WARNING: py:class reference target not found: prefix.anything",
319+
"WARNING: py:class reference target not found: anything.postfix",
320+
"WARNING: js:class reference target not found: prefix.anything.postfix",
321+
]
322+
323+
324+
@pytest.mark.sphinx(testroot='nitpicky-warnings')
325+
def test_nitpick_base(app, status, warning):
326+
app.builder.build_all()
327+
328+
warning = warning.getvalue().strip().split('\n')
329+
assert len(warning) == len(nitpick_warnings)
330+
for actual, expected in zip(warning, nitpick_warnings):
331+
assert expected in actual
332+
333+
334+
@pytest.mark.sphinx(testroot='nitpicky-warnings', confoverrides={
335+
'nitpick_ignore': [
336+
('py:const', 'prefix.anything.postfix'),
337+
('py:class', 'prefix.anything'),
338+
('py:class', 'anything.postfix'),
339+
('js:class', 'prefix.anything.postfix'),
340+
],
341+
})
342+
def test_nitpick_ignore(app, status, warning):
343+
app.builder.build_all()
344+
assert not len(warning.getvalue().strip())
345+
346+
347+
@pytest.mark.sphinx(testroot='nitpicky-warnings', confoverrides={
348+
'nitpick_ignore_regex': [
349+
(r'py:.*', r'.*postfix'),
350+
(r'.*:class', r'prefix.*'),
351+
]
352+
})
353+
def test_nitpick_ignore_regex1(app, status, warning):
354+
app.builder.build_all()
355+
assert not len(warning.getvalue().strip())
356+
357+
358+
@pytest.mark.sphinx(testroot='nitpicky-warnings', confoverrides={
359+
'nitpick_ignore_regex': [
360+
(r'py:.*', r'prefix.*'),
361+
(r'.*:class', r'.*postfix'),
362+
]
363+
})
364+
def test_nitpick_ignore_regex2(app, status, warning):
365+
app.builder.build_all()
366+
assert not len(warning.getvalue().strip())
367+
368+
369+
@pytest.mark.sphinx(testroot='nitpicky-warnings', confoverrides={
370+
'nitpick_ignore_regex': [
371+
# None of these should match
372+
(r'py:', r'.*'),
373+
(r':class', r'.*'),
374+
(r'', r'.*'),
375+
(r'.*', r'anything'),
376+
(r'.*', r'prefix'),
377+
(r'.*', r'postfix'),
378+
(r'.*', r''),
379+
]
380+
})
381+
def test_nitpick_ignore_regex_fullmatch(app, status, warning):
382+
app.builder.build_all()
383+
384+
warning = warning.getvalue().strip().split('\n')
385+
assert len(warning) == len(nitpick_warnings)
386+
for actual, expected in zip(warning, nitpick_warnings):
387+
assert expected in actual

0 commit comments

Comments
 (0)