diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ec80fee..de6e82a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,12 +35,8 @@ jobs: - python: '3.11' os: macos-latest - python: '3.10' - os: ubuntu-latest - - python: '3.10' - os: macos-latest - - python: '3.9' os: windows-latest - - python: '3.9' + - python: '3.10' os: ubuntu-latest versions: minimal runs-on: ${{matrix.os}} diff --git a/properdocs/commands/get_deps.py b/properdocs/commands/get_deps.py index cf9f33d9..7b61b29d 100644 --- a/properdocs/commands/get_deps.py +++ b/properdocs/commands/get_deps.py @@ -8,7 +8,6 @@ import io import logging import os -import sys import urllib.parse from collections.abc import Collection, Mapping, Sequence from typing import IO, Any, BinaryIO @@ -107,10 +106,7 @@ def _strings(obj) -> Sequence[str]: @functools.cache def _entry_points(group: str) -> Mapping[str, Any]: - if sys.version_info >= (3, 10): - from importlib.metadata import entry_points - else: - from importlib_metadata import entry_points + from importlib.metadata import entry_points eps = {ep.name: ep for ep in entry_points(group=group)} log.debug(f"Available '{group}' entry points: {sorted(eps)}") diff --git a/properdocs/commands/serve.py b/properdocs/commands/serve.py index afe3f847..cde09905 100644 --- a/properdocs/commands/serve.py +++ b/properdocs/commands/serve.py @@ -5,8 +5,9 @@ import shutil import sys import tempfile +from collections.abc import Callable from os.path import isdir, isfile, join -from typing import TYPE_CHECKING, BinaryIO, Callable +from typing import TYPE_CHECKING, BinaryIO from urllib.parse import urlsplit from properdocs.commands.build import build diff --git a/properdocs/config/config_options.py b/properdocs/config/config_options.py index 7a9a82a6..506e95d0 100644 --- a/properdocs/config/config_options.py +++ b/properdocs/config/config_options.py @@ -10,9 +10,9 @@ import types import warnings from collections import Counter, UserString -from collections.abc import Collection, Iterator, Mapping, MutableMapping +from collections.abc import Callable, Collection, Iterator, Mapping, MutableMapping from types import SimpleNamespace -from typing import Any, Callable, Generic, NamedTuple, TypeVar, Union, overload +from typing import Any, Generic, NamedTuple, TypeVar, Union, overload from urllib.parse import quote as urlquote from urllib.parse import urlsplit, urlunsplit diff --git a/properdocs/livereload/__init__.py b/properdocs/livereload/__init__.py index f9e0a0b2..d742252e 100644 --- a/properdocs/livereload/__init__.py +++ b/properdocs/livereload/__init__.py @@ -21,8 +21,8 @@ import webbrowser import wsgiref.simple_server import wsgiref.util -from collections.abc import Iterable -from typing import Any, BinaryIO, Callable +from collections.abc import Callable, Iterable +from typing import Any, BinaryIO import watchdog.events import watchdog.observers.polling diff --git a/properdocs/plugins.py b/properdocs/plugins.py index ff1b347f..78dcafb6 100644 --- a/properdocs/plugins.py +++ b/properdocs/plugins.py @@ -3,17 +3,12 @@ from __future__ import annotations import logging -import sys -from collections.abc import MutableMapping -from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, TypeVar, overload - -if sys.version_info >= (3, 10): - from importlib.metadata import EntryPoint, entry_points -else: - from importlib_metadata import EntryPoint, entry_points +from collections.abc import Callable, MutableMapping +from importlib.metadata import EntryPoint, entry_points +from typing import TYPE_CHECKING, Any, Concatenate, Generic, Literal, TypeVar, overload if TYPE_CHECKING: - import jinja2.environment + import jinja2 from properdocs import utils from properdocs.config.base import ( @@ -33,7 +28,7 @@ from properdocs.utils.templates import TemplateContext if TYPE_CHECKING: - from typing_extensions import Concatenate, ParamSpec + from typing_extensions import ParamSpec else: ParamSpec = TypeVar diff --git a/properdocs/structure/files.py b/properdocs/structure/files.py index 67c372bc..c9277da3 100644 --- a/properdocs/structure/files.py +++ b/properdocs/structure/files.py @@ -7,10 +7,10 @@ import posixpath import shutil import warnings -from collections.abc import Iterable, Iterator, Mapping, Sequence +from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence from functools import cached_property from pathlib import PurePath, PurePosixPath -from typing import TYPE_CHECKING, Callable, overload +from typing import TYPE_CHECKING, overload from urllib.parse import quote as urlquote import pathspec diff --git a/properdocs/structure/pages.py b/properdocs/structure/pages.py index b03bacfb..8c58e24f 100644 --- a/properdocs/structure/pages.py +++ b/properdocs/structure/pages.py @@ -4,8 +4,8 @@ import logging import posixpath import warnings -from collections.abc import Iterator, MutableMapping, Sequence -from typing import TYPE_CHECKING, Any, Callable +from collections.abc import Callable, Iterator, MutableMapping, Sequence +from typing import TYPE_CHECKING, Any from urllib.parse import unquote as urlunquote from urllib.parse import urljoin, urlsplit, urlunsplit diff --git a/properdocs/tests/structure/file_tests.py b/properdocs/tests/structure/file_tests.py index 3efc7b3a..744d09ae 100644 --- a/properdocs/tests/structure/file_tests.py +++ b/properdocs/tests/structure/file_tests.py @@ -1,3 +1,4 @@ +import itertools import os import sys import unittest @@ -64,7 +65,7 @@ def test_file_sort_key(self): ]: with self.subTest(case): files = [File(f, "", "", use_directory_urls=True) for f in case] - for a, b in zip(files, files[1:]): + for a, b in itertools.pairwise(files): self.assertLess(file_sort_key(a), file_sort_key(b)) def test_md_file(self): diff --git a/properdocs/tests/structure/page_tests.py b/properdocs/tests/structure/page_tests.py index 6ef13404..8c9d1026 100644 --- a/properdocs/tests/structure/page_tests.py +++ b/properdocs/tests/structure/page_tests.py @@ -785,11 +785,9 @@ def get_rendered_result( pg.render(cfg, Files(fs)) msgs = [f'{r.levelname}:{r.message}' for r in cm.records] self.assertEqual('\n'.join(msgs), textwrap.dedent(logs).strip('\n')) - elif sys.version_info >= (3, 10): + else: with self.assertNoLogs('properdocs.structure.pages'): pg.render(cfg, Files(fs)) - else: - pg.render(cfg, Files(fs)) assert pg.content is not None content = pg.content diff --git a/properdocs/utils/__init__.py b/properdocs/utils/__init__.py index 2cc6813c..a901548c 100644 --- a/properdocs/utils/__init__.py +++ b/properdocs/utils/__init__.py @@ -13,20 +13,16 @@ import posixpath import re import shutil -import sys import warnings +from bisect import insort # noqa: F401 - legacy re-export from collections import defaultdict -from collections.abc import Collection, Iterable, MutableSequence +from collections.abc import Collection, Iterable from datetime import datetime, timezone +from importlib.metadata import EntryPoint, entry_points from pathlib import PurePath from typing import TYPE_CHECKING, TypeVar from urllib.parse import urlsplit -if sys.version_info >= (3, 10): - from importlib.metadata import EntryPoint, entry_points -else: - from importlib_metadata import EntryPoint, entry_points - from properdocs import exceptions from properdocs.utils.yaml import get_yaml_loader, yaml_load # noqa: F401 - legacy re-export @@ -93,18 +89,6 @@ def reduce_list(data_set: Iterable[T]) -> list[T]: return list(dict.fromkeys(data_set)) -if sys.version_info >= (3, 10): - from bisect import insort -else: - - def insort(a: MutableSequence[T], x: T, *, key=lambda v: v) -> None: - kx = key(x) - i = len(a) - while i > 0 and kx < key(a[i - 1]): - i -= 1 - a.insert(i, x) - - def copy_file(source_path: str, output_path: str) -> None: """ Copy source_path to output_path, making sure any parent directories exist. diff --git a/properdocs/utils/cache.py b/properdocs/utils/cache.py index 070df169..8dc87f08 100644 --- a/properdocs/utils/cache.py +++ b/properdocs/utils/cache.py @@ -8,7 +8,7 @@ import os import random import urllib.request -from typing import Callable +from collections.abc import Callable import platformdirs diff --git a/properdocs/utils/rendering.py b/properdocs/utils/rendering.py index 545e1efb..0f1a3d7a 100644 --- a/properdocs/utils/rendering.py +++ b/properdocs/utils/rendering.py @@ -1,7 +1,8 @@ from __future__ import annotations import copy -from typing import TYPE_CHECKING, Callable +from collections.abc import Callable +from typing import TYPE_CHECKING import markdown import markdown.treeprocessors diff --git a/pyproject.toml b/pyproject.toml index ebc97d70..779faffc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,6 @@ classifiers = [ "Programming Language :: Python", # Begin Python versions "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -32,7 +31,7 @@ classifiers = [ "Typing :: Typed", ] dynamic = ["version"] -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ "click >=7.0", "Jinja2 >=2.11.1", @@ -106,7 +105,7 @@ _coverage = [ ] with-coverage = "test" [[tool.hatch.envs.test.matrix]] -python = ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] +python = ["3.10", "3.11", "3.12", "3.13", "3.14"] [tool.hatch.envs.test.overrides] matrix.type.scripts = [ { key = "with-coverage", value = "_coverage", if = ["default"] }, @@ -120,7 +119,7 @@ template = "test" [tool.hatch.envs.integration.scripts] test = "python -m properdocs.tests.integration" [[tool.hatch.envs.integration.matrix]] -python = ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] +python = ["3.10", "3.11", "3.12", "3.13", "3.14"] type = ["default", "no-babel"] [tool.hatch.envs.integration.overrides] matrix.type.features = [