18
18
"""
19
19
20
20
import hashlib
21
+ import importlib
21
22
import inspect
22
23
import itertools
23
24
import pydoc
24
25
import re
26
+ import sys
25
27
from collections .abc import Callable
26
28
from copy import deepcopy
29
+ from pathlib import Path
27
30
28
31
from docutils .nodes import Text , citation , comment , inline , reference , section
29
32
from sphinx .addnodes import desc_content , pending_xref
33
+ from sphinx .application import Sphinx as SphinxApp
30
34
from sphinx .util import logging
31
35
32
36
from . import __version__
@@ -52,7 +56,7 @@ def _traverse_or_findall(node, condition, **kwargs):
52
56
)
53
57
54
58
55
- def rename_references (app , what , name , obj , options , lines ):
59
+ def rename_references (app : SphinxApp , what , name , obj , options , lines ):
56
60
# decorate reference numbers so that there are no duplicates
57
61
# these are later undecorated in the doctree, in relabel_references
58
62
references = set ()
@@ -114,7 +118,7 @@ def is_docstring_section(node):
114
118
return False
115
119
116
120
117
- def relabel_references (app , doc ):
121
+ def relabel_references (app : SphinxApp , doc ):
118
122
# Change 'hash-ref' to 'ref' in label text
119
123
for citation_node in _traverse_or_findall (doc , citation ):
120
124
if not _is_cite_in_numpydoc_docstring (citation_node ):
@@ -141,7 +145,7 @@ def matching_pending_xref(node):
141
145
ref .replace (ref_text , new_text .copy ())
142
146
143
147
144
- def clean_backrefs (app , doc , docname ):
148
+ def clean_backrefs (app : SphinxApp , doc , docname ):
145
149
# only::latex directive has resulted in citation backrefs without reference
146
150
known_ref_ids = set ()
147
151
for ref in _traverse_or_findall (doc , reference , descend = True ):
@@ -161,7 +165,7 @@ def clean_backrefs(app, doc, docname):
161
165
DEDUPLICATION_TAG = " !! processed by numpydoc !!"
162
166
163
167
164
- def mangle_docstrings (app , what , name , obj , options , lines ):
168
+ def mangle_docstrings (app : SphinxApp , what , name , obj , options , lines ):
165
169
if DEDUPLICATION_TAG in lines :
166
170
return
167
171
show_inherited_class_members = app .config .numpydoc_show_inherited_class_members
@@ -190,6 +194,38 @@ def mangle_docstrings(app, what, name, obj, options, lines):
190
194
title_re = re .compile (pattern , re .IGNORECASE | re .DOTALL )
191
195
lines [:] = title_re .sub ("" , u_NL .join (lines )).split (u_NL )
192
196
else :
197
+ # Test the obj to find the module path, and skip the check if it's path is matched by
198
+ # numpydoc_validation_exclude_files
199
+ if (
200
+ app .config .numpydoc_validation_exclude_files
201
+ and app .config .numpydoc_validation_checks
202
+ ):
203
+ excluder = app .config .numpydoc_validation_files_excluder
204
+ module = inspect .getmodule (obj )
205
+ try :
206
+ # Get the module relative path from the name
207
+ if module :
208
+ mod_path = Path (module .__file__ )
209
+ package_rel_path = mod_path .parent .relative_to (
210
+ Path (
211
+ importlib .import_module (
212
+ module .__name__ .split ("." )[0 ]
213
+ ).__file__
214
+ ).parent
215
+ ).as_posix ()
216
+ module_file = mod_path .as_posix ().replace (
217
+ mod_path .parent .as_posix (), ""
218
+ )
219
+ path = package_rel_path + module_file
220
+ else :
221
+ path = None
222
+ except AttributeError as e :
223
+ path = None
224
+
225
+ if path and excluder and excluder .search (path ):
226
+ # Skip validation for this object.
227
+ return
228
+
193
229
try :
194
230
doc = get_doc_object (
195
231
obj , what , u_NL .join (lines ), config = cfg , builder = app .builder
@@ -239,7 +275,7 @@ def mangle_docstrings(app, what, name, obj, options, lines):
239
275
lines += [".." , DEDUPLICATION_TAG ]
240
276
241
277
242
- def mangle_signature (app , what , name , obj , options , sig , retann ):
278
+ def mangle_signature (app : SphinxApp , what , name , obj , options , sig , retann ):
243
279
# Do not try to inspect classes that don't define `__init__`
244
280
if inspect .isclass (obj ) and (
245
281
not hasattr (obj , "__init__" )
@@ -273,7 +309,7 @@ def _clean_text_signature(sig):
273
309
return start_sig + sig + ")"
274
310
275
311
276
- def setup (app , get_doc_object_ = get_doc_object ):
312
+ def setup (app : SphinxApp , get_doc_object_ = get_doc_object ):
277
313
if not hasattr (app , "add_config_value" ):
278
314
return None # probably called by nose, better bail out
279
315
@@ -299,6 +335,7 @@ def setup(app, get_doc_object_=get_doc_object):
299
335
app .add_config_value ("numpydoc_xref_ignore" , set (), True , types = [set , str ])
300
336
app .add_config_value ("numpydoc_validation_checks" , set (), True )
301
337
app .add_config_value ("numpydoc_validation_exclude" , set (), False )
338
+ app .add_config_value ("numpydoc_validation_exclude_files" , set (), False )
302
339
app .add_config_value ("numpydoc_validation_overrides" , dict (), False )
303
340
304
341
# Extra mangling domains
@@ -309,7 +346,7 @@ def setup(app, get_doc_object_=get_doc_object):
309
346
return metadata
310
347
311
348
312
- def update_config (app , config = None ):
349
+ def update_config (app : SphinxApp , config = None ):
313
350
"""Update the configuration with default values."""
314
351
if config is None : # needed for testing and old Sphinx
315
352
config = app .config
@@ -342,6 +379,21 @@ def update_config(app, config=None):
342
379
)
343
380
config .numpydoc_validation_excluder = exclude_expr
344
381
382
+ # Generate the regexp for files to ignore during validation
383
+ if isinstance (config .numpydoc_validation_exclude_files , str ):
384
+ raise ValueError (
385
+ f"numpydoc_validation_exclude_files must be a container of strings, "
386
+ f"e.g. [{ config .numpydoc_validation_exclude_files !r} ]."
387
+ )
388
+
389
+ config .numpydoc_validation_files_excluder = None
390
+ if config .numpydoc_validation_exclude_files :
391
+ exclude_files_expr = re .compile (
392
+ r"|" .join (exp for exp in config .numpydoc_validation_exclude_files )
393
+ )
394
+ config .numpydoc_validation_files_excluder = exclude_files_expr
395
+
396
+ # Generate the regexp for validation overrides
345
397
for check , patterns in config .numpydoc_validation_overrides .items ():
346
398
config .numpydoc_validation_overrides [check ] = re .compile (
347
399
r"|" .join (exp for exp in patterns )
0 commit comments