From fbdf433876c02799499bd8dff46c3d4afd2f429d Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Tue, 11 Aug 2020 21:48:21 -0700 Subject: [PATCH 01/20] WIP: Move get_doc_obj to docscrape --- numpydoc/docscrape.py | 27 +++++++++++++++++++++++++++ numpydoc/docscrape_sphinx.py | 7 +++---- numpydoc/validate.py | 5 +++-- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index 15b4e10d..4363ec9c 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -581,6 +581,12 @@ def __str__(self): return out +class ObjDoc(NumpyDocString): + def __init__(self, obj, doc=None, config={}): + self._f = obj + NumpyDocString.__init__(self, doc, config=config) + + class ClassDoc(NumpyDocString): extra_public_methods = ['__call__'] @@ -663,3 +669,24 @@ def _is_show_member(self, name): if name not in self._cls.__dict__: return False # class member is inherited, we do not show it return True + + +def get_doc_object(obj, what=None, doc=None, config={}): + if what is None: + if inspect.isclass(obj): + what = 'class' + elif inspect.ismodule(obj): + what = 'module' + elif isinstance(obj, Callable): + what = 'function' + else: + what = 'object' + + if what == 'class': + return ClassDoc(obj, func_doc=FunctionDoc, doc=doc, config=config) + elif what in ('function', 'method'): + return FunctionDoc(obj, doc=doc, config=config) + else: + if doc is None: + doc = pydoc.getdoc(obj) + return ObjDoc(obj, doc, config=config) diff --git a/numpydoc/docscrape_sphinx.py b/numpydoc/docscrape_sphinx.py index 38a49ba2..8e11b72c 100644 --- a/numpydoc/docscrape_sphinx.py +++ b/numpydoc/docscrape_sphinx.py @@ -10,7 +10,7 @@ import sphinx from sphinx.jinja2glue import BuiltinTemplateLoader -from .docscrape import NumpyDocString, FunctionDoc, ClassDoc +from .docscrape import NumpyDocString, FunctionDoc, ClassDoc, ObjDoc from .xref import make_xref @@ -411,11 +411,10 @@ def __init__(self, obj, doc=None, func_doc=None, config={}): ClassDoc.__init__(self, obj, doc=doc, func_doc=None, config=config) -class SphinxObjDoc(SphinxDocString): +class SphinxObjDoc(SphinxDocString, ObjDoc): def __init__(self, obj, doc=None, config={}): - self._f = obj self.load_config(config) - SphinxDocString.__init__(self, doc, config=config) + ObjDoc.__init__(self, obj, doc=doc, config=config) def get_doc_object(obj, what=None, doc=None, config={}, builder=None): diff --git a/numpydoc/validate.py b/numpydoc/validate.py index be50885b..822236a4 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -12,7 +12,7 @@ import pydoc import re import textwrap -from .docscrape import NumpyDocString +from .docscrape import get_doc_object DIRECTIVES = ["versionadded", "versionchanged", "deprecated"] @@ -130,7 +130,8 @@ def __init__(self, name): self.code_obj = inspect.unwrap(obj) self.raw_doc = obj.__doc__ or "" self.clean_doc = pydoc.getdoc(obj) - self.doc = NumpyDocString(self.clean_doc) +# self.doc = NumpyDocString(self.clean_doc) + self.doc = get_doc_object(obj) @staticmethod def _load_obj(name): From fd25d8fab703a213314e88796dd88b24c939711b Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Tue, 11 Aug 2020 21:49:12 -0700 Subject: [PATCH 02/20] WIP: mv _obj property to NumpyDocString --- numpydoc/docscrape.py | 10 +++++++++- numpydoc/docscrape_sphinx.py | 8 -------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index 4363ec9c..395801e4 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -411,8 +411,16 @@ def _parse(self): else: self[section] = content + @property + def _obj(self): + if hasattr(self, '_cls'): + return self._cls + elif hasattr(self, '_f'): + return self._f + return None + def _error_location(self, msg, error=True): - if hasattr(self, '_obj') and self._obj is not None: + if self._obj is not None: # we know where the docs came from: try: filename = inspect.getsourcefile(self._obj) diff --git a/numpydoc/docscrape_sphinx.py b/numpydoc/docscrape_sphinx.py index 8e11b72c..7ac55489 100644 --- a/numpydoc/docscrape_sphinx.py +++ b/numpydoc/docscrape_sphinx.py @@ -229,14 +229,6 @@ def _str_param_list(self, name, fake_autosummary=False): return out - @property - def _obj(self): - if hasattr(self, '_cls'): - return self._cls - elif hasattr(self, '_f'): - return self._f - return None - def _str_member_list(self, name): """ Generate a member listing, autosummary:: table where possible, From b99e782efed240cbaea5050a5fc39a127f2ef6dd Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Tue, 11 Aug 2020 21:56:40 -0700 Subject: [PATCH 03/20] Proof-of-concept: Docstring attrs covered by refactor. Running the test suite on this patch demonstrates that refactoring the boundary between NumpyDocString and SphinxDocString provides the necessary info to (potentially) do away with the validate.Docstring class. --- numpydoc/validate.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/numpydoc/validate.py b/numpydoc/validate.py index 822236a4..efa83fd5 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -126,12 +126,12 @@ class Docstring: def __init__(self, name): self.name = name obj = self._load_obj(name) - self.obj = obj - self.code_obj = inspect.unwrap(obj) - self.raw_doc = obj.__doc__ or "" - self.clean_doc = pydoc.getdoc(obj) -# self.doc = NumpyDocString(self.clean_doc) self.doc = get_doc_object(obj) + self.obj = self.doc._obj + self.code_obj = inspect.unwrap(self.obj) + self.raw_doc = self.obj.__doc__ or "" + self.clean_doc = pydoc.getdoc(self.obj) +# self.doc = NumpyDocString(self.clean_doc) @staticmethod def _load_obj(name): From 94f41216bf720b8ea6b888c5acf0a226bb495e4e Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Wed, 12 Aug 2020 15:52:04 -0700 Subject: [PATCH 04/20] NOTE TO SELF: get_doc_object in docscrape_sphinx --- numpydoc/docscrape_sphinx.py | 1 + 1 file changed, 1 insertion(+) diff --git a/numpydoc/docscrape_sphinx.py b/numpydoc/docscrape_sphinx.py index 7ac55489..b109fe7b 100644 --- a/numpydoc/docscrape_sphinx.py +++ b/numpydoc/docscrape_sphinx.py @@ -409,6 +409,7 @@ def __init__(self, obj, doc=None, config={}): ObjDoc.__init__(self, obj, doc=doc, config=config) +# TODO: refactor to use docscrape.get_doc_object def get_doc_object(obj, what=None, doc=None, config={}, builder=None): if what is None: if inspect.isclass(obj): From eac0a720edc286843ccc736005260989e678d8e2 Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Wed, 12 Aug 2020 17:27:46 -0700 Subject: [PATCH 05/20] Docstring -> Validator. --- numpydoc/__main__.py | 6 +++--- numpydoc/tests/test_validate.py | 6 +++--- numpydoc/validate.py | 18 ++++++++++-------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/numpydoc/__main__.py b/numpydoc/__main__.py index 534e9e0b..f342cc3a 100644 --- a/numpydoc/__main__.py +++ b/numpydoc/__main__.py @@ -6,13 +6,13 @@ import ast from .docscrape_sphinx import get_doc_object -from .validate import validate, Docstring +from .validate import validate, Validator def render_object(import_path, config=None): """Test numpydoc docstring generation for a given object""" - # TODO: Move Docstring._load_obj to a better place than validate - print(get_doc_object(Docstring(import_path).obj, + # TODO: Move Validator._load_obj to a better place than validate + print(get_doc_object(Validator._load_obj(import_path), config=dict(config or []))) return 0 diff --git a/numpydoc/tests/test_validate.py b/numpydoc/tests/test_validate.py index b8f4d873..704a25ef 100644 --- a/numpydoc/tests/test_validate.py +++ b/numpydoc/tests/test_validate.py @@ -1312,12 +1312,12 @@ def test_bad_docstrings(self, capsys, klass, func, msgs): assert msg in " ".join(err[1] for err in result["errors"]) -class TestDocstringClass: +class TestValidatorClass: @pytest.mark.parametrize("invalid_name", ["unknown_mod", "unknown_mod.MyClass"]) def test_raises_for_invalid_module_name(self, invalid_name): msg = 'No module can be imported from "{}"'.format(invalid_name) with pytest.raises(ImportError, match=msg): - numpydoc.validate.Docstring(invalid_name) + numpydoc.validate.Validator._load_obj(invalid_name) @pytest.mark.parametrize( "invalid_name", ["datetime.BadClassName", "datetime.bad_method_name"] @@ -1327,4 +1327,4 @@ def test_raises_for_invalid_attribute_name(self, invalid_name): obj_name, invalid_attr_name = name_components[-2], name_components[-1] msg = "'{}' has no attribute '{}'".format(obj_name, invalid_attr_name) with pytest.raises(AttributeError, match=msg): - numpydoc.validate.Docstring(invalid_name) + numpydoc.validate.Validator._load_obj(invalid_name) diff --git a/numpydoc/validate.py b/numpydoc/validate.py index efa83fd5..bd7fe3d5 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -121,17 +121,18 @@ def error(code, **kwargs): return (code, ERROR_MSGS[code].format(**kwargs)) -class Docstring: +class Validator: # TODO Can all this class be merged into NumpyDocString? - def __init__(self, name): - self.name = name - obj = self._load_obj(name) - self.doc = get_doc_object(obj) + def __init__(self, doc_object): + self.doc = doc_object self.obj = self.doc._obj self.code_obj = inspect.unwrap(self.obj) self.raw_doc = self.obj.__doc__ or "" self.clean_doc = pydoc.getdoc(self.obj) -# self.doc = NumpyDocString(self.clean_doc) + + @property + def name(self): + return '.'.join([self.obj.__module__, self.obj.__name__]) @staticmethod def _load_obj(name): @@ -150,7 +151,7 @@ def _load_obj(name): Examples -------- - >>> Docstring._load_obj('datetime.datetime') + >>> Validator._load_obj('datetime.datetime') """ for maxsplit in range(0, name.count(".") + 1): @@ -469,7 +470,8 @@ def validate(obj_name): they are validated, are not documented more than in the source code of this function. """ - doc = Docstring(obj_name) + obj = Validator._load_obj(obj_name) + doc = Validator(get_doc_object(obj)) errs = [] if not doc.raw_doc: From 27c013f23bc934fcbb43e72e3726590cfc120b26 Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Tue, 18 Aug 2020 13:24:50 -0700 Subject: [PATCH 06/20] Activate validation during sphinx-build. Add a conf option to turn on/off. TODO: test --- doc/conf.py | 1 + numpydoc/numpydoc.py | 9 +++++++++ numpydoc/tests/test_numpydoc.py | 1 + numpydoc/tests/tinybuild/conf.py | 1 + numpydoc/validate.py | 6 ++++-- 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index e9197631..dffea572 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -84,6 +84,7 @@ version = re.sub(r'(\.dev\d+).*?$', r'\1', version) numpydoc_xref_param_type = True numpydoc_xref_ignore = {'optional', 'type_without_description', 'BadException'} +numpydoc_validate = True # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 93cd975d..4ebecda9 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -34,6 +34,7 @@ raise RuntimeError("Sphinx 1.6.5 or newer is required") from .docscrape_sphinx import get_doc_object +from .validate import validate from .xref import DEFAULT_LINKS from . import __version__ @@ -173,6 +174,13 @@ def mangle_docstrings(app, what, name, obj, options, lines): logger.error('[numpydoc] While processing docstring for %r', name) raise + # TODO: validation only applies to non-module docstrings? + if app.config.numpydoc_validate: + errors = validate(doc)["errors"] + for err in errors: + logger.warn(err) + + if (app.config.numpydoc_edit_link and hasattr(obj, '__name__') and obj.__name__): if hasattr(obj, '__module__'): @@ -254,6 +262,7 @@ def setup(app, get_doc_object_=get_doc_object): app.add_config_value('numpydoc_xref_param_type', False, True) app.add_config_value('numpydoc_xref_aliases', dict(), True) app.add_config_value('numpydoc_xref_ignore', set(), True) + app.add_config_value('numpydoc_validate', False, True) # Extra mangling domains app.add_domain(NumpyPythonDomain) diff --git a/numpydoc/tests/test_numpydoc.py b/numpydoc/tests/test_numpydoc.py index 77e75400..1d87172e 100644 --- a/numpydoc/tests/test_numpydoc.py +++ b/numpydoc/tests/test_numpydoc.py @@ -19,6 +19,7 @@ class MockConfig(): numpydoc_edit_link = False numpydoc_citation_re = '[a-z0-9_.-]+' numpydoc_attributes_as_param_list = True + numpydoc_validate = False class MockBuilder(): diff --git a/numpydoc/tests/tinybuild/conf.py b/numpydoc/tests/tinybuild/conf.py index 8b16cdd2..7ca7b056 100644 --- a/numpydoc/tests/tinybuild/conf.py +++ b/numpydoc/tests/tinybuild/conf.py @@ -22,3 +22,4 @@ highlight_language = 'python3' numpydoc_class_members_toctree = False numpydoc_xref_param_type = True +numpydoc_validate = True diff --git a/numpydoc/validate.py b/numpydoc/validate.py index bd7fe3d5..a3d29ed1 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -470,8 +470,10 @@ def validate(obj_name): they are validated, are not documented more than in the source code of this function. """ - obj = Validator._load_obj(obj_name) - doc = Validator(get_doc_object(obj)) + if isinstance(obj_name, str): + doc = Validator(get_doc_object(Validator._load_obj(obj_name))) + else: + doc = Validator(obj_name) errs = [] if not doc.raw_doc: From d1050372c0ecba049e45bd1dbee94bc0841a49cc Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Tue, 18 Aug 2020 14:31:33 -0700 Subject: [PATCH 07/20] Replace logger.warn with warning. logger.warn is apparently deprecated --- numpydoc/numpydoc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 4ebecda9..1f0d00d0 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -178,7 +178,7 @@ def mangle_docstrings(app, what, name, obj, options, lines): if app.config.numpydoc_validate: errors = validate(doc)["errors"] for err in errors: - logger.warn(err) + logger.warning(err) if (app.config.numpydoc_edit_link and hasattr(obj, '__name__') and From 22c56f3f6c511e4003d1dc0a735dc598a06d8a7f Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Tue, 3 Nov 2020 11:17:03 -0800 Subject: [PATCH 08/20] DOC: Add numpydoc_validate to conf docs. --- doc/install.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/install.rst b/doc/install.rst index 6139efea..48c9e38b 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -96,6 +96,9 @@ numpydoc_xref_ignore : set or ``"all"`` desired cross reference mappings in ``numpydoc_xref_aliases`` and setting ``numpydoc_xref_ignore="all"`` is more convenient than explicitly listing terms to ignore in a set. +numpydoc_validate : bool + Whether or not to run docstring validation during the sphinx-build process. + Default is ``False``. numpydoc_edit_link : bool .. deprecated:: 0.7.0 From 1472c6fbc7b8f47238342c20cab2a8d16ee8f04c Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Tue, 3 Nov 2020 12:39:03 -0800 Subject: [PATCH 09/20] Add mechanism for validation check selection. Adds a config option with a set to allow users to select which validation checks are used. Default is an empty set, which means none of the validation checks raise warnings during the build process. Add documentation for new option and activate in the doc build. --- doc/conf.py | 4 ++++ doc/install.rst | 5 +++++ doc/validation.rst | 16 ++++++++++++++++ numpydoc/numpydoc.py | 8 +++++++- 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index dffea572..054e0f18 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -84,7 +84,11 @@ version = re.sub(r'(\.dev\d+).*?$', r'\1', version) numpydoc_xref_param_type = True numpydoc_xref_ignore = {'optional', 'type_without_description', 'BadException'} +# Run docstring validation as part of build process numpydoc_validate = True +# Report warnings from all build-in validation checks +from numpydoc.validate import ERROR_MSGS +numpydoc_validation_checks = set(ERROR_MSGS.keys()) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/install.rst b/doc/install.rst index 48c9e38b..d652c362 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -99,6 +99,11 @@ numpydoc_xref_ignore : set or ``"all"`` numpydoc_validate : bool Whether or not to run docstring validation during the sphinx-build process. Default is ``False``. +numpydoc_validation_checks : set + The set of validation checks to report during the sphinx build process. + Only has an effect when ``numpydoc_validate = True``. + By default, report warnings from all the validation checks provided by the + :doc:`validation` module. numpydoc_edit_link : bool .. deprecated:: 0.7.0 diff --git a/doc/validation.rst b/doc/validation.rst index 3672d839..30b436ea 100644 --- a/doc/validation.rst +++ b/doc/validation.rst @@ -15,3 +15,19 @@ For an exhaustive validation of the formatting of the docstring, use the ``--validate`` parameter. This will report the errors detected, such as incorrect capitalization, wrong order of the sections, and many other issues. + +Built-in Validation Checks +-------------------------- + +The `~numpydoc.validation` module provides a mapping with all of the checks +that are run as part of the validation procedure. +The mapping is of the form: ``error_code : `` where ``error_code`` +provides a shorthand for the check being run, and ```` provides +a more detailed message. For example:: + + "EX01" : "No examples section found" + +The full mapping of validation checks is given below. + +.. literalinclude:: ../numpydoc/validate.py + :lines: 36-90 diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 1f0d00d0..4623188c 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -176,9 +176,14 @@ def mangle_docstrings(app, what, name, obj, options, lines): # TODO: validation only applies to non-module docstrings? if app.config.numpydoc_validate: + # TODO: Currently, all validation checks are run and only those + # selected via config are reported. It would be more efficient to + # only run the selected checks. errors = validate(doc)["errors"] for err in errors: - logger.warning(err) + # err[0] = error code + if err[0] in app.config.numpydoc_validation_checks: + logger.warning(err) if (app.config.numpydoc_edit_link and hasattr(obj, '__name__') and @@ -263,6 +268,7 @@ def setup(app, get_doc_object_=get_doc_object): app.add_config_value('numpydoc_xref_aliases', dict(), True) app.add_config_value('numpydoc_xref_ignore', set(), True) app.add_config_value('numpydoc_validate', False, True) + app.add_config_value('numpydoc_validation_checks', set(), True) # Extra mangling domains app.add_domain(NumpyPythonDomain) From a1a7074b5775d81901358a3302b50071c336bc35 Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Tue, 3 Nov 2020 13:21:10 -0800 Subject: [PATCH 10/20] TST: modify how MockApp sets builder app. --- numpydoc/tests/test_numpydoc.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/numpydoc/tests/test_numpydoc.py b/numpydoc/tests/test_numpydoc.py index 1d87172e..068450af 100644 --- a/numpydoc/tests/test_numpydoc.py +++ b/numpydoc/tests/test_numpydoc.py @@ -31,9 +31,8 @@ class MockApp(): builder = MockBuilder() translator = None - -app = MockApp() -app.builder.app = app + def __init__(self): + self.builder.app = self def test_mangle_docstrings(): From 39f2f22c8df6a64359264432deac6a0d4964de9b Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Tue, 3 Nov 2020 16:05:58 -0800 Subject: [PATCH 11/20] TST: Add test of validation warnings. --- numpydoc/tests/test_numpydoc.py | 59 +++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/numpydoc/tests/test_numpydoc.py b/numpydoc/tests/test_numpydoc.py index 068450af..9b50d0f1 100644 --- a/numpydoc/tests/test_numpydoc.py +++ b/numpydoc/tests/test_numpydoc.py @@ -1,8 +1,11 @@ # -*- encoding:utf-8 -*- +import pytest +from io import StringIO from copy import deepcopy from numpydoc.numpydoc import mangle_docstrings, _clean_text_signature from numpydoc.xref import DEFAULT_LINKS from sphinx.ext.autodoc import ALL +from sphinx.util import logging class MockConfig(): @@ -33,6 +36,10 @@ class MockApp(): def __init__(self): self.builder.app = self + # Attrs required for logging + self.verbosity = 2 + self._warncount = 0 + self.warningiserror = False def test_mangle_docstrings(): @@ -92,6 +99,58 @@ def test_clean_text_signature(): assert _clean_text_signature('func($self, *args)') == 'func(*args)' +@pytest.fixture +def f(): + def _function_without_seealso_and_examples(): + """ + A function whose docstring has no examples or see also section. + + Expect SA01 and EX01 errors if validation enabled. + """ + pass + return _function_without_seealso_and_examples + + +@pytest.mark.parametrize( + ( + 'numpydoc_validate', + 'numpydoc_validation_checks', + 'expected_warn', + 'non_warnings', + ), + ( + # Validation configured off - expect no warnings + (False, set(['SA01', 'EX01']), [], []), + # Validation on with expected warnings + (True, set(['SA01', 'EX01']), ('SA01', 'EX01'), []), + # Validation on with only one activated check + (True, set(['SA01']), ('SA01',), ('EX01',)), + ), +) +def test_mangle_docstring_validation_warnings( + f, + numpydoc_validate, + numpydoc_validation_checks, + expected_warn, + non_warnings, +): + app = MockApp() + # Set up config for test + app.config.numpydoc_validate = numpydoc_validate + app.config.numpydoc_validation_checks = numpydoc_validation_checks + # Set up logging + status, warning = StringIO(), StringIO() + logging.setup(app, status, warning) + # Run mangle docstrings with the above configuration + mangle_docstrings(app, 'function', 'f', f, None, f.__doc__.split('\n')) + # Assert that all (and only) expected warnings are logged + warnings = warning.getvalue() + for w in expected_warn: + assert w in warnings + for w in non_warnings: + assert w not in warnings + + if __name__ == "__main__": import pytest pytest.main() From 1b6b424ce52e2b380abc7351109c24929039213c Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Fri, 29 Jan 2021 10:26:41 -0800 Subject: [PATCH 12/20] Specify some sensible validation defaults. --- doc/conf.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 054e0f18..5329938f 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -86,9 +86,18 @@ numpydoc_xref_ignore = {'optional', 'type_without_description', 'BadException'} # Run docstring validation as part of build process numpydoc_validate = True -# Report warnings from all build-in validation checks -from numpydoc.validate import ERROR_MSGS -numpydoc_validation_checks = set(ERROR_MSGS.keys()) +numpydoc_validation_checks = { + "GL06", # Unknown section name + "GL07", # Sections in wrong order + "GL08", # Object missing docstring + "PR01", # Missing parameters + "PR02", # Unknown parameters + "PR03", # Incorrect parameter ordering + "PR10", # Missing colon between parameter name and type + "RT01", # No returns section + "SA01", # Missing See Also section + "EX01", # Missing Examples section +} # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From 0cc6277d61eaffbdbd0f3753c4ac386ce69408f1 Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Fri, 29 Jan 2021 17:16:31 -0800 Subject: [PATCH 13/20] Add docstring name to validation warnings. --- numpydoc/numpydoc.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 4623188c..4424075b 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -180,10 +180,15 @@ def mangle_docstrings(app, what, name, obj, options, lines): # selected via config are reported. It would be more efficient to # only run the selected checks. errors = validate(doc)["errors"] - for err in errors: - # err[0] = error code - if err[0] in app.config.numpydoc_validation_checks: - logger.warning(err) + if {err[0] for err in errors} & app.config.numpydoc_validation_checks: + msg = ( + f"[numpydoc] Validation warnings while processing " + f"docstring for {name!r}:\n" + ) + for err in errors: + if err[0] in app.config.numpydoc_validation_checks: + msg += f" {err[0]}: {err[1]}\n" + logger.warning(msg) if (app.config.numpydoc_edit_link and hasattr(obj, '__name__') and From fd2122a289415e0e39ae29e366bedd38d8bdeabd Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Mon, 1 Feb 2021 10:54:14 -0800 Subject: [PATCH 14/20] Add all keyword to validation_check configuration. More flexibility in configuring which validation checks to run during sphinx build. If 'all' is present, treat the rest of the set as a blocklist, else an allowlist. --- doc/conf.py | 13 +------------ doc/install.rst | 21 +++++++++++++++++++-- doc/validation.rst | 2 ++ numpydoc/numpydoc.py | 8 +++++++- 4 files changed, 29 insertions(+), 15 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 5329938f..5c9062a2 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -86,18 +86,7 @@ numpydoc_xref_ignore = {'optional', 'type_without_description', 'BadException'} # Run docstring validation as part of build process numpydoc_validate = True -numpydoc_validation_checks = { - "GL06", # Unknown section name - "GL07", # Sections in wrong order - "GL08", # Object missing docstring - "PR01", # Missing parameters - "PR02", # Unknown parameters - "PR03", # Incorrect parameter ordering - "PR10", # Missing colon between parameter name and type - "RT01", # No returns section - "SA01", # Missing See Also section - "EX01", # Missing Examples section -} +numpydoc_validation_checks = {"all", "GL01", "SA04", "RT03"} # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/install.rst b/doc/install.rst index d652c362..f39e7935 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -102,8 +102,25 @@ numpydoc_validate : bool numpydoc_validation_checks : set The set of validation checks to report during the sphinx build process. Only has an effect when ``numpydoc_validate = True``. - By default, report warnings from all the validation checks provided by the - :doc:`validation` module. + If ``"all"`` is in the set, then the results of all of the + :ref:`built-in validation checks ` are reported. + If the set includes ``"all"`` and additional error codes, then all + validation checks *except* the listed error codes will be run. + If the set contains *only* individual error codes, then only those checks + will be run. + For example:: + + # Report warnings for all validation checks + numpydoc_validation_checks = {"all"} + + # Report warnings for all checks *except* for GL01, GL02, and GL05 + numpydoc_validation_checks = {"all", "GL01", "GL02", "GL05"} + + # Only report warnings for the SA01 and EX01 checks + numpydoc_validation_checks = {"SA01", "EX01"} + + The default is an empty set, thus no warnings from docstring validation + are reported. numpydoc_edit_link : bool .. deprecated:: 0.7.0 diff --git a/doc/validation.rst b/doc/validation.rst index 30b436ea..6c75e57d 100644 --- a/doc/validation.rst +++ b/doc/validation.rst @@ -16,6 +16,8 @@ For an exhaustive validation of the formatting of the docstring, use the incorrect capitalization, wrong order of the sections, and many other issues. +.. _validation_checks: + Built-in Validation Checks -------------------------- diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 4424075b..fe7a517a 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -34,7 +34,7 @@ raise RuntimeError("Sphinx 1.6.5 or newer is required") from .docscrape_sphinx import get_doc_object -from .validate import validate +from .validate import validate, ERROR_MSGS from .xref import DEFAULT_LINKS from . import __version__ @@ -298,6 +298,12 @@ def update_config(app, config=None): numpydoc_xref_aliases_complete[key] = value config.numpydoc_xref_aliases_complete = numpydoc_xref_aliases_complete + # Processing to determine whether numpydoc_validation_checks is treated + # as a blocklist or allowlist + if "all" in config.numpydoc_validation_checks: + block = deepcopy(config.numpydoc_validation_checks) + config.numpydoc_validation_checks = set(ERROR_MSGS.keys()) - block + # ------------------------------------------------------------------------------ # Docstring-mangling domains From fd9b0786a43bd351e247f880f478eb7e6decd1e3 Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Mon, 1 Feb 2021 11:29:39 -0800 Subject: [PATCH 15/20] Fix failing test. --- numpydoc/tests/test_docscrape.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index 080e8cec..13f99412 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -1497,6 +1497,8 @@ class Config(): def __init__(self, a, b): self.numpydoc_xref_aliases = a self.numpydoc_xref_aliases_complete = b + # numpydoc.update_config fails if this config option not present + self.numpydoc_validation_checks = set() xref_aliases_complete = deepcopy(DEFAULT_LINKS) for key in xref_aliases: From df6c15cc6b34a7c979c876072a6f61c043eb50c5 Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Mon, 1 Feb 2021 11:52:07 -0800 Subject: [PATCH 16/20] Make validation error mapping easier to read. --- doc/validation.rst | 2 +- numpydoc/validate.py | 36 ++++++++++++++++++------------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/doc/validation.rst b/doc/validation.rst index 6c75e57d..e1b2ee03 100644 --- a/doc/validation.rst +++ b/doc/validation.rst @@ -21,7 +21,7 @@ issues. Built-in Validation Checks -------------------------- -The `~numpydoc.validation` module provides a mapping with all of the checks +The ``numpydoc.validation`` module provides a mapping with all of the checks that are run as part of the validation procedure. The mapping is of the form: ``error_code : `` where ``error_code`` provides a shorthand for the check being run, and ```` provides diff --git a/numpydoc/validate.py b/numpydoc/validate.py index a3d29ed1..b33ea780 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -34,58 +34,58 @@ ] ERROR_MSGS = { "GL01": "Docstring text (summary) should start in the line immediately " - "after the opening quotes (not in the same line, or leaving a " - "blank line in between)", + "after the opening quotes (not in the same line, or leaving a " + "blank line in between)", "GL02": "Closing quotes should be placed in the line after the last text " - "in the docstring (do not close the quotes in the same line as " - "the text, or leave a blank line between the last text and the " - "quotes)", + "in the docstring (do not close the quotes in the same line as " + "the text, or leave a blank line between the last text and the " + "quotes)", "GL03": "Double line break found; please use only one blank line to " - "separate sections or paragraphs, and do not leave blank lines " - "at the end of docstrings", + "separate sections or paragraphs, and do not leave blank lines " + "at the end of docstrings", "GL05": 'Tabs found at the start of line "{line_with_tabs}", please use ' - "whitespace only", + "whitespace only", "GL06": 'Found unknown section "{section}". Allowed sections are: ' - "{allowed_sections}", + "{allowed_sections}", "GL07": "Sections are in the wrong order. Correct order is: {correct_sections}", "GL08": "The object does not have a docstring", "GL09": "Deprecation warning should precede extended summary", "GL10": "reST directives {directives} must be followed by two colons", "SS01": "No summary found (a short summary in a single line should be " - "present at the beginning of the docstring)", + "present at the beginning of the docstring)", "SS02": "Summary does not start with a capital letter", "SS03": "Summary does not end with a period", "SS04": "Summary contains heading whitespaces", "SS05": "Summary must start with infinitive verb, not third person " - '(e.g. use "Generate" instead of "Generates")', + '(e.g. use "Generate" instead of "Generates")', "SS06": "Summary should fit in a single line", "ES01": "No extended summary found", "PR01": "Parameters {missing_params} not documented", "PR02": "Unknown parameters {unknown_params}", "PR03": "Wrong parameters order. Actual: {actual_params}. " - "Documented: {documented_params}", + "Documented: {documented_params}", "PR04": 'Parameter "{param_name}" has no type', "PR05": 'Parameter "{param_name}" type should not finish with "."', "PR06": 'Parameter "{param_name}" type should use "{right_type}" instead ' - 'of "{wrong_type}"', + 'of "{wrong_type}"', "PR07": 'Parameter "{param_name}" has no description', "PR08": 'Parameter "{param_name}" description should start with a ' - "capital letter", + "capital letter", "PR09": 'Parameter "{param_name}" description should finish with "."', "PR10": 'Parameter "{param_name}" requires a space before the colon ' - "separating the parameter name and type", + "separating the parameter name and type", "RT01": "No Returns section found", "RT02": "The first line of the Returns section should contain only the " - "type, unless multiple values are being returned", + "type, unless multiple values are being returned", "RT03": "Return value has no description", "RT04": "Return value description should start with a capital letter", "RT05": 'Return value description should finish with "."', "YD01": "No Yields section found", "SA01": "See Also section not found", "SA02": "Missing period at end of description for See Also " - '"{reference_name}" reference', + '"{reference_name}" reference', "SA03": "Description should be capitalized for See Also " - '"{reference_name}" reference', + '"{reference_name}" reference', "SA04": 'Missing description for See Also "{reference_name}" reference', "EX01": "No examples section found", } From 1d359d8c7b01b30d58de58ef2a267e4ff5221284 Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Mon, 1 Feb 2021 13:13:15 -0800 Subject: [PATCH 17/20] Add check for invalid error codes in configuration. plus test. --- numpydoc/numpydoc.py | 10 +++++++++- numpydoc/tests/test_numpydoc.py | 12 +++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index fe7a517a..29d3f90a 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -300,9 +300,17 @@ def update_config(app, config=None): # Processing to determine whether numpydoc_validation_checks is treated # as a blocklist or allowlist + valid_error_codes = set(ERROR_MSGS.keys()) if "all" in config.numpydoc_validation_checks: block = deepcopy(config.numpydoc_validation_checks) - config.numpydoc_validation_checks = set(ERROR_MSGS.keys()) - block + config.numpydoc_validation_checks = valid_error_codes - block + # Ensure that the validation check set contains only valid error codes + invalid_error_codes = config.numpydoc_validation_checks - valid_error_codes + if invalid_error_codes: + raise ValueError( + f"Unrecognized validation code(s) in numpydoc_validation_checks " + f"config value: {invalid_error_codes}" + ) # ------------------------------------------------------------------------------ diff --git a/numpydoc/tests/test_numpydoc.py b/numpydoc/tests/test_numpydoc.py index 9b50d0f1..2d5bca16 100644 --- a/numpydoc/tests/test_numpydoc.py +++ b/numpydoc/tests/test_numpydoc.py @@ -2,7 +2,9 @@ import pytest from io import StringIO from copy import deepcopy -from numpydoc.numpydoc import mangle_docstrings, _clean_text_signature +from numpydoc.numpydoc import ( + mangle_docstrings, _clean_text_signature, update_config +) from numpydoc.xref import DEFAULT_LINKS from sphinx.ext.autodoc import ALL from sphinx.util import logging @@ -151,6 +153,14 @@ def test_mangle_docstring_validation_warnings( assert w not in warnings +def test_update_config_invalid_validation_set(): + app = MockApp() + # Results in {'a', 'l'} instead of {"all"} + app.config.numpydoc_validation_checks = set("all") + with pytest.raises(ValueError, match="Unrecognized validation code"): + update_config(app) + + if __name__ == "__main__": import pytest pytest.main() From 87dd52f9c5e3e421ef46e3aa969bc0a68f749a44 Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Wed, 3 Feb 2021 17:10:05 -0800 Subject: [PATCH 18/20] Add feature to exclude patterns from docstring validation. Modify updated config name to avoid sphinx warning. Add documentation for exclusion config value. --- doc/install.rst | 15 ++++++++++ numpydoc/numpydoc.py | 47 ++++++++++++++++++++++---------- numpydoc/tests/test_docscrape.py | 1 + numpydoc/tests/test_numpydoc.py | 39 ++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 14 deletions(-) diff --git a/doc/install.rst b/doc/install.rst index f39e7935..8610b504 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -121,6 +121,21 @@ numpydoc_validation_checks : set The default is an empty set, thus no warnings from docstring validation are reported. +numpydoc_validation_exclude : set + A container of strings using :py:mod:`re` syntax specifying patterns to + ignore for docstring validation. + For example, to skip docstring validation for all objects in + ``mypkg.mymodule``:: + + numpydoc_validation_exclude = {"mypkg.mymodule."} + + If you wanted to also skip getter methods of ``MyClass``:: + + numpydoc_validation_exclude = {"mypkg.mymodule.", "MyClass.get"} + + The default is an empty set meaning no objects are excluded from docstring + validation by default. + Only has an effect when ``numpydoc_validate = True``. numpydoc_edit_link : bool .. deprecated:: 0.7.0 diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 29d3f90a..1070d6d4 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -174,21 +174,26 @@ def mangle_docstrings(app, what, name, obj, options, lines): logger.error('[numpydoc] While processing docstring for %r', name) raise - # TODO: validation only applies to non-module docstrings? if app.config.numpydoc_validate: - # TODO: Currently, all validation checks are run and only those - # selected via config are reported. It would be more efficient to - # only run the selected checks. - errors = validate(doc)["errors"] - if {err[0] for err in errors} & app.config.numpydoc_validation_checks: - msg = ( - f"[numpydoc] Validation warnings while processing " - f"docstring for {name!r}:\n" - ) - for err in errors: - if err[0] in app.config.numpydoc_validation_checks: - msg += f" {err[0]}: {err[1]}\n" - logger.warning(msg) + # If the user has supplied patterns to ignore via the + # numpydoc_validation_exclude config option, skip validation for + # any objs whose name matches any of the patterns + excluder = app.config.numpydoc_validation_excluder + exclude_from_validation = excluder.search(name) if excluder else False + if not exclude_from_validation: + # TODO: Currently, all validation checks are run and only those + # selected via config are reported. It would be more efficient to + # only run the selected checks. + errors = validate(doc)["errors"] + if {err[0] for err in errors} & app.config.numpydoc_validation_checks: + msg = ( + f"[numpydoc] Validation warnings while processing " + f"docstring for {name!r}:\n" + ) + for err in errors: + if err[0] in app.config.numpydoc_validation_checks: + msg += f" {err[0]}: {err[1]}\n" + logger.warning(msg) if (app.config.numpydoc_edit_link and hasattr(obj, '__name__') and @@ -274,6 +279,7 @@ def setup(app, get_doc_object_=get_doc_object): app.add_config_value('numpydoc_xref_ignore', set(), True) app.add_config_value('numpydoc_validate', False, True) app.add_config_value('numpydoc_validation_checks', set(), True) + app.add_config_value('numpydoc_validation_exclude', set(), False) # Extra mangling domains app.add_domain(NumpyPythonDomain) @@ -312,6 +318,19 @@ def update_config(app, config=None): f"config value: {invalid_error_codes}" ) + # Generate the regexp for docstrings to ignore during validation + if isinstance(config.numpydoc_validation_exclude, str): + raise ValueError( + f"numpydoc_validation_exclude must be a container of strings, " + f"e.g. [{config.numpydoc_validation_exclude!r}]." + ) + config.numpydoc_validation_excluder = None + if config.numpydoc_validation_exclude: + exclude_expr = re.compile( + r"|".join(exp for exp in config.numpydoc_validation_exclude) + ) + config.numpydoc_validation_excluder = exclude_expr + # ------------------------------------------------------------------------------ # Docstring-mangling domains diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index 13f99412..0706b6d0 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -1499,6 +1499,7 @@ def __init__(self, a, b): self.numpydoc_xref_aliases_complete = b # numpydoc.update_config fails if this config option not present self.numpydoc_validation_checks = set() + self.numpydoc_validation_exclude = set() xref_aliases_complete = deepcopy(DEFAULT_LINKS) for key in xref_aliases: diff --git a/numpydoc/tests/test_numpydoc.py b/numpydoc/tests/test_numpydoc.py index 2d5bca16..d353394f 100644 --- a/numpydoc/tests/test_numpydoc.py +++ b/numpydoc/tests/test_numpydoc.py @@ -25,6 +25,8 @@ class MockConfig(): numpydoc_citation_re = '[a-z0-9_.-]+' numpydoc_attributes_as_param_list = True numpydoc_validate = False + numpydoc_validation_checks = set() + numpydoc_validation_exclude = set() class MockBuilder(): @@ -140,6 +142,8 @@ def test_mangle_docstring_validation_warnings( # Set up config for test app.config.numpydoc_validate = numpydoc_validate app.config.numpydoc_validation_checks = numpydoc_validation_checks + # Update configuration + update_config(app) # Set up logging status, warning = StringIO(), StringIO() logging.setup(app, status, warning) @@ -153,6 +157,33 @@ def test_mangle_docstring_validation_warnings( assert w not in warnings +def test_mangle_docstring_validation_exclude(): + def function_with_bad_docstring(): + """ + This docstring will raise docstring validation warnings.""" + app = MockApp() + app.config.numpydoc_validate = True + app.config.numpydoc_validation_checks = {"all"} + app.config.numpydoc_validation_exclude = [r"_bad_"] + # Call update_config to construct regexp from config value + update_config(app) + # Setup for catching warnings + status, warning = StringIO(), StringIO() + logging.setup(app, status, warning) + # Run mangle docstrings on function_with_bad_docstring + mangle_docstrings( + app, + 'function', + function_with_bad_docstring.__name__, + function_with_bad_docstring, + None, + function_with_bad_docstring.__doc__.split('\n'), + ) + # Validation is skipped due to exclude pattern matching fn name, therefore + # no warnings expected + assert warning.getvalue() == "" + + def test_update_config_invalid_validation_set(): app = MockApp() # Results in {'a', 'l'} instead of {"all"} @@ -161,6 +192,14 @@ def test_update_config_invalid_validation_set(): update_config(app) +def test_update_config_exclude_str(): + app = MockApp() + app.config.numpydoc_validation_checks = set() + app.config.numpydoc_validation_exclude = "shouldnt-be-a-str" + with pytest.raises(ValueError, match="\['shouldnt-be-a-str'\]"): + update_config(app) + + if __name__ == "__main__": import pytest pytest.main() From a13705cfbcd98d595c94cb34a0b9d6cce593281e Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Fri, 5 Feb 2021 09:52:06 -0800 Subject: [PATCH 19/20] Be explicit about regex syntax for exclude config val Co-authored-by: Eric Larson --- doc/install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install.rst b/doc/install.rst index 8610b504..1822aff9 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -131,7 +131,7 @@ numpydoc_validation_exclude : set If you wanted to also skip getter methods of ``MyClass``:: - numpydoc_validation_exclude = {"mypkg.mymodule.", "MyClass.get"} + numpydoc_validation_exclude = {r"mypkg\.mymodule\.", r"MyClass\.get$"} The default is an empty set meaning no objects are excluded from docstring validation by default. From 55de3404c1adadd69ab06f891bb2d5a22a1d168c Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Fri, 5 Feb 2021 10:02:17 -0800 Subject: [PATCH 20/20] Rm redundant numpydoc_validate config param. --- doc/conf.py | 1 - doc/install.rst | 14 +++++--------- numpydoc/numpydoc.py | 3 +-- numpydoc/tests/test_numpydoc.py | 11 +++-------- numpydoc/tests/tinybuild/conf.py | 1 - 5 files changed, 9 insertions(+), 21 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 5c9062a2..185b6b18 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -85,7 +85,6 @@ numpydoc_xref_param_type = True numpydoc_xref_ignore = {'optional', 'type_without_description', 'BadException'} # Run docstring validation as part of build process -numpydoc_validate = True numpydoc_validation_checks = {"all", "GL01", "SA04", "RT03"} # The language for content autogenerated by Sphinx. Refer to documentation diff --git a/doc/install.rst b/doc/install.rst index 1822aff9..82c7d6ba 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -96,12 +96,10 @@ numpydoc_xref_ignore : set or ``"all"`` desired cross reference mappings in ``numpydoc_xref_aliases`` and setting ``numpydoc_xref_ignore="all"`` is more convenient than explicitly listing terms to ignore in a set. -numpydoc_validate : bool - Whether or not to run docstring validation during the sphinx-build process. - Default is ``False``. numpydoc_validation_checks : set The set of validation checks to report during the sphinx build process. - Only has an effect when ``numpydoc_validate = True``. + The default is an empty set, so docstring validation is not run by + default. If ``"all"`` is in the set, then the results of all of the :ref:`built-in validation checks ` are reported. If the set includes ``"all"`` and additional error codes, then all @@ -118,9 +116,6 @@ numpydoc_validation_checks : set # Only report warnings for the SA01 and EX01 checks numpydoc_validation_checks = {"SA01", "EX01"} - - The default is an empty set, thus no warnings from docstring validation - are reported. numpydoc_validation_exclude : set A container of strings using :py:mod:`re` syntax specifying patterns to ignore for docstring validation. @@ -134,8 +129,9 @@ numpydoc_validation_exclude : set numpydoc_validation_exclude = {r"mypkg\.mymodule\.", r"MyClass\.get$"} The default is an empty set meaning no objects are excluded from docstring - validation by default. - Only has an effect when ``numpydoc_validate = True``. + validation. + Only has an effect when docstring validation is activated, i.e. + ``numpydoc_validation_checks`` is not an empty set. numpydoc_edit_link : bool .. deprecated:: 0.7.0 diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 1070d6d4..87a81689 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -174,7 +174,7 @@ def mangle_docstrings(app, what, name, obj, options, lines): logger.error('[numpydoc] While processing docstring for %r', name) raise - if app.config.numpydoc_validate: + if app.config.numpydoc_validation_checks: # If the user has supplied patterns to ignore via the # numpydoc_validation_exclude config option, skip validation for # any objs whose name matches any of the patterns @@ -277,7 +277,6 @@ def setup(app, get_doc_object_=get_doc_object): app.add_config_value('numpydoc_xref_param_type', False, True) app.add_config_value('numpydoc_xref_aliases', dict(), True) app.add_config_value('numpydoc_xref_ignore', set(), True) - app.add_config_value('numpydoc_validate', False, True) app.add_config_value('numpydoc_validation_checks', set(), True) app.add_config_value('numpydoc_validation_exclude', set(), False) diff --git a/numpydoc/tests/test_numpydoc.py b/numpydoc/tests/test_numpydoc.py index d353394f..26ff3d28 100644 --- a/numpydoc/tests/test_numpydoc.py +++ b/numpydoc/tests/test_numpydoc.py @@ -24,7 +24,6 @@ class MockConfig(): numpydoc_edit_link = False numpydoc_citation_re = '[a-z0-9_.-]+' numpydoc_attributes_as_param_list = True - numpydoc_validate = False numpydoc_validation_checks = set() numpydoc_validation_exclude = set() @@ -117,30 +116,27 @@ def _function_without_seealso_and_examples(): @pytest.mark.parametrize( ( - 'numpydoc_validate', 'numpydoc_validation_checks', 'expected_warn', 'non_warnings', ), ( # Validation configured off - expect no warnings - (False, set(['SA01', 'EX01']), [], []), + (set(), [], []), # Validation on with expected warnings - (True, set(['SA01', 'EX01']), ('SA01', 'EX01'), []), + (set(['SA01', 'EX01']), ('SA01', 'EX01'), []), # Validation on with only one activated check - (True, set(['SA01']), ('SA01',), ('EX01',)), + (set(['SA01']), ('SA01',), ('EX01',)), ), ) def test_mangle_docstring_validation_warnings( f, - numpydoc_validate, numpydoc_validation_checks, expected_warn, non_warnings, ): app = MockApp() # Set up config for test - app.config.numpydoc_validate = numpydoc_validate app.config.numpydoc_validation_checks = numpydoc_validation_checks # Update configuration update_config(app) @@ -162,7 +158,6 @@ def function_with_bad_docstring(): """ This docstring will raise docstring validation warnings.""" app = MockApp() - app.config.numpydoc_validate = True app.config.numpydoc_validation_checks = {"all"} app.config.numpydoc_validation_exclude = [r"_bad_"] # Call update_config to construct regexp from config value diff --git a/numpydoc/tests/tinybuild/conf.py b/numpydoc/tests/tinybuild/conf.py index 7ca7b056..8b16cdd2 100644 --- a/numpydoc/tests/tinybuild/conf.py +++ b/numpydoc/tests/tinybuild/conf.py @@ -22,4 +22,3 @@ highlight_language = 'python3' numpydoc_class_members_toctree = False numpydoc_xref_param_type = True -numpydoc_validate = True