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 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: 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..9a208cb0 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) @@ -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 | +-------------------------------------------+-------------------------------------+---------+----------------------------------------+ """ ) 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( 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 = [