Skip to content

Commit 7933dd9

Browse files
committed
MAINT: Modernize numpydoc validation
1 parent c9bd928 commit 7933dd9

9 files changed

Lines changed: 81 additions & 56 deletions

File tree

doc/conf.py

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727

2828
import mne
2929
import mne.html_templates._templates
30-
from mne.tests.test_docstring_parameters import error_ignores
3130
from mne.utils import (
3231
linkcode_resolve,
3332
run_subprocess,
@@ -432,42 +431,6 @@
432431
"pooch.HTTPDownloader",
433432
}
434433
numpydoc_validate = True
435-
numpydoc_validation_checks = {"all"} | set(error_ignores)
436-
numpydoc_validation_exclude = { # set of regex
437-
# dict subclasses
438-
r"\.clear",
439-
r"\.get$",
440-
r"\.copy$",
441-
r"\.fromkeys",
442-
r"\.items",
443-
r"\.keys",
444-
r"\.move_to_end",
445-
r"\.pop",
446-
r"\.popitem",
447-
r"\.setdefault",
448-
r"\.update",
449-
r"\.values",
450-
# list subclasses
451-
r"\.append",
452-
r"\.count",
453-
r"\.extend",
454-
r"\.index",
455-
r"\.insert",
456-
r"\.remove",
457-
r"\.sort",
458-
# we currently don't document these properly (probably okay)
459-
r"\.__getitem__",
460-
r"\.__contains__",
461-
r"\.__hash__",
462-
r"\.__mul__",
463-
r"\.__sub__",
464-
r"\.__add__",
465-
r"\.__iter__",
466-
r"\.__div__",
467-
r"\.__neg__",
468-
# copied from sklearn
469-
r"mne\.utils\.deprecated",
470-
}
471434

472435

473436
# -- Sphinx-gallery configuration --------------------------------------------

mne/epochs.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,11 @@ def iter_evoked(self, copy=False):
979979
copy : bool
980980
If False copies of data and measurement info will be omitted
981981
to save time.
982+
983+
Yields
984+
------
985+
evoked : instance of Evoked
986+
The epochs as a sequence of Evoked objects, one per epoch.
982987
"""
983988
self.__iter__()
984989

mne/forward/_make_forward.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ def _to_forward_dict(
947947

948948

949949
@contextmanager
950-
def use_coil_def(fname):
950+
def use_coil_def(fname): # numpydoc ignore=YD01
951951
"""Use a custom coil definition file.
952952
953953
Parameters

mne/tests/test_docstring_parameters.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,20 @@
4848
"mne.viz",
4949
]
5050

51+
pyproject_path = Path(__file__).parents[2] / "pyproject.toml"
52+
if not pyproject_path.is_file():
53+
pytest.skip(f"pyproject.toml not found: {pyproject_path}", allow_module_level=True)
54+
try:
55+
import tomllib
56+
except ModuleNotFoundError:
57+
# TODO VERSION: Remove this when Python 3.11+ is required
58+
pytest.skip("tomllib not available", allow_module_level=True)
59+
60+
pyproject = tomllib.loads(pyproject_path.read_text("utf-8"))
61+
numpydoc_checks = pyproject["tool"]["numpydoc_validation"]["checks"]
62+
assert numpydoc_checks[0] == "all"
63+
error_ignores = set(numpydoc_checks[1:])
64+
5165

5266
def _func_name(func, cls=None):
5367
"""Get the name."""
@@ -73,21 +87,6 @@ def _func_name(func, cls=None):
7387
"mne.channels.tests.test_montage",
7488
"mne.io.curry.tests.test_curry",
7589
]
76-
error_ignores = {
77-
# These we do not live by:
78-
"GL01", # Docstring should start in the line immediately after the quotes
79-
"GL02", # Closing quotes on own line (doesn't work on Python 3.13 anyway)
80-
"EX01",
81-
"EX02", # examples failed (we test them separately)
82-
"ES01", # no extended summary
83-
"SA01", # no see also
84-
"YD01", # no yields section
85-
"SA04", # no description in See Also
86-
"PR04", # Parameter "shape (n_channels" has no type
87-
"RT02", # The first line of the Returns section should contain only the type, unless multiple values are being returned # noqa
88-
# XXX should also verify that | is used rather than , to separate params
89-
# XXX should maybe also restore the parameter-desc-length < 800 char check
90-
}
9190
error_ignores_specific = { # specific instances to skip
9291
("regress_artifact", "SS05"), # "Regress" is actually imperative
9392
}

mne/time_frequency/tfr.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3387,6 +3387,11 @@ def iter_evoked(self, copy=False):
33873387
----------
33883388
copy : bool
33893389
Whether to yield copies of the data and measurement info, or views/pointers.
3390+
3391+
Yields
3392+
------
3393+
epoch : instance of AverageTFR
3394+
The time-frequency data for a single epoch, wrapped in an AverageTFR object.
33903395
"""
33913396
self.__iter__()
33923397
state = self.__getstate__()

mne/utils/docs.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5238,7 +5238,7 @@ def wrapper(func):
52385238
raise ValueError("Cannot copy docstring: docstring was empty.")
52395239
doc = source.__doc__
52405240
if func.__doc__ is not None:
5241-
doc += f"\n{inspect.cleandoc(func.__doc__)}"
5241+
doc += f"\n{inspect.cleandoc(func.__doc__)}\n"
52425242
func.__doc__ = doc
52435243
return func
52445244

@@ -5388,6 +5388,8 @@ def wrapper(func):
53885388
+ "\n".join(doc[first_parameter_end:])
53895389
)
53905390
func.__doc__ = f"{doc}{func_doc}"
5391+
if not func.__doc__.endswith("\n\n"):
5392+
func.__doc__ = func.__doc__ + "\n"
53915393
return func
53925394

53935395
return wrapper

mne/viz/_figure.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,7 @@ def get_browser_backend():
882882

883883

884884
@contextmanager
885-
def use_browser_backend(backend_name):
885+
def use_browser_backend(backend_name): # numpydoc ignore=YD01
886886
"""Create a 2D browser visualization context using the designated backend.
887887
888888
See :func:`mne.viz.set_browser_backend` for more details on the available

mne/viz/backends/renderer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def _get_3d_backend():
202202

203203

204204
@contextmanager
205-
def use_3d_backend(backend_name):
205+
def use_3d_backend(backend_name): # numpydoc ignore=YD01
206206
"""Create a 3d visualization context using the designated backend.
207207
208208
See :func:`mne.viz.set_3d_backend` for more details on the available

pyproject.toml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,54 @@ disable_error_code = [
279279
ignore_errors = false
280280
module = ['mne.annotations', 'mne.epochs', 'mne.evoked', 'mne.io']
281281

282+
[tool.numpydoc_validation]
283+
checks = [
284+
"all", # report on all checks, except the below
285+
"ES01", # no extended summary
286+
"EX01", # no examples
287+
"EX02", # examples failed (we test them separately)
288+
"GL01", # Docstring should start in the line immediately after the quotes
289+
"PR04", # Parameter "shape (n_channels" has no type
290+
"RT02", # The first line of the Returns section should contain only the type, unless multiple values are being returned # noqa
291+
"SA01", # no see also
292+
"SA04", # no description in See Also
293+
]
294+
exclude = [
295+
# dict subclasses
296+
'\.clear',
297+
'\.get$',
298+
'\.copy$',
299+
'\.fromkeys',
300+
'\.items',
301+
'\.keys',
302+
'\.move_to_end',
303+
'\.pop',
304+
'\.popitem',
305+
'\.setdefault',
306+
'\.update',
307+
'\.values',
308+
# list subclasses
309+
'\.append',
310+
'\.count',
311+
'\.extend',
312+
'\.index',
313+
'\.insert',
314+
'\.remove',
315+
'\.sort',
316+
# we currently don't document these properly (probably okay)
317+
'\.__getitem__',
318+
'\.__contains__',
319+
'\.__hash__',
320+
'\.__mul__',
321+
'\.__sub__',
322+
'\.__add__',
323+
'\.__iter__',
324+
'\.__div__',
325+
'\.__neg__',
326+
# copied from sklearn
327+
'mne\.utils\.deprecated',
328+
]
329+
282330
[tool.pytest.ini_options]
283331
# -r f (failed), E (error), s (skipped), x (xfail), X (xpassed), w (warnings)
284332
# don't put in xfail for pytest 8.0+ because then it prints the tracebacks,
@@ -408,6 +456,9 @@ ignore_case = true
408456
spaces_before_inline_comment = 2
409457
trailing_comma_inline_array = true
410458

459+
[tool.tomlsort.overrides."tool.numpydoc_validation.exclude"]
460+
inline_arrays = false
461+
411462
[tool.towncrier]
412463
directory = "doc/changes/dev/"
413464
filename = "doc/changes/dev.rst"

0 commit comments

Comments
 (0)