Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-numpydoc for openSUSE:Factory
checked in at 2026-03-24 18:48:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-numpydoc (Old)
and /work/SRC/openSUSE:Factory/.python-numpydoc.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-numpydoc"
Tue Mar 24 18:48:50 2026 rev:20 rq:1342100 version:1.10.0
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-numpydoc/python-numpydoc.changes
2025-08-02 00:41:21.605588128 +0200
+++
/work/SRC/openSUSE:Factory/.python-numpydoc.new.8177/python-numpydoc.changes
2026-03-24 18:49:40.132436514 +0100
@@ -1,0 +2,10 @@
+Mon Mar 23 20:44:53 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 1.10.0:
+ * Added "exclude_files" option for pyproject.toml config usage.
+ * Constructor checking for AST validator
+ * FIX: account for unreleased changes to sphinx
+ * TST: A few minor test improvements
+ * MAINT: rm unused kwarg from private method.
+
+-------------------------------------------------------------------
Old:
----
numpydoc-1.9.0.tar.gz
New:
----
numpydoc-1.10.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-numpydoc.spec ++++++
--- /var/tmp/diff_new_pack.qE6Gds/_old 2026-03-24 18:49:40.636457310 +0100
+++ /var/tmp/diff_new_pack.qE6Gds/_new 2026-03-24 18:49:40.636457310 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-numpydoc
#
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-numpydoc
-Version: 1.9.0
+Version: 1.10.0
Release: 0
Summary: Sphinx extension to support docstrings in Numpy format
License: BSD-3-Clause
@@ -27,16 +27,16 @@
Source:
https://files.pythonhosted.org/packages/source/n/numpydoc/numpydoc-%{version}.tar.gz
# https://docs.python.org/3/objects.inv (changes from time to time, accessed
2024-02-29)
Source1: python-objects.inv
-BuildRequires: %{python_module Sphinx >= 5}
-BuildRequires: %{python_module base >= 3.8}
+BuildRequires: %{python_module Sphinx >= 6}
+BuildRequires: %{python_module base >= 3.10}
BuildRequires: %{python_module pip}
-BuildRequires: %{python_module setuptools}
+BuildRequires: %{python_module setuptools >= 61.2}
BuildRequires: %{python_module wheel}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
Requires(post): update-alternatives
Requires(postun): update-alternatives
-Requires: python-Sphinx >= 5
+Requires: python-Sphinx >= 6
BuildArch: noarch
# SECTION test requirements
BuildRequires: %{python_module pytest}
++++++ numpydoc-1.9.0.tar.gz -> numpydoc-1.10.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/PKG-INFO new/numpydoc-1.10.0/PKG-INFO
--- old/numpydoc-1.9.0/PKG-INFO 2025-06-24 14:22:24.037762600 +0200
+++ new/numpydoc-1.10.0/PKG-INFO 2025-12-02 17:38:47.474620000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: numpydoc
-Version: 1.9.0
+Version: 1.10.0
Summary: Sphinx extension to support docstrings in Numpy format
Author-email: Pauli Virtanen and others <[email protected]>
License: Copyright (C) 2008-2023 Stefan van der Walt <[email protected]>,
Pauli Virtanen <[email protected]>
@@ -38,13 +38,12 @@
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Documentation
-Requires-Python: >=3.9
+Requires-Python: >=3.10
Description-Content-Type: text/x-rst
License-File: LICENSE.txt
Requires-Dist: sphinx>=6
@@ -70,7 +69,7 @@
The extension also adds the code description directives
``np:function``, ``np-c:function``, etc.
-numpydoc requires Python 3.9+ and sphinx 6+.
+numpydoc requires Python 3.10+ and sphinx 6+.
For usage information, please refer to the `documentation
<https://numpydoc.readthedocs.io/>`_.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/README.rst
new/numpydoc-1.10.0/README.rst
--- old/numpydoc-1.9.0/README.rst 2025-06-24 14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/README.rst 2025-12-02 17:38:37.000000000 +0100
@@ -17,7 +17,7 @@
The extension also adds the code description directives
``np:function``, ``np-c:function``, etc.
-numpydoc requires Python 3.9+ and sphinx 6+.
+numpydoc requires Python 3.10+ and sphinx 6+.
For usage information, please refer to the `documentation
<https://numpydoc.readthedocs.io/>`_.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/doc/install.rst
new/numpydoc-1.10.0/doc/install.rst
--- old/numpydoc-1.9.0/doc/install.rst 2025-06-24 14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/doc/install.rst 2025-12-02 17:38:37.000000000 +0100
@@ -5,7 +5,7 @@
Installation
============
-This extension requires Python 3.9+, sphinx 6+ and is available from:
+This extension requires Python 3.10+, sphinx 6+ and is available from:
* `numpydoc on PyPI <http://pypi.python.org/pypi/numpydoc>`_
* `numpydoc on GitHub <https://github.com/numpy/numpydoc/>`_
@@ -139,6 +139,18 @@
validation.
Only has an effect when docstring validation is activated, i.e.
``numpydoc_validation_checks`` is not an empty set.
+numpydoc_validation_exclude_files : set
+ A container of strings using :py:mod:`re` syntax specifying path patterns
to
+ ignore for docstring validation, relative to the package root.
+ For example, to skip docstring validation for all objects in
+ ``tests\``::
+
+ numpydoc_validation_exclude_files = {"^tests/.*$"}
+
+ The default is an empty set meaning no paths are excluded from docstring
+ validation.
+ Only has an effect when docstring validation is activated, i.e.
+ ``numpydoc_validation_checks`` is not an empty set.
numpydoc_validation_overrides : dict
A dictionary mapping :ref:`validation checks <validation_checks>` to a
container of strings using :py:mod:`re` syntax specifying patterns to
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/doc/release/notes.rst
new/numpydoc-1.10.0/doc/release/notes.rst
--- old/numpydoc-1.9.0/doc/release/notes.rst 2025-06-24 14:22:17.000000000
+0200
+++ new/numpydoc-1.10.0/doc/release/notes.rst 2025-12-02 17:38:37.000000000
+0100
@@ -20,7 +20,7 @@
Documentation
-------------
-- DOC: Do not use types for *args, **kwargs (`#585
<https://github.com/numpy/numpydoc/pull/585>`_).
+- DOC: Do not use types for ``*args``, ``**kwargs`` (`#585
<https://github.com/numpy/numpydoc/pull/585>`_).
- mention conda-forge in installation docs (`#595
<https://github.com/numpy/numpydoc/pull/595>`_).
- Fix typo in validation.rst (`#605
<https://github.com/numpy/numpydoc/pull/605>`_).
- Fix broken link in ``format.rst`` (`#628
<https://github.com/numpy/numpydoc/pull/628>`_).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/doc/validation.rst
new/numpydoc-1.10.0/doc/validation.rst
--- old/numpydoc-1.9.0/doc/validation.rst 2025-06-24 14:22:17.000000000
+0200
+++ new/numpydoc-1.10.0/doc/validation.rst 2025-12-02 17:38:37.000000000
+0100
@@ -36,6 +36,10 @@
expressions ``\.undocumented_method$`` or ``\.__repr__$``. This
maps to ``numpydoc_validation_exclude`` from the
:ref:`Sphinx build configuration <validation_during_sphinx_build>`.
+* ``exclude_files``: Exclude file paths (relative to the package root) matching
+ the regular expressions ``^tests/.*$`` or ``^module/gui.*$``. This maps to
+ ``numpydoc_validation_exclude_files`` from the
+ :ref:`Sphinx build configuration <validation_during_sphinx_build>`.
* ``override_SS05``: Allow docstrings to start with "Process ", "Assess ",
or "Access ". To override different checks, add a field for each code in
the form of ``override_<code>`` with a collection of regular expression(s)
@@ -57,6 +61,10 @@
'\.undocumented_method$',
'\.__repr__$',
]
+ exclude_files = [ # don't process filepaths that match these regex
+ '^tests/.*',
+ '^module/gui.*',
+ ]
override_SS05 = [ # override SS05 to allow docstrings starting with these
words
'^Process ',
'^Assess ',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc/_version.py
new/numpydoc-1.10.0/numpydoc/_version.py
--- old/numpydoc-1.9.0/numpydoc/_version.py 2025-06-24 14:22:17.000000000
+0200
+++ new/numpydoc-1.10.0/numpydoc/_version.py 2025-12-02 17:38:37.000000000
+0100
@@ -1 +1 @@
-__version__ = "1.9.0"
+__version__ = "1.10.0"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc/cli.py
new/numpydoc-1.10.0/numpydoc/cli.py
--- old/numpydoc-1.9.0/numpydoc/cli.py 2025-06-24 14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/numpydoc/cli.py 2025-12-02 17:38:37.000000000 +0100
@@ -4,14 +4,14 @@
import ast
from collections.abc import Sequence
from pathlib import Path
-from typing import List, Union
+from typing import List
from .docscrape_sphinx import get_doc_object
from .hooks import utils, validate_docstrings
from .validate import ERROR_MSGS, Validator, validate
-def render_object(import_path: str, config: Union[List[str], None] = None) ->
int:
+def render_object(import_path: str, config: List[str] | None = None) -> int:
"""Test numpydoc docstring generation for a given object."""
# TODO: Move Validator._load_obj to a better place than validate
print(get_doc_object(Validator._load_obj(import_path), config=dict(config
or [])))
@@ -117,7 +117,7 @@
return ap
-def main(argv: Union[Sequence[str], None] = None) -> int:
+def main(argv: Sequence[str] | None = None) -> int:
"""CLI for numpydoc."""
ap = get_parser()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc/docscrape.py
new/numpydoc-1.10.0/numpydoc/docscrape.py
--- old/numpydoc-1.9.0/numpydoc/docscrape.py 2025-06-24 14:22:17.000000000
+0200
+++ new/numpydoc-1.10.0/numpydoc/docscrape.py 2025-12-02 17:38:37.000000000
+0100
@@ -597,7 +597,7 @@
def __str__(self):
out = ""
- func, func_name = self.get_func()
+ _func, func_name = self.get_func()
roles = {"func": "function", "meth": "method"}
@@ -701,7 +701,7 @@
and not self._should_skip_member(name, self._cls)
and (
func is None
- or isinstance(func, (property, cached_property))
+ or isinstance(func, property | cached_property)
or inspect.isdatadescriptor(func)
)
and self._is_show_member(name)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc/docscrape_sphinx.py
new/numpydoc-1.10.0/numpydoc/docscrape_sphinx.py
--- old/numpydoc-1.9.0/numpydoc/docscrape_sphinx.py 2025-06-24
14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/numpydoc/docscrape_sphinx.py 2025-12-02
17:38:37.000000000 +0100
@@ -37,7 +37,7 @@
self.template = template_env.get_template("numpydoc_docstring.rst")
# string conversion routines
- def _str_header(self, name, symbol="`"):
+ def _str_header(self, name):
return [".. rubric:: " + name, ""]
def _str_field_list(self, name):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc/hooks/validate_docstrings.py
new/numpydoc-1.10.0/numpydoc/hooks/validate_docstrings.py
--- old/numpydoc-1.9.0/numpydoc/hooks/validate_docstrings.py 2025-06-24
14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/numpydoc/hooks/validate_docstrings.py 2025-12-02
17:38:37.000000000 +0100
@@ -63,7 +63,7 @@
@property
def is_function_or_method(self) -> bool:
- return isinstance(self.node, (ast.FunctionDef, ast.AsyncFunctionDef))
+ return isinstance(self.node, ast.FunctionDef | ast.AsyncFunctionDef)
@property
def is_mod(self) -> bool:
@@ -236,7 +236,7 @@
The node to visit.
"""
if isinstance(
- node, (ast.Module, ast.ClassDef, ast.FunctionDef,
ast.AsyncFunctionDef)
+ node, ast.Module | ast.ClassDef | ast.FunctionDef |
ast.AsyncFunctionDef
):
self.stack.append(node)
@@ -273,7 +273,12 @@
dict
Config options for the numpydoc validation hook.
"""
- options = {"checks": {"all"}, "exclude": set(), "overrides": {}}
+ options = {
+ "checks": {"all"},
+ "exclude": set(),
+ "overrides": {},
+ "exclude_files": set(),
+ }
dir_path = Path(dir_path).expanduser().resolve()
toml_path = dir_path / "pyproject.toml"
@@ -306,6 +311,13 @@
else [global_exclusions]
)
+ file_exclusions = config.get("exclude_files",
options["exclude_files"])
+ options["exclude_files"] = set(
+ file_exclusions
+ if not isinstance(file_exclusions, str)
+ else [file_exclusions]
+ )
+
extract_check_overrides(options, config.items())
elif cfg_path.is_file():
@@ -332,6 +344,16 @@
except configparser.NoOptionError:
pass
+ try:
+ options["exclude_files"] = set(
+ config.get(numpydoc_validation_config_section,
"exclude_files")
+ .rstrip(",")
+ .split(",")
+ or options["exclude_files"]
+ )
+ except configparser.NoOptionError:
+ pass
+
extract_check_overrides(
options, config.items(numpydoc_validation_config_section)
)
@@ -341,6 +363,7 @@
options["checks"] = validate.get_validation_checks(options["checks"])
options["exclude"] = compile_regex(options["exclude"])
+ options["exclude_files"] = compile_regex(options["exclude_files"])
return options
@@ -372,8 +395,8 @@
def run_hook(
files: List[str],
*,
- config: Union[Dict[str, Any], None] = None,
- ignore: Union[List[str], None] = None,
+ config: Dict[str, Any] | None = None,
+ ignore: List[str] | None = None,
) -> int:
"""
Run the numpydoc validation hook.
@@ -395,9 +418,12 @@
project_root, _ = find_project_root(files)
config_options = parse_config(config or project_root)
config_options["checks"] -= set(ignore or [])
+ exclude_re = config_options["exclude_files"]
findings = False
for file in files:
+ if exclude_re and exclude_re.match(file):
+ continue
if file_issues := process_file(file, config_options):
findings = True
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc/numpydoc.py
new/numpydoc-1.10.0/numpydoc/numpydoc.py
--- old/numpydoc-1.9.0/numpydoc/numpydoc.py 2025-06-24 14:22:17.000000000
+0200
+++ new/numpydoc-1.10.0/numpydoc/numpydoc.py 2025-12-02 17:38:37.000000000
+0100
@@ -18,15 +18,19 @@
"""
import hashlib
+import importlib
import inspect
import itertools
import pydoc
import re
+import sys
from collections.abc import Callable
from copy import deepcopy
+from pathlib import Path
from docutils.nodes import Text, citation, comment, inline, reference, section
from sphinx.addnodes import desc_content, pending_xref
+from sphinx.application import Sphinx as SphinxApp
from sphinx.util import logging
from . import __version__
@@ -52,7 +56,7 @@
)
-def rename_references(app, what, name, obj, options, lines):
+def rename_references(app: SphinxApp, what, name, obj, options, lines):
# decorate reference numbers so that there are no duplicates
# these are later undecorated in the doctree, in relabel_references
references = set()
@@ -84,7 +88,7 @@
section_node = citation_node.parent
def is_docstring_section(node):
- return isinstance(node, (section, desc_content))
+ return isinstance(node, section | desc_content)
while not is_docstring_section(section_node):
section_node = section_node.parent
@@ -114,7 +118,7 @@
return False
-def relabel_references(app, doc):
+def relabel_references(app: SphinxApp, doc):
# Change 'hash-ref' to 'ref' in label text
for citation_node in _traverse_or_findall(doc, citation):
if not _is_cite_in_numpydoc_docstring(citation_node):
@@ -141,7 +145,7 @@
ref.replace(ref_text, new_text.copy())
-def clean_backrefs(app, doc, docname):
+def clean_backrefs(app: SphinxApp, doc, docname):
# only::latex directive has resulted in citation backrefs without reference
known_ref_ids = set()
for ref in _traverse_or_findall(doc, reference, descend=True):
@@ -161,7 +165,7 @@
DEDUPLICATION_TAG = " !! processed by numpydoc !!"
-def mangle_docstrings(app, what, name, obj, options, lines):
+def mangle_docstrings(app: SphinxApp, what, name, obj, options, lines):
if DEDUPLICATION_TAG in lines:
return
show_inherited_class_members =
app.config.numpydoc_show_inherited_class_members
@@ -181,8 +185,12 @@
"xref_aliases": app.config.numpydoc_xref_aliases_complete,
"xref_ignore": app.config.numpydoc_xref_ignore,
}
-
- cfg.update(options or {})
+ # TODO: Find a cleaner way to take care of this change away from dict
+ # https://github.com/sphinx-doc/sphinx/issues/13942
+ try:
+ cfg.update(options or {})
+ except TypeError:
+ cfg.update(options.__dict__ or {})
u_NL = "\n"
if what == "module":
# Strip top title
@@ -190,6 +198,38 @@
title_re = re.compile(pattern, re.IGNORECASE | re.DOTALL)
lines[:] = title_re.sub("", u_NL.join(lines)).split(u_NL)
else:
+ # Test the obj to find the module path, and skip the check if it's
path is matched by
+ # numpydoc_validation_exclude_files
+ if (
+ app.config.numpydoc_validation_exclude_files
+ and app.config.numpydoc_validation_checks
+ ):
+ excluder = app.config.numpydoc_validation_files_excluder
+ module = inspect.getmodule(obj)
+ try:
+ # Get the module relative path from the name
+ if module:
+ mod_path = Path(module.__file__)
+ package_rel_path = mod_path.parent.relative_to(
+ Path(
+ importlib.import_module(
+ module.__name__.split(".")[0]
+ ).__file__
+ ).parent
+ ).as_posix()
+ module_file = mod_path.as_posix().replace(
+ mod_path.parent.as_posix(), ""
+ )
+ path = package_rel_path + module_file
+ else:
+ path = None
+ except AttributeError as e:
+ path = None
+
+ if path and excluder and excluder.search(path):
+ # Skip validation for this object.
+ return
+
try:
doc = get_doc_object(
obj, what, u_NL.join(lines), config=cfg, builder=app.builder
@@ -239,7 +279,7 @@
lines += ["..", DEDUPLICATION_TAG]
-def mangle_signature(app, what, name, obj, options, sig, retann):
+def mangle_signature(app: SphinxApp, what, name, obj, options, sig, retann):
# Do not try to inspect classes that don't define `__init__`
if inspect.isclass(obj) and (
not hasattr(obj, "__init__")
@@ -273,7 +313,7 @@
return start_sig + sig + ")"
-def setup(app, get_doc_object_=get_doc_object):
+def setup(app: SphinxApp, get_doc_object_=get_doc_object):
if not hasattr(app, "add_config_value"):
return None # probably called by nose, better bail out
@@ -299,6 +339,7 @@
app.add_config_value("numpydoc_xref_ignore", set(), True, types=[set, str])
app.add_config_value("numpydoc_validation_checks", set(), True)
app.add_config_value("numpydoc_validation_exclude", set(), False)
+ app.add_config_value("numpydoc_validation_exclude_files", set(), False)
app.add_config_value("numpydoc_validation_overrides", dict(), False)
# Extra mangling domains
@@ -309,7 +350,7 @@
return metadata
-def update_config(app, config=None):
+def update_config(app: SphinxApp, config=None):
"""Update the configuration with default values."""
if config is None: # needed for testing and old Sphinx
config = app.config
@@ -342,6 +383,21 @@
)
config.numpydoc_validation_excluder = exclude_expr
+ # Generate the regexp for files to ignore during validation
+ if isinstance(config.numpydoc_validation_exclude_files, str):
+ raise ValueError(
+ f"numpydoc_validation_exclude_files must be a container of
strings, "
+ f"e.g. [{config.numpydoc_validation_exclude_files!r}]."
+ )
+
+ config.numpydoc_validation_files_excluder = None
+ if config.numpydoc_validation_exclude_files:
+ exclude_files_expr = re.compile(
+ r"|".join(exp for exp in config.numpydoc_validation_exclude_files)
+ )
+ config.numpydoc_validation_files_excluder = exclude_files_expr
+
+ # Generate the regexp for validation overrides
for check, patterns in config.numpydoc_validation_overrides.items():
config.numpydoc_validation_overrides[check] = re.compile(
r"|".join(exp for exp in patterns)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc/tests/hooks/__init__.py
new/numpydoc-1.10.0/numpydoc/tests/hooks/__init__.py
--- old/numpydoc-1.9.0/numpydoc/tests/hooks/__init__.py 2025-06-24
14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/numpydoc/tests/hooks/__init__.py 1970-01-01
01:00:00.000000000 +0100
@@ -1 +0,0 @@
-"""Tests for hooks."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/numpydoc-1.9.0/numpydoc/tests/hooks/example_module.py
new/numpydoc-1.10.0/numpydoc/tests/hooks/example_module.py
--- old/numpydoc-1.9.0/numpydoc/tests/hooks/example_module.py 2025-06-24
14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/numpydoc/tests/hooks/example_module.py 2025-12-02
17:38:37.000000000 +0100
@@ -28,4 +28,35 @@
class NewClass:
- pass
+ class GoodConstructor:
+ """
+ A nested class to test constructors via AST hook.
+
+ Implements constructor via class docstring.
+
+ Parameters
+ ----------
+ name : str
+ The name of the new class.
+ """
+
+ def __init__(self, name):
+ self.name = name
+
+ class BadConstructor:
+ """
+ A nested class to test constructors via AST hook.
+
+ Implements a bad constructor docstring despite having a good class
docstring.
+
+ Parameters
+ ----------
+ name : str
+ The name of the new class.
+ """
+
+ def __init__(self, name):
+ """
+ A failing constructor implementation without parameters.
+ """
+ self.name = name
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc/tests/hooks/test_utils.py
new/numpydoc-1.10.0/numpydoc/tests/hooks/test_utils.py
--- old/numpydoc-1.9.0/numpydoc/tests/hooks/test_utils.py 2025-06-24
14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/numpydoc/tests/hooks/test_utils.py 2025-12-02
17:38:37.000000000 +0100
@@ -23,7 +23,10 @@
(tmp_path / reason_file).touch()
if files:
- expected_dir = Path("/") if expected_reason == "file system root" else
tmp_path
+ expected_dir = (
+ Path(tmp_path.anchor) if expected_reason == "file system root"
else tmp_path
+ )
+
for file in files:
(tmp_path / file).touch()
else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/numpydoc-1.9.0/numpydoc/tests/hooks/test_validate_hook.py
new/numpydoc-1.10.0/numpydoc/tests/hooks/test_validate_hook.py
--- old/numpydoc-1.9.0/numpydoc/tests/hooks/test_validate_hook.py
2025-06-24 14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/numpydoc/tests/hooks/test_validate_hook.py
2025-12-02 17:38:37.000000000 +0100
@@ -1,6 +1,7 @@
"""Test the numpydoc validate pre-commit hook."""
import inspect
+import re
from pathlib import Path
import pytest
@@ -25,42 +26,58 @@
"""Test that a file is correctly processed in the absence of config
files."""
expected = inspect.cleandoc(
- """
- numpydoc/tests/hooks/example_module.py:4: ES01 No extended summary
found
+ f"""
+ {example_module!s}:4: ES01 No extended summary found
+
+ {example_module!s}:4: PR01 Parameters {{'name'}} not documented
+
+ {example_module!s}:4: SA01 See Also section not found
+
+ {example_module!s}:4: EX01 No examples section found
+
+ {example_module!s}:8: ES01 No extended summary found
+
+ {example_module!s}:8: SA01 See Also section not found
+
+ {example_module!s}:8: EX01 No examples section found
- numpydoc/tests/hooks/example_module.py:4: PR01 Parameters {'name'} not
documented
+ {example_module!s}:11: GL08 The object does not have a docstring
- numpydoc/tests/hooks/example_module.py:4: SA01 See Also section not
found
+ {example_module!s}:17: ES01 No extended summary found
- numpydoc/tests/hooks/example_module.py:4: EX01 No examples section
found
+ {example_module!s}:17: PR01 Parameters {{'**kwargs'}} not documented
- numpydoc/tests/hooks/example_module.py:8: ES01 No extended summary
found
+ {example_module!s}:17: PR07 Parameter "*args" has no description
- numpydoc/tests/hooks/example_module.py:8: SA01 See Also section not
found
+ {example_module!s}:17: SA01 See Also section not found
- numpydoc/tests/hooks/example_module.py:8: EX01 No examples section
found
+ {example_module!s}:17: EX01 No examples section found
- numpydoc/tests/hooks/example_module.py:11: GL08 The object does not
have a docstring
+ {example_module!s}:26: SS05 Summary must start with infinitive verb,
not third person (e.g. use "Generate" instead of "Generates")
- numpydoc/tests/hooks/example_module.py:17: ES01 No extended summary
found
+ {example_module!s}:26: ES01 No extended summary found
- numpydoc/tests/hooks/example_module.py:17: PR01 Parameters
{'**kwargs'} not documented
+ {example_module!s}:26: SA01 See Also section not found
- numpydoc/tests/hooks/example_module.py:17: PR07 Parameter "*args" has
no description
+ {example_module!s}:26: EX01 No examples section found
- numpydoc/tests/hooks/example_module.py:17: SA01 See Also section not
found
+ {example_module!s}:30: GL08 The object does not have a docstring
- numpydoc/tests/hooks/example_module.py:17: EX01 No examples section
found
+ {example_module!s}:31: SA01 See Also section not found
- numpydoc/tests/hooks/example_module.py:26: SS05 Summary must start
with infinitive verb, not third person (e.g. use "Generate" instead of
"Generates")
+ {example_module!s}:31: EX01 No examples section found
- numpydoc/tests/hooks/example_module.py:26: ES01 No extended summary
found
+ {example_module!s}:46: SA01 See Also section not found
- numpydoc/tests/hooks/example_module.py:26: SA01 See Also section not
found
+ {example_module!s}:46: EX01 No examples section found
- numpydoc/tests/hooks/example_module.py:26: EX01 No examples section
found
+ {example_module!s}:58: ES01 No extended summary found
- numpydoc/tests/hooks/example_module.py:30: GL08 The object does not
have a docstring
+ {example_module!s}:58: PR01 Parameters {{'name'}} not documented
+
+ {example_module!s}:58: SA01 See Also section not found
+
+ {example_module!s}:58: EX01 No examples section found
"""
)
@@ -76,18 +93,20 @@
"""
expected = inspect.cleandoc(
- """
- numpydoc/tests/hooks/example_module.py:4: PR01 Parameters {'name'} not
documented
+ f"""
+ {example_module!s}:4: PR01 Parameters {{'name'}} not documented
+
+ {example_module!s}:11: GL08 The object does not have a docstring
- numpydoc/tests/hooks/example_module.py:11: GL08 The object does not
have a docstring
+ {example_module!s}:17: PR01 Parameters {{'**kwargs'}} not documented
- numpydoc/tests/hooks/example_module.py:17: PR01 Parameters
{'**kwargs'} not documented
+ {example_module!s}:17: PR07 Parameter "*args" has no description
- numpydoc/tests/hooks/example_module.py:17: PR07 Parameter "*args" has
no description
+ {example_module!s}:26: SS05 Summary must start with infinitive verb,
not third person (e.g. use "Generate" instead of "Generates")
- numpydoc/tests/hooks/example_module.py:26: SS05 Summary must start
with infinitive verb, not third person (e.g. use "Generate" instead of
"Generates")
+ {example_module!s}:30: GL08 The object does not have a docstring
- numpydoc/tests/hooks/example_module.py:30: GL08 The object does not
have a docstring
+ {example_module!s}:58: PR01 Parameters {{'name'}} not documented
"""
)
@@ -123,14 +142,14 @@
)
expected = inspect.cleandoc(
- """
- numpydoc/tests/hooks/example_module.py:4: PR01 Parameters {'name'} not
documented
+ f"""
+ {example_module!s}:4: PR01 Parameters {{'name'}} not documented
- numpydoc/tests/hooks/example_module.py:17: PR01 Parameters
{'**kwargs'} not documented
+ {example_module!s}:17: PR01 Parameters {{'**kwargs'}} not documented
- numpydoc/tests/hooks/example_module.py:17: PR07 Parameter "*args" has
no description
+ {example_module!s}:17: PR07 Parameter "*args" has no description
- numpydoc/tests/hooks/example_module.py:30: GL08 The object does not
have a docstring
+ {example_module!s}:30: GL08 The object does not have a docstring
"""
)
@@ -158,14 +177,14 @@
)
expected = inspect.cleandoc(
- """
- numpydoc/tests/hooks/example_module.py:4: PR01 Parameters {'name'} not
documented
+ f"""
+ {example_module!s}:4: PR01 Parameters {{'name'}} not documented
- numpydoc/tests/hooks/example_module.py:17: PR01 Parameters
{'**kwargs'} not documented
+ {example_module!s}:17: PR01 Parameters {{'**kwargs'}} not documented
- numpydoc/tests/hooks/example_module.py:17: PR07 Parameter "*args" has
no description
+ {example_module!s}:17: PR07 Parameter "*args" has no description
- numpydoc/tests/hooks/example_module.py:30: GL08 The object does not
have a docstring
+ {example_module!s}:30: GL08 The object does not have a docstring
"""
)
@@ -203,10 +222,10 @@
)
expected = inspect.cleandoc(
- """
- numpydoc/tests/hooks/example_module.py:4: PR01 Parameters {'name'} not
documented
+ f"""
+ {example_module!s}:4: PR01 Parameters {{'name'}} not documented
- numpydoc/tests/hooks/example_module.py:30: GL08 The object does not
have a docstring
+ {example_module!s}:30: GL08 The object does not have a docstring
"""
)
@@ -234,15 +253,83 @@
)
expected = inspect.cleandoc(
- """
- numpydoc/tests/hooks/example_module.py:4: PR01 Parameters {'name'} not
documented
+ f"""
+ {example_module!s}:4: PR01 Parameters {{'name'}} not documented
- numpydoc/tests/hooks/example_module.py:17: PR01 Parameters
{'**kwargs'} not documented
+ {example_module!s}:17: PR01 Parameters {{'**kwargs'}} not documented
- numpydoc/tests/hooks/example_module.py:17: PR07 Parameter "*args" has
no description
+ {example_module!s}:17: PR07 Parameter "*args" has no description
"""
)
return_code = run_hook([example_module], config=tmp_path)
assert return_code == 1
assert capsys.readouterr().err.strip() == expected
+
+
[email protected](
+ "file_exists, expected_code",
+ [(True, 0), (False, 1)],
+)
+def test_validate_hook_exclude_files_option_pyproject(
+ example_module, file_exists, expected_code, tmp_path
+):
+ """
+ Test that the hook correctly processes the toml config and either includes
+ or excludes files based on the `exclude_files` option.
+ """
+ exclude = str(example_module) if file_exists else "does_not_exist.py"
+
+ with open(tmp_path / "pyproject.toml", "w") as config_file:
+ config_file.write(
+ inspect.cleandoc(
+ f"""
+ [tool.numpydoc_validation]
+ checks = [
+ "all",
+ "EX01",
+ "SA01",
+ "ES01",
+ ]
+ exclude = '\\.__init__$'
+ override_SS05 = [
+ '^Creates',
+ ]
+ exclude_files = [
+ '{re.escape(exclude)}',
+ ]"""
+ )
+ )
+
+ return_code = run_hook([example_module], config=tmp_path)
+ assert return_code == expected_code # Should not-report/report findings.
+
+
[email protected](
+ "file_exists, expected_code",
+ [(True, 0), (False, 1)],
+)
+def test_validate_hook_exclude_files_option_setup_cfg(
+ example_module, file_exists, expected_code, tmp_path
+):
+ """
+ Test that the hook correctly processes the setup config and either includes
+ or excludes files based on the `exclude_files` option.
+ """
+ exclude = str(example_module) if file_exists else "does_not_exist.py"
+
+ with open(tmp_path / "setup.cfg", "w") as config_file:
+ config_file.write(
+ inspect.cleandoc(
+ f"""
+ [tool:numpydoc_validation]
+ checks = all,EX01,SA01,ES01
+ exclude = \\.NewClass$,\\.__init__$
+ override_SS05 = ^Creates
+ exclude_files = {re.escape(exclude)}
+ """
+ )
+ )
+
+ return_code = run_hook([example_module], config=tmp_path)
+ assert return_code == expected_code # Should not-report/report findings.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc/tests/test_docscrape.py
new/numpydoc-1.10.0/numpydoc/tests/test_docscrape.py
--- old/numpydoc-1.9.0/numpydoc/tests/test_docscrape.py 2025-06-24
14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/numpydoc/tests/test_docscrape.py 2025-12-02
17:38:37.000000000 +0100
@@ -6,7 +6,6 @@
import jinja2
import pytest
-from pytest import warns as assert_warns
from numpydoc.docscrape import ClassDoc, FunctionDoc, NumpyDocString
from numpydoc.docscrape_sphinx import (
@@ -187,7 +186,9 @@
def test_parameters(doc):
assert len(doc["Parameters"]) == 4
names = [n for n, _, _ in doc["Parameters"]]
- assert all(a == b for a, b in zip(names, ["mean", "cov", "shape"]))
+ assert all(
+ a == b for a, b in zip(names, ["mean", "cov", "shape", "dtype"],
strict=True)
+ )
arg, arg_type, desc = doc["Parameters"][1]
assert arg_type == "(N, N) ndarray"
@@ -209,7 +210,7 @@
def test_other_parameters(doc):
assert len(doc["Other Parameters"]) == 1
assert [n for n, _, _ in doc["Other Parameters"]] == ["spam"]
- arg, arg_type, desc = doc["Other Parameters"][0]
+ _arg, arg_type, desc = doc["Other Parameters"][0]
assert arg_type == "parrot"
assert desc[0].startswith("A parrot off its mortal coil")
@@ -242,7 +243,9 @@
("b", "int", "bananas."),
("", "int", "unknowns."),
]
- for (arg, arg_type, desc), (arg_, arg_type_, end) in zip(section, truth):
+ for (arg, arg_type, desc), (arg_, arg_type_, end) in zip(
+ section, truth, strict=True
+ ):
assert arg == arg_
assert arg_type == arg_type_
assert desc[0].startswith("The number of")
@@ -253,7 +256,9 @@
section = doc_sent["Receives"]
assert len(section) == 2
truth = [("b", "int", "bananas."), ("c", "int", "oranges.")]
- for (arg, arg_type, desc), (arg_, arg_type_, end) in zip(section, truth):
+ for (arg, arg_type, desc), (arg_, arg_type_, end) in zip(
+ section, truth, strict=True
+ ):
assert arg == arg_
assert arg_type == arg_type_
assert desc[0].startswith("The number of")
@@ -374,7 +379,7 @@
a = [l.rstrip() for l in _strip_blank_lines(a).split("\n")][:n_lines]
b = [l.rstrip() for l in _strip_blank_lines(b).split("\n")][:n_lines]
assert len(a) == len(b)
- for ii, (aa, bb) in enumerate(zip(a, b)):
+ for ii, (aa, bb) in enumerate(zip(a, b, strict=True)):
assert aa == bb
@@ -901,7 +906,7 @@
def test_see_also_trailing_comma_warning():
warnings.filterwarnings("error")
- with assert_warns(
+ with pytest.warns(
Warning,
match="Unexpected comma or period after function list at index 43 of
line .*",
):
@@ -994,13 +999,12 @@
def test_no_summary():
- str(
- SphinxDocString(
- """
- Parameters
- ----------"""
- )
+ ds = SphinxDocString(
+ """
+ Parameters
+ ----------"""
)
+ assert ds["Summary"] == [""]
def test_unicode():
@@ -1593,6 +1597,7 @@
# numpydoc.update_config fails if this config option not present
self.numpydoc_validation_checks = set()
self.numpydoc_validation_exclude = set()
+ self.numpydoc_validation_exclude_files = set()
self.numpydoc_validation_overrides = dict()
xref_aliases_complete = deepcopy(DEFAULT_LINKS)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc/tests/test_numpydoc.py
new/numpydoc-1.10.0/numpydoc/tests/test_numpydoc.py
--- old/numpydoc-1.9.0/numpydoc/tests/test_numpydoc.py 2025-06-24
14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/numpydoc/tests/test_numpydoc.py 2025-12-02
17:38:37.000000000 +0100
@@ -31,6 +31,7 @@
numpydoc_attributes_as_param_list = True
numpydoc_validation_checks = set()
numpydoc_validation_exclude = set()
+ numpydoc_validation_exclude_files = set()
numpydoc_validation_overrides = dict()
@@ -287,6 +288,61 @@
assert "id1" in citation["backrefs"]
[email protected](
+ "exclude_files, has_warnings",
+ [
+ (
+ [
+ r"^doesnt_match_any_file$",
+ ],
+ True,
+ ),
+ (
+ [
+ r"^.*test_numpydoc\.py$",
+ ],
+ False,
+ ),
+ ],
+)
+def test_mangle_skip_exclude_files(exclude_files, has_warnings):
+ """
+ Check that the regex expressions in numpydoc_validation_files_exclude
+ are correctly used to skip checks on files that match the patterns.
+ """
+
+ def process_something_noop_function():
+ """Process something."""
+
+ app = MockApp()
+ app.config.numpydoc_validation_checks = {"all"}
+
+ # Class attributes for config persist - need to reset them to unprocessed
states.
+ app.config.numpydoc_validation_exclude = set() # Reset to default...
+ app.config.numpydoc_validation_overrides = dict() # Reset to default...
+
+ app.config.numpydoc_validation_exclude_files = exclude_files
+ update_config(app)
+
+ # Setup for catching warnings
+ status, warning = StringIO(), StringIO()
+ logging.setup(app, status, warning)
+
+ # Simulate a file that matches the exclude pattern
+ mangle_docstrings(
+ app,
+ "function",
+ process_something_noop_function.__name__,
+ process_something_noop_function,
+ None,
+ process_something_noop_function.__doc__.split("\n"),
+ )
+
+ # Are warnings generated?
+ print(warning.getvalue())
+ assert bool(warning.getvalue()) is has_warnings
+
+
if __name__ == "__main__":
import pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc/tests/test_validate.py
new/numpydoc-1.10.0/numpydoc/tests/test_validate.py
--- old/numpydoc-1.9.0/numpydoc/tests/test_validate.py 2025-06-24
14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/numpydoc/tests/test_validate.py 2025-12-02
17:38:37.000000000 +0100
@@ -1,5 +1,6 @@
import warnings
from contextlib import nullcontext
+from dataclasses import dataclass
from functools import cached_property, partial, wraps
from inspect import getsourcefile, getsourcelines
@@ -1305,6 +1306,109 @@
pass
+class ConstructorDocumentedinEmbeddedClass: # ignore Gl08, ES01
+ """
+ Class to test the initialisation behaviour of a embedded class.
+ """
+
+ class EmbeddedClass1: # ignore GL08, ES01
+ """
+ An additional level for embedded class documentation checking.
+ """
+
+ class EmbeddedClass2:
+ """
+ This is an embedded class.
+
+ Extended summary.
+
+ Parameters
+ ----------
+ param1 : int
+ Description of param1.
+
+ See Also
+ --------
+ otherclass : A class that does something else.
+
+ Examples
+ --------
+ This is an example of how to use EmbeddedClass.
+ """
+
+ def __init__(self, param1: int) -> None:
+ pass
+
+
+class IncompleteConstructorDocumentedinEmbeddedClass:
+ """
+ Class to test the initialisation behaviour of a embedded class.
+ """
+
+ class EmbeddedClass1:
+ """
+ An additional level for embedded class documentation checking.
+ """
+
+ class EmbeddedClass2:
+ """
+ This is an embedded class.
+
+ Extended summary.
+
+ See Also
+ --------
+ otherclass : A class that does something else.
+
+ Examples
+ --------
+ This is an example of how to use EmbeddedClass.
+ """
+
+ def __init__(self, param1: int) -> None:
+ pass
+
+
+@dataclass
+class DataclassWithDocstring:
+ """
+ A class decorated by `dataclass`.
+
+ To check the functionality of `dataclass` objects do not break the
Validator.
+ As param1 is not documented this class should also raise PR01.
+ """
+
+ param1: int
+
+
+class ClassWithPropertyObject:
+ """
+ A class with a `property`.
+
+ To check the functionality of `property` objects do not break the
Validator.
+
+ Parameters
+ ----------
+ param1 : int
+ Description of param1.
+ """
+
+ def __init__(self, param1: int) -> None:
+ self._param1 = param1
+
+ @property
+ def param1(self) -> int:
+ """
+ Get the value of param1.
+
+ Returns
+ -------
+ int
+ The value of param1.
+ """
+ return self._param1
+
+
class TestValidator:
def _import_path(self, klass=None, func=None):
"""
@@ -1391,11 +1495,8 @@
],
)
def test_bad_generic_functions(self, capsys, func):
- with pytest.warns(UserWarning):
- errors = validate_one(
- self._import_path(klass="WarnGenericFormat", func=func)
- )
- assert "is too short" in w.msg
+ with pytest.warns(UserWarning, match="is too short"):
+ validate_one(self._import_path(klass="WarnGenericFormat",
func=func))
@pytest.mark.parametrize(
"func",
@@ -1660,6 +1761,18 @@
tuple(),
("PR01"), # Parameter not documented in class constructor
),
+ (
+
"ConstructorDocumentedinEmbeddedClass.EmbeddedClass1.EmbeddedClass2",
+ tuple(),
+ ("GL08",),
+ tuple(),
+ ),
+ (
+
"IncompleteConstructorDocumentedinEmbeddedClass.EmbeddedClass1.EmbeddedClass2",
+ ("GL08",),
+ tuple(),
+ ("PR01",),
+ ),
],
)
def test_constructor_docstrings(
@@ -1677,6 +1790,39 @@
for code in exc_init_codes:
assert code not in " ".join(err[0] for err in result["errors"])
+ if klass == "ConstructorDocumentedinEmbeddedClass":
+ raise NotImplementedError(
+ "Test for embedded class constructor docstring not implemented
yet."
+ )
+
+ def test_dataclass_object(self):
+ # Test validator methods complete execution on dataclass objects and
methods
+ # Test case ought to be removed if dataclass objects properly
supported.
+ result =
validate_one(self._import_path(klass="DataclassWithDocstring"))
+ # Check codes match as expected for dataclass objects.
+ errs = ["ES01", "SA01", "EX01", "PR01"]
+ for error in result["errors"]:
+ assert error[0] in errs
+ errs.remove(error[0])
+
+ # Test initialisation method (usually undocumented in dataclass)
raises any errors.
+ init_fn = self._import_path(klass="DataclassWithDocstring",
func="__init__")
+ result = validate_one(init_fn)
+ # Check that __init__ raises GL08 when the class docstring doesn't
document params.
+ assert result["errors"][0][0] == "GL08"
+
+ def test_property_object(self):
+ # Test validator methods complete execution on class property objects
+ # Test case ought to be removed if property objects properly supported.
+ result = validate_one(
+ self._import_path(klass="ClassWithPropertyObject", func="param1")
+ )
+ # Check codes match as expected for property objects.
+ errs = ["ES01", "SA01", "EX01"]
+ for error in result["errors"]:
+ assert error[0] in errs
+ errs.remove(error[0])
+
def decorator(x):
"""Test decorator."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc/validate.py
new/numpydoc-1.10.0/numpydoc/validate.py
--- old/numpydoc-1.9.0/numpydoc/validate.py 2025-06-24 14:22:17.000000000
+0200
+++ new/numpydoc-1.10.0/numpydoc/validate.py 2025-12-02 17:38:37.000000000
+0100
@@ -17,7 +17,7 @@
import textwrap
import tokenize
from copy import deepcopy
-from typing import Any, Dict, List, Optional, Set
+from typing import Any, Dict, List, Set
from .docscrape import get_doc_object
@@ -124,7 +124,7 @@
# and pandas, and they had between ~500 and ~1300 .py files as of 2023-08-16.
@functools.lru_cache(maxsize=2000)
def extract_ignore_validation_comments(
- filepath: Optional[os.PathLike],
+ filepath: os.PathLike | None,
encoding: str = "utf-8",
) -> Dict[int, List[str]]:
"""
@@ -572,6 +572,14 @@
return errs
+def _find_class_node(module_node: ast.AST, cls_name) -> ast.ClassDef:
+ # Find the class node within a module, when checking constructor
docstrings.
+ for node in ast.walk(module_node):
+ if isinstance(node, ast.ClassDef) and node.name == cls_name:
+ return node
+ raise ValueError(f"Could not find class node {cls_name}")
+
+
def validate(obj_name, validator_cls=None, **validator_kwargs):
"""
Validate the docstring.
@@ -639,20 +647,49 @@
report_GL08: bool = True
# Check if the object is a class and has a docstring in the constructor
# Also check if code_obj is defined, as undefined for the AstValidator
in validate_docstrings.py.
- if (
- doc.name.endswith(".__init__")
- and doc.is_function_or_method
- and hasattr(doc, "code_obj")
- ):
- cls_name = doc.code_obj.__qualname__.split(".")[0]
- cls = Validator._load_obj(f"{doc.code_obj.__module__}.{cls_name}")
- # cls = Validator._load_obj(f"{doc.name[:-9]}.{cls_name}") ##
Alternative
- cls_doc = Validator(get_doc_object(cls))
+ if doc.is_function_or_method and doc.name.endswith(".__init__"):
+ # Import here at runtime to avoid circular import as
+ # AstValidator is a subclass of Validator class without `doc_obj`
attribute.
+ from numpydoc.hooks.validate_docstrings import (
+ AstValidator, # Support abstract syntax tree hook.
+ )
+
+ if hasattr(doc, "code_obj"): # All Validator objects have this
attr.
+ cls_name = ".".join(
+ doc.code_obj.__qualname__.split(".")[:-1]
+ ) # Collect all class depths before the constructor.
+ cls =
Validator._load_obj(f"{doc.code_obj.__module__}.{cls_name}")
+ # cls = Validator._load_obj(f"{doc.name[:-9]}.{cls_name}") ##
Alternative
+ cls_doc = Validator(get_doc_object(cls))
+ elif isinstance(doc, AstValidator): # Supports class traversal
for ASTs.
+ ancestry = doc.ancestry
+ if len(ancestry) > 2: # e.g. module.class.__init__
+ parent = doc.ancestry[-1] # Get the parent
+ cls_name = ".".join(
+ [
+ getattr(node, "name", node.__module__)
+ for node in doc.ancestry
+ ]
+ )
+ cls_doc = AstValidator(
+ ast_node=parent,
+ filename=doc.source_file_name,
+ obj_name=cls_name,
+ ancestry=doc.ancestry[:-1],
+ )
+ else:
+ # Ignore edge case: __init__ functions that don't belong
to a class.
+ cls_doc = None
+ else:
+ raise TypeError(
+ f"Cannot load {doc.name} as a usable Validator object
(Validator does not have `doc_obj` attr or type `AstValidator`)."
+ )
# Parameter_mismatches, PR01, PR02, PR03 are checked for the class
docstring.
# If cls_doc has PR01, PR02, PR03 errors, i.e. invalid class
docstring,
# then we also report missing constructor docstring, GL08.
- report_GL08 = len(cls_doc.parameter_mismatches) > 0
+ if cls_doc:
+ report_GL08 = len(cls_doc.parameter_mismatches) > 0
# Check if GL08 is to be ignored:
if "GL08" in ignore_validation_comments:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc.egg-info/PKG-INFO
new/numpydoc-1.10.0/numpydoc.egg-info/PKG-INFO
--- old/numpydoc-1.9.0/numpydoc.egg-info/PKG-INFO 2025-06-24
14:22:24.000000000 +0200
+++ new/numpydoc-1.10.0/numpydoc.egg-info/PKG-INFO 2025-12-02
17:38:47.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: numpydoc
-Version: 1.9.0
+Version: 1.10.0
Summary: Sphinx extension to support docstrings in Numpy format
Author-email: Pauli Virtanen and others <[email protected]>
License: Copyright (C) 2008-2023 Stefan van der Walt <[email protected]>,
Pauli Virtanen <[email protected]>
@@ -38,13 +38,12 @@
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Documentation
-Requires-Python: >=3.9
+Requires-Python: >=3.10
Description-Content-Type: text/x-rst
License-File: LICENSE.txt
Requires-Dist: sphinx>=6
@@ -70,7 +69,7 @@
The extension also adds the code description directives
``np:function``, ``np-c:function``, etc.
-numpydoc requires Python 3.9+ and sphinx 6+.
+numpydoc requires Python 3.10+ and sphinx 6+.
For usage information, please refer to the `documentation
<https://numpydoc.readthedocs.io/>`_.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/numpydoc.egg-info/SOURCES.txt
new/numpydoc-1.10.0/numpydoc.egg-info/SOURCES.txt
--- old/numpydoc-1.9.0/numpydoc.egg-info/SOURCES.txt 2025-06-24
14:22:24.000000000 +0200
+++ new/numpydoc-1.10.0/numpydoc.egg-info/SOURCES.txt 2025-12-02
17:38:47.000000000 +0100
@@ -40,7 +40,6 @@
numpydoc/tests/test_numpydoc.py
numpydoc/tests/test_validate.py
numpydoc/tests/test_xref.py
-numpydoc/tests/hooks/__init__.py
numpydoc/tests/hooks/example_module.py
numpydoc/tests/hooks/test_utils.py
numpydoc/tests/hooks/test_validate_hook.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/numpydoc-1.9.0/pyproject.toml
new/numpydoc-1.10.0/pyproject.toml
--- old/numpydoc-1.9.0/pyproject.toml 2025-06-24 14:22:17.000000000 +0200
+++ new/numpydoc-1.10.0/pyproject.toml 2025-12-02 17:38:37.000000000 +0100
@@ -6,7 +6,7 @@
name = 'numpydoc'
description = 'Sphinx extension to support docstrings in Numpy format'
readme = 'README.rst'
-requires-python = '>=3.9'
+requires-python = '>=3.10'
dynamic = ['version']
keywords = [
'sphinx',
@@ -20,7 +20,6 @@
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
- 'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
@@ -46,7 +45,6 @@
[dependency-groups]
dev = [
'pre-commit>=3.3',
- "tomli; python_version < '3.11'",
{ include-group = "doc" },
{ include-group = "test" }
]
@@ -100,6 +98,7 @@
ignore = [
"PLR09", # Too many <...>
"PLR2004", # Magic value used in comparison
+ "PLC0415", # Imports not at top of file (we often nest intentionally)
"ISC001", # Conflicts with formatter
"ARG001", # FIXME: consider removing this and the following rules from
this list
"ARG002",
@@ -169,6 +168,7 @@
[tool.setuptools.package-data]
numpydoc = [
'tests/test_*.py',
+ 'tests/hooks/test_*.py',
'tests/tinybuild/Makefile',
'tests/tinybuild/index.rst',
'tests/tinybuild/*.py',