diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b463ee42..2f450a9b 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',