From 2913d4307407a1d7d8e2ff5924f6982154c79a2c Mon Sep 17 00:00:00 2001 From: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Date: Sat, 15 Feb 2025 15:07:11 -0500 Subject: [PATCH 1/4] Switch from table to printed items --- .pre-commit-hooks.yaml | 2 +- numpydoc/hooks/validate_docstrings.py | 43 +++++++++++++++++---------- 2 files changed, 28 insertions(+), 17 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..44c335b9 100644 --- a/numpydoc/hooks/validate_docstrings.py +++ b/numpydoc/hooks/validate_docstrings.py @@ -5,6 +5,7 @@ import os import re import sys +import textwrap try: import tomllib @@ -193,7 +194,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 +372,29 @@ def run_hook( config_options = parse_config(config or project_root) config_options["checks"] -= set(ignore or []) - findings = [] + indent = "\n" + " " * 9 + + 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 + last_line = None + + for line, obj, check, description in file_issues: + if last_line == line: + prefix = "" + else: + prefix = f"\n{line}\nin {obj}\n" + + print( + prefix, + *( + textwrap.indent(text, f" {check} - " if i == 0 else indent) + for i, text in enumerate(textwrap.wrap(description, 60)) + ), + sep="", + file=sys.stderr, + ) + last_line = line + + return bool(findings) From 447c9123de6f5df9261b983d4d7f2f297d0baeed Mon Sep 17 00:00:00 2001 From: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Date: Sat, 15 Feb 2025 15:11:49 -0500 Subject: [PATCH 2/4] Remove tabulate dependency --- numpydoc/hooks/validate_docstrings.py | 2 -- pyproject.toml | 1 - requirements/default.txt | 1 - 3 files changed, 4 deletions(-) diff --git a/numpydoc/hooks/validate_docstrings.py b/numpydoc/hooks/validate_docstrings.py index 44c335b9..07c4756a 100644 --- a/numpydoc/hooks/validate_docstrings.py +++ b/numpydoc/hooks/validate_docstrings.py @@ -15,8 +15,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 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 b8dc0a3407620c3b37fab4bf862bca077ba146ec Mon Sep 17 00:00:00 2001 From: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Date: Wed, 5 Mar 2025 22:50:38 -0500 Subject: [PATCH 3/4] Adjust format --- numpydoc/hooks/validate_docstrings.py | 22 +-- numpydoc/tests/hooks/test_validate_hook.py | 176 +++++++++------------ numpydoc/tests/test_main.py | 10 +- 3 files changed, 77 insertions(+), 131 deletions(-) diff --git a/numpydoc/hooks/validate_docstrings.py b/numpydoc/hooks/validate_docstrings.py index 07c4756a..75ff2539 100644 --- a/numpydoc/hooks/validate_docstrings.py +++ b/numpydoc/hooks/validate_docstrings.py @@ -5,7 +5,6 @@ import os import re import sys -import textwrap try: import tomllib @@ -370,29 +369,12 @@ def run_hook( config_options = parse_config(config or project_root) config_options["checks"] -= set(ignore or []) - indent = "\n" + " " * 9 - findings = False for file in files: if file_issues := process_file(file, config_options): findings = True - last_line = None for line, obj, check, description in file_issues: - if last_line == line: - prefix = "" - else: - prefix = f"\n{line}\nin {obj}\n" - - print( - prefix, - *( - textwrap.indent(text, f" {check} - " if i == 0 else indent) - for i, text in enumerate(textwrap.wrap(description, 60)) - ), - sep="", - file=sys.stderr, - ) - last_line = line + print(f"\n{line}: {check} {description}", file=sys.stderr) - return bool(findings) + 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) From bf3690bc05a5e130312ccc256328c4771d42c982 Mon Sep 17 00:00:00 2001 From: Stefanie Molin <24376333+stefmolin@users.noreply.github.com> Date: Sat, 8 Mar 2025 10:28:06 -0500 Subject: [PATCH 4/4] Fix test after Sphinx builder change in newer version --- 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 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: