Skip to content

Commit

Permalink
MNT: update vendored docs files (nipreps#834)
Browse files Browse the repository at this point in the history
* MNT: update vendored docs files

Copied from numpydoc 1.7.0.

* MNT: Ignore vendored files in CI spellchecking
  • Loading branch information
DimitriPapadopoulos authored Apr 17, 2024
1 parent 857a7ba commit 830b4fc
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 51 deletions.
2 changes: 1 addition & 1 deletion .codespellrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[codespell]
skip = .git,*.pdf,*.svg,viz-report.html
skip = .git,*.pdf,*.svg,numpydoc.py,viz-report.html
# objekt - used in the code purposefully different from object
# nd - import scipy.ndimage as nd
ignore-words-list = objekt,nd
41 changes: 29 additions & 12 deletions docs/sphinxext/docscrape.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Extract reference documentation from the NumPy source tree.
"""

import inspect
import textwrap
import re
Expand All @@ -11,12 +12,7 @@
import copy
import sys


# TODO: Remove try-except when support for Python 3.7 is dropped
try:
from functools import cached_property
except ImportError: # cached_property added in Python 3.8
cached_property = property
from functools import cached_property


def strip_blank_lines(l):
Expand Down Expand Up @@ -408,7 +404,7 @@ def _parse(self):
msg = "Docstring contains a Receives section but not Yields."
raise ValueError(msg)

for (section, content) in sections:
for section, content in sections:
if not section.startswith(".."):
section = (s.capitalize() for s in section.split(" "))
section = " ".join(section)
Expand Down Expand Up @@ -631,7 +627,6 @@ def __init__(self, obj, doc=None, config=None):


class ClassDoc(NumpyDocString):

extra_public_methods = ["__call__"]

def __init__(self, cls, doc=None, modulename="", func_doc=FunctionDoc, config=None):
Expand Down Expand Up @@ -711,6 +706,7 @@ def properties(self):
for name, func in inspect.getmembers(self._cls)
if (
not name.startswith("_")
and not self._should_skip_member(name, self._cls)
and (
func is None
or isinstance(func, (property, cached_property))
Expand All @@ -720,6 +716,19 @@ def properties(self):
)
]

@staticmethod
def _should_skip_member(name, klass):
if (
# Namedtuples should skip everything in their ._fields as the
# docstrings for each of the members is: "Alias for field number X"
issubclass(klass, tuple)
and hasattr(klass, "_asdict")
and hasattr(klass, "_fields")
and name in klass._fields
):
return True
return False

def _is_show_member(self, name):
if self.show_inherited_members:
return True # show all class members
Expand All @@ -728,7 +737,15 @@ def _is_show_member(self, name):
return True


def get_doc_object(obj, what=None, doc=None, config=None):
def get_doc_object(
obj,
what=None,
doc=None,
config=None,
class_doc=ClassDoc,
func_doc=FunctionDoc,
obj_doc=ObjDoc,
):
if what is None:
if inspect.isclass(obj):
what = "class"
Expand All @@ -742,10 +759,10 @@ def get_doc_object(obj, what=None, doc=None, config=None):
config = {}

if what == "class":
return ClassDoc(obj, func_doc=FunctionDoc, doc=doc, config=config)
return class_doc(obj, func_doc=func_doc, doc=doc, config=config)
elif what in ("function", "method"):
return FunctionDoc(obj, doc=doc, config=config)
return func_doc(obj, doc=doc, config=config)
else:
if doc is None:
doc = pydoc.getdoc(obj)
return ObjDoc(obj, doc, config=config)
return obj_doc(obj, doc, config=config)
38 changes: 16 additions & 22 deletions docs/sphinxext/docscrape_sphinx.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from sphinx.jinja2glue import BuiltinTemplateLoader

from .docscrape import NumpyDocString, FunctionDoc, ClassDoc, ObjDoc
from .docscrape import get_doc_object as get_doc_object_orig
from .xref import make_xref


Expand Down Expand Up @@ -372,9 +373,11 @@ def __str__(self, indent=0, func_role="obj"):
"notes": self._str_section("Notes"),
"references": self._str_references(),
"examples": self._str_examples(),
"attributes": self._str_param_list("Attributes", fake_autosummary=True)
if self.attributes_as_param_list
else self._str_member_list("Attributes"),
"attributes": (
self._str_param_list("Attributes", fake_autosummary=True)
if self.attributes_as_param_list
else self._str_member_list("Attributes")
),
"methods": self._str_member_list("Methods"),
}
ns = {k: "\n".join(v) for k, v in ns.items()}
Expand Down Expand Up @@ -407,20 +410,10 @@ def __init__(self, obj, doc=None, config=None):
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=None, builder=None):
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 config is None:
config = {}

template_dirs = [os.path.join(os.path.dirname(__file__), "templates")]
if builder is not None:
template_loader = BuiltinTemplateLoader()
Expand All @@ -430,11 +423,12 @@ def get_doc_object(obj, what=None, doc=None, config=None, builder=None):
template_env = SandboxedEnvironment(loader=template_loader)
config["template"] = template_env.get_template("numpydoc_docstring.rst")

if what == "class":
return SphinxClassDoc(obj, func_doc=SphinxFunctionDoc, doc=doc, config=config)
elif what in ("function", "method"):
return SphinxFunctionDoc(obj, doc=doc, config=config)
else:
if doc is None:
doc = pydoc.getdoc(obj)
return SphinxObjDoc(obj, doc, config=config)
return get_doc_object_orig(
obj,
what=what,
doc=doc,
config=config,
class_doc=SphinxClassDoc,
func_doc=SphinxFunctionDoc,
obj_doc=SphinxObjDoc,
)
47 changes: 31 additions & 16 deletions docs/sphinxext/numpydoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
.. [1] https://github.com/numpy/numpydoc
"""

from copy import deepcopy
import re
import pydoc
Expand All @@ -24,17 +25,17 @@
import hashlib
import itertools

from docutils.nodes import citation, Text, section, comment, reference
from docutils.nodes import citation, Text, section, comment, reference, inline
import sphinx
from sphinx.addnodes import pending_xref, desc_content
from sphinx.util import logging
from sphinx.errors import ExtensionError

if sphinx.__version__ < "4.2":
raise RuntimeError("Sphinx 4.2 or newer is required")
if sphinx.__version__ < "5":
raise RuntimeError("Sphinx 5 or newer is required")

from .docscrape_sphinx import get_doc_object
from .validate import validate, ERROR_MSGS
from .validate import validate, ERROR_MSGS, get_validation_checks
from .xref import DEFAULT_LINKS
from . import __version__

Expand Down Expand Up @@ -149,6 +150,10 @@ def clean_backrefs(app, doc, docname):
for ref in _traverse_or_findall(doc, reference, descend=True):
for id_ in ref["ids"]:
known_ref_ids.add(id_)
# some extensions produce backrefs to inline elements
for ref in _traverse_or_findall(doc, inline, descend=True):
for id_ in ref["ids"]:
known_ref_ids.add(id_)
for citation_node in _traverse_or_findall(doc, citation, descend=True):
# remove backrefs to non-existent refs
citation_node["backrefs"] = [
Expand Down Expand Up @@ -207,7 +212,19 @@ def mangle_docstrings(app, what, name, obj, options, lines):
# 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"]
report = validate(doc)
errors = [
err
for err in report["errors"]
if not (
(
overrides := app.config.numpydoc_validation_overrides.get(
err[0]
)
)
and re.search(overrides, report["docstring"])
)
]
if {err[0] for err in errors} & app.config.numpydoc_validation_checks:
msg = (
f"[numpydoc] Validation warnings while processing "
Expand Down Expand Up @@ -285,6 +302,7 @@ def setup(app, get_doc_object_=get_doc_object):
app.add_config_value("numpydoc_xref_ignore", set(), True)
app.add_config_value("numpydoc_validation_checks", set(), True)
app.add_config_value("numpydoc_validation_exclude", set(), False)
app.add_config_value("numpydoc_validation_overrides", dict(), False)

# Extra mangling domains
app.add_domain(NumpyPythonDomain)
Expand All @@ -310,17 +328,9 @@ 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 = 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}"
)
config.numpydoc_validation_checks = get_validation_checks(
config.numpydoc_validation_checks
)

# Generate the regexp for docstrings to ignore during validation
if isinstance(config.numpydoc_validation_exclude, str):
Expand All @@ -335,6 +345,11 @@ def update_config(app, config=None):
)
config.numpydoc_validation_excluder = exclude_expr

for check, patterns in config.numpydoc_validation_overrides.items():
config.numpydoc_validation_overrides[check] = re.compile(
r"|".join(exp for exp in patterns)
)


# ------------------------------------------------------------------------------
# Docstring-mangling domains
Expand Down

0 comments on commit 830b4fc

Please sign in to comment.