From 2431739e0bec247550dfaf76797a036d32ff4f3f Mon Sep 17 00:00:00 2001 From: Chiara Marmo Date: Tue, 9 Jan 2024 15:46:55 +0100 Subject: [PATCH 01/92] Filter `DeprecationWarning` in failing test for python 3.12 (#523) * Filter DeprecationWarning. * Update python versions in CI. * Apply suggestions from code review Co-authored-by: Eric Larson --------- Co-authored-by: Eric Larson --- .github/workflows/test.yml | 4 ++-- numpydoc/tests/test_validate.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1af5e7a5..3d9c7979 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: os: [Ubuntu] - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] sphinx-version: [ "sphinx==5.0", @@ -76,7 +76,7 @@ jobs: strategy: matrix: os: [ubuntu] - python-version: ["3.9", "3.10"] + python-version: ["3.11", "3.12"] steps: - uses: actions/checkout@v4 diff --git a/numpydoc/tests/test_validate.py b/numpydoc/tests/test_validate.py index d41e4bd0..0671684b 100644 --- a/numpydoc/tests/test_validate.py +++ b/numpydoc/tests/test_validate.py @@ -1348,6 +1348,7 @@ def test_bad_generic_functions(self, capsys, func): assert isinstance(errors, list) assert errors + @pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.parametrize( "klass,func,msgs", [ From eb08110922fba1330daa40101386b87cc8a207ae Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Tue, 9 Jan 2024 10:18:40 -0500 Subject: [PATCH 02/92] MAINT: Replace NameConstant with Constant (#524) --- numpydoc/tests/test_validate.py | 1 - numpydoc/validate.py | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/numpydoc/tests/test_validate.py b/numpydoc/tests/test_validate.py index 0671684b..d41e4bd0 100644 --- a/numpydoc/tests/test_validate.py +++ b/numpydoc/tests/test_validate.py @@ -1348,7 +1348,6 @@ def test_bad_generic_functions(self, capsys, func): assert isinstance(errors, list) assert errors - @pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.parametrize( "klass,func,msgs", [ diff --git a/numpydoc/validate.py b/numpydoc/validate.py index 7275758b..0f939166 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -521,9 +521,9 @@ def get_returns_not_on_nested_functions(node): if tree: returns = get_returns_not_on_nested_functions(tree[0]) return_values = [r.value for r in returns] - # Replace NameConstant nodes valued None for None. + # Replace Constant nodes valued None for None. for i, v in enumerate(return_values): - if isinstance(v, ast.NameConstant) and v.value is None: + if isinstance(v, ast.Constant) and v.value is None: return_values[i] = None return any(return_values) else: From 8e2d545131fc2a124dd01d749c385f827bb1072b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 12:25:37 -0500 Subject: [PATCH 03/92] [pre-commit.ci] pre-commit autoupdate (#526) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: ec91a2be3c44d88e1a3960a4937ad6ed3b63464e → e026c93888f91a47a9c9f4e029f3eb07d96375e6](https://github.com/psf/black/compare/ec91a2be3c44d88e1a3960a4937ad6ed3b63464e...e026c93888f91a47a9c9f4e029f3eb07d96375e6) * '[pre-commit.ci 🤖] Apply code format tools to PR' --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- numpydoc/__init__.py | 1 + numpydoc/__main__.py | 1 + numpydoc/docscrape.py | 1 + numpydoc/docscrape_sphinx.py | 8 +++++--- numpydoc/numpydoc.py | 1 + 6 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 25b53f36..aea73365 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,7 +17,7 @@ repos: - id: check-added-large-files - repo: https://github.com/psf/black - rev: ec91a2be3c44d88e1a3960a4937ad6ed3b63464e # frozen: 23.12.1 + rev: e026c93888f91a47a9c9f4e029f3eb07d96375e6 # frozen: 24.1.1 hooks: - id: black diff --git a/numpydoc/__init__.py b/numpydoc/__init__.py index 97f53053..5458b67f 100644 --- a/numpydoc/__init__.py +++ b/numpydoc/__init__.py @@ -2,6 +2,7 @@ This package provides the numpydoc Sphinx extension for handling docstrings formatted according to the NumPy documentation format. """ + from ._version import __version__ diff --git a/numpydoc/__main__.py b/numpydoc/__main__.py index 4a50da9b..53d5c504 100644 --- a/numpydoc/__main__.py +++ b/numpydoc/__main__.py @@ -1,6 +1,7 @@ """ Implementing `python -m numpydoc` functionality. """ + import sys import argparse import ast diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index 315be6c3..4fbbe63c 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -1,6 +1,7 @@ """Extract reference documentation from the NumPy source tree. """ + import inspect import textwrap import re diff --git a/numpydoc/docscrape_sphinx.py b/numpydoc/docscrape_sphinx.py index 26a8e6b3..771c1ea4 100644 --- a/numpydoc/docscrape_sphinx.py +++ b/numpydoc/docscrape_sphinx.py @@ -373,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()} diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 335de5a8..3513f95c 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -16,6 +16,7 @@ .. [1] https://github.com/numpy/numpydoc """ + from copy import deepcopy import re import pydoc From 46f532a824639a97479039fc122533915cdfa10f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niko=20F=C3=B6hr?= Date: Tue, 20 Feb 2024 07:26:06 +0200 Subject: [PATCH 04/92] fix 'Alias for field number X' problem with NamedTuples (#527) * fix 'Alias for field number X' problem with NamedTuples * TST: Add test for duplicated attrs w/ namedtuples. * TST: Add test of explicitly documented namedtuple params. --------- Co-authored-by: Ross Barnowski --- numpydoc/docscrape.py | 14 ++++++++ numpydoc/tests/test_docscrape.py | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index 4fbbe63c..fb3a0b63 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -706,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)) @@ -715,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 diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index 5077c425..8bbcdc53 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -1641,6 +1641,63 @@ def val(self): assert class_docstring["Attributes"][0].name == "val" +def test_namedtuple_no_duplicate_attributes(): + """ + Ensure that attributes of namedtuples are not duplicated in the docstring. + + See gh-257 + """ + from collections import namedtuple + + foo = namedtuple("Foo", ("bar", "baz")) + + # Create the SphinxClassDoc object via get_doc_object + sds = get_doc_object(foo) + assert sds["Attributes"] == [] + + +def test_namedtuple_class_docstring(): + """Ensure that class docstring is preserved when inheriting from namedtuple. + + See gh-257 + """ + from collections import namedtuple + + foo = namedtuple("Foo", ("bar", "baz")) + + class MyFoo(foo): + """MyFoo's class docstring""" + + # Create the SphinxClassDoc object via get_doc_object + sds = get_doc_object(MyFoo) + assert sds["Summary"] == ["MyFoo's class docstring"] + + # Example dataclass where constructor params are documented explicit. + # Parameter names/descriptions should be included in the docstring, but + # should not result in a duplicated `Attributes` section + class MyFooWithParams(foo): + """ + MyFoo's class docstring + + Parameters + ---------- + bar : str + The bar attribute + baz : str + The baz attribute + """ + + bar: str + baz: str + + sds = get_doc_object(MyFooWithParams) + assert "MyFoo's class docstring" in sds["Summary"] + assert len(sds["Attributes"]) == 0 + assert len(sds["Parameters"]) == 2 + assert sds["Parameters"][0].desc[0] == "The bar attribute" + assert sds["Parameters"][1].desc[0] == "The baz attribute" + + if __name__ == "__main__": import pytest From c334ca84e3d2cee3da8733dac74daa457283440e Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Tue, 5 Mar 2024 19:05:06 -0800 Subject: [PATCH 05/92] Update precommit repos (#531) --- .pre-commit-config.yaml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index aea73365..859fcf48 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,15 +17,14 @@ repos: - id: check-added-large-files - repo: https://github.com/psf/black - rev: e026c93888f91a47a9c9f4e029f3eb07d96375e6 # frozen: 24.1.1 + rev: 6fdf8a4af28071ed1d079c01122b34c5d587207a # frozen: 24.2.0 hooks: - id: black - repo: https://github.com/pre-commit/mirrors-prettier - rev: f12edd9c7be1c20cfa42420fd0e6df71e42b51ea # frozen: v4.0.0-alpha.8 + rev: ffb6a759a979008c0e6dff86e39f4745a2d9eac4 # frozen: v3.1.0 hooks: - id: prettier - entry: env PRETTIER_LEGACY_CLI=1 prettier # temporary fix for https://github.com/prettier/prettier/issues/15742 files: \.(html|md|yml|yaml) args: [--prose-wrap=preserve] @@ -35,7 +34,7 @@ repos: - id: blacken-docs - repo: https://github.com/asottile/pyupgrade - rev: 1bbebc88c6925a4e56fd5446b830b12c38c1c24a # frozen: v3.15.0 + rev: df17dfa3911b81b4a27190b0eea5b1debc7ffa0a # frozen: v3.15.1 hooks: - id: pyupgrade args: [--py38-plus] @@ -49,10 +48,7 @@ repos: files: "pyproject.toml|requirements/.*\\.txt|tools/generate_requirements.py" ci: - # This ensures that pr's aren't autofixed by the bot, rather you call - # the bot to make the fix autofix_prs: false autofix_commit_msg: | '[pre-commit.ci 🤖] Apply code format tools to PR' - # Update hook versions every month (so we don't get hit with weekly update pr's) - autoupdate_schedule: monthly + autoupdate_schedule: quarterly From c26538cd34e97ed6260d1232aba8b194e24815cc Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Tue, 5 Mar 2024 19:05:20 -0800 Subject: [PATCH 06/92] Add Python 3.12 to classifiers (#529) --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 374008b5..2ce34f74 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,6 +23,7 @@ classifiers = [ 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', ] dependencies = [ 'sphinx>=5', From 1e60071efe674328fdbc007e5792ebcf1ca6bbbf Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Wed, 6 Mar 2024 07:07:07 -0800 Subject: [PATCH 07/92] Require sphinx 6 (#530) --- .github/workflows/test.yml | 8 +------- pyproject.toml | 3 +-- requirements/default.txt | 3 +-- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3d9c7979..98b4d79b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,13 +18,7 @@ jobs: os: [Ubuntu] python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] sphinx-version: - [ - "sphinx==5.0", - "sphinx==5.3", - "sphinx==6.0", - "sphinx==6.2", - "sphinx>=7.0", - ] + ["sphinx==6.0", "sphinx==6.2", "sphinx==7.0", "sphinx>=7.2"] steps: - uses: actions/checkout@v4 diff --git a/pyproject.toml b/pyproject.toml index 2ce34f74..7742516d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,8 +26,7 @@ classifiers = [ 'Programming Language :: Python :: 3.12', ] dependencies = [ - 'sphinx>=5', - 'Jinja2>=2.10', + 'sphinx>=6', 'tabulate>=0.8.10', "tomli>=1.1.0;python_version<'3.11'", ] diff --git a/requirements/default.txt b/requirements/default.txt index 1b80561c..5a1986a1 100644 --- a/requirements/default.txt +++ b/requirements/default.txt @@ -1,6 +1,5 @@ # Generated via tools/generate_requirements.py and pre-commit hook. # Do not edit this file; modify pyproject.toml instead. -sphinx>=5 -Jinja2>=2.10 +sphinx>=6 tabulate>=0.8.10 tomli>=1.1.0;python_version<'3.11' From 19167fe935d8080665ce1d5c65a9312b04822e23 Mon Sep 17 00:00:00 2001 From: Philipp Hoffmann Date: Wed, 20 Mar 2024 18:55:34 +0100 Subject: [PATCH 08/92] PERF, validation: wrap inspect.getsourcelines with cache (#532) * wrap inspect.getsourcelines with cache --- numpydoc/validate.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/numpydoc/validate.py b/numpydoc/validate.py index 0f939166..da94665e 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -7,7 +7,7 @@ """ from copy import deepcopy -from typing import Dict, List, Set, Optional +from typing import Dict, List, Set, Optional, Any import ast import collections import functools @@ -116,7 +116,7 @@ # We have to balance memory usage with performance here. It shouldn't be too # bad to store these `dict`s (they should be rare), but to be safe let's keep # the limit low-ish. This was set by looking at scipy, numpy, matplotlib, -# and pandas and they had between ~500 and ~1300 .py files as of 2023-08-16. +# 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], @@ -212,7 +212,7 @@ def error(code, **kwargs): message : str Error message with variables replaced. """ - return (code, ERROR_MSGS[code].format(**kwargs)) + return code, ERROR_MSGS[code].format(**kwargs) class Validator: @@ -290,12 +290,18 @@ def source_file_name(self): except TypeError: # In some cases the object is something complex like a cython - # object that can't be easily introspected. An it's better to + # object that can't be easily introspected. And it's better to # return the source code file of the object as None, than crash pass else: return fname + # When calling validate, files are parsed twice + @staticmethod + @functools.lru_cache(maxsize=4000) + def _getsourcelines(obj: Any): + return inspect.getsourcelines(obj) + @property def source_file_def_line(self): """ @@ -303,11 +309,11 @@ def source_file_def_line(self): """ try: if isinstance(self.code_obj, property): - sourcelines = inspect.getsourcelines(self.code_obj.fget) + sourcelines = self._getsourcelines(self.code_obj.fget) elif isinstance(self.code_obj, functools.cached_property): - sourcelines = inspect.getsourcelines(self.code_obj.func) + sourcelines = self._getsourcelines(self.code_obj.func) else: - sourcelines = inspect.getsourcelines(self.code_obj) + sourcelines = self._getsourcelines(self.code_obj) # getsourcelines will return the line of the first decorator found for the # current function. We have to find the def declaration after that. def_line = next( @@ -320,7 +326,7 @@ def source_file_def_line(self): return sourcelines[-1] + def_line except (OSError, TypeError): # In some cases the object is something complex like a cython - # object that can't be easily introspected. An it's better to + # object that can't be easily introspected. And it's better to # return the line number as None, than crash pass @@ -613,7 +619,7 @@ def validate(obj_name, validator_cls=None, **validator_kwargs): else: doc = validator_cls(obj_name=obj_name, **validator_kwargs) - # lineno is only 0 if we have a module docstring in the file and we are + # lineno is only 0 if we have a module docstring in the file, and we are # validating that, so we change to 1 for readability of the output ignore_validation_comments = extract_ignore_validation_comments( doc.source_file_name From aaafe135bf460cdd45ce362c47c98dfe8fee6143 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Fri, 22 Mar 2024 08:27:17 -0700 Subject: [PATCH 09/92] Use trusted publisher (#533) --- .github/workflows/release.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..1829de41 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,34 @@ +name: Build Wheel and Release +on: + push: + tags: + - v* + +jobs: + pypi-publish: + name: upload release to PyPI + if: github.repository_owner == 'numpy' && startsWith(github.ref, 'refs/tags/v') && github.actor == 'jarrodmillman' && always() + runs-on: ubuntu-latest + # Specifying a GitHub environment is optional, but strongly encouraged + environment: release + permissions: + # IMPORTANT: this permission is mandatory for trusted publishing + id-token: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-python@v5 + name: Install Python + with: + python-version: "3.12" + + - name: Build wheels + run: | + git clean -fxd + pip install -U build twine wheel + python -m build --sdist --wheel + + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 From fd451ec48cbeee773f62b1517df1fd312afb9044 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Fri, 22 Mar 2024 09:20:59 -0700 Subject: [PATCH 10/92] Update release process (#534) --- RELEASE.rst | 40 +++++++++++++++------- doc/index.rst | 2 +- doc/release/index.rst | 12 +++++++ doc/{release_notes.rst => release/old.rst} | 19 ---------- pyproject.toml | 5 +++ 5 files changed, 45 insertions(+), 33 deletions(-) create mode 100644 doc/release/index.rst rename doc/{release_notes.rst => release/old.rst} (97%) diff --git a/RELEASE.rst b/RELEASE.rst index f4390f02..93524d9a 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -6,24 +6,36 @@ Introduction Example ``__version__`` -- 1.8.dev0 # development version of 1.8 (release candidate 1) -- 1.8rc1 # 1.8 release candidate 1 -- 1.8rc2.dev0 # development version of 1.8 (release candidate 2) +- 1.8rc0.dev0 # development version of 1.8 (first release candidate) +- 1.8rc0 # 1.8 release candidate 1 +- 1.8rc1.dev0 # development version of 1.8 (second release candidate) - 1.8 # 1.8 release -- 1.9.dev0 # development version of 1.9 (release candidate 1) +- 1.9rc0.dev0 # development version of 1.9 (first release candidate) Test release candidates on numpy, scipy, matplotlib, scikit-image, and networkx. Process ------- -- Review and update ``doc/release_notes.rst``. +- Set release variables:: + + export VERSION= + export PREVIOUS= + export ORG="numpy" + export REPO="numpydoc" + export LOG="doc/release/notes.rst" + +- Autogenerate release notes:: + + changelist ${ORG}/${REPO} v${PREVIOUS} main --version ${VERSION} --config pyproject.toml --format rst --out ${VERSION}.rst + changelist ${ORG}/${REPO} v${PREVIOUS} main --version ${VERSION} --config pyproject.toml --out ${VERSION}.md + cat ${VERSION}.rst | cat - ${LOG} > temp && mv temp ${LOG} && rm ${VERSION}.rst - Update ``__version__`` in ``numpydoc/_version.py``. - Commit changes:: - git add numpydoc/_version.py doc/release_notes.rst + git add numpydoc/_version.py ${LOG} git commit -m 'Designate release' - Add the version number (e.g., `v1.2.0`) as a tag in git:: @@ -39,16 +51,18 @@ Process where ``origin`` is the name of the ``github.com:numpy/numpydoc`` repository -- Review the github release page:: +- Create release from tag:: + + - go to https://github.com/numpy/numpydoc/releases/new?tag=v${VERSION} + - add v${VERSION} for the `Release title` + - paste contents (or upload) of ${VERSION}.md in the `Describe this release section` + - if pre-release check the box labelled `Set as a pre-release` - https://github.com/numpy/numpydoc/releases -- Publish on PyPi:: +- Update https://github.com/numpy/numpydoc/milestones:: - git clean -fxd - pip install --upgrade build wheel twine - python -m build --sdist --wheel - twine upload -s dist/* + - close old milestone + - ensure new milestone exists (perhaps setting due date) - Update ``__version__`` in ``numpydoc/_version.py``. diff --git a/doc/index.rst b/doc/index.rst index 389e3cb1..240bb5b5 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -23,5 +23,5 @@ Sphinx, and adds the code description directives ``np:function``, install format validation - release_notes + release/index example diff --git a/doc/release/index.rst b/doc/release/index.rst new file mode 100644 index 00000000..ebd12250 --- /dev/null +++ b/doc/release/index.rst @@ -0,0 +1,12 @@ +Release notes +============= + +.. toctree:: + :maxdepth: 2 + + old + +.. note:: + + For release notes (sparsely) kept prior to 1.0.0, look at the `releases page + on GitHub `__. diff --git a/doc/release_notes.rst b/doc/release/old.rst similarity index 97% rename from doc/release_notes.rst rename to doc/release/old.rst index 2f64f4cb..a75c129d 100644 --- a/doc/release_notes.rst +++ b/doc/release/old.rst @@ -1,22 +1,3 @@ -Release notes -============= - -.. roughly following https://sphinx-gallery.github.io/dev/maintainers.html, -.. 1.0.0 notes were generated by: -.. 1. tagging PRs as enhancement/bug/removed -.. 2. $ github_changelog_generator -u numpy -p numpydoc --since-tag=v0.9.2 -.. 3. $ pandoc CHANGELOG.md --wrap=none -o release_notes.rst -.. 4. adding a manual addition (CSS note), tweaking heading levels, adding TOC - -.. contents:: Page contents - :local: - :depth: 2 - -.. note:: - - For release notes (sparsely) kept prior to 1.0.0, look at the `releases page - on GitHub `__. - 1.6.0 ----- diff --git a/pyproject.toml b/pyproject.toml index 7742516d..de570e34 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,11 @@ test = [ [project.scripts] validate-docstrings = 'numpydoc.hooks.validate_docstrings:main' +[tool.changelist] +title_template = "{version}" +# Profiles that are excluded from the contributor list. +ignored_user_logins = ["dependabot[bot]", "pre-commit-ci[bot]"] + [tool.setuptools] include-package-data = false packages = [ From 6629e9f2a77c2706fc96996bb52919265469a362 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Fri, 22 Mar 2024 09:41:06 -0700 Subject: [PATCH 11/92] Designate 1.7.0rc0 release --- doc/release/index.rst | 1 + doc/release/notes.rst | 67 +++++++++++++++++++++++++++++++++++++++++++ numpydoc/_version.py | 2 +- 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 doc/release/notes.rst diff --git a/doc/release/index.rst b/doc/release/index.rst index ebd12250..de1bbfee 100644 --- a/doc/release/index.rst +++ b/doc/release/index.rst @@ -4,6 +4,7 @@ Release notes .. toctree:: :maxdepth: 2 + notes old .. note:: diff --git a/doc/release/notes.rst b/doc/release/notes.rst new file mode 100644 index 00000000..ae631c2e --- /dev/null +++ b/doc/release/notes.rst @@ -0,0 +1,67 @@ +1.7.0rc0 +======== + +We're happy to announce the release of numpydoc 1.7.0rc0! + +Enhancements +------------ + +- PERF: wrap inspect.getsourcelines with cache (`#532 `_). + +Bug Fixes +--------- + +- during tokenize, use UTF8 encoding on all platforms (`#510 `_). +- fix 'Alias for field number X' problem with NamedTuples (`#527 `_). + +Documentation +------------- + +- DOC: Fix typos found by codespell (`#514 `_). +- DOC: Update link to mailing list (`#518 `_). +- Add Python 3.12 to classifiers (`#529 `_). + +Maintenance +----------- + +- [pre-commit.ci] pre-commit autoupdate (`#508 `_). +- [pre-commit.ci] pre-commit autoupdate (`#513 `_). +- MAINT: apply refurb suggestion (`#515 `_). +- [pre-commit.ci] pre-commit autoupdate (`#516 `_). +- Bump actions/setup-python from 4 to 5 (`#520 `_). +- [pre-commit.ci] pre-commit autoupdate (`#521 `_). +- Filter ``DeprecationWarning`` in failing test for python 3.12 (`#523 `_). +- MAINT: Replace NameConstant with Constant (`#524 `_). +- [pre-commit.ci] pre-commit autoupdate (`#526 `_). +- Update precommit repos (`#531 `_). +- Require sphinx 6 (`#530 `_). +- Use trusted publisher (`#533 `_). + +Contributors +------------ + +8 authors added to this release (alphabetically): + +- Chiara Marmo (`@cmarmo `_) +- Daniel McCloy (`@drammock `_) +- Dimitri Papadopoulos Orfanos (`@DimitriPapadopoulos `_) +- Eric Larson (`@larsoner `_) +- Jarrod Millman (`@jarrodmillman `_) +- Niko Föhr (`@fohrloop `_) +- Philipp Hoffmann (`@dontgoto `_) +- Ross Barnowski (`@rossbar `_) + +9 reviewers added to this release (alphabetically): + +- Antoine Pitrou (`@pitrou `_) +- Charles Harris (`@charris `_) +- Daniel McCloy (`@drammock `_) +- Eric Larson (`@larsoner `_) +- GitHub Web Flow (`@web-flow `_) +- Jarrod Millman (`@jarrodmillman `_) +- Niko Föhr (`@fohrloop `_) +- Ross Barnowski (`@rossbar `_) +- Stefan van der Walt (`@stefanv `_) + +_These lists are automatically generated, and may not be complete or may contain +duplicates._ diff --git a/numpydoc/_version.py b/numpydoc/_version.py index 8b264c14..6eff2c81 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.7.0rc0.dev0" +__version__ = "1.7.0rc0" From 42cdcb15bc0492d1f15abc1ccd49916423a61230 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Fri, 22 Mar 2024 09:45:28 -0700 Subject: [PATCH 12/92] Bump version --- numpydoc/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpydoc/_version.py b/numpydoc/_version.py index 6eff2c81..3667106e 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.7.0rc0" +__version__ = "1.7.0rc1.dev0" From f558dbf6c928959d07988a7d0eaca864b7e32d04 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Fri, 22 Mar 2024 10:20:58 -0700 Subject: [PATCH 13/92] Update release process (#535) --- RELEASE.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASE.rst b/RELEASE.rst index 93524d9a..21781bc9 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -36,11 +36,11 @@ Process - Commit changes:: git add numpydoc/_version.py ${LOG} - git commit -m 'Designate release' + git commit -m "Designate ${VERSION} release" - Add the version number (e.g., `v1.2.0`) as a tag in git:: - git tag -s [-u ] v -m 'signed tag' + git tag -s v${VERSION} -m "signed ${VERSION} tag" If you do not have a gpg key, use -u instead; it is important for Debian packaging that the tags are annotated From b5ef4f56fff035c349303adab323ff5c5cdc4dd9 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Thu, 28 Mar 2024 04:49:29 -0700 Subject: [PATCH 14/92] Designate 1.7.0 release --- doc/release/notes.rst | 11 ++++++----- numpydoc/_version.py | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/release/notes.rst b/doc/release/notes.rst index ae631c2e..3dca7339 100644 --- a/doc/release/notes.rst +++ b/doc/release/notes.rst @@ -1,7 +1,7 @@ -1.7.0rc0 -======== +1.7.0 +===== -We're happy to announce the release of numpydoc 1.7.0rc0! +We're happy to announce the release of numpydoc 1.7.0! Enhancements ------------ @@ -20,6 +20,8 @@ Documentation - DOC: Fix typos found by codespell (`#514 `_). - DOC: Update link to mailing list (`#518 `_). - Add Python 3.12 to classifiers (`#529 `_). +- Update release process (`#534 `_). +- Update release process (`#535 `_). Maintenance ----------- @@ -63,5 +65,4 @@ Contributors - Ross Barnowski (`@rossbar `_) - Stefan van der Walt (`@stefanv `_) -_These lists are automatically generated, and may not be complete or may contain -duplicates._ +_These lists are automatically generated, and may not be complete or may contain duplicates._ diff --git a/numpydoc/_version.py b/numpydoc/_version.py index 3667106e..14d9d2f5 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.7.0rc1.dev0" +__version__ = "1.7.0" From d6a4d3886b98c63742e5c380966298f8ef28472e Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Thu, 28 Mar 2024 04:52:59 -0700 Subject: [PATCH 15/92] Bump version --- numpydoc/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpydoc/_version.py b/numpydoc/_version.py index 14d9d2f5..df1d1074 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.7.0" +__version__ = "1.8.0rc0.dev0" From 113bc28eddddbcdf342b184193841751b6b02d76 Mon Sep 17 00:00:00 2001 From: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Date: Sat, 30 Mar 2024 14:40:26 -0400 Subject: [PATCH 16/92] Fix typo in label-check.yml (#538) --- .github/workflows/label-check.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-check.yml b/.github/workflows/label-check.yml index 5c4aee62..d6e97f22 100644 --- a/.github/workflows/label-check.yml +++ b/.github/workflows/label-check.yml @@ -4,7 +4,7 @@ on: pull_request: types: - opened - - repoened + - reopened - labeled - unlabeled - synchronize From defebb1d5ffcef5f53c05a15091dbad2118ecd98 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Apr 2024 13:35:38 -0400 Subject: [PATCH 17/92] [pre-commit.ci] pre-commit autoupdate (#539) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: 6fdf8a4af28071ed1d079c01122b34c5d587207a → 552baf822992936134cbd31a38f69c8cfe7c0f05](https://github.com/psf/black/compare/6fdf8a4af28071ed1d079c01122b34c5d587207a...552baf822992936134cbd31a38f69c8cfe7c0f05) - [github.com/pre-commit/mirrors-prettier: ffb6a759a979008c0e6dff86e39f4745a2d9eac4 → f12edd9c7be1c20cfa42420fd0e6df71e42b51ea](https://github.com/pre-commit/mirrors-prettier/compare/ffb6a759a979008c0e6dff86e39f4745a2d9eac4...f12edd9c7be1c20cfa42420fd0e6df71e42b51ea) - [github.com/asottile/pyupgrade: df17dfa3911b81b4a27190b0eea5b1debc7ffa0a → 12af25eb252deaaecb6b259df40d01f42e716dc3](https://github.com/asottile/pyupgrade/compare/df17dfa3911b81b4a27190b0eea5b1debc7ffa0a...12af25eb252deaaecb6b259df40d01f42e716dc3) * '[pre-commit.ci 🤖] Apply code format tools to PR' --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 859fcf48..6dec8b89 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,12 +17,12 @@ repos: - id: check-added-large-files - repo: https://github.com/psf/black - rev: 6fdf8a4af28071ed1d079c01122b34c5d587207a # frozen: 24.2.0 + rev: 552baf822992936134cbd31a38f69c8cfe7c0f05 # frozen: 24.3.0 hooks: - id: black - repo: https://github.com/pre-commit/mirrors-prettier - rev: ffb6a759a979008c0e6dff86e39f4745a2d9eac4 # frozen: v3.1.0 + rev: f12edd9c7be1c20cfa42420fd0e6df71e42b51ea # frozen: v4.0.0-alpha.8 hooks: - id: prettier files: \.(html|md|yml|yaml) @@ -34,7 +34,7 @@ repos: - id: blacken-docs - repo: https://github.com/asottile/pyupgrade - rev: df17dfa3911b81b4a27190b0eea5b1debc7ffa0a # frozen: v3.15.1 + rev: 12af25eb252deaaecb6b259df40d01f42e716dc3 # frozen: v3.15.2 hooks: - id: pyupgrade args: [--py38-plus] From ef0a8b5425715205aaf00dfd42228515896c4452 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 20 Apr 2024 15:31:41 -0400 Subject: [PATCH 18/92] FIX: coroutines can have a return statement (#542) * FIX: coroutines can have a return statement The value returned by the coroutine is carried on the `StopIteration` Exception that is raised when exhausted. * CI: do not test Sphinx 7.3 * CI: also do not do sphinx 7.3.x on pre-release * CI: also do not use sphinx 7.3 on docs * STY: placate linter --- .circleci/config.yml | 1 + .github/workflows/test.yml | 6 +++++- numpydoc/docscrape.py | 4 ---- numpydoc/tests/test_docscrape.py | 4 +++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 66a60c8d..a67976c0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,6 +21,7 @@ jobs: source venv/bin/activate python -m pip install --upgrade pip wheel setuptools python -m pip install --upgrade -r requirements/doc.txt + python -m pip install 'sphinx!=7.3.*' python -m pip list - save_cache: key: pip-cache diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 98b4d79b..774323b6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,10 @@ jobs: os: [Ubuntu] python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] sphinx-version: - ["sphinx==6.0", "sphinx==6.2", "sphinx==7.0", "sphinx>=7.2"] + ["sphinx==6.0", "sphinx==6.2", "sphinx==7.0", "'sphinx>=7.2,<7.3'"] + exclude: + - python-version: "3.8" + sphinx-version: "'sphinx>=7.2,<7.3'" steps: - uses: actions/checkout@v4 @@ -84,6 +87,7 @@ jobs: python -m pip install --upgrade pip wheel setuptools python -m pip install --pre -r requirements/test.txt -r requirements/doc.txt python -m pip install codecov + python -m pip install 'sphinx!=7.3.*' python -m pip list - name: Install diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index fb3a0b63..8adcf869 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -394,12 +394,8 @@ def _parse(self): sections = list(self._read_sections()) section_names = {section for section, content in sections} - has_returns = "Returns" in section_names has_yields = "Yields" in section_names # We could do more tests, but we are not. Arbitrarily. - if has_returns and has_yields: - msg = "Docstring contains both a Returns and Yields section." - raise ValueError(msg) if not has_yields and "Receives" in section_names: msg = "Docstring contains a Receives section but not Yields." raise ValueError(msg) diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index 8bbcdc53..fc6efc0d 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -279,7 +279,9 @@ def test_returnyield(): The number of bananas. """ - assert_raises(ValueError, NumpyDocString, doc_text) + doc = NumpyDocString(doc_text) + assert len(doc["Returns"]) == 1 + assert len(doc["Yields"]) == 2 def test_section_twice(): From 01b4be7eeefa050111a735167e6fa1139abee906 Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Sun, 21 Apr 2024 12:14:31 -0700 Subject: [PATCH 19/92] DEV: Rm xfails from pytest summary. (#540) Co-authored-by: Jarrod Millman --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index de570e34..c76d2192 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -87,6 +87,6 @@ numpydoc = [ [tool.pytest.ini_options] addopts = ''' ---showlocals --doctest-modules -ra --cov-report= --cov=numpydoc +--showlocals --doctest-modules --cov-report= --cov=numpydoc --junit-xml=junit-results.xml --ignore=doc/ --ignore=tools/''' junit_family = 'xunit2' From 10f8ae6110f2b3755a6ce01d44379c7d35415473 Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Wed, 24 Apr 2024 11:15:51 -0700 Subject: [PATCH 20/92] Unwrap decorated objects for YD01 validation check (#541) * ENH: decorator unwrapping for Yields validation. * Add test for unwrapped Yields validation. --- numpydoc/tests/test_validate.py | 44 ++++++++++++++++++++++++++++++++- numpydoc/validate.py | 9 ++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/numpydoc/tests/test_validate.py b/numpydoc/tests/test_validate.py index d41e4bd0..eb00f896 100644 --- a/numpydoc/tests/test_validate.py +++ b/numpydoc/tests/test_validate.py @@ -2,10 +2,12 @@ import sys import warnings from contextlib import nullcontext -from functools import cached_property, partial +from functools import cached_property, partial, wraps from inspect import getsourcelines, getsourcefile from numpydoc import validate +from numpydoc.validate import Validator +from numpydoc.docscrape import get_doc_object import numpydoc.tests @@ -1692,3 +1694,43 @@ def test_source_file_name_with_properties(self, property, file_name): ) ) assert doc.source_file_name == file_name + + +def test_is_generator_validation_with_decorator(): + """Ensure that the check for a Yields section when an object is a generator + (YD01) works with decorated generators.""" + + def tinsel(f): + @wraps(f) + def wrapper(*args, **kwargs): + return f(*args, **kwargs) + + return wrapper + + def foo(): + """A simple generator""" + yield from range(10) + + @tinsel + def bar(): + """Generator wrapped once""" + yield from range(10) + + @tinsel + @tinsel + @tinsel + def baz(): + """Generator wrapped multiple times""" + yield from range(10) + + # foo without wrapper is a generator + v = Validator(get_doc_object(foo)) + assert v.is_generator_function + + # Wrapped once + v = Validator(get_doc_object(bar)) + assert v.is_generator_function + + # Wrapped multiple times + v = Validator(get_doc_object(baz)) + assert v.is_generator_function diff --git a/numpydoc/validate.py b/numpydoc/validate.py index da94665e..02253517 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -112,6 +112,13 @@ IGNORE_COMMENT_PATTERN = re.compile("(?:.* numpydoc ignore[=|:] ?)(.+)") +def _unwrap(obj): + """Iteratively traverse obj.__wrapped__ until first non-wrapped obj found.""" + while hasattr(obj, "__wrapped__"): + obj = obj.__wrapped__ + return obj + + # This function gets called once per function/method to be validated. # We have to balance memory usage with performance here. It shouldn't be too # bad to store these `dict`s (they should be rare), but to be safe let's keep @@ -273,7 +280,7 @@ def is_function_or_method(self): @property def is_generator_function(self): - return inspect.isgeneratorfunction(self.obj) + return inspect.isgeneratorfunction(_unwrap(self.obj)) @property def source_file_name(self): From d8e27dfa22acca6ddb4c09800910508dc2b86d73 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Fri, 26 Apr 2024 10:19:00 -0700 Subject: [PATCH 21/92] Drop Python 3.8 support (#545) * Drop Python 3.8 support * Remove workaround for Python 3.8 See https://github.com/numpy/numpydoc/pull/496/commits/d974f2509b32ca607669ef481751f8071785ebf9 --- .github/workflows/test.yml | 5 +---- README.rst | 2 +- doc/install.rst | 2 +- numpydoc/tests/test_validate.py | 6 +----- pyproject.toml | 3 +-- 5 files changed, 5 insertions(+), 13 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 774323b6..8e070737 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,12 +16,9 @@ jobs: strategy: matrix: os: [Ubuntu] - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] + python-version: ["3.9", "3.10", "3.11", "3.12"] sphinx-version: ["sphinx==6.0", "sphinx==6.2", "sphinx==7.0", "'sphinx>=7.2,<7.3'"] - exclude: - - python-version: "3.8" - sphinx-version: "'sphinx>=7.2,<7.3'" steps: - uses: actions/checkout@v4 diff --git a/README.rst b/README.rst index a5af9a00..87661b6f 100644 --- a/README.rst +++ b/README.rst @@ -18,7 +18,7 @@ docstrings formatted according to the NumPy documentation format. The extension also adds the code description directives ``np:function``, ``np-c:function``, etc. -numpydoc requires Python 3.8+ and sphinx 5+. +numpydoc requires Python 3.9+ and sphinx 6+. For usage information, please refer to the `documentation `_. diff --git a/doc/install.rst b/doc/install.rst index 480bd59a..6282ffed 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -5,7 +5,7 @@ Getting started Installation ============ -This extension requires Python 3.8+, sphinx 5+ and is available from: +This extension requires Python 3.9+, sphinx 6+ and is available from: * `numpydoc on PyPI `_ * `numpydoc on GitHub `_ diff --git a/numpydoc/tests/test_validate.py b/numpydoc/tests/test_validate.py index eb00f896..c66f9ee9 100644 --- a/numpydoc/tests/test_validate.py +++ b/numpydoc/tests/test_validate.py @@ -1,5 +1,4 @@ import pytest -import sys import warnings from contextlib import nullcontext from functools import cached_property, partial, wraps @@ -1638,15 +1637,12 @@ def test_raises_for_invalid_attribute_name(self, invalid_name): with pytest.raises(AttributeError, match=msg): numpydoc.validate.Validator._load_obj(invalid_name) - # inspect.getsourcelines does not return class decorators for Python 3.8. This was - # fixed starting with 3.9: https://github.com/python/cpython/issues/60060. @pytest.mark.parametrize( ["decorated_obj", "def_line"], [ [ "numpydoc.tests.test_validate.DecoratorClass", - getsourcelines(DecoratorClass)[-1] - + (2 if sys.version_info.minor > 8 else 0), + getsourcelines(DecoratorClass)[-1] + 2, ], [ "numpydoc.tests.test_validate.DecoratorClass.test_no_decorator", diff --git a/pyproject.toml b/pyproject.toml index c76d2192..f7543f3a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ requires = ['setuptools>=61.2'] name = 'numpydoc' description = 'Sphinx extension to support docstrings in Numpy format' readme = 'README.rst' -requires-python = '>=3.8' +requires-python = '>=3.9' dynamic = ['version'] keywords = [ 'sphinx', @@ -19,7 +19,6 @@ classifiers = [ 'Topic :: Documentation', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', From cfea34e8a9a1860995f90f179da4447e6e9baff8 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Sat, 27 Apr 2024 11:44:18 -0700 Subject: [PATCH 22/92] Clean up old sphinx cruft (#549) --- numpydoc/numpydoc.py | 3 --- numpydoc/tests/tinybuild/conf.py | 1 - 2 files changed, 4 deletions(-) diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 3513f95c..4046aaa1 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -31,9 +31,6 @@ from sphinx.util import logging from sphinx.errors import ExtensionError -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, get_validation_checks from .xref import DEFAULT_LINKS diff --git a/numpydoc/tests/tinybuild/conf.py b/numpydoc/tests/tinybuild/conf.py index fb3b5283..c82d973f 100644 --- a/numpydoc/tests/tinybuild/conf.py +++ b/numpydoc/tests/tinybuild/conf.py @@ -15,7 +15,6 @@ autosummary_generate = True autodoc_default_options = {"inherited-members": None} source_suffix = ".rst" -master_doc = "index" # NOTE: will be changed to `root_doc` in sphinx 4 exclude_patterns = ["_build"] intersphinx_mapping = { "python": ("https://docs.python.org/3", None), From 8eccee04e884225323261d2e562ab06017c7fd4b Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Sat, 27 Apr 2024 11:49:10 -0700 Subject: [PATCH 23/92] Test on sphinx 7.3 (#547) Test on sphinx-7.3 --- .circleci/config.yml | 1 - .github/workflows/test.yml | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a67976c0..66a60c8d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,6 @@ jobs: source venv/bin/activate python -m pip install --upgrade pip wheel setuptools python -m pip install --upgrade -r requirements/doc.txt - python -m pip install 'sphinx!=7.3.*' python -m pip list - save_cache: key: pip-cache diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8e070737..02eb7b43 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: os: [Ubuntu] python-version: ["3.9", "3.10", "3.11", "3.12"] sphinx-version: - ["sphinx==6.0", "sphinx==6.2", "sphinx==7.0", "'sphinx>=7.2,<7.3'"] + ["sphinx==6.0", "sphinx==6.2", "sphinx==7.0", "sphinx>=7.3"] steps: - uses: actions/checkout@v4 @@ -84,7 +84,6 @@ jobs: python -m pip install --upgrade pip wheel setuptools python -m pip install --pre -r requirements/test.txt -r requirements/doc.txt python -m pip install codecov - python -m pip install 'sphinx!=7.3.*' python -m pip list - name: Install From 1454aa93f19989e1f5ce3fb6c19d2fca49b61fdd Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Sat, 27 Apr 2024 12:42:35 -0700 Subject: [PATCH 24/92] Classify development status as Production/Stable (#548) --- pyproject.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f7543f3a..3d57ce47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,16 +13,18 @@ keywords = [ 'numpy', ] classifiers = [ - 'Development Status :: 4 - Beta', + 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', + 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', - 'Topic :: Documentation', + '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', + 'Topic :: Documentation', ] dependencies = [ 'sphinx>=6', From 3a21e5440c90a0f306c42fdc303083a12927969b Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Mon, 29 Apr 2024 10:14:38 -0400 Subject: [PATCH 25/92] BUG: Fix bug with validation encoding (#550) * BUG: Fix bug with validation encoding * FIX: Bashy * FIX: No doc build on Windows * FIX: Shel * FIX: Zero * FIX: User --- .github/workflows/test.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 02eb7b43..b58ef62a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,6 +19,13 @@ jobs: python-version: ["3.9", "3.10", "3.11", "3.12"] sphinx-version: ["sphinx==6.0", "sphinx==6.2", "sphinx==7.0", "sphinx>=7.3"] + include: + - os: Windows + python-version: "3.12" + sphinx-version: "sphinx" # version shouldn't really matter here + defaults: + run: + shell: bash -eo pipefail {0} steps: - uses: actions/checkout@v4 @@ -59,11 +66,13 @@ jobs: run: | sudo apt-get update sudo apt install texlive texlive-latex-extra latexmk dvipng + if: runner.os == 'Linux' - name: Build documentation run: | make -C doc html SPHINXOPTS="-nT" make -C doc latexpdf SPHINXOPTS="-nT" + if: runner.os == 'Linux' prerelease: runs-on: ${{ matrix.os }}-latest From e7c6baf00f5f73a4a8f8318d0cb4e04949c9a5d1 Mon Sep 17 00:00:00 2001 From: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Date: Tue, 30 Apr 2024 01:08:43 -0400 Subject: [PATCH 26/92] Unify CLIs (#537) * Combine CLIs into a single one, exposing as an entrypoint. * Update tests for CLI changes * Update python -m references in the docs * Update test.yml workflow * Use older type annotations * Show help when no subcommand is provided * Refactor lint subparser and hook tests * Rename test to match subcommand --- .github/workflows/test.yml | 16 +-- .pre-commit-hooks.yaml | 2 +- doc/validation.rst | 6 +- numpydoc/__main__.py | 53 +-------- numpydoc/cli.py | 128 +++++++++++++++++++++ numpydoc/hooks/validate_docstrings.py | 86 +++++--------- numpydoc/tests/hooks/test_validate_hook.py | 31 ++--- numpydoc/tests/test_main.py | 72 +++++++++--- pyproject.toml | 2 +- 9 files changed, 235 insertions(+), 161 deletions(-) create mode 100644 numpydoc/cli.py diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b58ef62a..853c8539 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -57,10 +57,10 @@ jobs: - name: Make sure CLI works run: | - python -m numpydoc numpydoc.tests.test_main._capture_stdout - echo '! python -m numpydoc numpydoc.tests.test_main._invalid_docstring' | bash - python -m numpydoc --validate numpydoc.tests.test_main._capture_stdout - echo '! python -m numpydoc --validate numpydoc.tests.test_main._docstring_with_errors' | bash + numpydoc render numpydoc.tests.test_main._capture_stdout + echo '! numpydoc render numpydoc.tests.test_main._invalid_docstring' | bash + numpydoc validate numpydoc.tests.test_main._capture_stdout + echo '! numpydoc validate numpydoc.tests.test_main._docstring_with_errors' | bash - name: Setup for doc build run: | @@ -110,10 +110,10 @@ jobs: - name: Make sure CLI works run: | - python -m numpydoc numpydoc.tests.test_main._capture_stdout - echo '! python -m numpydoc numpydoc.tests.test_main._invalid_docstring' | bash - python -m numpydoc --validate numpydoc.tests.test_main._capture_stdout - echo '! python -m numpydoc --validate numpydoc.tests.test_main._docstring_with_errors' | bash + numpydoc render numpydoc.tests.test_main._capture_stdout + echo '! numpydoc render numpydoc.tests.test_main._invalid_docstring' | bash + numpydoc validate numpydoc.tests.test_main._capture_stdout + echo '! numpydoc validate numpydoc.tests.test_main._docstring_with_errors' | bash - name: Setup for doc build run: | diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index b88e9ed2..2244d460 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -1,7 +1,7 @@ - id: numpydoc-validation name: numpydoc-validation description: This hook validates that docstrings in committed files adhere to numpydoc standards. - entry: validate-docstrings + entry: numpydoc lint require_serial: true language: python types: [python] diff --git a/doc/validation.rst b/doc/validation.rst index 4ce89017..858a67cc 100644 --- a/doc/validation.rst +++ b/doc/validation.rst @@ -22,7 +22,7 @@ command line options for this hook: .. code-block:: bash - $ python -m numpydoc.hooks.validate_docstrings --help + $ numpydoc lint --help Using a config file provides additional customization. Both ``pyproject.toml`` and ``setup.cfg`` are supported; however, if the project contains both @@ -102,12 +102,12 @@ can be called. For example, to do it for ``numpy.ndarray``, use: .. code-block:: bash - $ python -m numpydoc numpy.ndarray + $ numpydoc validate numpy.ndarray This will validate that the docstring can be built. For an exhaustive validation of the formatting of the docstring, use the -``--validate`` parameter. This will report the errors detected, such as +``validate`` subcommand. This will report the errors detected, such as incorrect capitalization, wrong order of the sections, and many other issues. Note that this will honor :ref:`inline ignore comments `, but will not look for any configuration like the :ref:`pre-commit hook ` diff --git a/numpydoc/__main__.py b/numpydoc/__main__.py index 53d5c504..b3b6d159 100644 --- a/numpydoc/__main__.py +++ b/numpydoc/__main__.py @@ -2,55 +2,6 @@ Implementing `python -m numpydoc` functionality. """ -import sys -import argparse -import ast +from .cli import main -from .docscrape_sphinx import get_doc_object -from .validate import validate, Validator - - -def render_object(import_path, config=None): - """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 []))) - return 0 - - -def validate_object(import_path): - exit_status = 0 - results = validate(import_path) - for err_code, err_desc in results["errors"]: - exit_status += 1 - print(":".join([import_path, err_code, err_desc])) - return exit_status - - -if __name__ == "__main__": - ap = argparse.ArgumentParser(description=__doc__) - ap.add_argument("import_path", help="e.g. numpy.ndarray") - - def _parse_config(s): - key, _, value = s.partition("=") - value = ast.literal_eval(value) - return key, value - - ap.add_argument( - "-c", - "--config", - type=_parse_config, - action="append", - help="key=val where val will be parsed by literal_eval, " - "e.g. -c use_plots=True. Multiple -c can be used.", - ) - ap.add_argument( - "--validate", action="store_true", help="validate the object and report errors" - ) - args = ap.parse_args() - - if args.validate: - exit_code = validate_object(args.import_path) - else: - exit_code = render_object(args.import_path, args.config) - - sys.exit(exit_code) +raise SystemExit(main()) diff --git a/numpydoc/cli.py b/numpydoc/cli.py new file mode 100644 index 00000000..de47d51d --- /dev/null +++ b/numpydoc/cli.py @@ -0,0 +1,128 @@ +"""The CLI for numpydoc.""" + +import argparse +import ast +from pathlib import Path +from typing import List, Sequence, Union + +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: + """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 []))) + return 0 + + +def validate_object(import_path: str) -> int: + """Run numpydoc docstring validation for a given object.""" + exit_status = 0 + results = validate(import_path) + for err_code, err_desc in results["errors"]: + exit_status += 1 + print(":".join([import_path, err_code, err_desc])) + return exit_status + + +def get_parser() -> argparse.ArgumentParser: + """ + Build an argument parser. + + Returns + ------- + argparse.ArgumentParser + The argument parser. + """ + ap = argparse.ArgumentParser(prog="numpydoc", description=__doc__) + subparsers = ap.add_subparsers(title="subcommands") + + def _parse_config(s): + key, _, value = s.partition("=") + value = ast.literal_eval(value) + return key, value + + render = subparsers.add_parser( + "render", + description="Generate an expanded RST-version of the docstring.", + help="generate the RST docstring with numpydoc", + ) + render.add_argument("import_path", help="e.g. numpy.ndarray") + render.add_argument( + "-c", + "--config", + type=_parse_config, + action="append", + help="key=val where val will be parsed by literal_eval, " + "e.g. -c use_plots=True. Multiple -c can be used.", + ) + render.set_defaults(func=render_object) + + validate = subparsers.add_parser( + "validate", + description="Validate an object's docstring against the numpydoc standard.", + help="validate the object's docstring and report errors", + ) + validate.add_argument("import_path", help="e.g. numpy.ndarray") + validate.set_defaults(func=validate_object) + + project_root_from_cwd, config_file = utils.find_project_root(["."]) + config_options = validate_docstrings.parse_config(project_root_from_cwd) + ignored_checks = [ + f"- {check}: {ERROR_MSGS[check]}" + for check in set(ERROR_MSGS.keys()) - config_options["checks"] + ] + ignored_checks_text = "\n " + "\n ".join(ignored_checks) + "\n" + + lint_parser = subparsers.add_parser( + "lint", + description="Run numpydoc validation on files with option to ignore individual checks.", + help="validate all docstrings in file(s) using the abstract syntax tree", + formatter_class=argparse.RawTextHelpFormatter, + ) + lint_parser.add_argument( + "files", type=str, nargs="+", help="File(s) to run numpydoc validation on." + ) + lint_parser.add_argument( + "--config", + type=str, + help=( + "Path to a directory containing a pyproject.toml or setup.cfg file.\n" + "The hook will look for it in the root project directory.\n" + "If both are present, only pyproject.toml will be used.\n" + "Options must be placed under\n" + " - [tool:numpydoc_validation] for setup.cfg files and\n" + " - [tool.numpydoc_validation] for pyproject.toml files." + ), + ) + lint_parser.add_argument( + "--ignore", + type=str, + nargs="*", + help=( + f"""Check codes to ignore.{ + ' Currently ignoring the following from ' + f'{Path(project_root_from_cwd) / config_file}: {ignored_checks_text}' + 'Values provided here will be in addition to the above, unless an alternate config is provided.' + if ignored_checks else '' + }""" + ), + ) + lint_parser.set_defaults(func=validate_docstrings.run_hook) + + return ap + + +def main(argv: Union[Sequence[str], None] = None) -> int: + """CLI for numpydoc.""" + ap = get_parser() + + args = vars(ap.parse_args(argv)) + + try: + func = args.pop("func") + return func(**args) + except KeyError: + ap.exit(status=2, message=ap.format_help()) diff --git a/numpydoc/hooks/validate_docstrings.py b/numpydoc/hooks/validate_docstrings.py index db8141d8..562a1f09 100644 --- a/numpydoc/hooks/validate_docstrings.py +++ b/numpydoc/hooks/validate_docstrings.py @@ -1,6 +1,5 @@ """Run numpydoc validation on contents of a file.""" -import argparse import ast import configparser import os @@ -13,7 +12,7 @@ import tomli as tomllib from pathlib import Path -from typing import Sequence, Tuple, Union +from typing import Any, Dict, List, Tuple, Union from tabulate import tabulate @@ -341,62 +340,35 @@ def process_file(filepath: os.PathLike, config: dict) -> "list[list[str]]": return docstring_visitor.findings -def main(argv: Union[Sequence[str], None] = None) -> int: - """Run the numpydoc validation hook.""" +def run_hook( + files: List[str], + *, + config: Union[Dict[str, Any], None] = None, + ignore: Union[List[str], None] = None, +) -> int: + """ + Run the numpydoc validation hook. - project_root_from_cwd, config_file = find_project_root(["."]) - config_options = parse_config(project_root_from_cwd) - ignored_checks = ( - "\n " - + "\n ".join( - [ - f"- {check}: {validate.ERROR_MSGS[check]}" - for check in set(validate.ERROR_MSGS.keys()) - config_options["checks"] - ] - ) - + "\n" - ) - - parser = argparse.ArgumentParser( - description="Run numpydoc validation on files with option to ignore individual checks.", - formatter_class=argparse.RawTextHelpFormatter, - ) - parser.add_argument( - "files", type=str, nargs="+", help="File(s) to run numpydoc validation on." - ) - parser.add_argument( - "--config", - type=str, - help=( - "Path to a directory containing a pyproject.toml or setup.cfg file.\n" - "The hook will look for it in the root project directory.\n" - "If both are present, only pyproject.toml will be used.\n" - "Options must be placed under\n" - " - [tool:numpydoc_validation] for setup.cfg files and\n" - " - [tool.numpydoc_validation] for pyproject.toml files." - ), - ) - parser.add_argument( - "--ignore", - type=str, - nargs="*", - help=( - f"""Check codes to ignore.{ - ' Currently ignoring the following from ' - f'{Path(project_root_from_cwd) / config_file}: {ignored_checks}' - 'Values provided here will be in addition to the above, unless an alternate config is provided.' - if config_options["checks"] else '' - }""" - ), - ) - - args = parser.parse_args(argv) - project_root, _ = find_project_root(args.files) - config_options = parse_config(args.config or project_root) - config_options["checks"] -= set(args.ignore or []) + Parameters + ---------- + files : list[str] + The absolute or relative paths to the files to inspect. + config : Union[dict[str, Any], None], optional + Configuration options for reviewing flagged issues. + ignore : Union[list[str], None], optional + Checks to ignore in the results. + + Returns + ------- + int + The return status: 1 if issues were found, 0 otherwise. + """ + project_root, _ = find_project_root(files) + config_options = parse_config(config or project_root) + config_options["checks"] -= set(ignore or []) findings = [] - for file in args.files: + for file in files: findings.extend(process_file(file, config_options)) if findings: @@ -411,7 +383,3 @@ def main(argv: Union[Sequence[str], None] = None) -> int: ) return 1 return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/numpydoc/tests/hooks/test_validate_hook.py b/numpydoc/tests/hooks/test_validate_hook.py index 5c635dfb..4e79f506 100644 --- a/numpydoc/tests/hooks/test_validate_hook.py +++ b/numpydoc/tests/hooks/test_validate_hook.py @@ -5,7 +5,7 @@ import pytest -from numpydoc.hooks.validate_docstrings import main +from numpydoc.hooks.validate_docstrings import run_hook @pytest.fixture @@ -72,11 +72,7 @@ def test_validate_hook(example_module, config, capsys): """ ) - args = [example_module] - if config: - args.append(f"--{config=}") - - return_code = main(args) + return_code = run_hook([example_module], config=config) assert return_code == 1 assert capsys.readouterr().err.rstrip() == expected @@ -109,7 +105,8 @@ def test_validate_hook_with_ignore(example_module, capsys): """ ) - return_code = main([example_module, "--ignore", "ES01", "SA01", "EX01"]) + return_code = run_hook([example_module], ignore=["ES01", "SA01", "EX01"]) + assert return_code == 1 assert capsys.readouterr().err.rstrip() == expected @@ -157,7 +154,7 @@ def test_validate_hook_with_toml_config(example_module, tmp_path, capsys): """ ) - return_code = main([example_module, "--config", str(tmp_path)]) + return_code = run_hook([example_module], config=tmp_path) assert return_code == 1 assert capsys.readouterr().err.rstrip() == expected @@ -196,23 +193,11 @@ def test_validate_hook_with_setup_cfg(example_module, tmp_path, capsys): """ ) - return_code = main([example_module, "--config", str(tmp_path)]) + return_code = run_hook([example_module], config=tmp_path) assert return_code == 1 assert capsys.readouterr().err.rstrip() == expected -def test_validate_hook_help(capsys): - """Test that help section is displaying.""" - - with pytest.raises(SystemExit): - return_code = main(["--help"]) - assert return_code == 0 - - out = capsys.readouterr().out - assert "--ignore" in out - assert "--config" in out - - def test_validate_hook_exclude_option_pyproject(example_module, tmp_path, capsys): """ Test that a file is correctly processed with the config coming from @@ -255,7 +240,7 @@ def test_validate_hook_exclude_option_pyproject(example_module, tmp_path, capsys """ ) - return_code = main([example_module, "--config", str(tmp_path)]) + return_code = run_hook([example_module], config=tmp_path) assert return_code == 1 assert capsys.readouterr().err.rstrip() == expected @@ -292,6 +277,6 @@ def test_validate_hook_exclude_option_setup_cfg(example_module, tmp_path, capsys """ ) - return_code = main([example_module, "--config", str(tmp_path)]) + return_code = run_hook([example_module], config=tmp_path) assert return_code == 1 assert capsys.readouterr().err.rstrip() == expected diff --git a/numpydoc/tests/test_main.py b/numpydoc/tests/test_main.py index 1f90b967..8023e1c9 100644 --- a/numpydoc/tests/test_main.py +++ b/numpydoc/tests/test_main.py @@ -1,8 +1,11 @@ -import sys +import inspect import io +import sys + import pytest + import numpydoc -import numpydoc.__main__ +import numpydoc.cli def _capture_stdout(func_name, *args, **kwargs): @@ -65,41 +68,40 @@ def _invalid_docstring(): def test_renders_package_docstring(): - out = _capture_stdout(numpydoc.__main__.render_object, "numpydoc") + out = _capture_stdout(numpydoc.cli.render_object, "numpydoc") assert out.startswith("This package provides the numpydoc Sphinx") -def test_renders_module_docstring(): - out = _capture_stdout(numpydoc.__main__.render_object, "numpydoc.__main__") - assert out.startswith("Implementing `python -m numpydoc` functionality.") +def test_renders_module_docstring(capsys): + numpydoc.cli.main(["render", "numpydoc.cli"]) + out = capsys.readouterr().out.strip("\n\r") + assert out.startswith(numpydoc.cli.__doc__) def test_renders_function_docstring(): out = _capture_stdout( - numpydoc.__main__.render_object, "numpydoc.tests.test_main._capture_stdout" + numpydoc.cli.render_object, "numpydoc.tests.test_main._capture_stdout" ) assert out.startswith("Return stdout of calling") def test_render_object_returns_correct_exit_status(): - exit_status = numpydoc.__main__.render_object( - "numpydoc.tests.test_main._capture_stdout" - ) + exit_status = numpydoc.cli.render_object("numpydoc.tests.test_main._capture_stdout") assert exit_status == 0 with pytest.raises(ValueError): - numpydoc.__main__.render_object("numpydoc.tests.test_main._invalid_docstring") + numpydoc.cli.render_object("numpydoc.tests.test_main._invalid_docstring") def test_validate_detects_errors(): out = _capture_stdout( - numpydoc.__main__.validate_object, + numpydoc.cli.validate_object, "numpydoc.tests.test_main._docstring_with_errors", ) assert "SS02" in out assert "Summary does not start with a capital letter" in out - exit_status = numpydoc.__main__.validate_object( + exit_status = numpydoc.cli.validate_object( "numpydoc.tests.test_main._docstring_with_errors" ) assert exit_status > 0 @@ -107,11 +109,51 @@ def test_validate_detects_errors(): def test_validate_perfect_docstring(): out = _capture_stdout( - numpydoc.__main__.validate_object, "numpydoc.tests.test_main._capture_stdout" + numpydoc.cli.validate_object, "numpydoc.tests.test_main._capture_stdout" ) assert out == "" - exit_status = numpydoc.__main__.validate_object( + exit_status = numpydoc.cli.validate_object( "numpydoc.tests.test_main._capture_stdout" ) assert exit_status == 0 + + +@pytest.mark.parametrize("args", [[], ["--ignore", "ES01", "SA01", "EX01"]]) +def test_lint(capsys, args): + argv = ["lint", "numpydoc/__main__.py"] + args + if args: + expected = "" + expected_status = 0 + else: + expected = inspect.cleandoc( + """ + +------------------------+----------+---------+----------------------------+ + | file | item | check | description | + +========================+==========+=========+============================+ + | numpydoc/__main__.py:1 | __main__ | ES01 | No extended summary found | + +------------------------+----------+---------+----------------------------+ + | numpydoc/__main__.py:1 | __main__ | SA01 | See Also section not found | + +------------------------+----------+---------+----------------------------+ + | numpydoc/__main__.py:1 | __main__ | EX01 | No examples section found | + +------------------------+----------+---------+----------------------------+ + """ + ) + expected_status = 1 + + return_status = numpydoc.cli.main(argv) + err = capsys.readouterr().err.strip("\n\r") + assert err == expected + assert return_status == expected_status + + +def test_lint_help(capsys): + """Test that lint help section is displaying.""" + + with pytest.raises(SystemExit): + return_code = numpydoc.cli.main(["lint", "--help"]) + assert return_code == 0 + + out = capsys.readouterr().out + assert "--ignore" in out + assert "--config" in out diff --git a/pyproject.toml b/pyproject.toml index 3d57ce47..89cca8fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ test = [ ] [project.scripts] -validate-docstrings = 'numpydoc.hooks.validate_docstrings:main' +numpydoc = 'numpydoc.cli:main' [tool.changelist] title_template = "{version}" From 6711ab3b308ae60a0f73e7d8ee5db0d6e6b36828 Mon Sep 17 00:00:00 2001 From: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Date: Wed, 8 May 2024 17:36:12 -0400 Subject: [PATCH 27/92] DOC: Add note about TOML regex; fix typo (#552) Add note about TOML regex; fix typo --- doc/validation.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/validation.rst b/doc/validation.rst index 858a67cc..aa9d5236 100644 --- a/doc/validation.rst +++ b/doc/validation.rst @@ -33,7 +33,7 @@ the pre-commit hook as follows: ``ES01`` (using the same logic as the :ref:`validation during Sphinx build ` for ``numpydoc_validation_checks``). * ``exclude``: Don't report issues on objects matching any of the regular - regular expressions ``\.undocumented_method$`` or ``\.__repr__$``. This + expressions ``\.undocumented_method$`` or ``\.__repr__$``. This maps to ``numpydoc_validation_exclude`` from the :ref:`Sphinx build configuration `. * ``override_SS05``: Allow docstrings to start with "Process ", "Assess ", @@ -52,6 +52,7 @@ the pre-commit hook as follows: "SA01", "ES01", ] + # remember to use single quotes for regex in TOML exclude = [ # don't report on objects that match any of these regex '\.undocumented_method$', '\.__repr__$', From 691a2c44dadfde9bd1de6eee29987d17f4d5a7f9 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Sat, 11 May 2024 07:39:34 -0700 Subject: [PATCH 28/92] Require GHA update grouping (#553) --- .github/dependabot.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 918c3a5c..66c89692 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,3 +6,7 @@ updates: interval: "monthly" labels: - "type: Maintenance" + groups: + actions: + patterns: + - "*" From eece14b835d543259b20d1ec28f624402475fc71 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Sat, 11 May 2024 07:57:26 -0700 Subject: [PATCH 29/92] Update pre-commit config (#554) --- .pre-commit-config.yaml | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6dec8b89..8c63976c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,29 +3,30 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: c4a0b883114b00d8d76b479c820ce7950211c99b # frozen: v4.5.0 + rev: 2c9f875913ee60ca25ce70243dc24d5b6415598c # frozen: v4.6.0 hooks: - - id: trailing-whitespace - - id: end-of-file-fixer - - id: debug-statements + - id: check-added-large-files - id: check-ast - - id: mixed-line-ending - - id: check-yaml - args: [--allow-multiple-documents] + - id: check-case-conflict - id: check-json - id: check-toml - - id: check-added-large-files + - id: check-yaml + args: [--allow-multiple-documents] + - id: debug-statements + - id: end-of-file-fixer + - id: mixed-line-ending + - id: trailing-whitespace - repo: https://github.com/psf/black - rev: 552baf822992936134cbd31a38f69c8cfe7c0f05 # frozen: 24.3.0 + rev: 3702ba224ecffbcec30af640c149f231d90aebdb # frozen: 24.4.2 hooks: - id: black - repo: https://github.com/pre-commit/mirrors-prettier - rev: f12edd9c7be1c20cfa42420fd0e6df71e42b51ea # frozen: v4.0.0-alpha.8 + rev: ffb6a759a979008c0e6dff86e39f4745a2d9eac4 # frozen: v3.1.0 hooks: - id: prettier - files: \.(html|md|yml|yaml) + types_or: [yaml, toml, markdown, css, scss, javascript, json] args: [--prose-wrap=preserve] - repo: https://github.com/adamchainz/blacken-docs From 100fc5d683aaeb0c8dd42b902399daae2fef9046 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Sat, 11 May 2024 08:13:26 -0700 Subject: [PATCH 30/92] Use ruff for linting and formatting --- .pre-commit-config.yaml | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8c63976c..cd7c3531 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -17,11 +17,6 @@ repos: - id: mixed-line-ending - id: trailing-whitespace - - repo: https://github.com/psf/black - rev: 3702ba224ecffbcec30af640c149f231d90aebdb # frozen: 24.4.2 - hooks: - - id: black - - repo: https://github.com/pre-commit/mirrors-prettier rev: ffb6a759a979008c0e6dff86e39f4745a2d9eac4 # frozen: v3.1.0 hooks: @@ -29,16 +24,12 @@ repos: types_or: [yaml, toml, markdown, css, scss, javascript, json] args: [--prose-wrap=preserve] - - repo: https://github.com/adamchainz/blacken-docs - rev: 960ead214cd1184149d366c6d27ca6c369ce46b6 # frozen: 1.16.0 - hooks: - - id: blacken-docs - - - repo: https://github.com/asottile/pyupgrade - rev: 12af25eb252deaaecb6b259df40d01f42e716dc3 # frozen: v3.15.2 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: "f8a3f8c471fb698229face5ed7640a64900b781e" # frozen: v0.4.4 hooks: - - id: pyupgrade - args: [--py38-plus] + - id: ruff + args: ["--fix", "--show-fixes", "--exit-non-zero-on-fix"] + - id: ruff-format - repo: local hooks: From 60ef001f94d5cf52efdbe6b102eda89c24a6c245 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Sat, 11 May 2024 08:14:12 -0700 Subject: [PATCH 31/92] Add ruff configuration --- pyproject.toml | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 89cca8fc..e882da19 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,6 +68,92 @@ title_template = "{version}" # Profiles that are excluded from the contributor list. ignored_user_logins = ["dependabot[bot]", "pre-commit-ci[bot]"] +[tool.ruff.lint] +extend-select = [ + "B", # flake8-bugbear + "I", # isort + "ARG", # flake8-unused-arguments + "C4", # flake8-comprehensions + "EM", # flake8-errmsg + "ICN", # flake8-import-conventions + "G", # flake8-logging-format + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "PTH", # flake8-use-pathlib + "RET", # flake8-return + "RUF", # Ruff-specific + "SIM", # flake8-simplify + "T20", # flake8-print + "UP", # pyupgrade + "YTT", # flake8-2020 + "EXE", # flake8-executable + "NPY", # NumPy specific rules + "PD", # pandas-vet + "FURB", # refurb + "PYI", # flake8-pyi +] +ignore = [ + "PLR09", # Too many <...> + "PLR2004", # Magic value used in comparison + "ISC001", # Conflicts with formatter + "ARG001", # FIXME: consider removing this and the following rules from this list + "ARG002", + "B004", + "B007", + "B023", + "B028", + "B034", + "C408", + "E402", + "E741", + "EM101", + "EM102", + "EXE001", + "F401", + "F811", + "F821", + "F841", + "PIE810", + "PLW0603", + "PLW2901", + "PLW3301", + "PT006", + "PT007", + "PT011", + "PT012", + "PT013", + "PTH100", + "PTH118", + "PTH120", + "PTH123", + "PYI024", + "RET503", + "RET504", + "RET505", + "RET506", + "RET507", + "RET508", + "RUF005", + "RUF012", + "RUF013", + "SIM102", + "SIM105", + "SIM108", + "SIM115", + "T201", + "UP006", + "UP031", + "UP035", +] + +[tool.ruff.lint.per-file-ignores] +"doc/example.py" = ["ARG001", "F401", "I001"] + +[tool.ruff.format] +docstring-code-format = true + [tool.setuptools] include-package-data = false packages = [ From be316333f436519e0e2ab1379cbdedde79c9ac68 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Sat, 11 May 2024 09:00:01 -0700 Subject: [PATCH 32/92] Autoformat with ruff --- doc/conf.py | 8 +-- doc/example.py | 1 - numpydoc/cli.py | 3 +- numpydoc/docscrape.py | 15 ++-- numpydoc/docscrape_sphinx.py | 11 ++- numpydoc/hooks/utils.py | 4 +- numpydoc/numpydoc.py | 42 ++++++----- numpydoc/tests/hooks/example_module.py | 3 - numpydoc/tests/hooks/test_validate_hook.py | 2 +- numpydoc/tests/test_docscrape.py | 40 ++++------- numpydoc/tests/test_full.py | 5 +- numpydoc/tests/test_main.py | 4 +- numpydoc/tests/test_numpydoc.py | 15 ++-- numpydoc/tests/test_validate.py | 70 ++++--------------- numpydoc/tests/test_xref.py | 7 +- numpydoc/tests/tinybuild/conf.py | 2 +- .../tests/tinybuild/numpydoc_test_module.py | 3 +- numpydoc/validate.py | 9 ++- numpydoc/xref.py | 6 +- 19 files changed, 88 insertions(+), 162 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 315bac73..9bffda88 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -4,17 +4,15 @@ # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html -from datetime import date -import numpydoc - # -- Path setup -------------------------------------------------------------- - # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. - import os import sys +from datetime import date + +import numpydoc # for example.py sys.path.insert(0, os.path.abspath(".")) diff --git a/doc/example.py b/doc/example.py index 9d3eccaa..c8d4a85f 100644 --- a/doc/example.py +++ b/doc/example.py @@ -127,4 +127,3 @@ def foo(var1, var2, *args, long_var_name="hi", only_seldom_used_keyword=0, **kwa # separate following codes (according to PEP257). # But for function, method and module, there should be no blank lines # after closing the docstring. - pass diff --git a/numpydoc/cli.py b/numpydoc/cli.py index de47d51d..ef8cff2c 100644 --- a/numpydoc/cli.py +++ b/numpydoc/cli.py @@ -2,8 +2,9 @@ import argparse import ast +from collections.abc import Sequence from pathlib import Path -from typing import List, Sequence, Union +from typing import List, Union from .docscrape_sphinx import get_doc_object from .hooks import utils, validate_docstrings diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index 8adcf869..a241dc21 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -1,18 +1,15 @@ -"""Extract reference documentation from the NumPy source tree. - -""" +"""Extract reference documentation from the NumPy source tree.""" +import copy import inspect -import textwrap -import re import pydoc -from warnings import warn +import re +import sys +import textwrap from collections import namedtuple from collections.abc import Callable, Mapping -import copy -import sys - from functools import cached_property +from warnings import warn def strip_blank_lines(l): diff --git a/numpydoc/docscrape_sphinx.py b/numpydoc/docscrape_sphinx.py index 771c1ea4..64588f55 100644 --- a/numpydoc/docscrape_sphinx.py +++ b/numpydoc/docscrape_sphinx.py @@ -1,20 +1,17 @@ -import re import inspect -import textwrap -import pydoc -from collections.abc import Callable import os +import pydoc +import re +import textwrap from jinja2 import FileSystemLoader from jinja2.sandbox import SandboxedEnvironment -import sphinx from sphinx.jinja2glue import BuiltinTemplateLoader -from .docscrape import NumpyDocString, FunctionDoc, ClassDoc, ObjDoc +from .docscrape import ClassDoc, FunctionDoc, NumpyDocString, ObjDoc from .docscrape import get_doc_object as get_doc_object_orig from .xref import make_xref - IMPORT_MATPLOTLIB_RE = r"\b(import +matplotlib|from +matplotlib +import)\b" diff --git a/numpydoc/hooks/utils.py b/numpydoc/hooks/utils.py index 4f1d82aa..448e1245 100644 --- a/numpydoc/hooks/utils.py +++ b/numpydoc/hooks/utils.py @@ -2,8 +2,8 @@ import itertools import os +from collections.abc import Sequence from pathlib import Path -from typing import Sequence def find_project_root(srcs: Sequence[str]): @@ -31,7 +31,7 @@ def find_project_root(srcs: Sequence[str]): `Black `_. """ if not srcs: - return Path(".").resolve(), "current directory" + return Path().resolve(), "current directory" common_path = Path( os.path.commonpath([Path(src).expanduser().resolve() for src in srcs]) diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 4046aaa1..2a8e1066 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -17,24 +17,22 @@ """ -from copy import deepcopy -import re -import pydoc -import inspect -from collections.abc import Callable import hashlib +import inspect import itertools +import pydoc +import re +from collections.abc import Callable +from copy import deepcopy -from docutils.nodes import citation, Text, section, comment, reference, inline -import sphinx -from sphinx.addnodes import pending_xref, desc_content +from docutils.nodes import Text, citation, comment, inline, reference, section +from sphinx.addnodes import desc_content, pending_xref from sphinx.util import logging -from sphinx.errors import ExtensionError +from . import __version__ from .docscrape_sphinx import get_doc_object -from .validate import validate, ERROR_MSGS, get_validation_checks +from .validate import get_validation_checks, validate from .xref import DEFAULT_LINKS -from . import __version__ logger = logging.getLogger(__name__) @@ -248,10 +246,10 @@ def mangle_signature(app, what, name, obj, options, sig, retann): return "", "" if not (isinstance(obj, Callable) or hasattr(obj, "__argspec_is_invalid_")): - return + return None if not hasattr(obj, "__doc__"): - return + return None doc = get_doc_object(obj, config={"show_class_members": False}) sig = doc["Signature"] or _clean_text_signature( getattr(obj, "__text_signature__", None) @@ -275,7 +273,7 @@ def _clean_text_signature(sig): def setup(app, get_doc_object_=get_doc_object): if not hasattr(app, "add_config_value"): - return # probably called by nose, better bail out + return None # probably called by nose, better bail out global get_doc_object get_doc_object = get_doc_object_ @@ -417,12 +415,18 @@ def match_items(lines, content_old): Examples -------- - >>> lines = ['', 'A', '', 'B', ' ', '', 'C', 'D'] - >>> lines_old = ['a', '', '', 'b', '', 'c'] - >>> items_old = [('file1.py', 0), ('file1.py', 1), ('file1.py', 2), - ... ('file2.py', 0), ('file2.py', 1), ('file2.py', 2)] + >>> lines = ["", "A", "", "B", " ", "", "C", "D"] + >>> lines_old = ["a", "", "", "b", "", "c"] + >>> items_old = [ + ... ("file1.py", 0), + ... ("file1.py", 1), + ... ("file1.py", 2), + ... ("file2.py", 0), + ... ("file2.py", 1), + ... ("file2.py", 2), + ... ] >>> content_old = ViewList(lines_old, items=items_old) - >>> match_items(lines, content_old) # doctest: +NORMALIZE_WHITESPACE + >>> match_items(lines, content_old) # doctest: +NORMALIZE_WHITESPACE [('file1.py', 0), ('file1.py', 0), ('file2.py', 0), ('file2.py', 0), ('file2.py', 2), ('file2.py', 2), ('file2.py', 2), ('file2.py', 2)] >>> # first 2 ``lines`` are matched to 'a', second 2 to 'b', rest to 'c' diff --git a/numpydoc/tests/hooks/example_module.py b/numpydoc/tests/hooks/example_module.py index b36f519a..87e9b52d 100644 --- a/numpydoc/tests/hooks/example_module.py +++ b/numpydoc/tests/hooks/example_module.py @@ -3,7 +3,6 @@ def some_function(name): """Welcome to some function.""" - pass class MyClass: @@ -23,11 +22,9 @@ def do_something(self, *args, **kwargs): ---------- *args """ - pass def process(self): """Process stuff.""" - pass class NewClass: diff --git a/numpydoc/tests/hooks/test_validate_hook.py b/numpydoc/tests/hooks/test_validate_hook.py index 4e79f506..d1418656 100644 --- a/numpydoc/tests/hooks/test_validate_hook.py +++ b/numpydoc/tests/hooks/test_validate_hook.py @@ -8,7 +8,7 @@ from numpydoc.hooks.validate_docstrings import run_hook -@pytest.fixture +@pytest.fixture() def example_module(request): fullpath = ( Path(request.config.rootdir) diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index fc6efc0d..a7f68c4e 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -1,24 +1,22 @@ -from collections import namedtuple -from copy import deepcopy import re import textwrap import warnings +from collections import namedtuple +from copy import deepcopy import jinja2 +import pytest +from pytest import warns as assert_warns -from numpydoc.numpydoc import update_config -from numpydoc.xref import DEFAULT_LINKS -from numpydoc.docscrape import NumpyDocString, FunctionDoc, ClassDoc, ParseError +from numpydoc.docscrape import ClassDoc, FunctionDoc, NumpyDocString from numpydoc.docscrape_sphinx import ( - SphinxDocString, SphinxClassDoc, + SphinxDocString, SphinxFunctionDoc, get_doc_object, ) -import pytest -from pytest import raises as assert_raises -from pytest import warns as assert_warns - +from numpydoc.numpydoc import update_config +from numpydoc.xref import DEFAULT_LINKS doc_txt = """\ numpy.multivariate_normal(mean, cov, shape=None, spam=None) @@ -316,11 +314,9 @@ class Dummy: def spam(self, a, b): """Spam\n\nSpam spam.""" - pass def ham(self, c, d): """Cheese\n\nNo cheese.""" - pass def dummy_func(arg): """ @@ -897,8 +893,6 @@ class Dummy: func_d """ - pass - s = str(FunctionDoc(Dummy, role="func")) assert ":func:`func_a`, :func:`func_b`" in s assert " some relationship" in s @@ -941,8 +935,6 @@ class BadSection: This class has a nope section. """ - pass - with pytest.warns(UserWarning, match="Unknown section Mope") as record: NumpyDocString(doc_text) assert len(record) == 1 @@ -1085,11 +1077,9 @@ class Dummy: def spam(self, a, b): """Spam\n\nSpam spam.""" - pass def ham(self, c, d): """Cheese\n\nNo cheese.""" - pass @property def spammity(self): @@ -1099,8 +1089,6 @@ def spammity(self): class Ignorable: """local class, to be ignored""" - pass - for cls in (ClassDoc, SphinxClassDoc): doc = cls(Dummy, config=dict(show_class_members=False)) assert "Methods" not in str(doc), (cls, str(doc)) @@ -1128,11 +1116,9 @@ class SubDummy(Dummy): def ham(self, c, d): """Cheese\n\nNo cheese.\nOverloaded Dummy.ham""" - pass def bar(self, a, b): """Bar\n\nNo bar""" - pass for cls in (ClassDoc, SphinxClassDoc): doc = cls( @@ -1274,7 +1260,7 @@ class Foo: @property def an_attribute(self): """Test attribute""" - return None + return @property def no_docstring(self): @@ -1288,12 +1274,12 @@ def no_docstring2(self): def multiline_sentence(self): """This is a sentence. It spans multiple lines.""" - return None + return @property def midword_period(self): """The sentence for numpy.org.""" - return None + return @property def no_period(self): @@ -1302,7 +1288,7 @@ def no_period(self): Apparently. """ - return None + return doc = SphinxClassDoc(Foo, class_doc_txt) line_by_line_compare( @@ -1378,7 +1364,7 @@ class Foo: @property def an_attribute(self): """Test attribute""" - return None + return attr_doc = """:Attributes: diff --git a/numpydoc/tests/test_full.py b/numpydoc/tests/test_full.py index c4ae1340..9ab241fa 100644 --- a/numpydoc/tests/test_full.py +++ b/numpydoc/tests/test_full.py @@ -1,13 +1,12 @@ import os.path as op import re import shutil -from packaging import version import pytest -import sphinx +from docutils import __version__ as docutils_version +from packaging import version from sphinx.application import Sphinx from sphinx.util.docutils import docutils_namespace -from docutils import __version__ as docutils_version # Test framework adapted from sphinx-gallery (BSD 3-clause) diff --git a/numpydoc/tests/test_main.py b/numpydoc/tests/test_main.py index 8023e1c9..12c06840 100644 --- a/numpydoc/tests/test_main.py +++ b/numpydoc/tests/test_main.py @@ -33,7 +33,7 @@ def _capture_stdout(func_name, *args, **kwargs): Examples -------- - >>> _capture_stdout(print, 'hello world') + >>> _capture_stdout(print, "hello world") 'hello world' """ f = io.StringIO() @@ -53,7 +53,6 @@ def _docstring_with_errors(): ---------- made_up_param : str """ - pass def _invalid_docstring(): @@ -64,7 +63,6 @@ def _invalid_docstring(): -------- : this is invalid """ - pass def test_renders_package_docstring(): diff --git a/numpydoc/tests/test_numpydoc.py b/numpydoc/tests/test_numpydoc.py index 8df2205c..30e6f602 100644 --- a/numpydoc/tests/test_numpydoc.py +++ b/numpydoc/tests/test_numpydoc.py @@ -1,20 +1,20 @@ -import pytest from collections import defaultdict +from copy import deepcopy from io import StringIO from pathlib import PosixPath -from copy import deepcopy +import pytest from docutils import nodes +from sphinx.ext.autodoc import ALL +from sphinx.util import logging from numpydoc.numpydoc import ( - mangle_docstrings, _clean_text_signature, - update_config, clean_backrefs, + mangle_docstrings, + update_config, ) from numpydoc.xref import DEFAULT_LINKS -from sphinx.ext.autodoc import ALL -from sphinx.util import logging class MockConfig: @@ -142,7 +142,7 @@ def test_clean_text_signature(): assert _clean_text_signature("func($self, *args)") == "func(*args)" -@pytest.fixture +@pytest.fixture() def f(): def _function_without_seealso_and_examples(): """ @@ -150,7 +150,6 @@ def _function_without_seealso_and_examples(): Expect SA01 and EX01 errors if validation enabled. """ - pass return _function_without_seealso_and_examples diff --git a/numpydoc/tests/test_validate.py b/numpydoc/tests/test_validate.py index c66f9ee9..8b40794f 100644 --- a/numpydoc/tests/test_validate.py +++ b/numpydoc/tests/test_validate.py @@ -1,14 +1,14 @@ -import pytest import warnings from contextlib import nullcontext from functools import cached_property, partial, wraps -from inspect import getsourcelines, getsourcefile +from inspect import getsourcefile, getsourcelines + +import pytest +import numpydoc.tests from numpydoc import validate -from numpydoc.validate import Validator from numpydoc.docscrape import get_doc_object -import numpydoc.tests - +from numpydoc.validate import Validator validate_one = validate.validate @@ -150,7 +150,6 @@ class GoodDocStrings: def one_liner(self): """Allow one liner docstrings (including quotes).""" # This should fail, but not because of the position of the quotes - pass def plot(self, kind, color="blue", **kwargs): """ @@ -164,7 +163,7 @@ def plot(self, kind, color="blue", **kwargs): kind : str Kind of matplotlib plot, e.g.:: - 'foo' + "foo" color : str, default 'blue' Color name or rgb code. @@ -180,7 +179,6 @@ def plot(self, kind, color="blue", **kwargs): -------- >>> result = 1 + 1 """ - pass def swap(self, arr, i, j, *args, **kwargs): """ @@ -206,7 +204,6 @@ def swap(self, arr, i, j, *args, **kwargs): -------- >>> result = 1 + 1 """ - pass def sample(self): """ @@ -230,7 +227,6 @@ def sample(self): -------- >>> result = 1 + 1 """ - pass def random_letters(self): """ @@ -256,7 +252,6 @@ def random_letters(self): -------- >>> result = 1 + 1 """ - pass def sample_values(self): """ @@ -278,7 +273,6 @@ def sample_values(self): -------- >>> result = 1 + 1 """ - pass def head(self): """ @@ -414,7 +408,6 @@ def contains(self, pat, case=True, na=float("NaN")): >>> s * 2 50 """ - pass def mode(self, axis, numeric_only): """ @@ -446,7 +439,6 @@ def mode(self, axis, numeric_only): -------- >>> result = 1 + 1 """ - pass def good_imports(self): """ @@ -466,7 +458,6 @@ def good_imports(self): >>> datetime.MAXYEAR 9999 """ - pass def no_returns(self): """ @@ -483,7 +474,6 @@ def no_returns(self): -------- >>> result = 1 + 1 """ - pass def empty_returns(self): """ @@ -508,7 +498,7 @@ def say_hello(): if True: return else: - return None + return def warnings(self): """ @@ -529,7 +519,6 @@ def warnings(self): -------- >>> result = 1 + 1 """ - pass def multiple_variables_on_one_line(self, matrix, a, b, i, j): """ @@ -555,7 +544,6 @@ def multiple_variables_on_one_line(self, matrix, a, b, i, j): -------- >>> result = 1 + 1 """ - pass def other_parameters(self, param1, param2): """ @@ -582,7 +570,6 @@ def other_parameters(self, param1, param2): -------- >>> result = 1 + 1 """ - pass def valid_options_in_parameter_description_sets(self, bar): """ @@ -628,7 +615,6 @@ def parameters_with_trailing_underscores(self, str_): -------- >>> result = 1 + 1 """ - pass def parameter_with_wrong_types_as_substrings(self, a, b, c, d, e, f): r""" @@ -662,7 +648,6 @@ def parameter_with_wrong_types_as_substrings(self, a, b, c, d, e, f): -------- >>> result = 1 + 1 """ - pass class BadGenericDocStrings: @@ -693,7 +678,6 @@ def astype(self, dtype): Verb in third-person of the present simple, should be infinitive. """ - pass def astype1(self, dtype): """ @@ -701,7 +685,6 @@ def astype1(self, dtype): Does not start with verb. """ - pass def astype2(self, dtype): """ @@ -709,7 +692,6 @@ def astype2(self, dtype): Missing dot at the end. """ - pass def astype3(self, dtype): """ @@ -718,7 +700,6 @@ def astype3(self, dtype): Summary is too verbose and doesn't fit in a single line. """ - pass def two_linebreaks_between_sections(self, foo): """ @@ -732,7 +713,6 @@ def two_linebreaks_between_sections(self, foo): foo : str Description of foo parameter. """ - pass def linebreak_at_end_of_docstring(self, foo): """ @@ -746,7 +726,6 @@ def linebreak_at_end_of_docstring(self, foo): Description of foo parameter. """ - pass def plot(self, kind, **kwargs): """ @@ -770,7 +749,6 @@ def plot(self, kind, **kwargs): kind: str kind of matplotlib plot """ - pass def unknown_section(self): """ @@ -792,7 +770,7 @@ def sections_in_wrong_order(self): Examples -------- - >>> print('So far Examples is good, as it goes before Parameters') + >>> print("So far Examples is good, as it goes before Parameters") So far Examples is good, as it goes before Parameters See Also @@ -835,7 +813,6 @@ def directives_without_two_colons(self, first, second): .. deprecated 0.00.0 """ - pass class WarnGenericFormat: @@ -852,7 +829,6 @@ def too_short_header_underline(self, a, b): a, b : int Foo bar baz. """ - pass class BadSummaries: @@ -878,19 +854,16 @@ def wrong_line(self): """Quotes are on the wrong line. Both opening and closing.""" - pass def no_punctuation(self): """ Has the right line but forgets punctuation """ - pass def no_capitalization(self): """ provides a lowercase summary. """ - pass def no_infinitive(self): """ @@ -1022,7 +995,6 @@ def blank_lines(self, kind): kind : str Foo bar baz. """ - pass def integer_parameter(self, kind): """ @@ -1033,7 +1005,6 @@ def integer_parameter(self, kind): kind : integer Foo bar baz. """ - pass def string_parameter(self, kind): """ @@ -1044,7 +1015,6 @@ def string_parameter(self, kind): kind : string Foo bar baz. """ - pass def boolean_parameter(self, kind): """ @@ -1055,7 +1025,6 @@ def boolean_parameter(self, kind): kind : boolean Foo bar baz. """ - pass def list_incorrect_parameter_type(self, kind): """ @@ -1066,7 +1035,6 @@ def list_incorrect_parameter_type(self, kind): kind : list of boolean, integer, float or string Foo bar baz. """ - pass def bad_parameter_spacing(self, a, b): """ @@ -1077,7 +1045,6 @@ def bad_parameter_spacing(self, a, b): a, b : int Foo bar baz. """ - pass class BadReturns: @@ -1171,7 +1138,6 @@ def no_desc(self): -------- Series.tail """ - pass def desc_no_period(self): """ @@ -1183,7 +1149,6 @@ def desc_no_period(self): Series.iloc : Return a slice of the elements in the Series, which can also be used to return the first or last n """ - pass def desc_first_letter_lowercase(self): """ @@ -1195,7 +1160,6 @@ def desc_first_letter_lowercase(self): Series.iloc : Return a slice of the elements in the Series, which can also be used to return the first or last n. """ - pass def prefix_pandas(self): """ @@ -1206,7 +1170,6 @@ def prefix_pandas(self): pandas.Series.rename : Alter Series index labels or name. DataFrame.head : The first `n` rows of the caller object. """ - pass class BadExamples: @@ -1214,28 +1177,25 @@ def missing_whitespace_around_arithmetic_operator(self): """ Examples -------- - >>> 2+5 + >>> 2 + 5 7 """ - pass def indentation_is_not_a_multiple_of_four(self): """ Examples -------- >>> if 2 + 5: - ... pass + ... pass """ - pass def missing_whitespace_after_comma(self): """ Examples -------- >>> import datetime - >>> value = datetime.date(2019,1,1) + >>> value = datetime.date(2019, 1, 1) """ - pass class TestValidator: @@ -1326,7 +1286,7 @@ def test_bad_class(self, capsys): def test_bad_generic_functions(self, capsys, func): with pytest.warns(UserWarning): errors = validate_one( - self._import_path(klass="WarnGenericFormat", func=func) # noqa:F821 + self._import_path(klass="WarnGenericFormat", func=func) ) assert "is too short" in w.msg @@ -1344,7 +1304,7 @@ def test_bad_generic_functions(self, capsys, func): ) def test_bad_generic_functions(self, capsys, func): errors = validate_one( - self._import_path(klass="BadGenericDocStrings", func=func) # noqa:F821 + self._import_path(klass="BadGenericDocStrings", func=func) )["errors"] assert isinstance(errors, list) assert errors @@ -1600,24 +1560,20 @@ class DecoratorClass: def test_no_decorator(self): """Test method without decorators.""" - pass @property def test_property(self): """Test property method.""" - pass @cached_property def test_cached_property(self): """Test property method.""" - pass @decorator @decorator @decorator def test_three_decorators(self): """Test method with three decorators.""" - pass class TestValidatorClass: diff --git a/numpydoc/tests/test_xref.py b/numpydoc/tests/test_xref.py index b4b31252..2256f759 100644 --- a/numpydoc/tests/test_xref.py +++ b/numpydoc/tests/test_xref.py @@ -1,5 +1,6 @@ import pytest -from numpydoc.xref import make_xref, DEFAULT_LINKS + +from numpydoc.xref import DEFAULT_LINKS, make_xref # Use the default numpydoc link mapping xref_aliases = DEFAULT_LINKS @@ -99,7 +100,7 @@ dict[tuple(str, str), int] :class:`python:dict`\[:class:`python:tuple`\(:class:`python:str`, :class:`python:str`), :class:`python:int`] -""" # noqa: E501 +""" data_ignore_obj = r""" (...) array_like, float, optional @@ -194,7 +195,7 @@ dict[tuple(str, str), int] :class:`python:dict`\[:class:`python:tuple`\(:class:`python:str`, :class:`python:str`), :class:`python:int`] -""" # noqa: E501 +""" xref_ignore = {"or", "in", "of", "default", "optional"} diff --git a/numpydoc/tests/tinybuild/conf.py b/numpydoc/tests/tinybuild/conf.py index c82d973f..a0719227 100644 --- a/numpydoc/tests/tinybuild/conf.py +++ b/numpydoc/tests/tinybuild/conf.py @@ -4,7 +4,7 @@ path = os.path.dirname(__file__) if path not in sys.path: sys.path.insert(0, path) -import numpydoc_test_module # noqa +import numpydoc_test_module extensions = [ "sphinx.ext.autodoc", diff --git a/numpydoc/tests/tinybuild/numpydoc_test_module.py b/numpydoc/tests/tinybuild/numpydoc_test_module.py index d303e9e1..d0415714 100644 --- a/numpydoc/tests/tinybuild/numpydoc_test_module.py +++ b/numpydoc/tests/tinybuild/numpydoc_test_module.py @@ -37,7 +37,6 @@ class MyClass: def example(self, x): """Example method.""" - pass def my_function(*args, **kwargs): @@ -61,4 +60,4 @@ def my_function(*args, **kwargs): ---------- .. [3] https://numpydoc.readthedocs.io """ - return None + return diff --git a/numpydoc/validate.py b/numpydoc/validate.py index 02253517..c0409c71 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -6,8 +6,6 @@ with all the detected errors. """ -from copy import deepcopy -from typing import Dict, List, Set, Optional, Any import ast import collections import functools @@ -18,10 +16,11 @@ import re import textwrap import tokenize +from copy import deepcopy +from typing import Any, Dict, List, Optional, Set from .docscrape import get_doc_object - DIRECTIVES = ["versionadded", "versionchanged", "deprecated"] DIRECTIVE_PATTERN = re.compile( r"^\s*\.\. ({})(?!::)".format("|".join(DIRECTIVES)), re.I | re.M @@ -252,10 +251,10 @@ def _load_obj(name): Examples -------- - >>> Validator._load_obj('datetime.datetime') + >>> Validator._load_obj("datetime.datetime") """ - for maxsplit in range(0, name.count(".") + 1): + for maxsplit in range(name.count(".") + 1): module, *func_parts = name.rsplit(".", maxsplit) try: obj = importlib.import_module(module) diff --git a/numpydoc/xref.py b/numpydoc/xref.py index a0cc8a5d..f1b9d79f 100644 --- a/numpydoc/xref.py +++ b/numpydoc/xref.py @@ -16,11 +16,7 @@ QUALIFIED_NAME_RE = re.compile( # e.g int, numpy.array, ~numpy.array, .class_in_current_module - r"^" - r"[~\.]?" - r"[a-zA-Z_]\w*" - r"(?:\.[a-zA-Z_]\w*)*" - r"$" + r"^" r"[~\.]?" r"[a-zA-Z_]\w*" r"(?:\.[a-zA-Z_]\w*)*" r"$" ) CONTAINER_SPLIT_RE = re.compile( From 83fc1b2fd89773dabe02d50f99c7b49e2b503bb7 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Sat, 11 May 2024 09:01:17 -0700 Subject: [PATCH 33/92] Ignore ruff formatting with git blame --- .git-blame-ignore-revs | 1 + 1 file changed, 1 insertion(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 9984dc57..d873f107 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1 +1,2 @@ 4b38c01e680cf2032acb09819bc0985e5dfc5ca8 +be316333f436519e0e2ab1379cbdedde79c9ac68 From 2e6d88b291eb402209f4b583839c6348e95eed69 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Sat, 11 May 2024 10:20:59 -0700 Subject: [PATCH 34/92] Fix line numbers --- numpydoc/tests/hooks/test_validate_hook.py | 56 +++++++++++----------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/numpydoc/tests/hooks/test_validate_hook.py b/numpydoc/tests/hooks/test_validate_hook.py index d1418656..9a208cb0 100644 --- a/numpydoc/tests/hooks/test_validate_hook.py +++ b/numpydoc/tests/hooks/test_validate_hook.py @@ -39,35 +39,35 @@ def test_validate_hook(example_module, config, capsys): +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | EX01 | No examples section found | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:9 | example_module.MyClass | ES01 | No extended summary found | + | numpydoc/tests/hooks/example_module.py:8 | example_module.MyClass | ES01 | No extended summary found | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:9 | example_module.MyClass | SA01 | See Also section not found | + | numpydoc/tests/hooks/example_module.py:8 | example_module.MyClass | SA01 | See Also section not found | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:9 | example_module.MyClass | EX01 | No examples section found | + | numpydoc/tests/hooks/example_module.py:8 | example_module.MyClass | EX01 | No examples section found | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:12 | example_module.MyClass.__init__ | GL08 | The object does not have a docstring | + | numpydoc/tests/hooks/example_module.py:11 | example_module.MyClass.__init__ | GL08 | The object does not have a docstring | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | ES01 | No extended summary found | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | ES01 | No extended summary found | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | SA01 | See Also section not found | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | SA01 | See Also section not found | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | EX01 | No examples section found | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | EX01 | No examples section found | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:28 | example_module.MyClass.process | SS05 | Summary must start with infinitive verb, not third | + | numpydoc/tests/hooks/example_module.py:26 | example_module.MyClass.process | SS05 | Summary must start with infinitive verb, not third | | | | | person (e.g. use "Generate" instead of | | | | | "Generates") | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:28 | example_module.MyClass.process | ES01 | No extended summary found | + | numpydoc/tests/hooks/example_module.py:26 | example_module.MyClass.process | ES01 | No extended summary found | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:28 | example_module.MyClass.process | SA01 | See Also section not found | + | numpydoc/tests/hooks/example_module.py:26 | example_module.MyClass.process | SA01 | See Also section not found | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:28 | example_module.MyClass.process | EX01 | No examples section found | + | numpydoc/tests/hooks/example_module.py:26 | example_module.MyClass.process | EX01 | No examples section found | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:33 | example_module.NewClass | GL08 | The object does not have a docstring | + | numpydoc/tests/hooks/example_module.py:30 | example_module.NewClass | GL08 | The object does not have a docstring | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ """ ) @@ -90,17 +90,17 @@ def test_validate_hook_with_ignore(example_module, capsys): +===========================================+=====================================+=========+====================================================+ | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | PR01 | Parameters {'name'} not documented | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:12 | example_module.MyClass.__init__ | GL08 | The object does not have a docstring | + | numpydoc/tests/hooks/example_module.py:11 | example_module.MyClass.__init__ | GL08 | The object does not have a docstring | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:28 | example_module.MyClass.process | SS05 | Summary must start with infinitive verb, not third | + | numpydoc/tests/hooks/example_module.py:26 | example_module.MyClass.process | SS05 | Summary must start with infinitive verb, not third | | | | | person (e.g. use "Generate" instead of | | | | | "Generates") | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:33 | example_module.NewClass | GL08 | The object does not have a docstring | + | numpydoc/tests/hooks/example_module.py:30 | example_module.NewClass | GL08 | The object does not have a docstring | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ """ ) @@ -145,11 +145,11 @@ def test_validate_hook_with_toml_config(example_module, tmp_path, capsys): +===========================================+=====================================+=========+========================================+ | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | PR01 | Parameters {'name'} not documented | +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:33 | example_module.NewClass | GL08 | The object does not have a docstring | + | numpydoc/tests/hooks/example_module.py:30 | example_module.NewClass | GL08 | The object does not have a docstring | +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ """ ) @@ -184,11 +184,11 @@ def test_validate_hook_with_setup_cfg(example_module, tmp_path, capsys): +===========================================+=====================================+=========+========================================+ | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | PR01 | Parameters {'name'} not documented | +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:33 | example_module.NewClass | GL08 | The object does not have a docstring | + | numpydoc/tests/hooks/example_module.py:30 | example_module.NewClass | GL08 | The object does not have a docstring | +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ """ ) @@ -235,7 +235,7 @@ def test_validate_hook_exclude_option_pyproject(example_module, tmp_path, capsys +===========================================+==============================+=========+======================================+ | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | PR01 | Parameters {'name'} not documented | +-------------------------------------------+------------------------------+---------+--------------------------------------+ - | numpydoc/tests/hooks/example_module.py:33 | example_module.NewClass | GL08 | The object does not have a docstring | + | numpydoc/tests/hooks/example_module.py:30 | example_module.NewClass | GL08 | The object does not have a docstring | +-------------------------------------------+------------------------------+---------+--------------------------------------+ """ ) @@ -270,9 +270,9 @@ def test_validate_hook_exclude_option_setup_cfg(example_module, tmp_path, capsys +===========================================+=====================================+=========+========================================+ | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | PR01 | Parameters {'name'} not documented | +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:18 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | + | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ """ ) From b7c66884aad6227df90918c2aeeac47032b64056 Mon Sep 17 00:00:00 2001 From: Matt Haberland Date: Mon, 3 Jun 2024 11:25:59 -0700 Subject: [PATCH 35/92] DOC: Clarify recommendations regarding use of backticks (#525) * doc/format.rst * Apply suggestions from code review * MAINT: partially respond to some comments to prepare for discussion * MAINT: adjustments per review * MAINT: fix links to numpy --------- Co-authored-by: Jarrod Millman Co-authored-by: Ross Barnowski --- doc/conf.py | 2 +- doc/format.rst | 61 +++++++++++++++++++++++++++++++++++--------------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 9bffda88..b1b2e63d 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -139,6 +139,6 @@ # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { "python": ("https://docs.python.org/3/", None), - "numpy": ("https://numpy.org/devdocs/", None), + "numpy": ("https://numpy.org/doc/stable/", None), "sklearn": ("https://scikit-learn.org/stable/", None), } diff --git a/doc/format.rst b/doc/format.rst index 2f9753c5..92cc2d36 100644 --- a/doc/format.rst +++ b/doc/format.rst @@ -175,8 +175,9 @@ respective types. y Description of parameter `y` (with type not specified). -Enclose variables in single backticks. The colon must be preceded -by a space, or omitted if the type is absent. +The colon must be preceded by a space, or omitted if the type is absent. +When referring to a parameter anywhere within the docstring, enclose its +name in single backticks. For the parameter types, be as precise as possible. Below are a few examples of parameters and their types. @@ -549,6 +550,8 @@ not explicitly imported, `.. plot::` can be used directly if Documenting classes ------------------- +.. _classdoc: + Class docstring ``````````````` Use the same sections as outlined above (all except :ref:`Returns ` @@ -562,10 +565,12 @@ section, may be used to describe non-method attributes of the class:: Attributes ---------- x : float - The X coordinate. + Description of attribute `x`. y : float - The Y coordinate. + Description of attribute `y`. +When referring to an attribute anywhere within the docstring, enclose its +name in single backticks. Attributes that are properties and have their own docstrings can be simply listed by name:: @@ -606,6 +611,8 @@ becomes useful to have an additional **Methods** section: """ +When referring to a method anywhere within the docstring, enclose its +name in single backticks. If it is necessary to explain a private method (use with care!), it can be referred to in the :ref:`Extended Summary ` or the :ref:`Notes ` section. @@ -690,11 +697,11 @@ belong in docstrings. Other points to keep in mind ---------------------------- * Equations : as discussed in the :ref:`Notes ` section above, LaTeX - formatting should be kept to a minimum. Often it's possible to show equations as - Python code or pseudo-code instead, which is much more readable in a - terminal. For inline display use double backticks (like ``y = np.sin(x)``). - For display with blank lines above and below, use a double colon and indent - the code, like:: + formatting should be kept to a minimum. Often it's possible to show + equations as Python code or pseudo-code instead, which is much more readable + in a terminal. For inline display of code, use double backticks + like ````y = np.sin(x)````. For display with blank lines above and below, + use a double colon and indent the code, like:: end of previous sentence:: @@ -717,9 +724,13 @@ Other points to keep in mind (i.e. scalar types, sequence types), those arguments can be documented with type `array_like`. -* Links : If you need to include hyperlinks in your docstring, note that - some docstring sections are not parsed as standard reST, and in these - sections, numpydoc may become confused by hyperlink targets such as:: +* Links : Depending on project settings, hyperlinks to documentation of + modules, classes, functions, methods, and attributes should automatically + be created if a recognized name is included within single backticks (e.g. + ```numpy``` renders as :any:`numpy`). If you need to include other + hyperlinks, note that some docstring sections are not parsed as standard + reST, and in these sections, numpydoc may become confused by hyperlink + targets such as:: .. _Example: http://www.example.com @@ -729,17 +740,31 @@ Other points to keep in mind `Example `_ - Common reST concepts -------------------- For paragraphs, indentation is significant and indicates indentation in the output. New paragraphs are marked with a blank line. -Use ``*italics*``, ``**bold**`` and ````monospace```` if needed in any -explanations -(but not for variable names and doctest code or multi-line code). -Variable, module, function, and class names should be written between -single back-ticks (```numpy```). +Use ``*italics*``, ``**bold**`` if needed in any explanations. + +Use of backticks in reST is a common point of confusion because it is different +from markdown. In most flavors of markdown, single backticks are used for +monospaced font; in reST, *double* backticks are for ``monospaced font``, +whereas the behavior of single backticks is defined by the default role. This +leads to the following style recommendations: + +- Module, class, function, method, and attribute names should render as + hyperlinks in monospaced font (e.g. :any:`numpy`); depending on project + settings, this may be accomplished simply be enclosing them in single + backticks. If the hyperlink does not render as intended, explicitly + include the appropriate role and/or namespace. +- This guide continues to recommended that parameter names be enclosed within + single backticks. Currently, this may cause parameter names to render + improperly and cause warnings, but numpydoc will soon release a feature + that causes them to render as monospaced hyperlinks to the parameter + documentation. +- All other text that is intended to render in ``monospaced`` font should be + enclosed within ````double backticks````. A more extensive example of reST markup can be found in `this example document `_; From 58530b92ba8d5a7528b9f3b8b7535d86ecd2b227 Mon Sep 17 00:00:00 2001 From: M Bussonnier Date: Mon, 3 Jun 2024 11:50:44 -0700 Subject: [PATCH 36/92] Use intersphinx registry to avoid out of date links. (#563) * Use intersphinx registry to avoid out of date links. * Update doc/conf.py --------- Co-authored-by: Eric Larson --- doc/conf.py | 11 +++++------ pyproject.toml | 1 + requirements/doc.txt | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index b1b2e63d..519fb795 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -12,6 +12,8 @@ import sys from datetime import date +from intersphinx_registry import get_intersphinx_mapping + import numpydoc # for example.py @@ -136,9 +138,6 @@ # -- Intersphinx setup ---------------------------------------------------- -# Example configuration for intersphinx: refer to the Python standard library. -intersphinx_mapping = { - "python": ("https://docs.python.org/3/", None), - "numpy": ("https://numpy.org/doc/stable/", None), - "sklearn": ("https://scikit-learn.org/stable/", None), -} +# Example configuration for intersphinx: refer to several Python libraries. + +intersphinx_mapping = get_intersphinx_mapping(packages=["python", "numpy", "sklearn"]) diff --git a/pyproject.toml b/pyproject.toml index e882da19..5ee947a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -53,6 +53,7 @@ doc = [ 'matplotlib>=3.5', 'pydata-sphinx-theme>=0.13.3', 'sphinx>=7', + 'intersphinx_registry', ] test = [ 'pytest', diff --git a/requirements/doc.txt b/requirements/doc.txt index f3d9b058..950966b6 100644 --- a/requirements/doc.txt +++ b/requirements/doc.txt @@ -4,3 +4,4 @@ numpy>=1.22 matplotlib>=3.5 pydata-sphinx-theme>=0.13.3 sphinx>=7 +intersphinx_registry From 342bdce878c10e4a308d9493ae6ceb8aaab4e9a1 Mon Sep 17 00:00:00 2001 From: M Bussonnier Date: Wed, 12 Jun 2024 11:42:06 -0700 Subject: [PATCH 37/92] Do not rely on requirements.txt in ci, use .[test,doc] (#566) This is one step toward not needing those file and having one less command to sugest to users. --- .github/workflows/test.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 853c8539..8eed0ce9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,14 +37,13 @@ jobs: - name: Setup environment run: | python -m pip install --upgrade pip wheel setuptools - python -m pip install -r requirements/test.txt -r requirements/doc.txt python -m pip install codecov python -m pip install ${{ matrix.sphinx-version }} python -m pip list - name: Install run: | - python -m pip install . + python -m pip install .[test,doc] pip list - name: Run test suite @@ -91,13 +90,12 @@ jobs: - name: Setup environment run: | python -m pip install --upgrade pip wheel setuptools - python -m pip install --pre -r requirements/test.txt -r requirements/doc.txt python -m pip install codecov python -m pip list - name: Install run: | - python -m pip install . + python -m pip install .[test,doc] pip list - name: Run test suite From ecd9d1f59b965f7c913e3c261b275137883880ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brigitta=20Sip=C5=91cz?= Date: Tue, 18 Jun 2024 07:12:46 -0700 Subject: [PATCH 38/92] CI: update action that got moved org (#567) --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7e2f5eea..6d52fc24 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,7 +5,7 @@ jobs: name: Run CircleCI artifacts redirector steps: - name: GitHub Action step - uses: larsoner/circleci-artifacts-redirector-action@master + uses: scientific-python/circleci-artifacts-redirector-action@4e13a10d89177f4bfc8007a7064bdbeda848d8d1 # v1.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} api-token: ${{ secrets.CIRCLECI_ARTIFACT_REDIRECTOR_TOKEN }} From 7bf31727bc8aa94703d15581783b378039351f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Melissa=20Weber=20Mendon=C3=A7a?= Date: Thu, 20 Jun 2024 16:51:43 -0300 Subject: [PATCH 39/92] Fix navbar for documentation pages (#569) Prevents duplicate search field. --- doc/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/conf.py b/doc/conf.py index 519fb795..ca41a854 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -82,7 +82,7 @@ html_theme = "pydata_sphinx_theme" html_theme_options = { "show_prev_next": False, - "navbar_end": ["theme-switcher", "search-field.html", "navbar-icon-links.html"], + "navbar_end": ["theme-switcher", "navbar-icon-links.html"], "icon_links": [ { "name": "GitHub", From b7986bab022b29747c73f51b36ea98532545356d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:33:10 +0000 Subject: [PATCH 40/92] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-prettier: ffb6a759a979008c0e6dff86e39f4745a2d9eac4 → f12edd9c7be1c20cfa42420fd0e6df71e42b51ea](https://github.com/pre-commit/mirrors-prettier/compare/ffb6a759a979008c0e6dff86e39f4745a2d9eac4...f12edd9c7be1c20cfa42420fd0e6df71e42b51ea) - [github.com/astral-sh/ruff-pre-commit: f8a3f8c471fb698229face5ed7640a64900b781e → 1dc9eb131c2ea4816c708e4d85820d2cc8542683](https://github.com/astral-sh/ruff-pre-commit/compare/f8a3f8c471fb698229face5ed7640a64900b781e...1dc9eb131c2ea4816c708e4d85820d2cc8542683) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cd7c3531..93d62216 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,14 +18,14 @@ repos: - id: trailing-whitespace - repo: https://github.com/pre-commit/mirrors-prettier - rev: ffb6a759a979008c0e6dff86e39f4745a2d9eac4 # frozen: v3.1.0 + rev: f12edd9c7be1c20cfa42420fd0e6df71e42b51ea # frozen: v4.0.0-alpha.8 hooks: - id: prettier types_or: [yaml, toml, markdown, css, scss, javascript, json] args: [--prose-wrap=preserve] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "f8a3f8c471fb698229face5ed7640a64900b781e" # frozen: v0.4.4 + rev: "1dc9eb131c2ea4816c708e4d85820d2cc8542683" # frozen: v0.5.0 hooks: - id: ruff args: ["--fix", "--show-fixes", "--exit-non-zero-on-fix"] From 1c66689c1a824316e4228df2496543ba98b5c43c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 17:33:24 +0000 Subject: [PATCH 41/92] =?UTF-8?q?'[pre-commit.ci=20=F0=9F=A4=96]=20Apply?= =?UTF-8?q?=20code=20format=20tools=20to=20PR'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pre-commit-config.yaml | 4 ++-- numpydoc/docscrape_sphinx.py | 2 +- numpydoc/numpydoc.py | 6 ++++-- numpydoc/validate.py | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 93d62216..41a80e7d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,14 +18,14 @@ repos: - id: trailing-whitespace - repo: https://github.com/pre-commit/mirrors-prettier - rev: f12edd9c7be1c20cfa42420fd0e6df71e42b51ea # frozen: v4.0.0-alpha.8 + rev: f12edd9c7be1c20cfa42420fd0e6df71e42b51ea # frozen: v4.0.0-alpha.8 hooks: - id: prettier types_or: [yaml, toml, markdown, css, scss, javascript, json] args: [--prose-wrap=preserve] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "1dc9eb131c2ea4816c708e4d85820d2cc8542683" # frozen: v0.5.0 + rev: "1dc9eb131c2ea4816c708e4d85820d2cc8542683" # frozen: v0.5.0 hooks: - id: ruff args: ["--fix", "--show-fixes", "--exit-non-zero-on-fix"] diff --git a/numpydoc/docscrape_sphinx.py b/numpydoc/docscrape_sphinx.py index 64588f55..ed389fb4 100644 --- a/numpydoc/docscrape_sphinx.py +++ b/numpydoc/docscrape_sphinx.py @@ -329,7 +329,7 @@ def _str_references(self): out += [".. only:: latex", ""] items = [] for line in self["References"]: - m = re.match(r".. \[([a-z0-9._-]+)\]", line, re.I) + m = re.match(r".. \[([a-z0-9._-]+)\]", line, re.IGNORECASE) if m: items.append(m.group(1)) out += [" " + ", ".join([f"[{item}]_" for item in items]), ""] diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 2a8e1066..a04443b3 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -58,7 +58,9 @@ def rename_references(app, what, name, obj, options, lines): references = set() for line in lines: line = line.strip() - m = re.match(r"^\.\. +\[(%s)\]" % app.config.numpydoc_citation_re, line, re.I) + m = re.match( + r"^\.\. +\[(%s)\]" % app.config.numpydoc_citation_re, line, re.IGNORECASE + ) if m: references.add(m.group(1)) @@ -185,7 +187,7 @@ def mangle_docstrings(app, what, name, obj, options, lines): if what == "module": # Strip top title pattern = "^\\s*[#*=]{4,}\\n[a-z0-9 -]+\\n[#*=]{4,}\\s*" - title_re = re.compile(pattern, re.I | re.S) + title_re = re.compile(pattern, re.IGNORECASE | re.DOTALL) lines[:] = title_re.sub("", u_NL.join(lines)).split(u_NL) else: try: diff --git a/numpydoc/validate.py b/numpydoc/validate.py index c0409c71..138e9d48 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -23,7 +23,7 @@ DIRECTIVES = ["versionadded", "versionchanged", "deprecated"] DIRECTIVE_PATTERN = re.compile( - r"^\s*\.\. ({})(?!::)".format("|".join(DIRECTIVES)), re.I | re.M + r"^\s*\.\. ({})(?!::)".format("|".join(DIRECTIVES)), re.IGNORECASE | re.MULTILINE ) ALLOWED_SECTIONS = [ "Parameters", From 1ca0c4e74155f6b8e98885177cfe6bf4e99e72d6 Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Mon, 1 Jul 2024 13:46:16 -0400 Subject: [PATCH 42/92] FIX: Fixes --- numpydoc/docscrape.py | 17 ++++++++--------- numpydoc/hooks/utils.py | 2 +- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index a241dc21..f3b4a0ce 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -711,23 +711,22 @@ def properties(self): @staticmethod def _should_skip_member(name, klass): - if ( + return ( # 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 - if name not in self._cls.__dict__: - return False # class member is inherited, we do not show it - return True + return ( + # show all class members + self.show_inherited_members + # or class member is not inherited + or name in self._cls.__dict__ + ) def get_doc_object( diff --git a/numpydoc/hooks/utils.py b/numpydoc/hooks/utils.py index 448e1245..6f40c69c 100644 --- a/numpydoc/hooks/utils.py +++ b/numpydoc/hooks/utils.py @@ -31,7 +31,7 @@ def find_project_root(srcs: Sequence[str]): `Black `_. """ if not srcs: - return Path().resolve(), "current directory" + return Path.cwd(), "current directory" common_path = Path( os.path.commonpath([Path(src).expanduser().resolve() for src in srcs]) From 1246ddf52ca375f794fde1c4bd38bc927b36eb11 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Wed, 3 Jul 2024 10:38:58 -0700 Subject: [PATCH 43/92] Update .pre-commit-config.yaml --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 41a80e7d..425c165f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/pre-commit/mirrors-prettier - rev: f12edd9c7be1c20cfa42420fd0e6df71e42b51ea # frozen: v4.0.0-alpha.8 + rev: ffb6a759a979008c0e6dff86e39f4745a2d9eac4 # frozen: v3.1.0 hooks: - id: prettier types_or: [yaml, toml, markdown, css, scss, javascript, json] From 7716617eac1f61c6b0563781ea5f3a3cf7301d93 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Fri, 12 Jul 2024 15:49:46 +0100 Subject: [PATCH 44/92] Move "Attributes" and "Methods" below "Parameters" (#571) --- numpydoc/docscrape.py | 14 +++---- numpydoc/docscrape_sphinx.py | 12 +++--- numpydoc/templates/numpydoc_docstring.rst | 4 +- numpydoc/tests/test_docscrape.py | 45 +++++++++++++++++++---- 4 files changed, 52 insertions(+), 23 deletions(-) diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index f3b4a0ce..aa13217e 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -120,17 +120,17 @@ class NumpyDocString(Mapping): "Summary": [""], "Extended Summary": [], "Parameters": [], + "Attributes": [], + "Methods": [], "Returns": [], "Yields": [], "Receives": [], + "Other Parameters": [], "Raises": [], "Warns": [], - "Other Parameters": [], - "Attributes": [], - "Methods": [], + "Warnings": [], "See Also": [], "Notes": [], - "Warnings": [], "References": "", "Examples": "", "index": {}, @@ -549,8 +549,10 @@ def __str__(self, func_role=""): out += self._str_signature() out += self._str_summary() out += self._str_extended_summary() + out += self._str_param_list("Parameters") + for param_list in ("Attributes", "Methods"): + out += self._str_param_list(param_list) for param_list in ( - "Parameters", "Returns", "Yields", "Receives", @@ -563,8 +565,6 @@ def __str__(self, func_role=""): out += self._str_see_also(func_role) for s in ("Notes", "References", "Examples"): out += self._str_section(s) - for param_list in ("Attributes", "Methods"): - out += self._str_param_list(param_list) out += self._str_index() return "\n".join(out) diff --git a/numpydoc/docscrape_sphinx.py b/numpydoc/docscrape_sphinx.py index ed389fb4..9b1ccf78 100644 --- a/numpydoc/docscrape_sphinx.py +++ b/numpydoc/docscrape_sphinx.py @@ -359,6 +359,12 @@ def __str__(self, indent=0, func_role="obj"): "summary": self._str_summary(), "extended_summary": self._str_extended_summary(), "parameters": self._str_param_list("Parameters"), + "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"), "returns": self._str_returns("Returns"), "yields": self._str_returns("Yields"), "receives": self._str_returns("Receives"), @@ -370,12 +376,6 @@ 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") - ), - "methods": self._str_member_list("Methods"), } ns = {k: "\n".join(v) for k, v in ns.items()} diff --git a/numpydoc/templates/numpydoc_docstring.rst b/numpydoc/templates/numpydoc_docstring.rst index 79ab1f8e..f6b6a0ae 100644 --- a/numpydoc/templates/numpydoc_docstring.rst +++ b/numpydoc/templates/numpydoc_docstring.rst @@ -2,6 +2,8 @@ {{summary}} {{extended_summary}} {{parameters}} +{{attributes}} +{{methods}} {{returns}} {{yields}} {{receives}} @@ -13,5 +15,3 @@ {{notes}} {{references}} {{examples}} -{{attributes}} -{{methods}} diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index a7f68c4e..4cafc762 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -1203,6 +1203,17 @@ def test_duplicate_signature(): b c + Other Parameters + ---------------- + + another parameter : str + This parameter is less important. + + Notes + ----- + + Some notes about the class. + Examples -------- For usage examples, see `ode`. @@ -1223,10 +1234,6 @@ def test_class_members_doc(): jac : callable ``jac(t, y, *jac_args)`` Bbb. - Examples - -------- - For usage examples, see `ode`. - Attributes ---------- t : float @@ -1251,6 +1258,19 @@ def test_class_members_doc(): b c + Other Parameters + ---------------- + another parameter : str + This parameter is less important. + + Notes + ----- + Some notes about the class. + + Examples + -------- + For usage examples, see `ode`. + """, ) @@ -1304,10 +1324,6 @@ def no_period(self): **jac** : callable ``jac(t, y, *jac_args)`` Bbb. - .. rubric:: Examples - - For usage examples, see `ode`. - :Attributes: **t** : float @@ -1345,6 +1361,19 @@ def no_period(self): **c** ===== ========== + :Other Parameters: + + **another parameter** : str + This parameter is less important. + + .. rubric:: Notes + + Some notes about the class. + + .. rubric:: Examples + + For usage examples, see `ode`. + """, ) From 97a6026508e0dd5382865672e9563a72cc113bd2 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Mon, 22 Jul 2024 11:45:02 +0100 Subject: [PATCH 45/92] docscrape: fixes from SciPy (#576) Co-authored-by: Matt Haberland Co-authored-by: Ross Barnowski --- numpydoc/docscrape.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index aa13217e..bfc2840e 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -344,7 +344,7 @@ def parse_item_name(text): def _parse_index(self, section, content): """ - .. index: default + .. index:: default :refguide: something, else, and more """ @@ -446,7 +446,7 @@ def _error_location(self, msg, error=True): if error: raise ValueError(msg) else: - warn(msg) + warn(msg, stacklevel=3) # string conversion routines From 0c324a9da5a0fe560a66776ae6fd648ed4f25f49 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Wed, 24 Jul 2024 09:03:08 -0700 Subject: [PATCH 46/92] Ignore bots in release notes --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 5ee947a3..24dec3ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,7 +67,7 @@ numpydoc = 'numpydoc.cli:main' [tool.changelist] title_template = "{version}" # Profiles that are excluded from the contributor list. -ignored_user_logins = ["dependabot[bot]", "pre-commit-ci[bot]"] +ignored_user_logins = ["dependabot[bot]", "pre-commit-ci[bot]", "web-flow"] [tool.ruff.lint] extend-select = [ From 98fd2f3f0758f7e412f871c4532c30a920c22235 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Wed, 24 Jul 2024 09:05:39 -0700 Subject: [PATCH 47/92] Designate 1.8.0rc0 release --- doc/release/notes.rst | 72 +++++++++++++++++++++++++++++++++++++++++++ numpydoc/_version.py | 2 +- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/doc/release/notes.rst b/doc/release/notes.rst index 3dca7339..b4f7fb73 100644 --- a/doc/release/notes.rst +++ b/doc/release/notes.rst @@ -1,3 +1,75 @@ +1.8.0rc0 +======== + +We're happy to announce the release of numpydoc 1.8.0rc0! + +Enhancements +------------ + +- Unify CLIs (`#537 `_). +- Move "Attributes" and "Methods" below "Parameters" (`#571 `_). + +Bug Fixes +--------- + +- FIX: coroutines can have a return statement (`#542 `_). +- Unwrap decorated objects for YD01 validation check (`#541 `_). +- Fix bug with validation encoding (`#550 `_). + +Documentation +------------- + +- Classify development status as Production/Stable (`#548 `_). +- Add note about TOML regex; fix typo (`#552 `_). +- DOC: Clarify recommendations regarding use of backticks (`#525 `_). + +Maintenance +----------- + +- Fix typo in label-check.yml (`#538 `_). +- [pre-commit.ci] pre-commit autoupdate (`#539 `_). +- DEV: Rm xfails from pytest summary (`#540 `_). +- Drop Python 3.8 support (`#545 `_). +- Clean up old sphinx cruft (`#549 `_). +- Test on sphinx 7.3 (`#547 `_). +- Require GHA update grouping (`#553 `_). +- Update pre-commit config (`#554 `_). +- Use ruff for linting and formatting (`#555 `_). +- Use intersphinx registry to avoid out of date links (`#563 `_). +- Do not rely on requirements.txt in ci, use .[test,doc] (`#566 `_). +- CI: update action that got moved org (`#567 `_). +- Fix navbar for documentation pages (`#569 `_). +- [pre-commit.ci] pre-commit autoupdate (`#570 `_). +- docscrape: fixes from SciPy (`#576 `_). + +Contributors +------------ + +10 authors added to this release (alphabetically): + +- Brigitta Sipőcz (`@bsipocz `_) +- Eric Larson (`@larsoner `_) +- Jarrod Millman (`@jarrodmillman `_) +- Lucas Colley (`@lucascolley `_) +- M Bussonnier (`@Carreau `_) +- Matt Haberland (`@mdhaber `_) +- Melissa Weber Mendonça (`@melissawm `_) +- Ross Barnowski (`@rossbar `_) +- Stefanie Molin (`@stefmolin `_) +- Thomas A Caswell (`@tacaswell `_) + +7 reviewers added to this release (alphabetically): + +- Eric Larson (`@larsoner `_) +- Jarrod Millman (`@jarrodmillman `_) +- M Bussonnier (`@Carreau `_) +- Matt Haberland (`@mdhaber `_) +- Ross Barnowski (`@rossbar `_) +- Stefan van der Walt (`@stefanv `_) +- Stefanie Molin (`@stefmolin `_) + +_These lists are automatically generated, and may not be complete or may contain duplicates._ + 1.7.0 ===== diff --git a/numpydoc/_version.py b/numpydoc/_version.py index df1d1074..5f18c551 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.8.0rc0.dev0" +__version__ = "1.8.0rc0" From a63a1e1df75241cc57923778bfa1b460b8d0e412 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Wed, 24 Jul 2024 09:07:30 -0700 Subject: [PATCH 48/92] Bump version --- numpydoc/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpydoc/_version.py b/numpydoc/_version.py index 5f18c551..6475ad62 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.8.0rc0" +__version__ = "1.8.0rc1.dev0" From 0c7f017e25a462c1bb4f214d2e29a51977cd4621 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Wed, 24 Jul 2024 09:30:53 -0700 Subject: [PATCH 49/92] Designate 1.8.0rc1 release --- README.rst | 11 ----------- doc/release/notes.rst | 4 ++-- numpydoc/_version.py | 2 +- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/README.rst b/README.rst index 87661b6f..aa8b0082 100644 --- a/README.rst +++ b/README.rst @@ -2,17 +2,6 @@ numpydoc -- Numpy's Sphinx extensions ===================================== -.. image:: https://readthedocs.org/projects/numpydoc/badge/?version=latest - :alt: Documentation Status - :scale: 100% - :target: https://numpydoc.readthedocs.io/en/latest/ - -.. image:: https://codecov.io/gh/numpy/numpydoc/branch/main/graph/badge.svg - :target: https://app.codecov.io/gh/numpy/numpydoc/branch/main - -.. image:: https://github.com/numpy/numpydoc/actions/workflows/test.yml/badge.svg?branch=main - :target: https://github.com/numpy/numpydoc/actions/workflows/test.yml - This package provides the ``numpydoc`` Sphinx extension for handling docstrings formatted according to the NumPy documentation format. The extension also adds the code description directives diff --git a/doc/release/notes.rst b/doc/release/notes.rst index b4f7fb73..e9c015a2 100644 --- a/doc/release/notes.rst +++ b/doc/release/notes.rst @@ -1,7 +1,7 @@ -1.8.0rc0 +1.8.0rc1 ======== -We're happy to announce the release of numpydoc 1.8.0rc0! +We're happy to announce the release of numpydoc 1.8.0rc1! Enhancements ------------ diff --git a/numpydoc/_version.py b/numpydoc/_version.py index 6475ad62..d7970d64 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.8.0rc1.dev0" +__version__ = "1.8.0rc1" From 18d278c37514ef69a5e0be41b24f3ecb937f5079 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Wed, 24 Jul 2024 09:31:39 -0700 Subject: [PATCH 50/92] Bump version --- README.rst | 11 +++++++++++ numpydoc/_version.py | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index aa8b0082..87661b6f 100644 --- a/README.rst +++ b/README.rst @@ -2,6 +2,17 @@ numpydoc -- Numpy's Sphinx extensions ===================================== +.. image:: https://readthedocs.org/projects/numpydoc/badge/?version=latest + :alt: Documentation Status + :scale: 100% + :target: https://numpydoc.readthedocs.io/en/latest/ + +.. image:: https://codecov.io/gh/numpy/numpydoc/branch/main/graph/badge.svg + :target: https://app.codecov.io/gh/numpy/numpydoc/branch/main + +.. image:: https://github.com/numpy/numpydoc/actions/workflows/test.yml/badge.svg?branch=main + :target: https://github.com/numpy/numpydoc/actions/workflows/test.yml + This package provides the ``numpydoc`` Sphinx extension for handling docstrings formatted according to the NumPy documentation format. The extension also adds the code description directives diff --git a/numpydoc/_version.py b/numpydoc/_version.py index d7970d64..328a21c1 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.8.0rc1" +__version__ = "1.8.0rc2.dev0" From aeb6812e609768c980daeb4c0dc748f6145081ae Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Wed, 24 Jul 2024 15:00:27 -0400 Subject: [PATCH 51/92] MAINT: Remove scale to work around PyPI bug (#578) --- .github/workflows/release.yml | 39 +++++++++++++++++++++++------------ README.rst | 1 - 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1829de41..3320cf96 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,34 +1,47 @@ name: Build Wheel and Release on: + pull_request: + branches: + - main push: tags: - v* jobs: - pypi-publish: - name: upload release to PyPI - if: github.repository_owner == 'numpy' && startsWith(github.ref, 'refs/tags/v') && github.actor == 'jarrodmillman' && always() + sdist_wheel: + name: sdist and wheels runs-on: ubuntu-latest - # Specifying a GitHub environment is optional, but strongly encouraged - environment: release - permissions: - # IMPORTANT: this permission is mandatory for trusted publishing - id-token: write steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-python@v5 - name: Install Python with: python-version: "3.12" - - name: Build wheels run: | git clean -fxd pip install -U build twine wheel python -m build --sdist --wheel + - run: twine check --strict dist/* + - uses: actions/upload-artifact@v4 + with: + name: dist + path: dist - - name: Publish package distributions to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + pypi-publish: + needs: sdist_wheel + name: upload release to PyPI + if: github.repository_owner == 'numpy' && startsWith(github.ref, 'refs/tags/v') && github.actor == 'jarrodmillman' && always() + runs-on: ubuntu-latest + # Specifying a GitHub environment is optional, but strongly encouraged + environment: release + permissions: + # IMPORTANT: this permission is mandatory for trusted publishing + id-token: write + steps: + - uses: actions/download-artifact@v4 + with: + name: dist + path: dist + - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/README.rst b/README.rst index 87661b6f..354a79d9 100644 --- a/README.rst +++ b/README.rst @@ -4,7 +4,6 @@ numpydoc -- Numpy's Sphinx extensions .. image:: https://readthedocs.org/projects/numpydoc/badge/?version=latest :alt: Documentation Status - :scale: 100% :target: https://numpydoc.readthedocs.io/en/latest/ .. image:: https://codecov.io/gh/numpy/numpydoc/branch/main/graph/badge.svg From ec75b72323c78ba2f1123eff3f54e95fc59752ed Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Wed, 24 Jul 2024 12:33:21 -0700 Subject: [PATCH 52/92] Designate 1.8.0rc2 release --- doc/release/notes.rst | 5 +++-- numpydoc/_version.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/release/notes.rst b/doc/release/notes.rst index e9c015a2..ff84781b 100644 --- a/doc/release/notes.rst +++ b/doc/release/notes.rst @@ -1,7 +1,7 @@ -1.8.0rc1 +1.8.0rc2 ======== -We're happy to announce the release of numpydoc 1.8.0rc1! +We're happy to announce the release of numpydoc 1.8.0rc2! Enhancements ------------ @@ -41,6 +41,7 @@ Maintenance - Fix navbar for documentation pages (`#569 `_). - [pre-commit.ci] pre-commit autoupdate (`#570 `_). - docscrape: fixes from SciPy (`#576 `_). +- MAINT: Remove scale to work around PyPI bug (`#578 `_). Contributors ------------ diff --git a/numpydoc/_version.py b/numpydoc/_version.py index 328a21c1..cdd52720 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.8.0rc2.dev0" +__version__ = "1.8.0rc2" From df1197232e886f703482ab7aacd3722547d461ba Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Wed, 24 Jul 2024 12:34:41 -0700 Subject: [PATCH 53/92] Bump version --- numpydoc/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpydoc/_version.py b/numpydoc/_version.py index cdd52720..6f24021f 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.8.0rc2" +__version__ = "1.8.0rc3.dev0" From 819ea4eb25d7d600c0ea3384f02bef08dfab8cf9 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Fri, 9 Aug 2024 08:50:09 -0700 Subject: [PATCH 54/92] Designate 1.8.0 release --- doc/release/notes.rst | 6 +++--- numpydoc/_version.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/release/notes.rst b/doc/release/notes.rst index ff84781b..ad1ccda1 100644 --- a/doc/release/notes.rst +++ b/doc/release/notes.rst @@ -1,7 +1,7 @@ -1.8.0rc2 -======== +1.8.0 +===== -We're happy to announce the release of numpydoc 1.8.0rc2! +We're happy to announce the release of numpydoc 1.8.0! Enhancements ------------ diff --git a/numpydoc/_version.py b/numpydoc/_version.py index 6f24021f..29654eec 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.8.0rc3.dev0" +__version__ = "1.8.0" From fc81b259770808fba3d2107501d51fd091c8df94 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Fri, 9 Aug 2024 08:52:23 -0700 Subject: [PATCH 55/92] Bump version --- numpydoc/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpydoc/_version.py b/numpydoc/_version.py index 29654eec..fe918984 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.8.0" +__version__ = "1.9.0rc0.dev0" From e478841c2c698465930c7e7a89a9faa29c4a0031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Brigitta=20Sip=C5=91cz?= Date: Wed, 14 Aug 2024 08:12:30 -0700 Subject: [PATCH 56/92] CI: use hashes for actions' versions in publishing job (#579) --- .github/workflows/release.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3320cf96..10fee7ef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,10 +12,10 @@ jobs: name: sdist and wheels runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1 with: python-version: "3.12" - name: Build wheels @@ -24,7 +24,7 @@ jobs: pip install -U build twine wheel python -m build --sdist --wheel - run: twine check --strict dist/* - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 with: name: dist path: dist @@ -40,8 +40,8 @@ jobs: # IMPORTANT: this permission is mandatory for trusted publishing id-token: write steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: dist path: dist - - uses: pypa/gh-action-pypi-publish@release/v1 + - uses: pypa/gh-action-pypi-publish@ec4db0b4ddc65acdf4bff5fa45ac92d78b56bdf0 # v1.9.0 From bc8ed844c59a8019d9d3362fd118f4b04ddc896d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:22:17 -0400 Subject: [PATCH 57/92] Bump the actions group with 2 updates (#581) Bumps the actions group with 2 updates: [actions/upload-artifact](https://github.com/actions/upload-artifact) and [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish). Updates `actions/upload-artifact` from 4.3.6 to 4.4.0 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/834a144ee995460fba8ed112a2fc961b36a5ec5a...50769540e7f4bd5e21e526ee35c689e35e0d6874) Updates `pypa/gh-action-pypi-publish` from 1.9.0 to 1.10.0 - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/ec4db0b4ddc65acdf4bff5fa45ac92d78b56bdf0...8a08d616893759ef8e1aa1f2785787c0b97e20d6) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 10fee7ef..6cb6c6b2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: pip install -U build twine wheel python -m build --sdist --wheel - run: twine check --strict dist/* - - uses: actions/upload-artifact@834a144ee995460fba8ed112a2fc961b36a5ec5a # v4.3.6 + - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 with: name: dist path: dist @@ -44,4 +44,4 @@ jobs: with: name: dist path: dist - - uses: pypa/gh-action-pypi-publish@ec4db0b4ddc65acdf4bff5fa45ac92d78b56bdf0 # v1.9.0 + - uses: pypa/gh-action-pypi-publish@8a08d616893759ef8e1aa1f2785787c0b97e20d6 # v1.10.0 From fa0ccf45ebe1ce0db26fe4a1a405d9f62e3364fd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 09:37:33 -0400 Subject: [PATCH 58/92] Bump pypa/gh-action-pypi-publish from 1.10.0 to 1.10.2 in the actions group (#582) Bump pypa/gh-action-pypi-publish in the actions group Bumps the actions group with 1 update: [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish). Updates `pypa/gh-action-pypi-publish` from 1.10.0 to 1.10.2 - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/8a08d616893759ef8e1aa1f2785787c0b97e20d6...897895f1e160c830e369f9779632ebc134688e1b) --- updated-dependencies: - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6cb6c6b2..b3cb5dae 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,4 +44,4 @@ jobs: with: name: dist path: dist - - uses: pypa/gh-action-pypi-publish@8a08d616893759ef8e1aa1f2785787c0b97e20d6 # v1.10.0 + - uses: pypa/gh-action-pypi-publish@897895f1e160c830e369f9779632ebc134688e1b # v1.10.2 From bf210cc997f38c6f9bb012e12ea0aee28a5535c3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Oct 2024 14:06:39 -0400 Subject: [PATCH 59/92] [pre-commit.ci] pre-commit autoupdate (#583) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/pre-commit/pre-commit-hooks: 2c9f875913ee60ca25ce70243dc24d5b6415598c → cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b](https://github.com/pre-commit/pre-commit-hooks/compare/2c9f875913ee60ca25ce70243dc24d5b6415598c...cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b) - [github.com/pre-commit/mirrors-prettier: ffb6a759a979008c0e6dff86e39f4745a2d9eac4 → f12edd9c7be1c20cfa42420fd0e6df71e42b51ea](https://github.com/pre-commit/mirrors-prettier/compare/ffb6a759a979008c0e6dff86e39f4745a2d9eac4...f12edd9c7be1c20cfa42420fd0e6df71e42b51ea) - [github.com/astral-sh/ruff-pre-commit: 1dc9eb131c2ea4816c708e4d85820d2cc8542683 → 75b98813cfb7e663870a28c74366a1e99d7bfe79](https://github.com/astral-sh/ruff-pre-commit/compare/1dc9eb131c2ea4816c708e4d85820d2cc8542683...75b98813cfb7e663870a28c74366a1e99d7bfe79) * '[pre-commit.ci 🤖] Apply code format tools to PR' --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 6 +++--- numpydoc/tests/hooks/test_validate_hook.py | 2 +- numpydoc/tests/test_numpydoc.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 425c165f..0e4f84e6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: 2c9f875913ee60ca25ce70243dc24d5b6415598c # frozen: v4.6.0 + rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # frozen: v5.0.0 hooks: - id: check-added-large-files - id: check-ast @@ -18,14 +18,14 @@ repos: - id: trailing-whitespace - repo: https://github.com/pre-commit/mirrors-prettier - rev: ffb6a759a979008c0e6dff86e39f4745a2d9eac4 # frozen: v3.1.0 + rev: f12edd9c7be1c20cfa42420fd0e6df71e42b51ea # frozen: v4.0.0-alpha.8 hooks: - id: prettier types_or: [yaml, toml, markdown, css, scss, javascript, json] args: [--prose-wrap=preserve] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "1dc9eb131c2ea4816c708e4d85820d2cc8542683" # frozen: v0.5.0 + rev: "75b98813cfb7e663870a28c74366a1e99d7bfe79" # frozen: v0.6.9 hooks: - id: ruff args: ["--fix", "--show-fixes", "--exit-non-zero-on-fix"] diff --git a/numpydoc/tests/hooks/test_validate_hook.py b/numpydoc/tests/hooks/test_validate_hook.py index 9a208cb0..ab71a871 100644 --- a/numpydoc/tests/hooks/test_validate_hook.py +++ b/numpydoc/tests/hooks/test_validate_hook.py @@ -8,7 +8,7 @@ from numpydoc.hooks.validate_docstrings import run_hook -@pytest.fixture() +@pytest.fixture def example_module(request): fullpath = ( Path(request.config.rootdir) diff --git a/numpydoc/tests/test_numpydoc.py b/numpydoc/tests/test_numpydoc.py index 30e6f602..f46e2565 100644 --- a/numpydoc/tests/test_numpydoc.py +++ b/numpydoc/tests/test_numpydoc.py @@ -142,7 +142,7 @@ def test_clean_text_signature(): assert _clean_text_signature("func($self, *args)") == "func(*args)" -@pytest.fixture() +@pytest.fixture def f(): def _function_without_seealso_and_examples(): """ From 1338660931330bfd881c2c5792ac7ac1ee3dab96 Mon Sep 17 00:00:00 2001 From: Ross Barnowski Date: Thu, 17 Oct 2024 07:21:24 -0700 Subject: [PATCH 60/92] MAINT: Add _exception_on_warning to MockApp (#586) MockApp in test suite is now breaking due to the absence of a private _exception_on_warning attribute. Fix by explicitly adding to the MockApp. --- numpydoc/tests/test_numpydoc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/numpydoc/tests/test_numpydoc.py b/numpydoc/tests/test_numpydoc.py index f46e2565..997cb0a5 100644 --- a/numpydoc/tests/test_numpydoc.py +++ b/numpydoc/tests/test_numpydoc.py @@ -49,6 +49,7 @@ def __init__(self): self.verbosity = 2 self._warncount = 0 self.warningiserror = False + self._exception_on_warning = False def test_mangle_docstrings_basic(): From 2af51f711c8610a86678f05543e19ca1b6f97853 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Thu, 17 Oct 2024 16:27:03 +0200 Subject: [PATCH 61/92] DOC: Do not use types for *args, **kwargs (#585) Docstrings are primarily intended for the caller, and there *args, **kwargs are not variables with a type but a signature pattern (this is also hinted at by using *args, **kwargs instead of args, kwargs as parameter names). It's rather confusing to try and type them, I'd even claim it's misleading and will tempt less experienced programmers to call `def func(*args)` with *args declared as tuple with a single tuple argument `func((1, 2, 3))`. This omission is also not an information loss for the few people, who look at the signature from the function body perspective (aka developers). That args and kwargs resolve to a tuple / dict in the function is a hard-coded fact. --- doc/format.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/format.rst b/doc/format.rst index 92cc2d36..6579191c 100644 --- a/doc/format.rst +++ b/doc/format.rst @@ -225,11 +225,11 @@ description, they can be combined:: Input arrays, description of `x1`, `x2`. When documenting variable length positional, or keyword arguments, leave the -leading star(s) in front of the name:: +leading star(s) in front of the name and do not specify a type:: - *args : tuple + *args Additional arguments should be passed as keyword arguments - **kwargs : dict, optional + **kwargs Extra arguments to `metric`: refer to each metric documentation for a list of all possible arguments. From a233ebf4919ccc717c6c56ba80ea1fb4437dbb78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 09:41:23 -0500 Subject: [PATCH 62/92] Bump the actions group across 1 directory with 2 updates (#590) Bumps the actions group with 2 updates in the / directory: [actions/upload-artifact](https://github.com/actions/upload-artifact) and [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish). Updates `actions/upload-artifact` from 4.4.0 to 4.4.3 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/50769540e7f4bd5e21e526ee35c689e35e0d6874...b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882) Updates `pypa/gh-action-pypi-publish` from 1.10.2 to 1.12.2 - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/897895f1e160c830e369f9779632ebc134688e1b...15c56dba361d8335944d31a2ecd17d700fc7bcbc) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b3cb5dae..9ea6e46c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: pip install -U build twine wheel python -m build --sdist --wheel - run: twine check --strict dist/* - - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0 + - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: dist path: dist @@ -44,4 +44,4 @@ jobs: with: name: dist path: dist - - uses: pypa/gh-action-pypi-publish@897895f1e160c830e369f9779632ebc134688e1b # v1.10.2 + - uses: pypa/gh-action-pypi-publish@15c56dba361d8335944d31a2ecd17d700fc7bcbc # v1.12.2 From 99786ec5bf8817abf50d80a8210e333fa879cb18 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Mon, 16 Dec 2024 15:08:07 +0000 Subject: [PATCH 63/92] mention conda-forge in installation docs (#595) --- doc/install.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/install.rst b/doc/install.rst index 6282ffed..c72d777f 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -9,6 +9,7 @@ This extension requires Python 3.9+, sphinx 6+ and is available from: * `numpydoc on PyPI `_ * `numpydoc on GitHub `_ +* `numpydoc on conda-forge `_ `'numpydoc'` should be added to the ``extensions`` option in your Sphinx ``conf.py``. ``'sphinx.ext.autosummary'`` will automatically be loaded From d03b31c83b5c1980625c37aa0619ad36c208b99d Mon Sep 17 00:00:00 2001 From: Daniel McCloy Date: Tue, 17 Dec 2024 16:01:43 -0600 Subject: [PATCH 64/92] Don't pass maxsplit as positional arg (#596) --- numpydoc/docscrape_sphinx.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpydoc/docscrape_sphinx.py b/numpydoc/docscrape_sphinx.py index 9b1ccf78..3b2f325a 100644 --- a/numpydoc/docscrape_sphinx.py +++ b/numpydoc/docscrape_sphinx.py @@ -160,7 +160,7 @@ def _process_param(self, param, desc, fake_autosummary): display_param = f":obj:`{param} <{link_prefix}{param}>`" if obj_doc: # Overwrite desc. Take summary logic of autosummary - desc = re.split(r"\n\s*\n", obj_doc.strip(), 1)[0] + desc = re.split(r"\n\s*\n", obj_doc.strip(), maxsplit=1)[0] # XXX: Should this have DOTALL? # It does not in autosummary m = re.search(r"^([A-Z].*?\.)(?:\s|$)", " ".join(desc.split())) From dec2b9e27c9cb82aa720d76fb432ec7aa27976d9 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Mon, 23 Dec 2024 20:38:04 +0000 Subject: [PATCH 65/92] Ignore some errors at module level (#593) --- .gitignore | 1 + numpydoc/__main__.py | 4 +-- numpydoc/hooks/validate_docstrings.py | 4 +++ numpydoc/tests/hooks/test_validate_hook.py | 2 -- numpydoc/tests/test_main.py | 16 ++++------- numpydoc/validate.py | 33 +++++++++++++--------- 6 files changed, 32 insertions(+), 28 deletions(-) diff --git a/.gitignore b/.gitignore index 26f7400b..60696edd 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ doc/_build numpydoc/tests/tinybuild/_build numpydoc/tests/tinybuild/generated MANIFEST +node_modules diff --git a/numpydoc/__main__.py b/numpydoc/__main__.py index b3b6d159..8cd0943e 100644 --- a/numpydoc/__main__.py +++ b/numpydoc/__main__.py @@ -1,6 +1,6 @@ """ -Implementing `python -m numpydoc` functionality. -""" +Implementing `python -m numpydoc` functionality +""" # '.' omitted at end of docstring for testing purposes! from .cli import main diff --git a/numpydoc/hooks/validate_docstrings.py b/numpydoc/hooks/validate_docstrings.py index 562a1f09..f5251522 100644 --- a/numpydoc/hooks/validate_docstrings.py +++ b/numpydoc/hooks/validate_docstrings.py @@ -60,6 +60,10 @@ def name(self) -> str: def is_function_or_method(self) -> bool: return isinstance(self.node, (ast.FunctionDef, ast.AsyncFunctionDef)) + @property + def is_mod(self) -> bool: + return self.is_module + @property def is_generator_function(self) -> bool: if not self.is_function_or_method: diff --git a/numpydoc/tests/hooks/test_validate_hook.py b/numpydoc/tests/hooks/test_validate_hook.py index ab71a871..18b03818 100644 --- a/numpydoc/tests/hooks/test_validate_hook.py +++ b/numpydoc/tests/hooks/test_validate_hook.py @@ -29,8 +29,6 @@ def test_validate_hook(example_module, config, capsys): +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ | file | item | check | description | +===========================================+=====================================+=========+====================================================+ - | numpydoc/tests/hooks/example_module.py:1 | example_module | EX01 | No examples section found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | ES01 | No extended summary found | +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | PR01 | Parameters {'name'} not documented | diff --git a/numpydoc/tests/test_main.py b/numpydoc/tests/test_main.py index 12c06840..bd06be3f 100644 --- a/numpydoc/tests/test_main.py +++ b/numpydoc/tests/test_main.py @@ -117,7 +117,7 @@ def test_validate_perfect_docstring(): assert exit_status == 0 -@pytest.mark.parametrize("args", [[], ["--ignore", "ES01", "SA01", "EX01"]]) +@pytest.mark.parametrize("args", [[], ["--ignore", "SS03"]]) def test_lint(capsys, args): argv = ["lint", "numpydoc/__main__.py"] + args if args: @@ -126,15 +126,11 @@ def test_lint(capsys, args): else: expected = inspect.cleandoc( """ - +------------------------+----------+---------+----------------------------+ - | file | item | check | description | - +========================+==========+=========+============================+ - | numpydoc/__main__.py:1 | __main__ | ES01 | No extended summary found | - +------------------------+----------+---------+----------------------------+ - | numpydoc/__main__.py:1 | __main__ | SA01 | See Also section not found | - +------------------------+----------+---------+----------------------------+ - | numpydoc/__main__.py:1 | __main__ | EX01 | No examples section found | - +------------------------+----------+---------+----------------------------+ + +------------------------+----------+---------+------------------------------------+ + | file | item | check | description | + +========================+==========+=========+====================================+ + | numpydoc/__main__.py:1 | __main__ | SS03 | Summary does not end with a period | + +------------------------+----------+---------+------------------------------------+ """ ) expected_status = 1 diff --git a/numpydoc/validate.py b/numpydoc/validate.py index 138e9d48..495d7201 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -277,6 +277,10 @@ def type(self): def is_function_or_method(self): return inspect.isfunction(self.obj) + @property + def is_mod(self): + return inspect.ismodule(self.obj) + @property def is_generator_function(self): return inspect.isgeneratorfunction(_unwrap(self.obj)) @@ -690,7 +694,7 @@ def validate(obj_name, validator_cls=None, **validator_kwargs): if doc.num_summary_lines > 1: errs.append(error("SS06")) - if not doc.extended_summary: + if not doc.is_mod and not doc.extended_summary: errs.append(("ES01", "No extended summary found")) # PR01: Parameters not documented @@ -742,20 +746,21 @@ def validate(obj_name, validator_cls=None, **validator_kwargs): if not doc.yields and doc.is_generator_function: errs.append(error("YD01")) - if not doc.see_also: - errs.append(error("SA01")) - else: - for rel_name, rel_desc in doc.see_also.items(): - if rel_desc: - if not rel_desc.endswith("."): - errs.append(error("SA02", reference_name=rel_name)) - if rel_desc[0].isalpha() and not rel_desc[0].isupper(): - errs.append(error("SA03", reference_name=rel_name)) - else: - errs.append(error("SA04", reference_name=rel_name)) + if not doc.is_mod: + if not doc.see_also: + errs.append(error("SA01")) + else: + for rel_name, rel_desc in doc.see_also.items(): + if rel_desc: + if not rel_desc.endswith("."): + errs.append(error("SA02", reference_name=rel_name)) + if rel_desc[0].isalpha() and not rel_desc[0].isupper(): + errs.append(error("SA03", reference_name=rel_name)) + else: + errs.append(error("SA04", reference_name=rel_name)) - if not doc.examples: - errs.append(error("EX01")) + if not doc.examples: + errs.append(error("EX01")) errs = [err for err in errs if err[0] not in ignore_validation_comments] From e4a555428bae23eb5a1bfa5b93bac9b1b883dc67 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:18:20 -0500 Subject: [PATCH 66/92] [pre-commit.ci] pre-commit autoupdate (#598) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/astral-sh/ruff-pre-commit: 75b98813cfb7e663870a28c74366a1e99d7bfe79 → 89c421dff2e1026ba12cdb9ebd731f4a83aa8021](https://github.com/astral-sh/ruff-pre-commit/compare/75b98813cfb7e663870a28c74366a1e99d7bfe79...89c421dff2e1026ba12cdb9ebd731f4a83aa8021) * '[pre-commit.ci 🤖] Apply code format tools to PR' --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- numpydoc/tests/test_docscrape.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0e4f84e6..08185da6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: args: [--prose-wrap=preserve] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "75b98813cfb7e663870a28c74366a1e99d7bfe79" # frozen: v0.6.9 + rev: "89c421dff2e1026ba12cdb9ebd731f4a83aa8021" # frozen: v0.8.6 hooks: - id: ruff args: ["--fix", "--show-fixes", "--exit-non-zero-on-fix"] diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index 4cafc762..f10adc45 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -1596,8 +1596,8 @@ def __init__(self, a, b): self.numpydoc_validation_overrides = dict() xref_aliases_complete = deepcopy(DEFAULT_LINKS) - for key in xref_aliases: - xref_aliases_complete[key] = xref_aliases[key] + for key, val in xref_aliases.items(): + xref_aliases_complete[key] = val config = Config(xref_aliases, xref_aliases_complete) app = namedtuple("config", "config")(config) update_config(app) From b5cbfe35c231a9a698738923f323647e5650f4e4 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Thu, 9 Jan 2025 16:31:02 -0800 Subject: [PATCH 67/92] Add Python 3.13 support (#599) --- .github/workflows/test.yml | 4 ++-- pyproject.toml | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8eed0ce9..8db3074c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: os: [Ubuntu] - python-version: ["3.9", "3.10", "3.11", "3.12"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] sphinx-version: ["sphinx==6.0", "sphinx==6.2", "sphinx==7.0", "sphinx>=7.3"] include: @@ -78,7 +78,7 @@ jobs: strategy: matrix: os: [ubuntu] - python-version: ["3.11", "3.12"] + python-version: ["3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 diff --git a/pyproject.toml b/pyproject.toml index 24dec3ee..04f18d86 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', 'Topic :: Documentation', ] dependencies = [ From 06cd4a7e160d8f37be9f04db1cff883ca0faf304 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Thu, 9 Jan 2025 16:44:57 -0800 Subject: [PATCH 68/92] Update readthedocs config (#600) --- .readthedocs.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index a124b7ca..252fca8e 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -6,9 +6,9 @@ version: 2 # Set the OS, Python version and other tools you might need build: - os: ubuntu-22.04 + os: ubuntu-24.04 tools: - python: "3.11" + python: "3.13" # You can also specify other tool versions: # nodejs: "19" # rust: "1.64" From 6d5eb428b8acea6ced4d86d086e36daf3f03ffbf Mon Sep 17 00:00:00 2001 From: Matt Gebert Date: Sat, 11 Jan 2025 02:25:24 +1100 Subject: [PATCH 69/92] MAINT: Changed class constructor __init__ GL08 reporting (#592) Co-authored-by: Stefan van der Walt Co-authored-by: Eric Larson --- doc/format.rst | 4 +- doc/validation.rst | 3 + numpydoc/tests/test_validate.py | 141 ++++++++++++++++++++++++++++++++ numpydoc/validate.py | 24 +++++- 4 files changed, 170 insertions(+), 2 deletions(-) diff --git a/doc/format.rst b/doc/format.rst index 6579191c..ecdd1d4f 100644 --- a/doc/format.rst +++ b/doc/format.rst @@ -557,7 +557,9 @@ Class docstring Use the same sections as outlined above (all except :ref:`Returns ` are applicable). The constructor (``__init__``) should also be documented here, the :ref:`Parameters ` section of the docstring details the -constructor's parameters. +constructor's parameters. While repetition is unnecessary, a docstring for +the class constructor (``__init__``) can, optionally, be added to provide +detailed initialization documentation. An **Attributes** section, located below the :ref:`Parameters ` section, may be used to describe non-method attributes of the class:: diff --git a/doc/validation.rst b/doc/validation.rst index aa9d5236..68844c2b 100644 --- a/doc/validation.rst +++ b/doc/validation.rst @@ -183,6 +183,9 @@ inline comments: def __init__(self): # numpydoc ignore=GL08 pass +Note that a properly formatted :ref:`class ` docstring +silences ``G08`` for an ``__init__`` constructor without a docstring. + This is supported by the :ref:`CLI `, :ref:`pre-commit hook `, and :ref:`Sphinx extension `. diff --git a/numpydoc/tests/test_validate.py b/numpydoc/tests/test_validate.py index 8b40794f..9f0f7942 100644 --- a/numpydoc/tests/test_validate.py +++ b/numpydoc/tests/test_validate.py @@ -1198,6 +1198,113 @@ def missing_whitespace_after_comma(self): """ +class ConstructorDocumentedInClassAndInit: + """ + Class to test constructor documented via class and constructor docstrings. + + A case where both the class docstring and the constructor docstring are + defined. + + Parameters + ---------- + param1 : int + Description of param1. + + See Also + -------- + otherclass : A class that does something else. + + Examples + -------- + This is an example of how to use ConstructorDocumentedInClassAndInit. + """ + + def __init__(self, param1: int) -> None: + """ + Constructor docstring with additional information. + + Extended information. + + Parameters + ---------- + param1 : int + Description of param1 with extra details. + + See Also + -------- + otherclass : A class that does something else. + + Examples + -------- + This is an example of how to use ConstructorDocumentedInClassAndInit. + """ + + +class ConstructorDocumentedInClass: + """ + Class to test constructor documented via class docstring. + + Useful to ensure that validation of `__init__` does not signal GL08, + when the class docstring properly documents the `__init__` constructor. + + Parameters + ---------- + param1 : int + Description of param1. + + See Also + -------- + otherclass : A class that does something else. + + Examples + -------- + This is an example of how to use ConstructorDocumentedInClass. + """ + + def __init__(self, param1: int) -> None: + pass + + +class ConstructorDocumentedInClassWithNoParameters: + """ + Class to test constructor documented via class docstring with no parameters. + + Useful to ensure that validation of `__init__` does not signal GL08, + when the class docstring properly documents the `__init__` constructor. + + See Also + -------- + otherclass : A class that does something else. + + Examples + -------- + This is an example of how to use ConstructorDocumentedInClassWithNoParameters. + """ + + def __init__(self) -> None: + pass + + +class IncompleteConstructorDocumentedInClass: + """ + Class to test an incomplete constructor docstring. + + This class does not properly document parameters. + Unnecessary extended summary. + + See Also + -------- + otherclass : A class that does something else. + + Examples + -------- + This is an example of how to use IncompleteConstructorDocumentedInClass. + """ + + def __init__(self, param1: int): + pass + + class TestValidator: def _import_path(self, klass=None, func=None): """ @@ -1536,6 +1643,40 @@ def test_bad_docstrings(self, capsys, klass, func, msgs): for msg in msgs: assert msg in " ".join(err[1] for err in result["errors"]) + @pytest.mark.parametrize( + "klass,exp_init_codes,exc_init_codes,exp_klass_codes", + [ + ("ConstructorDocumentedInClass", tuple(), ("GL08",), tuple()), + ("ConstructorDocumentedInClassAndInit", tuple(), ("GL08",), tuple()), + ( + "ConstructorDocumentedInClassWithNoParameters", + tuple(), + ("GL08",), + tuple(), + ), + ( + "IncompleteConstructorDocumentedInClass", + ("GL08",), + tuple(), + ("PR01"), # Parameter not documented in class constructor + ), + ], + ) + def test_constructor_docstrings( + self, klass, exp_init_codes, exc_init_codes, exp_klass_codes + ): + # First test the class docstring itself, checking expected_klass_codes match + result = validate_one(self._import_path(klass=klass)) + for err in result["errors"]: + assert err[0] in exp_klass_codes + + # Then test the constructor docstring + result = validate_one(self._import_path(klass=klass, func="__init__")) + for code in exp_init_codes: + assert code in " ".join(err[0] for err in result["errors"]) + for code in exc_init_codes: + assert code not in " ".join(err[0] for err in result["errors"]) + def decorator(x): """Test decorator.""" diff --git a/numpydoc/validate.py b/numpydoc/validate.py index 495d7201..858a06d2 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -637,7 +637,29 @@ def validate(obj_name, validator_cls=None, **validator_kwargs): errs = [] if not doc.raw_doc: - if "GL08" not in ignore_validation_comments: + 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)) + + # 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 + + # Check if GL08 is to be ignored: + if "GL08" in ignore_validation_comments: + report_GL08 = False + # Add GL08 error? + if report_GL08: errs.append(error("GL08")) return { "type": doc.type, From 7a6120bb972ee11a9bab7d533178b618ec8e947c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 09:50:56 -0500 Subject: [PATCH 70/92] Bump the actions group with 2 updates (#603) Bumps the actions group with 2 updates: [actions/upload-artifact](https://github.com/actions/upload-artifact) and [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish). Updates `actions/upload-artifact` from 4.4.3 to 4.6.0 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882...65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08) Updates `pypa/gh-action-pypi-publish` from 1.12.2 to 1.12.4 - [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases) - [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/15c56dba361d8335944d31a2ecd17d700fc7bcbc...76f52bc884231f62b9a034ebfe128415bbaabdfc) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: pypa/gh-action-pypi-publish dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9ea6e46c..98567a5e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: pip install -U build twine wheel python -m build --sdist --wheel - run: twine check --strict dist/* - - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + - uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: dist path: dist @@ -44,4 +44,4 @@ jobs: with: name: dist path: dist - - uses: pypa/gh-action-pypi-publish@15c56dba361d8335944d31a2ecd17d700fc7bcbc # v1.12.2 + - uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 From 532cd7d71ceee4e00fd13fa5faf038f2b4d95905 Mon Sep 17 00:00:00 2001 From: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Date: Sat, 15 Feb 2025 12:58:51 -0500 Subject: [PATCH 71/92] Fix typo in validation.rst (#605) --- doc/validation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/validation.rst b/doc/validation.rst index 68844c2b..3d2babae 100644 --- a/doc/validation.rst +++ b/doc/validation.rst @@ -184,7 +184,7 @@ inline comments: pass Note that a properly formatted :ref:`class ` docstring -silences ``G08`` for an ``__init__`` constructor without a docstring. +silences ``GL08`` for an ``__init__`` constructor without a docstring. This is supported by the :ref:`CLI `, :ref:`pre-commit hook `, and From a36287a3be5ed71cf1cc4f67a3d7cc37fb12634d Mon Sep 17 00:00:00 2001 From: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Date: Tue, 11 Mar 2025 11:27:48 -0400 Subject: [PATCH 72/92] Rework hook output to remove the table (#611) * Switch from table to printed items * Remove tabulate dependency * Adjust format * Fix test after Sphinx builder change in newer version --- .pre-commit-hooks.yaml | 2 +- numpydoc/hooks/validate_docstrings.py | 27 ++-- numpydoc/tests/hooks/test_validate_hook.py | 176 +++++++++------------ numpydoc/tests/test_main.py | 10 +- numpydoc/tests/test_numpydoc.py | 1 + pyproject.toml | 1 - requirements/default.txt | 1 - 7 files changed, 86 insertions(+), 132 deletions(-) diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 2244d460..69493db7 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -2,6 +2,6 @@ name: numpydoc-validation description: This hook validates that docstrings in committed files adhere to numpydoc standards. entry: numpydoc lint - require_serial: true + require_serial: false language: python types: [python] diff --git a/numpydoc/hooks/validate_docstrings.py b/numpydoc/hooks/validate_docstrings.py index f5251522..75ff2539 100644 --- a/numpydoc/hooks/validate_docstrings.py +++ b/numpydoc/hooks/validate_docstrings.py @@ -14,8 +14,6 @@ from pathlib import Path from typing import Any, Dict, List, Tuple, Union -from tabulate import tabulate - from .. import docscrape, validate from .utils import find_project_root @@ -193,7 +191,7 @@ def _get_numpydoc_issues(self, node: ast.AST) -> None: ) self.findings.extend( [ - [f'{self.filepath}:{report["file_line"]}', name, check, description] + [f"{self.filepath}:{report['file_line']}", name, check, description] for check, description in report["errors"] if not self._ignore_issue(node, check) ] @@ -371,19 +369,12 @@ def run_hook( config_options = parse_config(config or project_root) config_options["checks"] -= set(ignore or []) - findings = [] + findings = False for file in files: - findings.extend(process_file(file, config_options)) - - if findings: - print( - tabulate( - findings, - headers=["file", "item", "check", "description"], - tablefmt="grid", - maxcolwidths=50, - ), - file=sys.stderr, - ) - return 1 - return 0 + if file_issues := process_file(file, config_options): + findings = True + + for line, obj, check, description in file_issues: + print(f"\n{line}: {check} {description}", file=sys.stderr) + + return int(findings) diff --git a/numpydoc/tests/hooks/test_validate_hook.py b/numpydoc/tests/hooks/test_validate_hook.py index 18b03818..25851db5 100644 --- a/numpydoc/tests/hooks/test_validate_hook.py +++ b/numpydoc/tests/hooks/test_validate_hook.py @@ -26,53 +26,47 @@ def test_validate_hook(example_module, config, capsys): expected = inspect.cleandoc( """ - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | file | item | check | description | - +===========================================+=====================================+=========+====================================================+ - | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | ES01 | No extended summary found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | PR01 | Parameters {'name'} not documented | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | SA01 | See Also section not found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | EX01 | No examples section found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:8 | example_module.MyClass | ES01 | No extended summary found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:8 | example_module.MyClass | SA01 | See Also section not found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:8 | example_module.MyClass | EX01 | No examples section found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:11 | example_module.MyClass.__init__ | GL08 | The object does not have a docstring | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | ES01 | No extended summary found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | SA01 | See Also section not found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | EX01 | No examples section found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:26 | example_module.MyClass.process | SS05 | Summary must start with infinitive verb, not third | - | | | | person (e.g. use "Generate" instead of | - | | | | "Generates") | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:26 | example_module.MyClass.process | ES01 | No extended summary found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:26 | example_module.MyClass.process | SA01 | See Also section not found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:26 | example_module.MyClass.process | EX01 | No examples section found | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:30 | example_module.NewClass | GL08 | The object does not have a docstring | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ + numpydoc/tests/hooks/example_module.py:4: ES01 No extended summary found + + numpydoc/tests/hooks/example_module.py:4: PR01 Parameters {'name'} not documented + + numpydoc/tests/hooks/example_module.py:4: SA01 See Also section not found + + numpydoc/tests/hooks/example_module.py:4: EX01 No examples section found + + numpydoc/tests/hooks/example_module.py:8: ES01 No extended summary found + + numpydoc/tests/hooks/example_module.py:8: SA01 See Also section not found + + numpydoc/tests/hooks/example_module.py:8: EX01 No examples section found + + numpydoc/tests/hooks/example_module.py:11: GL08 The object does not have a docstring + + numpydoc/tests/hooks/example_module.py:17: ES01 No extended summary found + + numpydoc/tests/hooks/example_module.py:17: PR01 Parameters {'**kwargs'} not documented + + numpydoc/tests/hooks/example_module.py:17: PR07 Parameter "*args" has no description + + numpydoc/tests/hooks/example_module.py:17: SA01 See Also section not found + + numpydoc/tests/hooks/example_module.py:17: EX01 No examples section 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") + + numpydoc/tests/hooks/example_module.py:26: ES01 No extended summary found + + numpydoc/tests/hooks/example_module.py:26: SA01 See Also section not found + + numpydoc/tests/hooks/example_module.py:26: EX01 No examples section found + + numpydoc/tests/hooks/example_module.py:30: GL08 The object does not have a docstring """ ) return_code = run_hook([example_module], config=config) assert return_code == 1 - assert capsys.readouterr().err.rstrip() == expected + assert capsys.readouterr().err.strip() == expected def test_validate_hook_with_ignore(example_module, capsys): @@ -83,30 +77,24 @@ def test_validate_hook_with_ignore(example_module, capsys): expected = inspect.cleandoc( """ - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | file | item | check | description | - +===========================================+=====================================+=========+====================================================+ - | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | PR01 | Parameters {'name'} not documented | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:11 | example_module.MyClass.__init__ | GL08 | The object does not have a docstring | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:26 | example_module.MyClass.process | SS05 | Summary must start with infinitive verb, not third | - | | | | person (e.g. use "Generate" instead of | - | | | | "Generates") | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ - | numpydoc/tests/hooks/example_module.py:30 | example_module.NewClass | GL08 | The object does not have a docstring | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------------------+ + numpydoc/tests/hooks/example_module.py:4: PR01 Parameters {'name'} not documented + + numpydoc/tests/hooks/example_module.py:11: GL08 The object does not have a docstring + + numpydoc/tests/hooks/example_module.py:17: PR01 Parameters {'**kwargs'} not documented + + numpydoc/tests/hooks/example_module.py:17: PR07 Parameter "*args" has no description + + numpydoc/tests/hooks/example_module.py:26: SS05 Summary must start with infinitive verb, not third person (e.g. use "Generate" instead of "Generates") + + numpydoc/tests/hooks/example_module.py:30: GL08 The object does not have a docstring """ ) return_code = run_hook([example_module], ignore=["ES01", "SA01", "EX01"]) assert return_code == 1 - assert capsys.readouterr().err.rstrip() == expected + assert capsys.readouterr().err.strip() == expected def test_validate_hook_with_toml_config(example_module, tmp_path, capsys): @@ -138,23 +126,19 @@ def test_validate_hook_with_toml_config(example_module, tmp_path, capsys): expected = inspect.cleandoc( """ - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | file | item | check | description | - +===========================================+=====================================+=========+========================================+ - | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | PR01 | Parameters {'name'} not documented | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:30 | example_module.NewClass | GL08 | The object does not have a docstring | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ + numpydoc/tests/hooks/example_module.py:4: PR01 Parameters {'name'} not documented + + numpydoc/tests/hooks/example_module.py:17: PR01 Parameters {'**kwargs'} not documented + + numpydoc/tests/hooks/example_module.py:17: PR07 Parameter "*args" has no description + + numpydoc/tests/hooks/example_module.py:30: GL08 The object does not have a docstring """ ) return_code = run_hook([example_module], config=tmp_path) assert return_code == 1 - assert capsys.readouterr().err.rstrip() == expected + assert capsys.readouterr().err.strip() == expected def test_validate_hook_with_setup_cfg(example_module, tmp_path, capsys): @@ -177,23 +161,19 @@ def test_validate_hook_with_setup_cfg(example_module, tmp_path, capsys): expected = inspect.cleandoc( """ - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | file | item | check | description | - +===========================================+=====================================+=========+========================================+ - | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | PR01 | Parameters {'name'} not documented | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:30 | example_module.NewClass | GL08 | The object does not have a docstring | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ + numpydoc/tests/hooks/example_module.py:4: PR01 Parameters {'name'} not documented + + numpydoc/tests/hooks/example_module.py:17: PR01 Parameters {'**kwargs'} not documented + + numpydoc/tests/hooks/example_module.py:17: PR07 Parameter "*args" has no description + + numpydoc/tests/hooks/example_module.py:30: GL08 The object does not have a docstring """ ) return_code = run_hook([example_module], config=tmp_path) assert return_code == 1 - assert capsys.readouterr().err.rstrip() == expected + assert capsys.readouterr().err.strip() == expected def test_validate_hook_exclude_option_pyproject(example_module, tmp_path, capsys): @@ -228,19 +208,15 @@ def test_validate_hook_exclude_option_pyproject(example_module, tmp_path, capsys expected = inspect.cleandoc( """ - +-------------------------------------------+------------------------------+---------+--------------------------------------+ - | file | item | check | description | - +===========================================+==============================+=========+======================================+ - | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | PR01 | Parameters {'name'} not documented | - +-------------------------------------------+------------------------------+---------+--------------------------------------+ - | numpydoc/tests/hooks/example_module.py:30 | example_module.NewClass | GL08 | The object does not have a docstring | - +-------------------------------------------+------------------------------+---------+--------------------------------------+ + numpydoc/tests/hooks/example_module.py:4: PR01 Parameters {'name'} not documented + + numpydoc/tests/hooks/example_module.py:30: GL08 The object does not have a docstring """ ) return_code = run_hook([example_module], config=tmp_path) assert return_code == 1 - assert capsys.readouterr().err.rstrip() == expected + assert capsys.readouterr().err.strip() == expected def test_validate_hook_exclude_option_setup_cfg(example_module, tmp_path, capsys): @@ -263,18 +239,14 @@ def test_validate_hook_exclude_option_setup_cfg(example_module, tmp_path, capsys expected = inspect.cleandoc( """ - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | file | item | check | description | - +===========================================+=====================================+=========+========================================+ - | numpydoc/tests/hooks/example_module.py:4 | example_module.some_function | PR01 | Parameters {'name'} not documented | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR01 | Parameters {'**kwargs'} not documented | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ - | numpydoc/tests/hooks/example_module.py:17 | example_module.MyClass.do_something | PR07 | Parameter "*args" has no description | - +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ + numpydoc/tests/hooks/example_module.py:4: PR01 Parameters {'name'} not documented + + numpydoc/tests/hooks/example_module.py:17: PR01 Parameters {'**kwargs'} not documented + + numpydoc/tests/hooks/example_module.py:17: PR07 Parameter "*args" has no description """ ) return_code = run_hook([example_module], config=tmp_path) assert return_code == 1 - assert capsys.readouterr().err.rstrip() == expected + assert capsys.readouterr().err.strip() == expected diff --git a/numpydoc/tests/test_main.py b/numpydoc/tests/test_main.py index bd06be3f..e07e7df2 100644 --- a/numpydoc/tests/test_main.py +++ b/numpydoc/tests/test_main.py @@ -124,15 +124,7 @@ def test_lint(capsys, args): expected = "" expected_status = 0 else: - expected = inspect.cleandoc( - """ - +------------------------+----------+---------+------------------------------------+ - | file | item | check | description | - +========================+==========+=========+====================================+ - | numpydoc/__main__.py:1 | __main__ | SS03 | Summary does not end with a period | - +------------------------+----------+---------+------------------------------------+ - """ - ) + expected = "numpydoc/__main__.py:1: SS03 Summary does not end with a period" expected_status = 1 return_status = numpydoc.cli.main(argv) diff --git a/numpydoc/tests/test_numpydoc.py b/numpydoc/tests/test_numpydoc.py index 997cb0a5..bedef5fa 100644 --- a/numpydoc/tests/test_numpydoc.py +++ b/numpydoc/tests/test_numpydoc.py @@ -36,6 +36,7 @@ class MockConfig: class MockBuilder: config = MockConfig() + _translator = None class MockApp: diff --git a/pyproject.toml b/pyproject.toml index 04f18d86..53458910 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,6 @@ classifiers = [ ] dependencies = [ 'sphinx>=6', - 'tabulate>=0.8.10', "tomli>=1.1.0;python_version<'3.11'", ] diff --git a/requirements/default.txt b/requirements/default.txt index 5a1986a1..dfe792ef 100644 --- a/requirements/default.txt +++ b/requirements/default.txt @@ -1,5 +1,4 @@ # Generated via tools/generate_requirements.py and pre-commit hook. # Do not edit this file; modify pyproject.toml instead. sphinx>=6 -tabulate>=0.8.10 tomli>=1.1.0;python_version<'3.11' From fba6ee565b2bd886d3317f309c11b8790c7db44e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 06:54:56 -0700 Subject: [PATCH 73/92] Bump the actions group with 3 updates (#609) Bumps the actions group with 3 updates: [scientific-python/attach-next-milestone-action](https://github.com/scientific-python/attach-next-milestone-action), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [actions/download-artifact](https://github.com/actions/download-artifact). Updates `scientific-python/attach-next-milestone-action` from bc07be829f693829263e57d5e8489f4e57d3d420 to c9cfab10ad0c67fed91b01103db26b7f16634639 - [Release notes](https://github.com/scientific-python/attach-next-milestone-action/releases) - [Commits](https://github.com/scientific-python/attach-next-milestone-action/compare/bc07be829f693829263e57d5e8489f4e57d3d420...c9cfab10ad0c67fed91b01103db26b7f16634639) Updates `actions/upload-artifact` from 4.6.0 to 4.6.1 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08...4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1) Updates `actions/download-artifact` from 4.1.8 to 4.1.9 - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/fa0a91b85d4f404e444e00e005971372dc801d16...cc203385981b70ca67e1cc392babf9cc229d5806) --- updated-dependencies: - dependency-name: scientific-python/attach-next-milestone-action dependency-type: direct:production dependency-group: actions - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: actions/download-artifact dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/milestone-merged-prs.yml | 2 +- .github/workflows/release.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/milestone-merged-prs.yml b/.github/workflows/milestone-merged-prs.yml index 71ae037c..f455839d 100644 --- a/.github/workflows/milestone-merged-prs.yml +++ b/.github/workflows/milestone-merged-prs.yml @@ -12,7 +12,7 @@ jobs: name: attach to PR runs-on: ubuntu-latest steps: - - uses: scientific-python/attach-next-milestone-action@bc07be829f693829263e57d5e8489f4e57d3d420 + - uses: scientific-python/attach-next-milestone-action@c9cfab10ad0c67fed91b01103db26b7f16634639 with: token: ${{ secrets.MILESTONE_LABELER_TOKEN }} force: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 98567a5e..131b9d43 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: pip install -U build twine wheel python -m build --sdist --wheel - run: twine check --strict dist/* - - uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: dist path: dist @@ -40,7 +40,7 @@ jobs: # IMPORTANT: this permission is mandatory for trusted publishing id-token: write steps: - - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 + - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 with: name: dist path: dist From 08bf5f919048a6faca435c2dede025c96a975c71 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 15 Apr 2025 12:59:25 -0400 Subject: [PATCH 74/92] [pre-commit.ci] pre-commit autoupdate (#614) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/astral-sh/ruff-pre-commit: 89c421dff2e1026ba12cdb9ebd731f4a83aa8021 → 971923581912ef60a6b70dbf0c3e9a39563c9d47](https://github.com/astral-sh/ruff-pre-commit/compare/89c421dff2e1026ba12cdb9ebd731f4a83aa8021...971923581912ef60a6b70dbf0c3e9a39563c9d47) * '[pre-commit.ci 🤖] Apply code format tools to PR' --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- numpydoc/cli.py | 9 +++++---- numpydoc/docscrape.py | 3 +-- numpydoc/validate.py | 3 +-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 08185da6..8e4d289d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: args: [--prose-wrap=preserve] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "89c421dff2e1026ba12cdb9ebd731f4a83aa8021" # frozen: v0.8.6 + rev: "971923581912ef60a6b70dbf0c3e9a39563c9d47" # frozen: v0.11.4 hooks: - id: ruff args: ["--fix", "--show-fixes", "--exit-non-zero-on-fix"] diff --git a/numpydoc/cli.py b/numpydoc/cli.py index ef8cff2c..53335fdf 100644 --- a/numpydoc/cli.py +++ b/numpydoc/cli.py @@ -104,10 +104,11 @@ def _parse_config(s): nargs="*", help=( f"""Check codes to ignore.{ - ' Currently ignoring the following from ' - f'{Path(project_root_from_cwd) / config_file}: {ignored_checks_text}' - 'Values provided here will be in addition to the above, unless an alternate config is provided.' - if ignored_checks else '' + " Currently ignoring the following from " + f"{Path(project_root_from_cwd) / config_file}: {ignored_checks_text}" + "Values provided here will be in addition to the above, unless an alternate config is provided." + if ignored_checks + else "" }""" ), ) diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index bfc2840e..54863d5f 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -232,8 +232,7 @@ def _parse_param_list(self, content, single_element_is_type=False): # NOTE: param line with single element should never have a # a " :" before the description line, so this should probably # warn. - if header.endswith(" :"): - header = header[:-2] + header = header.removesuffix(" :") if single_element_is_type: arg_name, arg_type = "", header else: diff --git a/numpydoc/validate.py b/numpydoc/validate.py index 858a06d2..db605949 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -80,8 +80,7 @@ "PR06": 'Parameter "{param_name}" type should use "{right_type}" instead ' 'of "{wrong_type}"', "PR07": 'Parameter "{param_name}" has no description', - "PR08": 'Parameter "{param_name}" description should start with a ' - "capital letter", + "PR08": 'Parameter "{param_name}" description should start with a 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", From 5b437b5516f5222797e44dffd75274a51c54ae5d Mon Sep 17 00:00:00 2001 From: Maxine Hartnett <117409426+maxinelasp@users.noreply.github.com> Date: Tue, 15 Apr 2025 11:21:54 -0600 Subject: [PATCH 75/92] BUG: Correct functionality of numpydoc SS05 (#613) * BUG: Correct functionality of numpydoc SS05. Currently SS05 checks for infinitive verbs by checking if the last character is "s". However, if the first word is "process", which is valid, this incorrectly throws a numpydoc validation error. This commit allows the first word to end in two "s"es without flagging as an error. This will allow for words like "process" or "progress," while still checking for invalid words like "creates." * Update numpydoc/validate.py * FIX: Overrides --------- Co-authored-by: Eric Larson --- numpydoc/tests/hooks/example_module.py | 4 ++-- numpydoc/tests/hooks/test_validate_hook.py | 12 ++++-------- numpydoc/validate.py | 8 +++++++- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/numpydoc/tests/hooks/example_module.py b/numpydoc/tests/hooks/example_module.py index 87e9b52d..9f75bdf0 100644 --- a/numpydoc/tests/hooks/example_module.py +++ b/numpydoc/tests/hooks/example_module.py @@ -23,8 +23,8 @@ def do_something(self, *args, **kwargs): *args """ - def process(self): - """Process stuff.""" + def create(self): + """Creates stuff.""" class NewClass: diff --git a/numpydoc/tests/hooks/test_validate_hook.py b/numpydoc/tests/hooks/test_validate_hook.py index 25851db5..47f315c2 100644 --- a/numpydoc/tests/hooks/test_validate_hook.py +++ b/numpydoc/tests/hooks/test_validate_hook.py @@ -116,9 +116,7 @@ def test_validate_hook_with_toml_config(example_module, tmp_path, capsys): ] exclude = '\\.__init__$' override_SS05 = [ - '^Process', - '^Assess', - '^Access', + '^Creates', ] """ ) @@ -154,7 +152,7 @@ def test_validate_hook_with_setup_cfg(example_module, tmp_path, capsys): [tool:numpydoc_validation] checks = all,EX01,SA01,ES01 exclude = \\.__init__$ - override_SS05 = ^Process,^Assess,^Access + override_SS05 = ^Creates """ ) ) @@ -198,9 +196,7 @@ def test_validate_hook_exclude_option_pyproject(example_module, tmp_path, capsys '\.__init__$', ] override_SS05 = [ - '^Process', - '^Assess', - '^Access', + '^Creates', ] """ ) @@ -232,7 +228,7 @@ def test_validate_hook_exclude_option_setup_cfg(example_module, tmp_path, capsys [tool:numpydoc_validation] checks = all,EX01,SA01,ES01 exclude = \\.NewClass$,\\.__init__$ - override_SS05 = ^Process,^Assess,^Access + override_SS05 = ^Creates """ ) ) diff --git a/numpydoc/validate.py b/numpydoc/validate.py index db605949..d0debfa2 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -710,7 +710,13 @@ def validate(obj_name, validator_cls=None, **validator_kwargs): errs.append(error("SS03")) if doc.summary != doc.summary.lstrip(): errs.append(error("SS04")) - elif doc.is_function_or_method and doc.summary.split(" ")[0][-1] == "s": + # Heuristic to check for infinitive verbs - shouldn't end in "s" + elif ( + doc.is_function_or_method + and len(doc.summary.split(" ")[0]) > 1 + and doc.summary.split(" ")[0][-1] == "s" + and doc.summary.split(" ")[0][-2] != "s" + ): errs.append(error("SS05")) if doc.num_summary_lines > 1: errs.append(error("SS06")) From 9862b6a5afde6003d67e26a6d7d775e2132ef55f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 12:57:48 -0400 Subject: [PATCH 76/92] Bump actions/download-artifact from 4.2.1 to 4.3.0 in the actions group (#620) Bumps the actions group with 1 update: [actions/download-artifact](https://github.com/actions/download-artifact). Updates `actions/download-artifact` from 4.2.1 to 4.3.0 - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/95815c38cf2ff2164869cbab79da8d1f422bc89e...d3f86a106a0bac45b974a628896c90dbdf5c8093) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: 4.3.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 131b9d43..dc0b7a30 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,7 +40,7 @@ jobs: # IMPORTANT: this permission is mandatory for trusted publishing id-token: write steps: - - uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: dist path: dist From 8dbddc68a4a7a67b9209461010f47434c18e7bf2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Jun 2025 08:44:12 -0600 Subject: [PATCH 77/92] Bump scientific-python/circleci-artifacts-redirector-action from 1.0.0 to 1.1.0 in the actions group (#627) Bump scientific-python/circleci-artifacts-redirector-action Bumps the actions group with 1 update: [scientific-python/circleci-artifacts-redirector-action](https://github.com/scientific-python/circleci-artifacts-redirector-action). Updates `scientific-python/circleci-artifacts-redirector-action` from 1.0.0 to 1.1.0 - [Release notes](https://github.com/scientific-python/circleci-artifacts-redirector-action/releases) - [Commits](https://github.com/scientific-python/circleci-artifacts-redirector-action/compare/4e13a10d89177f4bfc8007a7064bdbeda848d8d1...7eafdb60666f57706a5525a2f5eb76224dc8779b) --- updated-dependencies: - dependency-name: scientific-python/circleci-artifacts-redirector-action dependency-version: 1.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6d52fc24..0353ba98 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,7 +5,7 @@ jobs: name: Run CircleCI artifacts redirector steps: - name: GitHub Action step - uses: scientific-python/circleci-artifacts-redirector-action@4e13a10d89177f4bfc8007a7064bdbeda848d8d1 # v1.0.0 + uses: scientific-python/circleci-artifacts-redirector-action@7eafdb60666f57706a5525a2f5eb76224dc8779b # v1.1.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} api-token: ${{ secrets.CIRCLECI_ARTIFACT_REDIRECTOR_TOKEN }} From 84ebcc022b2a44bae4c56f90e4ed4e1c1b69723e Mon Sep 17 00:00:00 2001 From: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Date: Mon, 2 Jun 2025 11:47:46 -0400 Subject: [PATCH 78/92] Switch to dependency groups (#626) * Switch to dependency groups * Override install step to use dependency group --- .circleci/config.yml | 2 +- .github/workflows/test.yml | 4 ++-- .pre-commit-config.yaml | 8 ------- .readthedocs.yaml | 15 ++++--------- MANIFEST.in | 1 - pyproject.toml | 6 ++++-- requirements/default.txt | 4 ---- requirements/developer.txt | 4 ---- requirements/doc.txt | 7 ------ requirements/test.txt | 5 ----- tools/generate_requirements.py | 39 ---------------------------------- 11 files changed, 11 insertions(+), 84 deletions(-) delete mode 100644 requirements/default.txt delete mode 100644 requirements/developer.txt delete mode 100644 requirements/doc.txt delete mode 100644 requirements/test.txt delete mode 100755 tools/generate_requirements.py diff --git a/.circleci/config.yml b/.circleci/config.yml index 66a60c8d..98cae9bc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,7 +20,7 @@ jobs: python3 -m venv venv source venv/bin/activate python -m pip install --upgrade pip wheel setuptools - python -m pip install --upgrade -r requirements/doc.txt + python -m pip install --upgrade --group doc python -m pip list - save_cache: key: pip-cache diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8db3074c..b6c46a46 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -43,7 +43,7 @@ jobs: - name: Install run: | - python -m pip install .[test,doc] + python -m pip install . --group test --group doc pip list - name: Run test suite @@ -95,7 +95,7 @@ jobs: - name: Install run: | - python -m pip install .[test,doc] + python -m pip install . --group test --group doc pip list - name: Run test suite diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8e4d289d..1fa15182 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,14 +31,6 @@ repos: args: ["--fix", "--show-fixes", "--exit-non-zero-on-fix"] - id: ruff-format - - repo: local - hooks: - - id: generate_requirements.py - name: generate_requirements.py - language: system - entry: python tools/generate_requirements.py - files: "pyproject.toml|requirements/.*\\.txt|tools/generate_requirements.py" - ci: autofix_prs: false autofix_commit_msg: | diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 252fca8e..ebc00e82 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,22 +13,15 @@ build: # nodejs: "19" # rust: "1.64" # golang: "1.19" + jobs: + install: + - python -m pip install --upgrade pip wheel setuptools + - python -m pip install . --group doc # Build documentation in the "doc/" directory with Sphinx sphinx: configuration: doc/conf.py - # Optionally build your docs in additional formats such as PDF and ePub # formats: # - pdf # - epub - -# Optional but recommended, declare the Python requirements required -# to build your documentation -# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html -python: - install: - - method: pip - path: . - extra_requirements: - - doc diff --git a/MANIFEST.in b/MANIFEST.in index d1508eee..0a6df3ac 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,7 +2,6 @@ include MANIFEST.in include *.txt include *.rst recursive-include doc * -recursive-include requirements * recursive-include numpydoc * # Exclude what we don't want to include diff --git a/pyproject.toml b/pyproject.toml index 53458910..b6acaa4c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,10 +43,12 @@ file = 'LICENSE.txt' Homepage = 'https://numpydoc.readthedocs.io' Source = 'https://github.com/numpy/numpydoc/' -[project.optional-dependencies] -developer = [ +[dependency-groups] +dev = [ 'pre-commit>=3.3', "tomli; python_version < '3.11'", + { include-group = "doc" }, + { include-group = "test" } ] doc = [ 'numpy>=1.22', diff --git a/requirements/default.txt b/requirements/default.txt deleted file mode 100644 index dfe792ef..00000000 --- a/requirements/default.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Generated via tools/generate_requirements.py and pre-commit hook. -# Do not edit this file; modify pyproject.toml instead. -sphinx>=6 -tomli>=1.1.0;python_version<'3.11' diff --git a/requirements/developer.txt b/requirements/developer.txt deleted file mode 100644 index dbeefe57..00000000 --- a/requirements/developer.txt +++ /dev/null @@ -1,4 +0,0 @@ -# Generated via tools/generate_requirements.py and pre-commit hook. -# Do not edit this file; modify pyproject.toml instead. -pre-commit>=3.3 -tomli; python_version < '3.11' diff --git a/requirements/doc.txt b/requirements/doc.txt deleted file mode 100644 index 950966b6..00000000 --- a/requirements/doc.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Generated via tools/generate_requirements.py and pre-commit hook. -# Do not edit this file; modify pyproject.toml instead. -numpy>=1.22 -matplotlib>=3.5 -pydata-sphinx-theme>=0.13.3 -sphinx>=7 -intersphinx_registry diff --git a/requirements/test.txt b/requirements/test.txt deleted file mode 100644 index 2a9e670f..00000000 --- a/requirements/test.txt +++ /dev/null @@ -1,5 +0,0 @@ -# Generated via tools/generate_requirements.py and pre-commit hook. -# Do not edit this file; modify pyproject.toml instead. -pytest -pytest-cov -matplotlib diff --git a/tools/generate_requirements.py b/tools/generate_requirements.py deleted file mode 100755 index 388d2ccc..00000000 --- a/tools/generate_requirements.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python -"""Generate requirements/*.txt files from pyproject.toml.""" - -import sys -from pathlib import Path - -try: # standard module since Python 3.11 - import tomllib as toml -except ImportError: - try: # available for older Python via pip - import tomli as toml - except ImportError: - sys.exit("Please install `tomli` first: `pip install tomli`") - -script_pth = Path(__file__) -repo_dir = script_pth.parent.parent -script_relpth = script_pth.relative_to(repo_dir) -header = [ - f"# Generated via {script_relpth.as_posix()} and pre-commit hook.", - "# Do not edit this file; modify pyproject.toml instead.", -] - - -def generate_requirement_file(name: str, req_list: list[str]) -> None: - req_fname = repo_dir / "requirements" / f"{name}.txt" - req_fname.write_text("\n".join(header + req_list) + "\n") - - -def main() -> None: - pyproject = toml.loads((repo_dir / "pyproject.toml").read_text()) - - generate_requirement_file("default", pyproject["project"]["dependencies"]) - - for key, opt_list in pyproject["project"]["optional-dependencies"].items(): - generate_requirement_file(key, opt_list) - - -if __name__ == "__main__": - main() From 139a3441554ca74270a93cfcc7486035cf2557cc Mon Sep 17 00:00:00 2001 From: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Date: Mon, 2 Jun 2025 11:49:36 -0400 Subject: [PATCH 79/92] Switch to storing AST nodes on the stack for more accurate method signature check and easy access to parent nodes (#623) Switch to storing AST nodes on the stack for more accurate method signature check --- numpydoc/hooks/validate_docstrings.py | 51 ++++++++++++++++++++------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/numpydoc/hooks/validate_docstrings.py b/numpydoc/hooks/validate_docstrings.py index 75ff2539..aa318e47 100644 --- a/numpydoc/hooks/validate_docstrings.py +++ b/numpydoc/hooks/validate_docstrings.py @@ -33,7 +33,12 @@ class AstValidator(validate.Validator): """ def __init__( - self, *, ast_node: ast.AST, filename: os.PathLike, obj_name: str + self, + *, + ast_node: ast.AST, + filename: os.PathLike, + obj_name: str, + ancestry: list[ast.AST], ) -> None: self.node: ast.AST = ast_node self.raw_doc: str = ast.get_docstring(self.node, clean=False) or "" @@ -46,6 +51,8 @@ def __init__( self.is_class: bool = isinstance(ast_node, ast.ClassDef) self.is_module: bool = isinstance(ast_node, ast.Module) + self.ancestry: list[ast.AST] = ancestry + @staticmethod def _load_obj(name): raise NotImplementedError("AstValidator does not support this method.") @@ -91,7 +98,7 @@ def source_file_def_line(self) -> int: @property def signature_parameters(self) -> Tuple[str]: - def extract_signature(node): + def extract_signature(node, parent): args_node = node.args params = [] for arg_type in ["posonlyargs", "args", "vararg", "kwonlyargs", "kwarg"]: @@ -104,17 +111,21 @@ def extract_signature(node): else: params.extend([arg.arg for arg in entries]) params = tuple(params) - if params and params[0] in {"self", "cls"}: + if ( + params + and params[0] in {"self", "cls"} + and isinstance(parent, ast.ClassDef) + ): return params[1:] return params params = tuple() if self.is_function_or_method: - params = extract_signature(self.node) + params = extract_signature(self.node, self.ancestry[-1]) elif self.is_class: for child in self.node.body: if isinstance(child, ast.FunctionDef) and child.name == "__init__": - params = extract_signature(child) + params = extract_signature(child, self.node) return params @property @@ -144,9 +155,23 @@ def __init__( self.config: dict = config self.filepath: str = filepath self.module_name: str = Path(self.filepath).stem - self.stack: list[str] = [] + self.stack: list[ast.AST] = [] self.findings: list = [] + @property + def node_name(self) -> str: + """ + Get the full name of the current node in the stack. + + Returns + ------- + str + The full name of the current node in the stack. + """ + return ".".join( + [getattr(node, "name", self.module_name) for node in self.stack] + ) + def _ignore_issue(self, node: ast.AST, check: str) -> bool: """ Check whether the issue should be ignored. @@ -185,9 +210,13 @@ def _get_numpydoc_issues(self, node: ast.AST) -> None: node : ast.AST The node under inspection. """ - name = ".".join(self.stack) + name = self.node_name report = validate.validate( - name, AstValidator, ast_node=node, filename=self.filepath + name, + AstValidator, + ast_node=node, + filename=self.filepath, + ancestry=self.stack[:-1], ) self.findings.extend( [ @@ -209,13 +238,11 @@ def visit(self, node: ast.AST) -> None: if isinstance( node, (ast.Module, ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef) ): - self.stack.append( - self.module_name if isinstance(node, ast.Module) else node.name - ) + self.stack.append(node) if not ( self.config["exclude"] - and re.search(self.config["exclude"], ".".join(self.stack)) + and re.search(self.config["exclude"], self.node_name) ): self._get_numpydoc_issues(node) From 259f8ac8291485c1b11dda83e6ad29c4231d724c Mon Sep 17 00:00:00 2001 From: Gilles Peiffer Date: Mon, 2 Jun 2025 22:33:13 +0200 Subject: [PATCH 80/92] Fix broken link in `format.rst` (#628) --- doc/format.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/format.rst b/doc/format.rst index ecdd1d4f..3b3693a4 100644 --- a/doc/format.rst +++ b/doc/format.rst @@ -769,9 +769,9 @@ leads to the following style recommendations: enclosed within ````double backticks````. A more extensive example of reST markup can be found in `this example -document `_; +document `_; the `quick reference -`_ is +`_ is useful while editing. Line spacing and indentation are significant and should be carefully From 865b865b3d1dfb8cd2139fa76cefe3643e1bf52a Mon Sep 17 00:00:00 2001 From: Yuki Kobayashi Date: Wed, 4 Jun 2025 14:01:32 +0900 Subject: [PATCH 81/92] Fix pip setup command in github workflow (#629) --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b6c46a46..b463ee42 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,7 +38,7 @@ jobs: run: | python -m pip install --upgrade pip wheel setuptools python -m pip install codecov - python -m pip install ${{ matrix.sphinx-version }} + python -m pip install "${{ matrix.sphinx-version }}" python -m pip list - name: Install From 80441357dcf5bd8197ad9fa8a9447c07c1f2da29 Mon Sep 17 00:00:00 2001 From: Yuki Kobayashi Date: Sat, 7 Jun 2025 13:41:51 +0900 Subject: [PATCH 82/92] Specity the types of `numpydoc_xref_ignore` option (#631) Added `types` parameter to accept the value `"all"` for the `numpydoc_xref_ignore` option. Fixes gh-630 --- numpydoc/numpydoc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index a04443b3..9a920e35 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -296,7 +296,7 @@ def setup(app, get_doc_object_=get_doc_object): app.add_config_value("numpydoc_attributes_as_param_list", True, True) 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_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_overrides", dict(), False) From 610a25e4d33114df619b88c3e8083ec11b9729d0 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Tue, 24 Jun 2025 05:15:02 -0700 Subject: [PATCH 83/92] Designate 1.9.0rc0 release --- numpydoc/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpydoc/_version.py b/numpydoc/_version.py index fe918984..b3de187d 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.9.0rc0.dev0" +__version__ = "1.9.0rc0" From 3db2f68e5a6af0de867f9ec1ea94c6052d1d824f Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Tue, 24 Jun 2025 05:18:49 -0700 Subject: [PATCH 84/92] Designate 1.9.0 release --- doc/release/notes.rst | 79 +++++++++++++++++++++++++++++++++++++++++++ numpydoc/_version.py | 2 +- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/doc/release/notes.rst b/doc/release/notes.rst index ad1ccda1..74406b6a 100644 --- a/doc/release/notes.rst +++ b/doc/release/notes.rst @@ -1,3 +1,82 @@ +1.9.0 +===== + +We're happy to announce the release of numpydoc 1.9.0! + +Enhancements +------------ + +- ignore some errors at module level (`#593 `_). +- Rework hook output to remove the table (`#611 `_). +- Switch to storing AST nodes on the stack for more accurate method signature check and easy access to parent nodes (`#623 `_). + +Bug Fixes +--------- + +- MAINT: Changed class constructor __init__ GL08 reporting (`#592 `_). +- BUG: Correct functionality of numpydoc SS05 (`#613 `_). +- Specity the types of ``numpydoc_xref_ignore`` option (`#631 `_). + +Documentation +------------- + +- DOC: Do not use types for *args, **kwargs (`#585 `_). +- mention conda-forge in installation docs (`#595 `_). +- Fix typo in validation.rst (`#605 `_). +- Fix broken link in ``format.rst`` (`#628 `_). + +Maintenance +----------- + +- CI: use hashes for actions' versions in publishing job (`#579 `_). +- Bump the actions group with 2 updates (`#581 `_). +- Bump pypa/gh-action-pypi-publish from 1.10.0 to 1.10.2 in the actions group (`#582 `_). +- [pre-commit.ci] pre-commit autoupdate (`#583 `_). +- MAINT: Add _exception_on_warning to MockApp (`#586 `_). +- Bump the actions group across 1 directory with 2 updates (`#590 `_). +- don't pass maxsplit as positional arg (`#596 `_). +- [pre-commit.ci] pre-commit autoupdate (`#598 `_). +- Add Python 3.13 support (`#599 `_). +- Update readthedocs config (`#600 `_). +- Bump the actions group with 2 updates (`#603 `_). +- Bump the actions group with 3 updates (`#609 `_). +- [pre-commit.ci] pre-commit autoupdate (`#614 `_). +- Bump actions/download-artifact from 4.2.1 to 4.3.0 in the actions group (`#620 `_). +- Bump scientific-python/circleci-artifacts-redirector-action from 1.0.0 to 1.1.0 in the actions group (`#627 `_). +- Switch to dependency groups (`#626 `_). +- Fix pip setup command in github workflow (`#629 `_). + +Contributors +------------ + +13 authors added to this release (alphabetically): + +- Brigitta Sipőcz (`@bsipocz `_) +- Daniel McCloy (`@drammock `_) +- Eric Larson (`@larsoner `_) +- Gilles Peiffer (`@Peiffap `_) +- Jarrod Millman (`@jarrodmillman `_) +- Lucas Colley (`@lucascolley `_) +- Matt Gebert (`@mattgebert `_) +- Maxine Hartnett (`@maxinelasp `_) +- Ross Barnowski (`@rossbar `_) +- Stefan van der Walt (`@stefanv `_) +- Stefanie Molin (`@stefmolin `_) +- Tim Hoffmann (`@timhoffm `_) +- Yuki Kobayashi (`@koyuki7w `_) + +7 reviewers added to this release (alphabetically): + +- Charles Harris (`@charris `_) +- Eric Larson (`@larsoner `_) +- Jarrod Millman (`@jarrodmillman `_) +- Lucas Colley (`@lucascolley `_) +- Matt Gebert (`@mattgebert `_) +- Ross Barnowski (`@rossbar `_) +- Stefan van der Walt (`@stefanv `_) + +_These lists are automatically generated, and may not be complete or may contain duplicates._ + 1.8.0 ===== diff --git a/numpydoc/_version.py b/numpydoc/_version.py index b3de187d..0a0a43a5 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.9.0rc0" +__version__ = "1.9.0" From 1244f519fa2f3caeab8ba606bb24c8a1859fcb19 Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Tue, 24 Jun 2025 05:26:27 -0700 Subject: [PATCH 85/92] Bump version --- numpydoc/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpydoc/_version.py b/numpydoc/_version.py index 0a0a43a5..21565c81 100644 --- a/numpydoc/_version.py +++ b/numpydoc/_version.py @@ -1 +1 @@ -__version__ = "1.9.0" +__version__ = "1.10.0rc0.dev0" From 8c66165fe5ea76b977157340da40ffbcb65fafbe Mon Sep 17 00:00:00 2001 From: Jarrod Millman Date: Tue, 24 Jun 2025 11:41:11 -0700 Subject: [PATCH 86/92] Fix circleci doc buld (#634) --- doc/release/notes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/release/notes.rst b/doc/release/notes.rst index 74406b6a..88b052ba 100644 --- a/doc/release/notes.rst +++ b/doc/release/notes.rst @@ -20,7 +20,7 @@ Bug Fixes Documentation ------------- -- DOC: Do not use types for *args, **kwargs (`#585 `_). +- DOC: Do not use types for ``*args``, ``**kwargs`` (`#585 `_). - mention conda-forge in installation docs (`#595 `_). - Fix typo in validation.rst (`#605 `_). - Fix broken link in ``format.rst`` (`#628 `_). From bad5c0bb1cbe543ac03059f52a46ffa4728e860e Mon Sep 17 00:00:00 2001 From: Matt Gebert Date: Tue, 22 Jul 2025 01:27:55 +1000 Subject: [PATCH 87/92] Added "exclude_files" option for pyproject.toml config usage. (#635) * feat(numpydoc/hooks/validate_docstrings.py): Added a pyproject.toml config option `exclude_files` that allows regex path exclusions Solution to Issue #497 * fix(test_validate_hook.py): Corrected test for exclude_files toml option, which should have 0 findings * refactor(test_validate_hook.py): Added extra testcase to verify no-matching exclude_files option * refactor(test_validate_hook.py): Modified toml exclude_files test mark, to correct parameter order * refactor(test_validate_hook.py): Change string type * test(test_validate_hook.py): Added correct pyproject.toml and setup.cfg test cases for the `exclude_files` option * feat(numpydoc.py): Added config option `numpydoc_validation_exclude_files` for Sphinx plugin Uses very similar regex processing to `numpydoc_validation_exclude` but instead applies to a module check before any numpydoc validation is performed. * fix(numpydoc.py): Corrected module path check for `numpydoc_validation_exclude_files` option * refactor(numpydoc.py): Changed `numpydoc_validation_exclue_files` sphinx option to use `inspect`, and simplified path checking using `__file__` * fix(Modified-`numpydoc_validation_exclude_files`-option-to-only-activate-if-`numpydoc_validation_checks`-is-not-empty): Mimicing same behaviour as `numpydoc_validation_exclude` * docs(validation.rst,-install.rst): Added docs for new feature `numpydoc_validation_exclude_files` for Sphinx and `exclude_files` for pyproject.toml * docs(validation.rst,-install.rst): Fixed indentation and linebreaks to properly format * chore(numpydoc.py): use package-relative filename instead of absolute. * docs(validation.rst,-install.rst): indicate relative path not absolute path for `exclude_files` options --- doc/install.rst | 12 ++++ doc/validation.rst | 8 +++ numpydoc/hooks/validate_docstrings.py | 28 ++++++++- numpydoc/numpydoc.py | 66 +++++++++++++++++++--- numpydoc/tests/hooks/test_validate_hook.py | 66 ++++++++++++++++++++++ numpydoc/tests/test_docscrape.py | 1 + numpydoc/tests/test_numpydoc.py | 56 ++++++++++++++++++ 7 files changed, 229 insertions(+), 8 deletions(-) diff --git a/doc/install.rst b/doc/install.rst index c72d777f..2471b765 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -139,6 +139,18 @@ numpydoc_validation_exclude : set 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 ` to a container of strings using :py:mod:`re` syntax specifying patterns to diff --git a/doc/validation.rst b/doc/validation.rst index 3d2babae..a0729b6b 100644 --- a/doc/validation.rst +++ b/doc/validation.rst @@ -36,6 +36,10 @@ the pre-commit hook as follows: expressions ``\.undocumented_method$`` or ``\.__repr__$``. This maps to ``numpydoc_validation_exclude`` from the :ref:`Sphinx build configuration `. +* ``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 `. * ``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_`` with a collection of regular expression(s) @@ -57,6 +61,10 @@ the pre-commit hook as follows: '\.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 --git a/numpydoc/hooks/validate_docstrings.py b/numpydoc/hooks/validate_docstrings.py index aa318e47..a718e4ef 100644 --- a/numpydoc/hooks/validate_docstrings.py +++ b/numpydoc/hooks/validate_docstrings.py @@ -273,7 +273,12 @@ def parse_config(dir_path: os.PathLike = None) -> dict: 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 @@ def extract_check_overrides(options, config_items): 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 @@ def extract_check_overrides(options, config_items): 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 @@ def extract_check_overrides(options, config_items): options["checks"] = validate.get_validation_checks(options["checks"]) options["exclude"] = compile_regex(options["exclude"]) + options["exclude_files"] = compile_regex(options["exclude_files"]) return options @@ -395,9 +418,12 @@ def run_hook( 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 --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 9a920e35..9c1bb0ed 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -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 _traverse_or_findall(node, condition, **kwargs): ) -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() @@ -114,7 +118,7 @@ def is_docstring_section(node): 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 @@ def matching_pending_xref(node): 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 @@ def clean_backrefs(app, doc, docname): 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 @@ -190,6 +194,38 @@ def mangle_docstrings(app, what, name, obj, options, lines): 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 +275,7 @@ def mangle_docstrings(app, what, name, obj, options, lines): 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 +309,7 @@ def _clean_text_signature(sig): 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 +335,7 @@ def setup(app, get_doc_object_=get_doc_object): 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 +346,7 @@ def setup(app, get_doc_object_=get_doc_object): 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 +379,21 @@ def update_config(app, config=None): ) 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 --git a/numpydoc/tests/hooks/test_validate_hook.py b/numpydoc/tests/hooks/test_validate_hook.py index 47f315c2..b235313b 100644 --- a/numpydoc/tests/hooks/test_validate_hook.py +++ b/numpydoc/tests/hooks/test_validate_hook.py @@ -246,3 +246,69 @@ def test_validate_hook_exclude_option_setup_cfg(example_module, tmp_path, capsys return_code = run_hook([example_module], config=tmp_path) assert return_code == 1 assert capsys.readouterr().err.strip() == expected + + +@pytest.mark.parametrize( + "regex, expected_code", + [(".*(/|\\\\)example.*\.py", 0), (".*/non_existent_match.*\.py", 1)], +) +def test_validate_hook_exclude_files_option_pyproject( + example_module, regex, 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. + """ + + 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 = [ + '{regex}', + ]""" + ) + ) + + return_code = run_hook([example_module], config=tmp_path) + assert return_code == expected_code # Should not-report/report findings. + + +@pytest.mark.parametrize( + "regex, expected_code", + [(".*(/|\\\\)example.*\.py", 0), (".*/non_existent_match.*\.py", 1)], +) +def test_validate_hook_exclude_files_option_setup_cfg( + example_module, regex, 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. + """ + + 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 = {regex} + """ + ) + ) + + return_code = run_hook([example_module], config=tmp_path) + assert return_code == expected_code # Should not-report/report findings. diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index f10adc45..c122515a 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -1593,6 +1593,7 @@ def __init__(self, a, b): # 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 --git a/numpydoc/tests/test_numpydoc.py b/numpydoc/tests/test_numpydoc.py index bedef5fa..f879d7fb 100644 --- a/numpydoc/tests/test_numpydoc.py +++ b/numpydoc/tests/test_numpydoc.py @@ -31,6 +31,7 @@ class MockConfig: 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 @@ def test_clean_backrefs(): assert "id1" in citation["backrefs"] +@pytest.mark.parametrize( + "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 From afca43f04477ff788e01243948ffa8d1211453fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 08:35:40 -0400 Subject: [PATCH 88/92] Bump the actions group across 1 directory with 3 updates (#644) Bumps the actions group with 3 updates in the / directory: [scientific-python/circleci-artifacts-redirector-action](https://github.com/scientific-python/circleci-artifacts-redirector-action), [actions/checkout](https://github.com/actions/checkout) and [actions/download-artifact](https://github.com/actions/download-artifact). Updates `scientific-python/circleci-artifacts-redirector-action` from 1.1.0 to 1.2.0 - [Release notes](https://github.com/scientific-python/circleci-artifacts-redirector-action/releases) - [Commits](https://github.com/scientific-python/circleci-artifacts-redirector-action/compare/7eafdb60666f57706a5525a2f5eb76224dc8779b...839631420e45a08af893032e5a5e8843bf47e8ff) Updates `actions/checkout` from 4 to 5 - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v4...v5) Updates `actions/download-artifact` from 4.3.0 to 5.0.0 - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/d3f86a106a0bac45b974a628896c90dbdf5c8093...634f93cb2916e3fdff6788551b99b062d0335ce0) --- updated-dependencies: - dependency-name: scientific-python/circleci-artifacts-redirector-action dependency-version: 1.2.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: actions - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions - dependency-name: actions/download-artifact dependency-version: 5.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- .github/workflows/release.yml | 4 ++-- .github/workflows/test.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0353ba98..ebed3deb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -5,7 +5,7 @@ jobs: name: Run CircleCI artifacts redirector steps: - name: GitHub Action step - uses: scientific-python/circleci-artifacts-redirector-action@7eafdb60666f57706a5525a2f5eb76224dc8779b # v1.1.0 + uses: scientific-python/circleci-artifacts-redirector-action@839631420e45a08af893032e5a5e8843bf47e8ff # v1.2.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} api-token: ${{ secrets.CIRCLECI_ARTIFACT_REDIRECTOR_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dc0b7a30..3d77cdf9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: name: sdist and wheels runs-on: ubuntu-latest steps: - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: fetch-depth: 0 - uses: actions/setup-python@39cd14951b08e74b54015e9e001cdefcf80e669f # v5.1.1 @@ -40,7 +40,7 @@ jobs: # IMPORTANT: this permission is mandatory for trusted publishing id-token: write steps: - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 with: name: dist path: dist diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b463ee42..7fee6aa9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: run: shell: bash -eo pipefail {0} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Python setup uses: actions/setup-python@v5 @@ -80,7 +80,7 @@ jobs: os: [ubuntu] python-version: ["3.11", "3.12", "3.13"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Python setup uses: actions/setup-python@v5 From 0240ee08523cd6488b28cd5cd3857bb4d85f438c Mon Sep 17 00:00:00 2001 From: Matt Gebert Date: Wed, 10 Sep 2025 23:21:19 +1000 Subject: [PATCH 89/92] build(pyproject.toml): drop support for python 3.9 (require 3.10+) (#641) * build(pyproject.toml): drop support for python 3.9 (require 3.10+) In upgrading via #592 and #622, requires stable use of __qualname__, not supported in dataclasses in python3.9 (solves #637). * style: Replace isinstance calls that use tuples to the `|` operator as per ruff UP038 * refactor(cli.py): exchange union use for '|' as per ruff UP007 * refactor(test_docscrape): explicitly declare strict=True for testing zips * test(test_docscrape.py): use strict and include 4th parameter check for the docscrape test * refactor(validate.py): remove `Optional[X]` for use of `X | None` ruff UP007, UP045 * refactor(test_docscrape.py): ruff formatting --- .github/workflows/test.yml | 2 +- README.rst | 2 +- doc/install.rst | 2 +- numpydoc/cli.py | 6 +++--- numpydoc/docscrape.py | 2 +- numpydoc/hooks/validate_docstrings.py | 8 ++++---- numpydoc/numpydoc.py | 2 +- numpydoc/tests/test_docscrape.py | 14 ++++++++++---- numpydoc/validate.py | 4 ++-- pyproject.toml | 3 +-- 10 files changed, 25 insertions(+), 20 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7fee6aa9..b188cba4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: os: [Ubuntu] - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13"] sphinx-version: ["sphinx==6.0", "sphinx==6.2", "sphinx==7.0", "sphinx>=7.3"] include: diff --git a/README.rst b/README.rst index 354a79d9..fdd35942 100644 --- a/README.rst +++ b/README.rst @@ -17,7 +17,7 @@ docstrings formatted according to the NumPy documentation format. 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 `_. diff --git a/doc/install.rst b/doc/install.rst index 2471b765..5d61010f 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -5,7 +5,7 @@ Getting started 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 `_ * `numpydoc on GitHub `_ diff --git a/numpydoc/cli.py b/numpydoc/cli.py index 53335fdf..30daa3f5 100644 --- a/numpydoc/cli.py +++ b/numpydoc/cli.py @@ -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 @@ def _parse_config(s): 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 --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index 54863d5f..9cf5c5a9 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -701,7 +701,7 @@ def properties(self): 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 --git a/numpydoc/hooks/validate_docstrings.py b/numpydoc/hooks/validate_docstrings.py index a718e4ef..70823f10 100644 --- a/numpydoc/hooks/validate_docstrings.py +++ b/numpydoc/hooks/validate_docstrings.py @@ -63,7 +63,7 @@ def name(self) -> str: @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 @@ def visit(self, node: ast.AST) -> None: 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) @@ -395,8 +395,8 @@ def process_file(filepath: os.PathLike, config: dict) -> "list[list[str]]": 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. diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index 9c1bb0ed..b1431519 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -88,7 +88,7 @@ def _is_cite_in_numpydoc_docstring(citation_node): 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 diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index c122515a..dbfc5c14 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -187,7 +187,9 @@ def test_extended_summary(doc): 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" @@ -242,7 +244,9 @@ def test_yields(): ("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 +257,9 @@ def test_sent(): 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 +380,7 @@ def line_by_line_compare(a, b, n_lines=None): 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 diff --git a/numpydoc/validate.py b/numpydoc/validate.py index d0debfa2..18373b77 100644 --- a/numpydoc/validate.py +++ b/numpydoc/validate.py @@ -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 @@ def _unwrap(obj): # 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]]: """ diff --git a/pyproject.toml b/pyproject.toml index b6acaa4c..c8158115 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ requires = ['setuptools>=61.2'] 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 @@ classifiers = [ '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', From 9e1cfe8360c0e31e325e96ddca2fdcd1b9b14872 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 12:04:11 -0700 Subject: [PATCH 90/92] [pre-commit.ci] pre-commit autoupdate (#639) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1fa15182..75fd12ce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: cef0300fd0fc4d2a87a85fa2093c6b283ea36f4b # frozen: v5.0.0 + rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0 hooks: - id: check-added-large-files - id: check-ast @@ -25,7 +25,7 @@ repos: args: [--prose-wrap=preserve] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "971923581912ef60a6b70dbf0c3e9a39563c9d47" # frozen: v0.11.4 + rev: "9c89adb347f6b973f4905a4be0051eb2ecf85dea" # frozen: v0.13.3 hooks: - id: ruff args: ["--fix", "--show-fixes", "--exit-non-zero-on-fix"] From b0d24c092e550210aefb285b78fb94408d36d12e Mon Sep 17 00:00:00 2001 From: Eric Larson Date: Fri, 10 Oct 2025 11:34:54 -0400 Subject: [PATCH 91/92] MAINT: Make pre-commit run --all pass (#650) --- .pre-commit-config.yaml | 4 ++-- numpydoc/docscrape.py | 2 +- numpydoc/tests/test_docscrape.py | 2 +- numpydoc/tests/test_validate.py | 7 ++----- pyproject.toml | 1 + 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 75fd12ce..edb0146e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0 + rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0 hooks: - id: check-added-large-files - id: check-ast @@ -25,7 +25,7 @@ repos: args: [--prose-wrap=preserve] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "9c89adb347f6b973f4905a4be0051eb2ecf85dea" # frozen: v0.13.3 + rev: "9c89adb347f6b973f4905a4be0051eb2ecf85dea" # frozen: v0.13.3 hooks: - id: ruff args: ["--fix", "--show-fixes", "--exit-non-zero-on-fix"] diff --git a/numpydoc/docscrape.py b/numpydoc/docscrape.py index 9cf5c5a9..26a08259 100644 --- a/numpydoc/docscrape.py +++ b/numpydoc/docscrape.py @@ -597,7 +597,7 @@ def get_func(self): def __str__(self): out = "" - func, func_name = self.get_func() + _func, func_name = self.get_func() roles = {"func": "function", "meth": "method"} diff --git a/numpydoc/tests/test_docscrape.py b/numpydoc/tests/test_docscrape.py index dbfc5c14..cf7c0de9 100644 --- a/numpydoc/tests/test_docscrape.py +++ b/numpydoc/tests/test_docscrape.py @@ -211,7 +211,7 @@ def test_parameters(doc): 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") diff --git a/numpydoc/tests/test_validate.py b/numpydoc/tests/test_validate.py index 9f0f7942..b8e17f8d 100644 --- a/numpydoc/tests/test_validate.py +++ b/numpydoc/tests/test_validate.py @@ -1391,11 +1391,8 @@ def test_bad_class(self, capsys): ], ) 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", diff --git a/pyproject.toml b/pyproject.toml index c8158115..b8911d85 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -99,6 +99,7 @@ extend-select = [ 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", From a212204a310fb7a7ba8e2b54964a688aa696b8e4 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 10 Oct 2025 11:47:02 -0400 Subject: [PATCH 92/92] FIX: account for unreleased changes to sphinx (#649) --- numpydoc/numpydoc.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/numpydoc/numpydoc.py b/numpydoc/numpydoc.py index b1431519..2b9757d7 100644 --- a/numpydoc/numpydoc.py +++ b/numpydoc/numpydoc.py @@ -185,8 +185,12 @@ def mangle_docstrings(app: SphinxApp, what, name, obj, options, lines): "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