From 3ac1b7f3b1d3aae8bb30b33578537eb712164610 Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Sat, 14 Mar 2026 15:50:43 +0100 Subject: [PATCH 1/3] Drop support for Python 3.9 --- .github/workflows/ci.yml | 6 +----- properdocs/config/config_options.py | 4 ++-- properdocs/livereload/__init__.py | 4 ++-- properdocs/plugins.py | 15 ++++++--------- properdocs/structure/files.py | 4 ++-- properdocs/structure/pages.py | 4 ++-- properdocs/tests/structure/file_tests.py | 3 ++- properdocs/tests/structure/page_tests.py | 4 +--- properdocs/utils/__init__.py | 22 +++------------------- properdocs/utils/cache.py | 2 +- properdocs/utils/rendering.py | 3 ++- pyproject.toml | 7 +++---- 12 files changed, 27 insertions(+), 51 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 111353d9..1a2107da 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,12 +34,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/config/config_options.py b/properdocs/config/config_options.py index 6f936e81..077f02b8 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..6bceaa98 100644 --- a/properdocs/plugins.py +++ b/properdocs/plugins.py @@ -3,14 +3,9 @@ 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, Generic, Literal, TypeVar, overload if TYPE_CHECKING: import jinja2.environment @@ -33,7 +28,9 @@ from properdocs.utils.templates import TemplateContext if TYPE_CHECKING: - from typing_extensions import Concatenate, ParamSpec + from typing import Concatenate + + 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 8e141a0c..aa68e6bf 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 6c58385f..3a97a297 100644 --- a/properdocs/tests/structure/page_tests.py +++ b/properdocs/tests/structure/page_tests.py @@ -784,11 +784,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 6bf97ffb..dfa56086 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 eeb778e8..7b5ec62d 100644 --- a/properdocs/utils/cache.py +++ b/properdocs/utils/cache.py @@ -1,6 +1,6 @@ import datetime import urllib.request -from typing import Callable +from collections.abc import Callable import mkdocs_get_deps.cache 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 4fe71bac..3660fce9 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", @@ -114,7 +113,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"] }, @@ -127,7 +126,7 @@ detached = false [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 = [ From 9b2429411d8accda24765f52b35e0bb5d665f785 Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Tue, 24 Mar 2026 11:12:13 +0100 Subject: [PATCH 2/3] Fixup --- properdocs/plugins.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/properdocs/plugins.py b/properdocs/plugins.py index 6bceaa98..ed3f95d7 100644 --- a/properdocs/plugins.py +++ b/properdocs/plugins.py @@ -5,7 +5,7 @@ import logging from collections.abc import Callable, MutableMapping from importlib.metadata import EntryPoint, entry_points -from typing import TYPE_CHECKING, Any, Generic, Literal, TypeVar, overload +from typing import TYPE_CHECKING, Any, Concatenate, Generic, Literal, TypeVar, overload if TYPE_CHECKING: import jinja2.environment @@ -28,8 +28,6 @@ from properdocs.utils.templates import TemplateContext if TYPE_CHECKING: - from typing import Concatenate - from typing_extensions import ParamSpec else: ParamSpec = TypeVar From 7dcc9b2bbd6e39c1357eae50e829d10a87621569 Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Tue, 24 Mar 2026 11:13:33 +0100 Subject: [PATCH 3/3] Fixup --- properdocs/plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/properdocs/plugins.py b/properdocs/plugins.py index ed3f95d7..78dcafb6 100644 --- a/properdocs/plugins.py +++ b/properdocs/plugins.py @@ -8,7 +8,7 @@ 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 (