From 567cfc25dd9b9b7da175335d9a15f21bdf12f264 Mon Sep 17 00:00:00 2001 From: Patrick Stotko Date: Thu, 16 Oct 2025 17:28:37 +0200 Subject: [PATCH] Drop Python 3.9 support --- .github/workflows/lint.yml | 2 +- .github/workflows/tests.yml | 2 +- README.md | 2 +- noxfile.py | 4 +- pyproject.toml | 6 +-- src/charonload/__init__.py | 2 +- src/charonload/_compat/hashlib.py | 3 +- src/charonload/_config.py | 68 +++++++------------------------ src/charonload/_persistence.py | 3 +- 9 files changed, 29 insertions(+), 63 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e380735..10aa79a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - python: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python: ["3.10", "3.11", "3.12", "3.13"] name: "Python ${{ matrix.python }}" runs-on: ubuntu-24.04 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d7537b4..90c6bd4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: os: ["ubuntu-24.04", "windows-2025"] - python: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python: ["3.10", "3.11", "3.12", "3.13"] name: "${{ matrix.os }} / Python ${{ matrix.python }}" runs-on: ${{ matrix.os }} diff --git a/README.md b/README.md index cece1fe..0bd25fd 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ CharonLoad reduces the burden to start writing and experimenting with custom GPU ## Installation -CharonLoad requires **Python >=3.9** and can be installed from PyPI: +CharonLoad requires **Python >=3.10** and can be installed from PyPI: ```sh pip install charonload diff --git a/noxfile.py b/noxfile.py index 906c259..ac87350 100644 --- a/noxfile.py +++ b/noxfile.py @@ -71,7 +71,9 @@ def docs_live(session: nox.Session) -> None: # sphinx-build force_building = "-E" watch_dirs_and_files = ["src", "README.md", "CHANGELOG.md"] - watch_args = [v for pair in zip(["--watch"] * len(watch_dirs_and_files), watch_dirs_and_files) for v in pair] + watch_args = [ + v for pair in zip(["--watch"] * len(watch_dirs_and_files), watch_dirs_and_files, strict=True) for v in pair + ] session.run( "sphinx-autobuild", "-b", diff --git a/pyproject.toml b/pyproject.toml index 34f9872..91adf6b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,9 +4,10 @@ version = "0.2.1" authors = [{ name = "Patrick Stotko", email = "stotko@cs.uni-bonn.de" }] description = "Develop C++/CUDA extensions with PyTorch like Python scripts" readme = "README.md" -requires-python = ">=3.9" +requires-python = ">=3.10" dependencies = [ "cmake>=3.27", + 'dlltracer ; platform_system == "Windows"', 'ninja ; platform_system != "Windows"', "filelock", "torch", @@ -21,7 +22,6 @@ classifiers = [ "License :: OSI Approved :: MIT License", "Programming Language :: C++", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -92,7 +92,7 @@ line-length = 120 [tool.isort] profile = "black" multi_line_output = 3 -py_version = 39 +py_version = 310 [tool.docformatter] diff --git a/src/charonload/__init__.py b/src/charonload/__init__.py index 9aedab5..f4cb356 100644 --- a/src/charonload/__init__.py +++ b/src/charonload/__init__.py @@ -20,7 +20,7 @@ import sys -required_version = (3, 8) +required_version = (3, 10) if sys.version_info[:2] < required_version: # pragma: no cover msg = "%s requires Python %d.%d+" % (__package__, *required_version) # noqa: UP031 diff --git a/src/charonload/_compat/hashlib.py b/src/charonload/_compat/hashlib.py index 46509d8..55c7d98 100644 --- a/src/charonload/_compat/hashlib.py +++ b/src/charonload/_compat/hashlib.py @@ -2,9 +2,10 @@ import sys from hashlib import * # noqa: F403 -from typing import TYPE_CHECKING, BinaryIO, Callable +from typing import TYPE_CHECKING, BinaryIO if TYPE_CHECKING: + from collections.abc import Callable from hashlib import _Hash diff --git a/src/charonload/_config.py b/src/charonload/_config.py index 9d7f304..04caf13 100644 --- a/src/charonload/_config.py +++ b/src/charonload/_config.py @@ -11,7 +11,7 @@ import sysconfig import tempfile from collections import UserDict -from dataclasses import dataclass +from dataclasses import KW_ONLY, dataclass from typing import TYPE_CHECKING import colorama @@ -22,7 +22,7 @@ colorama.just_fix_windows_console() -@dataclass(init=False) # Python 3.10+: Use "_: KW_ONLY" +@dataclass class Config: """ Set of user-specified configuration options for setting up the import logic of :class:`JITCompileFinder`. @@ -33,14 +33,16 @@ class Config: project_directory: pathlib.Path | str """The absolute path to the root directory of the C++/CUDA extension containing the root ``CMakeLists.txt`` file.""" - build_directory: pathlib.Path | str | None + build_directory: pathlib.Path | str | None = None """ An optional absolute path to a build directory. If not specified, the build will be placed in the temporary directory of the operating system. """ - clean_build: bool + _: KW_ONLY + + clean_build: bool = False """ Whether to remove all cached files of previous builds from the build directory. @@ -53,13 +55,13 @@ class Config: :class:`ResolvedConfig`. """ - build_type: str + build_type: str = "RelWithDebInfo" """The build type passed to CMake to compile the extension.""" - cmake_options: dict[str, str] | None + cmake_options: dict[str, str] | None = None """Additional CMake options to pass to the project when JIT compiling.""" - stubs_directory: pathlib.Path | str | None + stubs_directory: pathlib.Path | str | None = None """ An optional absolute path to the directory where stub files of the extension should be generated. @@ -68,7 +70,7 @@ class Config: if set to ``None``. """ - stubs_invalid_ok: bool + stubs_invalid_ok: bool = False """ Whether to accept invalid stubs and skip raising an error. @@ -79,7 +81,7 @@ class Config: :class:`ResolvedConfig`. """ - verbose: bool + verbose: bool = False """ Whether to enable printing the full log of the JIT compilation. @@ -92,29 +94,8 @@ class Config: :class:`ResolvedConfig`. """ - def __init__( - self: Self, - project_directory: pathlib.Path | str, - build_directory: pathlib.Path | str | None = None, - *, - clean_build: bool = False, - build_type: str = "RelWithDebInfo", - cmake_options: dict[str, str] | None = None, - stubs_directory: pathlib.Path | str | None = None, - stubs_invalid_ok: bool = False, - verbose: bool = False, - ) -> None: - self.project_directory = project_directory - self.build_directory = build_directory - self.clean_build = clean_build - self.build_type = build_type - self.cmake_options = cmake_options - self.stubs_directory = stubs_directory - self.stubs_invalid_ok = stubs_invalid_ok - self.verbose = verbose - - -@dataclass(init=False) # Python 3.10+: Use "kw_only=True" + +@dataclass class ResolvedConfig: """ Set of resolved configuration options that is **actually used** in the import logic of :class:`JITCompileFinder`. @@ -122,6 +103,8 @@ class ResolvedConfig: This has been resolved from :class:`Config` and from the environment variables. """ + _: KW_ONLY + full_project_directory: pathlib.Path """The full absolute path to the project directory.""" @@ -146,27 +129,6 @@ class ResolvedConfig: verbose: bool """Flag to enable printing the full log of the JIT compilation.""" - def __init__( - self: Self, - *, - full_project_directory: pathlib.Path, - full_build_directory: pathlib.Path, - clean_build: bool, - build_type: str, - cmake_options: dict[str, str], - full_stubs_directory: pathlib.Path | None, - stubs_invalid_ok: bool, - verbose: bool, - ) -> None: - self.full_project_directory = full_project_directory - self.full_build_directory = full_build_directory - self.clean_build = clean_build - self.build_type = build_type - self.cmake_options = cmake_options - self.full_stubs_directory = full_stubs_directory - self.stubs_invalid_ok = stubs_invalid_ok - self.verbose = verbose - class ConfigDict(UserDict[str, ResolvedConfig]): """ diff --git a/src/charonload/_persistence.py b/src/charonload/_persistence.py index 96c51eb..aa85b9d 100644 --- a/src/charonload/_persistence.py +++ b/src/charonload/_persistence.py @@ -6,12 +6,13 @@ import pathlib import sys from dataclasses import dataclass -from typing import TYPE_CHECKING, Any, Callable +from typing import TYPE_CHECKING, Any from ._errors import _SerializerNotConnectedError if TYPE_CHECKING: # pragma: no cover import enum + from collections.abc import Callable from ._compat.typing import Self