diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c763fe7..0e128069 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: strategy: matrix: - python-version: ['3.7', '3.8', '3.9', '3.10', '3.11'] + python-version: ['3.10', '3.11'] experimental: [false] name: Python ${{ matrix.python-version}} diff --git a/pyproject.toml b/pyproject.toml index d9851026..4c560a2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,7 @@ select = [ # Remove E999 once pattern matching is supported # https://github.com/charliermarsh/ruff/issues/282 ignore = ["E402", "E501", "E731", "E741", "E999", "B904", "B020"] -target-version = "py37" +target-version = "py310" [tool.ruff.flake8-bugbear] extend-immutable-calls = ["typer.Argument", "typer.Option"] diff --git a/setup.py b/setup.py index 121c4ab4..cfea04d0 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ # https://github.com/pallets/jinja/issues/1585 "markupsafe==2.0.1", ], - python_requires=">=3.7", + python_requires=">=3.10", classifiers=[ "Intended Audience :: Developers", "Natural Language :: English", diff --git a/sphinx_js/__init__.py b/sphinx_js/__init__.py index 1a9b5d9c..845d3e01 100644 --- a/sphinx_js/__init__.py +++ b/sphinx_js/__init__.py @@ -1,4 +1,4 @@ -from functools import lru_cache +from functools import cache from os.path import join, normpath from typing import Any @@ -15,7 +15,7 @@ # Cache this to guarantee it only runs once. -@lru_cache(maxsize=None) +@cache def fix_js_make_xref(): """Monkeypatch to fix sphinx.domains.javascript TypedField and GroupedField @@ -83,7 +83,7 @@ class JSGroupedField(JSXrefMixin, GroupedField): # Cache this to guarantee it only runs once. -@lru_cache(maxsize=None) +@cache def fix_staticfunction_objtype(): """Add support for staticfunction objtype diff --git a/sphinx_js/ir.py b/sphinx_js/ir.py index e75f38c4..6e7e6766 100644 --- a/sphinx_js/ir.py +++ b/sphinx_js/ir.py @@ -24,12 +24,12 @@ """ from dataclasses import InitVar, dataclass -from typing import Any, List, Optional, Union +from typing import Any, List from .analyzer_utils import dotted_path #: Human-readable type of a value. None if we don't know the type. -Type = Optional[str] +Type = str | None # In the far future, we may take full control of our RST templates rather than # using the js-domain directives provided by Sphinx. This would give us the # freedom to link type names in formal param lists and param description lists @@ -107,7 +107,7 @@ class Param: description: ReStructuredText = ReStructuredText("") has_default: bool = False is_variadic: bool = False - type: Optional[Type] = None + type: Type | None = None #: Return the default value of this parameter, string-formatted so it can #: be immediately suffixed to an equal sign in a formal param list. For #: example, the number 6 becomes the string "6" to create ``foo=6``. If @@ -172,23 +172,23 @@ class TopLevel: filename: str #: The path to the dependency, i.e., the file the object is from. #: Either absolute or relative to the root_for_relative_js_paths. - deppath: Optional[str] + deppath: str | None #: The human-readable description of the entity or '' if absent description: ReStructuredText #: Line number where the object (excluding any prefixing comment) begins line: int #: Explanation of the deprecation (which implies True) or True or False - deprecated: Union[ReStructuredText, bool] + deprecated: ReStructuredText | bool #: List of preformatted textual examples - examples: List[str] + examples: list[str] #: List of paths to also refer the reader to - see_alsos: List[str] + see_alsos: list[str] #: Explicitly documented sub-properties of the object, a la jsdoc's #: @properties - properties: List["Attribute"] + properties: list["Attribute"] #: None if not exported for use by outside code. Otherwise, the Sphinx #: dotted path to the module it is exported from, e.g. 'foo.bar' - exported_from: Optional[Pathname] + exported_from: Pathname | None @dataclass @@ -208,9 +208,9 @@ class Attribute(TopLevel, _Member): class Function(TopLevel, _Member): """A function or a method of a class""" - params: List[Param] + params: list[Param] exceptions: List[Exc] # noqa: Linter is buggy. - returns: List[Return] + returns: list[Return] @dataclass @@ -221,10 +221,10 @@ class _MembersAndSupers: #: we'd have to pass the doclets_by_class map in and keep it around, along #: with a callable that would create the member IRs from it on demand.) #: Does not include the default constructor. - members: List[Union[Function, Attribute]] + members: list[Function | Attribute] #: Objects this one extends: for example, superclasses of a class or #: superinterfaces of an interface - supers: List[Pathname] + supers: list[Pathname] @dataclass @@ -236,11 +236,11 @@ class Interface(TopLevel, _MembersAndSupers): class Class(TopLevel, _MembersAndSupers): #: The default constructor for this class. Absent if the constructor is #: inherited. - constructor: Optional[Function] + constructor: Function | None #: Whether this is an abstract class is_abstract: bool #: Interfaces this class implements - interfaces: List[Pathname] + interfaces: list[Pathname] # There's room here for additional fields like @example on the class doclet # itself. These are supported and extracted by jsdoc, but they end up in an # `undocumented: True` doclet and so are presently filtered out. But we do diff --git a/sphinx_js/renderers.py b/sphinx_js/renderers.py index b881e515..d8a94560 100644 --- a/sphinx_js/renderers.py +++ b/sphinx_js/renderers.py @@ -1,5 +1,4 @@ from re import sub -from typing import List, Union from docutils.parsers.rst import Parser as RstParser from docutils.statemachine import StringList @@ -288,8 +287,8 @@ def _template_vars(self, name, obj): def _members_of( self, obj: Class, - include: List[str], - exclude: List[str], + include: list[str], + exclude: list[str], should_include_private: bool, ) -> str: """Return RST describing the members of a given class. @@ -313,8 +312,8 @@ def rst_for(obj): ) def members_to_include( - include: List[str], - ) -> List[Union[Attribute, Function]]: + include: list[str], + ) -> list[Attribute | Function]: """Return the members that should be included (before excludes and access specifiers are taken into account). diff --git a/sphinx_js/typedoc.py b/sphinx_js/typedoc.py index 62d5999c..d3eaaf9f 100644 --- a/sphinx_js/typedoc.py +++ b/sphinx_js/typedoc.py @@ -3,11 +3,12 @@ import re import subprocess from codecs import getreader +from collections.abc import Iterator from errno import ENOENT from json import load from os.path import basename, join, normpath, relpath, sep, splitext from tempfile import NamedTemporaryFile -from typing import Any, Dict, Iterator, List, Optional, Tuple, Union +from typing import Any from sphinx.errors import SphinxError @@ -79,14 +80,14 @@ def _parent_nodes(self, node: Node) -> Iterator[Node]: # Found one! yield node - def _containing_module(self, node: Node) -> Optional[Pathname]: + def _containing_module(self, node: Node) -> Pathname | None: """Return the Pathname pointing to the module containing the given node, None if one isn't found.""" for node in self._parent_nodes(node): return Pathname(make_path_segments(node, self._base_dir)) return None - def _containing_deppath(self, node: Node) -> Optional[str]: + def _containing_deppath(self, node: Node) -> str | None: """Return the path pointing to the module containing the given node. The path is absolute or relative to `root_for_relative_js_paths`. Raises ValueError if one isn't found. @@ -123,7 +124,7 @@ def _top_level_properties(self, node): def _constructor_and_members( self, cls: Node - ) -> Tuple[Optional[Function], List[Union[Function, Attribute]]]: + ) -> tuple[Function | None, list[Function | Attribute]]: """Return the constructor and other members of a class. In TS, a constructor may have multiple (overloaded) type signatures but @@ -159,9 +160,7 @@ def _convert_all_nodes(self, root): todo.extend(more_todo) return done - def _convert_node( - self, node: Node - ) -> Tuple[Optional[TopLevel], List[Dict[str, Any]]]: + def _convert_node(self, node: Node) -> tuple[TopLevel | None, list[dict[str, Any]]]: """Convert a node of TypeScript JSON output to an IR object. :return: A tuple: (the IR object, a list of other nodes found within @@ -178,7 +177,7 @@ def _convert_node( if source.get("fileName", ".")[0] == "/": return None, [] - ir: Optional[TopLevel] = None + ir: TopLevel | None = None kind = node.get("kindString") if kind == "External module": # We shouldn't need these until we implement automodule. But what @@ -349,7 +348,7 @@ def _make_param(self, param): default=param["defaultValue"] if has_default else NO_DEFAULT, ) - def _make_returns(self, signature: Node) -> List[Return]: + def _make_returns(self, signature: Node) -> list[Return]: """Return the Returns a function signature can have. Because, in TypeDoc, each signature can have only 1 @return tag, we diff --git a/tox.ini b/tox.ini index 2b1515ea..a8e6a337 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,8 @@ [tox] -envlist = py37, py38, py39, py310, py311 +envlist = py310, py311 [gh-actions] python = - 3.7: py37 - 3.8: py38 - 3.9: py39 3.10: py310 3.11: py311 @@ -21,19 +18,3 @@ commands_pre = npm install --no-save jsdoc@4.0.0 typedoc@0.15.0 # any commands we call. I hack around this with env: commands = env PATH="{env:PATH}" pytest -vv {posargs} - -[testenv:flake8] -# Pinned so new checks aren't added by surprise: -deps = - flake8>=3.8,<3.9 - flake8-quotes - flake8-import-order -skip_install=True -commands = flake8 sphinx_js tests - -[flake8] -# I101: the "pep8" import-order-style is advertised as not complaining about -# import order, but it does. Ignore it. -ignore = E501, E127, E302, E305, W503, I101, W504 -import-order-style = pep8 -application-import-names = sphinx_js, tests