27
27
28
28
from docutils .nodes import Text , citation , comment , inline , reference , section
29
29
from sphinx .addnodes import desc_content , pending_xref
30
+ from sphinx .application import Sphinx as SphinxApp
30
31
from sphinx .util import logging
31
32
32
33
from . import __version__
@@ -52,7 +53,7 @@ def _traverse_or_findall(node, condition, **kwargs):
52
53
)
53
54
54
55
55
- def rename_references (app , what , name , obj , options , lines ):
56
+ def rename_references (app : SphinxApp , what , name , obj , options , lines ):
56
57
# decorate reference numbers so that there are no duplicates
57
58
# these are later undecorated in the doctree, in relabel_references
58
59
references = set ()
@@ -114,7 +115,7 @@ def is_docstring_section(node):
114
115
return False
115
116
116
117
117
- def relabel_references (app , doc ):
118
+ def relabel_references (app : SphinxApp , doc ):
118
119
# Change 'hash-ref' to 'ref' in label text
119
120
for citation_node in _traverse_or_findall (doc , citation ):
120
121
if not _is_cite_in_numpydoc_docstring (citation_node ):
@@ -141,7 +142,7 @@ def matching_pending_xref(node):
141
142
ref .replace (ref_text , new_text .copy ())
142
143
143
144
144
- def clean_backrefs (app , doc , docname ):
145
+ def clean_backrefs (app : SphinxApp , doc , docname ):
145
146
# only::latex directive has resulted in citation backrefs without reference
146
147
known_ref_ids = set ()
147
148
for ref in _traverse_or_findall (doc , reference , descend = True ):
@@ -161,7 +162,7 @@ def clean_backrefs(app, doc, docname):
161
162
DEDUPLICATION_TAG = " !! processed by numpydoc !!"
162
163
163
164
164
- def mangle_docstrings (app , what , name , obj , options , lines ):
165
+ def mangle_docstrings (app : SphinxApp , what , name , obj , options , lines ):
165
166
if DEDUPLICATION_TAG in lines :
166
167
return
167
168
show_inherited_class_members = app .config .numpydoc_show_inherited_class_members
@@ -190,6 +191,19 @@ def mangle_docstrings(app, what, name, obj, options, lines):
190
191
title_re = re .compile (pattern , re .IGNORECASE | re .DOTALL )
191
192
lines [:] = title_re .sub ("" , u_NL .join (lines )).split (u_NL )
192
193
else :
194
+ # Test the obj to find the module path, and skip the check if it's path is matched by
195
+ # numpydoc_validation_exclude_files
196
+ if app .config .numpydoc_validation_exclude_files :
197
+ excluder = app .config .numpydoc_validation_files_excluder
198
+ module = getattr (obj , "__module__" , None )
199
+ if module :
200
+ # Perform the exclusion check solely on the module if there's no __path__.
201
+ path = getattr (obj , "__path__" , module )
202
+ exclude_from_validation = excluder .search (path ) if excluder else False
203
+ if exclude_from_validation :
204
+ # Skip validation for this object.
205
+ return
206
+
193
207
try :
194
208
doc = get_doc_object (
195
209
obj , what , u_NL .join (lines ), config = cfg , builder = app .builder
@@ -239,7 +253,7 @@ def mangle_docstrings(app, what, name, obj, options, lines):
239
253
lines += [".." , DEDUPLICATION_TAG ]
240
254
241
255
242
- def mangle_signature (app , what , name , obj , options , sig , retann ):
256
+ def mangle_signature (app : SphinxApp , what , name , obj , options , sig , retann ):
243
257
# Do not try to inspect classes that don't define `__init__`
244
258
if inspect .isclass (obj ) and (
245
259
not hasattr (obj , "__init__" )
@@ -273,7 +287,7 @@ def _clean_text_signature(sig):
273
287
return start_sig + sig + ")"
274
288
275
289
276
- def setup (app , get_doc_object_ = get_doc_object ):
290
+ def setup (app : SphinxApp , get_doc_object_ = get_doc_object ):
277
291
if not hasattr (app , "add_config_value" ):
278
292
return None # probably called by nose, better bail out
279
293
@@ -299,6 +313,7 @@ def setup(app, get_doc_object_=get_doc_object):
299
313
app .add_config_value ("numpydoc_xref_ignore" , set (), True , types = [set , str ])
300
314
app .add_config_value ("numpydoc_validation_checks" , set (), True )
301
315
app .add_config_value ("numpydoc_validation_exclude" , set (), False )
316
+ app .add_config_value ("numpydoc_validation_exclude_files" , set (), False )
302
317
app .add_config_value ("numpydoc_validation_overrides" , dict (), False )
303
318
304
319
# Extra mangling domains
@@ -309,7 +324,7 @@ def setup(app, get_doc_object_=get_doc_object):
309
324
return metadata
310
325
311
326
312
- def update_config (app , config = None ):
327
+ def update_config (app : SphinxApp , config = None ):
313
328
"""Update the configuration with default values."""
314
329
if config is None : # needed for testing and old Sphinx
315
330
config = app .config
@@ -342,6 +357,21 @@ def update_config(app, config=None):
342
357
)
343
358
config .numpydoc_validation_excluder = exclude_expr
344
359
360
+ # Generate the regexp for files to ignore during validation
361
+ if isinstance (config .numpydoc_validation_exclude_files , str ):
362
+ raise ValueError (
363
+ f"numpydoc_validation_exclude_files must be a container of strings, "
364
+ f"e.g. [{ config .numpydoc_validation_exclude_files !r} ]."
365
+ )
366
+
367
+ config .numpydoc_validation_files_excluder = None
368
+ if config .numpydoc_validation_exclude_files :
369
+ exclude_files_expr = re .compile (
370
+ r"|" .join (exp for exp in config .numpydoc_validation_exclude_files )
371
+ )
372
+ config .numpydoc_validation_files_excluder = exclude_files_expr
373
+
374
+ # Generate the regexp for validation overrides
345
375
for check , patterns in config .numpydoc_validation_overrides .items ():
346
376
config .numpydoc_validation_overrides [check ] = re .compile (
347
377
r"|" .join (exp for exp in patterns )
0 commit comments