From a17d55eaeeef4f92fae61ccb1811a33bcd01bef9 Mon Sep 17 00:00:00 2001 From: Avasam Date: Sat, 11 Jul 2026 14:38:15 -0400 Subject: [PATCH 1/2] Python 3.15 `__lazy_modules__` (auto-applied w/ `flake8-lazy --apply=set`) --- newsfragments/5257.feature.rst | 1 + pyproject.toml | 1 + setuptools/__init__.py | 11 +++++++++ setuptools/_core_metadata.py | 16 +++++++++++++ setuptools/_discovery.py | 2 ++ setuptools/_entry_points.py | 11 +++++++++ setuptools/_imp.py | 2 ++ setuptools/_importlib.py | 2 ++ setuptools/_itertools.py | 2 ++ setuptools/_normalization.py | 2 ++ setuptools/_path.py | 2 ++ setuptools/_reqs.py | 2 ++ setuptools/_scripts.py | 17 +++++++++++++ setuptools/_shutil.py | 7 ++++++ setuptools/_static.py | 2 ++ setuptools/archive_util.py | 8 +++++++ setuptools/build_meta.py | 14 +++++++++++ setuptools/command/_requirestxt.py | 12 ++++++++++ setuptools/command/alias.py | 2 ++ setuptools/command/bdist_egg.py | 13 ++++++++++ setuptools/command/bdist_rpm.py | 5 ++++ setuptools/command/bdist_wheel.py | 23 ++++++++++++++++++ setuptools/command/build.py | 2 ++ setuptools/command/build_clib.py | 7 ++++++ setuptools/command/build_ext.py | 17 +++++++++++++ setuptools/command/build_py.py | 20 ++++++++++++++++ setuptools/command/develop.py | 2 ++ setuptools/command/dist_info.py | 10 ++++++++ setuptools/command/easy_install.py | 2 ++ setuptools/command/editable_wheel.py | 25 +++++++++++++++++++ setuptools/command/egg_info.py | 17 +++++++++++++ setuptools/command/install.py | 11 +++++++++ setuptools/command/install_egg_info.py | 6 +++++ setuptools/command/install_lib.py | 6 +++++ setuptools/command/install_scripts.py | 6 +++++ setuptools/command/rotate.py | 2 ++ setuptools/command/sdist.py | 13 ++++++++++ setuptools/command/setopt.py | 8 +++++++ setuptools/command/test.py | 2 ++ setuptools/compat/py310.py | 2 ++ setuptools/compat/py311.py | 8 +++++-- setuptools/config/__init__.py | 5 ++++ setuptools/config/_apply_pyprojecttoml.py | 9 +++++++ setuptools/config/expand.py | 16 +++++++++++++ setuptools/config/pyprojecttoml.py | 10 ++++++++ setuptools/config/setupcfg.py | 13 ++++++++++ setuptools/depends.py | 9 +++++++ setuptools/discovery.py | 11 +++++++++ setuptools/dist.py | 29 +++++++++++++++++++++++ setuptools/extension.py | 10 ++++++++ setuptools/glob.py | 2 ++ setuptools/installer.py | 14 +++++++++++ setuptools/launch.py | 2 ++ setuptools/logging.py | 2 ++ setuptools/monkey.py | 2 ++ setuptools/msvc.py | 12 ++++++++++ setuptools/namespaces.py | 2 ++ setuptools/unicode_utils.py | 2 ++ setuptools/warnings.py | 2 ++ setuptools/wheel.py | 21 ++++++++++++++++ setuptools/windows_support.py | 2 ++ tox.ini | 8 +++++++ 62 files changed, 504 insertions(+), 2 deletions(-) create mode 100644 newsfragments/5257.feature.rst diff --git a/newsfragments/5257.feature.rst b/newsfragments/5257.feature.rst new file mode 100644 index 0000000000..ee3ef451f8 --- /dev/null +++ b/newsfragments/5257.feature.rst @@ -0,0 +1 @@ +Speed up setuptools imports on Python 3.15+ by adding ``__lazy_modules__`` -- by :user:`Avasam` diff --git a/pyproject.toml b/pyproject.toml index 5d55b4b2c2..4ab0714007 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -116,6 +116,7 @@ check = [ # Deprecated rules must now be selected by exact rule code "ruff >= 0.13.0; sys_platform != 'cygwin'", + "flake8-lazy", # Until Ruff gains support for automatically inserting and validating __lazy_modules__ ] cover = [ diff --git a/setuptools/__init__.py b/setuptools/__init__.py index 87ca47bbc9..5f45df0991 100644 --- a/setuptools/__init__.py +++ b/setuptools/__init__.py @@ -7,6 +7,17 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + f"{__spec__.parent}.depends", + f"{__spec__.parent}.dist", + f"{__spec__.parent}.extension", + f"{__spec__.parent}.version", + f"{__spec__.parent}.warnings", + "functools", +} + import functools import os import sys diff --git a/setuptools/_core_metadata.py b/setuptools/_core_metadata.py index a52d5cf755..5b2e269829 100644 --- a/setuptools/_core_metadata.py +++ b/setuptools/_core_metadata.py @@ -6,6 +6,22 @@ from __future__ import annotations +__lazy_modules__ = { + "distutils", + "distutils.util", + "email", + "email.message", + f"{__spec__.parent}._static", + f"{__spec__.parent}.warnings", + "packaging", + "packaging.markers", + "packaging.requirements", + "packaging.utils", + "packaging.version", + "tempfile", + "textwrap", +} + import os import stat import textwrap diff --git a/setuptools/_discovery.py b/setuptools/_discovery.py index d1b4a0ee03..96dea0ba6d 100644 --- a/setuptools/_discovery.py +++ b/setuptools/_discovery.py @@ -1,3 +1,5 @@ +__lazy_modules__ = {"functools", "operator", "packaging", "packaging.requirements"} + import functools import operator diff --git a/setuptools/_entry_points.py b/setuptools/_entry_points.py index cd5dd2c8ac..93412267ef 100644 --- a/setuptools/_entry_points.py +++ b/setuptools/_entry_points.py @@ -1,3 +1,14 @@ +__lazy_modules__ = { + f"{__spec__.parent}._importlib", + f"{__spec__.parent}._itertools", + f"{__spec__.parent}.errors", + "itertools", + "jaraco", + "jaraco.text", + "more_itertools", + "operator", +} + import functools import itertools import operator diff --git a/setuptools/_imp.py b/setuptools/_imp.py index f1d9f29218..efa5f6ec18 100644 --- a/setuptools/_imp.py +++ b/setuptools/_imp.py @@ -3,6 +3,8 @@ from the deprecated imp module. """ +__lazy_modules__ = {"importlib", "importlib.machinery", "importlib.util", "tokenize"} + import importlib.machinery import importlib.util import os diff --git a/setuptools/_importlib.py b/setuptools/_importlib.py index 2b27bc10cd..69b2ee583b 100644 --- a/setuptools/_importlib.py +++ b/setuptools/_importlib.py @@ -1,2 +1,4 @@ +__lazy_modules__ = {"importlib", "importlib.metadata", "importlib.resources"} + import importlib.metadata as metadata # noqa: F401 import importlib.resources as resources # noqa: F401 diff --git a/setuptools/_itertools.py b/setuptools/_itertools.py index d6ca841353..2851fe4dd6 100644 --- a/setuptools/_itertools.py +++ b/setuptools/_itertools.py @@ -1,3 +1,5 @@ +__lazy_modules__ = {"more_itertools"} + from more_itertools import consume # noqa: F401 diff --git a/setuptools/_normalization.py b/setuptools/_normalization.py index 6b8d4ddbf9..754d3f04e5 100644 --- a/setuptools/_normalization.py +++ b/setuptools/_normalization.py @@ -3,6 +3,8 @@ and core metadata """ +__lazy_modules__ = {"packaging"} + import re from typing import TYPE_CHECKING diff --git a/setuptools/_path.py b/setuptools/_path.py index 0a5b26ea4b..b909c0aebc 100644 --- a/setuptools/_path.py +++ b/setuptools/_path.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"more_itertools"} + import contextlib import os import sys diff --git a/setuptools/_reqs.py b/setuptools/_reqs.py index 19ef375cf1..4d5039aa7f 100644 --- a/setuptools/_reqs.py +++ b/setuptools/_reqs.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"jaraco", "jaraco.text"} + from collections.abc import Callable, Iterable, Iterator from functools import lru_cache from typing import TYPE_CHECKING, TypeVar, overload diff --git a/setuptools/_scripts.py b/setuptools/_scripts.py index 88bf02f927..08458f3183 100644 --- a/setuptools/_scripts.py +++ b/setuptools/_scripts.py @@ -1,5 +1,22 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + "distutils", + "distutils.command", + "distutils.command.build_scripts", + "distutils.util", + f"{__spec__.parent}._importlib", + f"{__spec__.parent}.warnings", + "re", + "shlex", + "shutil", + "struct", + "subprocess", + "textwrap", +} + import os import re import shlex diff --git a/setuptools/_shutil.py b/setuptools/_shutil.py index b9a514efcc..82a886dbff 100644 --- a/setuptools/_shutil.py +++ b/setuptools/_shutil.py @@ -1,5 +1,12 @@ """Convenience layer on top of stdlib's shutil and os""" +__lazy_modules__ = { + "collections", + "collections.abc", + "distutils", + f"{__spec__.parent}.compat", +} + import os import stat from collections.abc import Callable diff --git a/setuptools/_static.py b/setuptools/_static.py index af35862cf8..caf5958750 100644 --- a/setuptools/_static.py +++ b/setuptools/_static.py @@ -1,3 +1,5 @@ +__lazy_modules__ = {f"{__spec__.parent}.warnings", "functools"} + from functools import wraps from typing import TypeVar diff --git a/setuptools/archive_util.py b/setuptools/archive_util.py index 1a02010bb2..1a7aab54de 100644 --- a/setuptools/archive_util.py +++ b/setuptools/archive_util.py @@ -1,5 +1,13 @@ """Utilities for extracting common archive formats""" +__lazy_modules__ = { + "contextlib", + f"{__spec__.parent}._path", + "shutil", + "tarfile", + "zipfile", +} + import contextlib import os import posixpath diff --git a/setuptools/build_meta.py b/setuptools/build_meta.py index c80f53321c..a591629205 100644 --- a/setuptools/build_meta.py +++ b/setuptools/build_meta.py @@ -28,6 +28,20 @@ from __future__ import annotations +__lazy_modules__ = { + "distutils", + "distutils.util", + f"{__spec__.parent}._path", + f"{__spec__.parent}._reqs", + "io", + "pathlib", + "shlex", + "shutil", + "tempfile", + "tokenize", + "warnings", +} + import contextlib import io import os diff --git a/setuptools/command/_requirestxt.py b/setuptools/command/_requirestxt.py index 9029b12514..72f6f1721a 100644 --- a/setuptools/command/_requirestxt.py +++ b/setuptools/command/_requirestxt.py @@ -9,6 +9,18 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._reqs", + "io", + "itertools", + "jaraco", + "jaraco.text", + "packaging", + "packaging.requirements", +} + import io from collections import defaultdict from collections.abc import Mapping diff --git a/setuptools/command/alias.py b/setuptools/command/alias.py index 0ffa3116d6..6ced15a945 100644 --- a/setuptools/command/alias.py +++ b/setuptools/command/alias.py @@ -1,3 +1,5 @@ +__lazy_modules__ = {"distutils", "distutils.errors"} + from setuptools.command.setopt import config_file, edit_config, option_base from distutils.errors import DistutilsOptionError diff --git a/setuptools/command/bdist_egg.py b/setuptools/command/bdist_egg.py index 955f54ed19..3c076c2ec1 100644 --- a/setuptools/command/bdist_egg.py +++ b/setuptools/command/bdist_egg.py @@ -4,6 +4,19 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + "distutils", + "distutils.dir_util", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._path", + "re", + "setuptools.extension", + "sysconfig", + "textwrap", + "types", +} + import marshal import os import re diff --git a/setuptools/command/bdist_rpm.py b/setuptools/command/bdist_rpm.py index 6dbb27002a..f75402e661 100644 --- a/setuptools/command/bdist_rpm.py +++ b/setuptools/command/bdist_rpm.py @@ -1,3 +1,8 @@ +__lazy_modules__ = { + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.dist", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.warnings", +} + from ..dist import Distribution from ..warnings import SetuptoolsDeprecationWarning diff --git a/setuptools/command/bdist_wheel.py b/setuptools/command/bdist_wheel.py index 3bdfa0b35a..9df50b7210 100644 --- a/setuptools/command/bdist_wheel.py +++ b/setuptools/command/bdist_wheel.py @@ -6,6 +6,29 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + "distutils", + "email", + "email.generator", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._core_metadata", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._normalization", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.warnings", + f"{__spec__.parent}.egg_info", + "glob", + "packaging", + "re", + "shutil", + "struct", + "sysconfig", + "typing", + "warnings", + "wheel", + "wheel.wheelfile", + "zipfile", +} + import os import re import shutil diff --git a/setuptools/command/build.py b/setuptools/command/build.py index 54cbb8d2e7..60a7630e10 100644 --- a/setuptools/command/build.py +++ b/setuptools/command/build.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {f"{(__spec__.parent or '').rsplit('.', 1)[0]}.dist"} + from typing import Protocol from ..dist import Distribution diff --git a/setuptools/command/build_clib.py b/setuptools/command/build_clib.py index f376f4ce4d..5d00debfc4 100644 --- a/setuptools/command/build_clib.py +++ b/setuptools/command/build_clib.py @@ -1,3 +1,10 @@ +__lazy_modules__ = { + "distutils", + "distutils.errors", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.dist", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.modified", +} + from ..dist import Distribution from ..modified import newer_pairwise_group diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py index dbb956db8d..ac329c5bc3 100644 --- a/setuptools/command/build_ext.py +++ b/setuptools/command/build_ext.py @@ -1,5 +1,22 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + "distutils", + "distutils.ccompiler", + "importlib", + "importlib.machinery", + "importlib.util", + "itertools", + "operator", + "pathlib", + "setuptools.dist", + "setuptools.errors", + "setuptools.extension", + "textwrap", +} + import itertools import operator import os diff --git a/setuptools/command/build_py.py b/setuptools/command/build_py.py index 3c7c2d1bd6..b878ab09be 100644 --- a/setuptools/command/build_py.py +++ b/setuptools/command/build_py.py @@ -1,5 +1,25 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + "distutils", + "distutils.errors", + "distutils.util", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._path", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.dist", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.warnings", + "fnmatch", + "functools", + "glob", + "itertools", + "more_itertools", + "operator", + "pathlib", + "textwrap", + "typing", +} + import fnmatch import itertools import operator diff --git a/setuptools/command/develop.py b/setuptools/command/develop.py index 2d468845e5..cdea9ffb6f 100644 --- a/setuptools/command/develop.py +++ b/setuptools/command/develop.py @@ -1,3 +1,5 @@ +__lazy_modules__ = {"subprocess", "typing"} + import site import subprocess import sys diff --git a/setuptools/command/dist_info.py b/setuptools/command/dist_info.py index dca01ff0ce..a6ba10aed1 100644 --- a/setuptools/command/dist_info.py +++ b/setuptools/command/dist_info.py @@ -3,6 +3,16 @@ As defined in the wheel specification """ +__lazy_modules__ = { + "contextlib", + "distutils", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._shutil", + f"{__spec__.parent}.egg_info", + "pathlib", + "shutil", + "typing", +} + import os import shutil from contextlib import contextmanager diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py index 8765793d4c..228f809224 100644 --- a/setuptools/command/easy_install.py +++ b/setuptools/command/easy_install.py @@ -1,3 +1,5 @@ +__lazy_modules__ = {"types"} + import os import sys import types diff --git a/setuptools/command/editable_wheel.py b/setuptools/command/editable_wheel.py index 6f44f13643..8c60a8f050 100644 --- a/setuptools/command/editable_wheel.py +++ b/setuptools/command/editable_wheel.py @@ -12,6 +12,31 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + "contextlib", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.compat", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.discovery", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.dist", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.warnings", + f"{__spec__.parent}.build", + f"{__spec__.parent}.build_py", + f"{__spec__.parent}.dist_info", + f"{__spec__.parent}.egg_info", + f"{__spec__.parent}.install", + f"{__spec__.parent}.install_scripts", + "inspect", + "io", + "itertools", + "operator", + "pathlib", + "shutil", + "tempfile", + "traceback", + "types", +} + import io import logging import operator diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index 138e29ee61..4b84a4a127 100644 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -4,6 +4,23 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + "distutils", + "distutils.errors", + "distutils.util", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._importlib", + "functools", + "packaging", + "packaging.requirements", + "packaging.version", + "re", + "setuptools.command.setopt", + "setuptools.glob", + "setuptools.unicode_utils", +} + import functools import os import re diff --git a/setuptools/command/install.py b/setuptools/command/install.py index 19ca601458..e2828d816b 100644 --- a/setuptools/command/install.py +++ b/setuptools/command/install.py @@ -1,5 +1,16 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + "distutils", + "distutils.errors", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.dist", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.warnings", + "inspect", + "platform", +} + import inspect import platform from collections.abc import Callable diff --git a/setuptools/command/install_egg_info.py b/setuptools/command/install_egg_info.py index 46138d2fd7..757a322f9d 100644 --- a/setuptools/command/install_egg_info.py +++ b/setuptools/command/install_egg_info.py @@ -1,3 +1,9 @@ +__lazy_modules__ = { + "distutils", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._path", + "setuptools.archive_util", +} + import os from setuptools import Command, namespaces diff --git a/setuptools/command/install_lib.py b/setuptools/command/install_lib.py index 8e1e072710..c7d122601e 100644 --- a/setuptools/command/install_lib.py +++ b/setuptools/command/install_lib.py @@ -1,5 +1,11 @@ from __future__ import annotations +__lazy_modules__ = { + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._path", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.dist", + "itertools", +} + import os import sys from itertools import product, starmap diff --git a/setuptools/command/install_scripts.py b/setuptools/command/install_scripts.py index 5d7d3869ec..ed3334abda 100644 --- a/setuptools/command/install_scripts.py +++ b/setuptools/command/install_scripts.py @@ -1,5 +1,11 @@ from __future__ import annotations +__lazy_modules__ = { + "distutils", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._path", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.dist", +} + import os import sys diff --git a/setuptools/command/rotate.py b/setuptools/command/rotate.py index 9ff72f5600..4089d2c0f5 100644 --- a/setuptools/command/rotate.py +++ b/setuptools/command/rotate.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"distutils", "distutils.errors", "distutils.util", "typing"} + import os from typing import ClassVar diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index 17279ac421..a01d7bf139 100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -1,5 +1,18 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + "contextlib", + "distutils", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._importlib", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.dist", + f"{__spec__.parent}.build", + "itertools", + "re", + "typing", +} + import contextlib import os import re diff --git a/setuptools/command/setopt.py b/setuptools/command/setopt.py index 349041ecb6..b213252eb1 100644 --- a/setuptools/command/setopt.py +++ b/setuptools/command/setopt.py @@ -1,3 +1,11 @@ +__lazy_modules__ = { + "configparser", + "distutils", + "distutils.errors", + "distutils.util", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.unicode_utils", +} + import configparser import os diff --git a/setuptools/command/test.py b/setuptools/command/test.py index 5d03c91102..10317af4bf 100644 --- a/setuptools/command/test.py +++ b/setuptools/command/test.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"setuptools.warnings", "typing"} + from typing import NoReturn from setuptools import Command diff --git a/setuptools/compat/py310.py b/setuptools/compat/py310.py index 58a4d9f366..033615a776 100644 --- a/setuptools/compat/py310.py +++ b/setuptools/compat/py310.py @@ -1,3 +1,5 @@ +__lazy_modules__ = {"tomli", "tomllib"} + import sys __all__ = ['tomllib'] diff --git a/setuptools/compat/py311.py b/setuptools/compat/py311.py index 2aec70b8cc..c29ab9cc42 100644 --- a/setuptools/compat/py311.py +++ b/setuptools/compat/py311.py @@ -1,5 +1,7 @@ from __future__ import annotations +__lazy_modules__ = {"collections", "collections.abc", "shutil"} + import shutil import sys from collections.abc import Callable @@ -10,8 +12,10 @@ from _typeshed import ExcInfo, StrOrBytesPath -# Same as shutil._OnExcCallback from typeshed -_OnExcCallback: TypeAlias = Callable[[Callable[..., Any], str, BaseException], object] + # Same as shutil._OnExcCallback from typeshed + _OnExcCallback: TypeAlias = Callable[ + [Callable[..., Any], str, BaseException], object + ] def shutil_rmtree( diff --git a/setuptools/config/__init__.py b/setuptools/config/__init__.py index 76754b0ced..db0eed5980 100644 --- a/setuptools/config/__init__.py +++ b/setuptools/config/__init__.py @@ -2,6 +2,11 @@ ``setuptools.config.setupcfg`` """ +__lazy_modules__ = { + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.warnings", + "functools", +} + from collections.abc import Callable from functools import wraps from typing import TypeVar, cast diff --git a/setuptools/config/_apply_pyprojecttoml.py b/setuptools/config/_apply_pyprojecttoml.py index 140969feee..eb527502c4 100644 --- a/setuptools/config/_apply_pyprojecttoml.py +++ b/setuptools/config/_apply_pyprojecttoml.py @@ -10,6 +10,15 @@ from __future__ import annotations +__lazy_modules__ = { + "email", + "email.headerregistry", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.errors", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.extension", + "inspect", + "itertools", +} + import logging import os from collections.abc import Callable, Mapping diff --git a/setuptools/config/expand.py b/setuptools/config/expand.py index fd29ddd6db..60919c0d43 100644 --- a/setuptools/config/expand.py +++ b/setuptools/config/expand.py @@ -20,6 +20,22 @@ from __future__ import annotations +__lazy_modules__ = { + "ast", + "configparser", + "distutils", + "distutils.errors", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._path", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.discovery", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.warnings", + "glob", + "importlib", + "importlib.machinery", + "itertools", + "pathlib", + "types", +} + import ast import importlib import os diff --git a/setuptools/config/pyprojecttoml.py b/setuptools/config/pyprojecttoml.py index 9e2b16c2e5..2acfbe48c5 100644 --- a/setuptools/config/pyprojecttoml.py +++ b/setuptools/config/pyprojecttoml.py @@ -11,6 +11,16 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._path", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.errors", + f"{__spec__.parent}._apply_pyprojecttoml", + "functools", + "types", +} + import logging import os from collections.abc import Callable, Mapping diff --git a/setuptools/config/setupcfg.py b/setuptools/config/setupcfg.py index 96aeb9a3c5..0531de89c4 100644 --- a/setuptools/config/setupcfg.py +++ b/setuptools/config/setupcfg.py @@ -11,6 +11,19 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + "contextlib", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}._path", + f"{(__spec__.parent or '').rsplit('.', 1)[0]}.errors", + "functools", + "packaging", + "packaging.markers", + "packaging.requirements", + "packaging.version", +} + import contextlib import functools import os diff --git a/setuptools/depends.py b/setuptools/depends.py index e5223b7956..a12527ec84 100644 --- a/setuptools/depends.py +++ b/setuptools/depends.py @@ -1,5 +1,14 @@ from __future__ import annotations +__lazy_modules__ = { + "contextlib", + "dis", + f"{__spec__.parent}._imp", + "packaging", + "packaging.version", + "types", +} + import contextlib import dis import marshal diff --git a/setuptools/discovery.py b/setuptools/discovery.py index 296d3193ab..a31c2decf6 100644 --- a/setuptools/discovery.py +++ b/setuptools/discovery.py @@ -39,6 +39,17 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + "distutils", + "distutils.util", + f"{__spec__.parent}._path", + "fnmatch", + "glob", + "pathlib", +} + import itertools import os from collections.abc import Iterable, Iterator, Mapping diff --git a/setuptools/dist.py b/setuptools/dist.py index e600404198..f2fab5ce1a 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -1,5 +1,34 @@ from __future__ import annotations +__lazy_modules__ = { + "distutils.cmd", + "distutils.command", + "distutils.debug", + "distutils.dist", + "distutils.errors", + "distutils.fancy_getopt", + "distutils.log", + "distutils.util", + f"{__spec__.parent}._importlib", + f"{__spec__.parent}._normalization", + f"{__spec__.parent}._path", + f"{__spec__.parent}._reqs", + f"{__spec__.parent}.config", + f"{__spec__.parent}.discovery", + f"{__spec__.parent}.errors", + "glob", + "io", + "itertools", + "more_itertools", + "numbers", + "packaging", + "packaging.markers", + "packaging.specifiers", + "packaging.version", + "pathlib", + "re", +} + import functools import io import itertools diff --git a/setuptools/extension.py b/setuptools/extension.py index 3e63cbe12a..ff04235d28 100644 --- a/setuptools/extension.py +++ b/setuptools/extension.py @@ -1,5 +1,15 @@ from __future__ import annotations +__lazy_modules__ = { + "collections", + "collections.abc", + "distutils.errors", + "distutils.extension", + "functools", + "re", + "setuptools._path", +} + import functools import re from collections.abc import Iterable diff --git a/setuptools/glob.py b/setuptools/glob.py index f32411e302..6624b52c9a 100644 --- a/setuptools/glob.py +++ b/setuptools/glob.py @@ -8,6 +8,8 @@ from __future__ import annotations +__lazy_modules__ = {"collections", "collections.abc", "fnmatch"} + import fnmatch import os import re diff --git a/setuptools/installer.py b/setuptools/installer.py index 36a8b09227..d96e39c08a 100644 --- a/setuptools/installer.py +++ b/setuptools/installer.py @@ -1,5 +1,19 @@ from __future__ import annotations +__lazy_modules__ = { + "distutils", + "distutils.errors", + f"{__spec__.parent}._importlib", + f"{__spec__.parent}.wheel", + "glob", + "itertools", + "packaging", + "packaging.requirements", + "packaging.utils", + "subprocess", + "tempfile", +} + import glob import itertools import os diff --git a/setuptools/launch.py b/setuptools/launch.py index 0d162647d5..d5dbe7b56d 100644 --- a/setuptools/launch.py +++ b/setuptools/launch.py @@ -6,6 +6,8 @@ # Note that setuptools gets imported implicitly by the # invocation of this script using python -m setuptools.launch +__lazy_modules__ = {"tokenize"} + import sys import tokenize diff --git a/setuptools/logging.py b/setuptools/logging.py index 532da899f7..e61d8cfcad 100644 --- a/setuptools/logging.py +++ b/setuptools/logging.py @@ -1,3 +1,5 @@ +__lazy_modules__ = {"distutils", "distutils.log", "inspect", "logging"} + import inspect import logging import sys diff --git a/setuptools/monkey.py b/setuptools/monkey.py index 24bb8180f9..bb482f7bee 100644 --- a/setuptools/monkey.py +++ b/setuptools/monkey.py @@ -4,6 +4,8 @@ from __future__ import annotations +__lazy_modules__ = {"distutils", "distutils.filelist", "inspect", "platform"} + import inspect import platform import sys diff --git a/setuptools/msvc.py b/setuptools/msvc.py index f506c8222d..91281c1d18 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -7,6 +7,18 @@ from __future__ import annotations +__lazy_modules__ = { + "contextlib", + "distutils", + "distutils.errors", + f"{__spec__.parent}._path", + f"{__spec__.parent}.compat", + "itertools", + "json", + "more_itertools", + "winreg", +} + import contextlib import itertools import json diff --git a/setuptools/namespaces.py b/setuptools/namespaces.py index 7760f07fb4..dafc21a122 100644 --- a/setuptools/namespaces.py +++ b/setuptools/namespaces.py @@ -1,3 +1,5 @@ +__lazy_modules__ = {"distutils", f"{__spec__.parent}.compat"} + import itertools import os diff --git a/setuptools/unicode_utils.py b/setuptools/unicode_utils.py index dbce03e1d1..8ecdbd5954 100644 --- a/setuptools/unicode_utils.py +++ b/setuptools/unicode_utils.py @@ -1,3 +1,5 @@ +__lazy_modules__ = {"configparser", "unicodedata"} + import sys import unicodedata from configparser import RawConfigParser diff --git a/setuptools/warnings.py b/setuptools/warnings.py index 97f6971cf7..beaf7cf91c 100644 --- a/setuptools/warnings.py +++ b/setuptools/warnings.py @@ -7,6 +7,8 @@ from __future__ import annotations +__lazy_modules__ = {"datetime", "inspect", "textwrap", "warnings"} + import os import warnings from datetime import date diff --git a/setuptools/wheel.py b/setuptools/wheel.py index 9366303154..d9f56f6eb9 100644 --- a/setuptools/wheel.py +++ b/setuptools/wheel.py @@ -1,5 +1,26 @@ """Wheels support.""" +__lazy_modules__ = { + "collections", + "collections.abc", + "distutils", + "distutils.util", + "email", + f"{__spec__.parent}._discovery", + f"{__spec__.parent}._importlib", + f"{__spec__.parent}.unicode_utils", + "itertools", + "packaging", + "packaging.requirements", + "packaging.tags", + "packaging.utils", + "packaging.version", + "setuptools.archive_util", + "setuptools.command", + "setuptools.command.egg_info", + "zipfile", +} + import contextlib import email import functools diff --git a/setuptools/windows_support.py b/setuptools/windows_support.py index 7a2b53a291..4ee57de0c4 100644 --- a/setuptools/windows_support.py +++ b/setuptools/windows_support.py @@ -1,3 +1,5 @@ +__lazy_modules__ = {"platform"} + import platform diff --git a/tox.ini b/tox.ini index bcee70d589..8eb89664a6 100644 --- a/tox.ini +++ b/tox.ini @@ -7,6 +7,14 @@ setenv = SETUPTOOLS_ENFORCE_DEPRECATION = {env:SETUPTOOLS_ENFORCE_DEPRECATION:0} # TODO: return to 1 (temporarily disabled) commands = pytest {posargs} + # flake8-lazy has no pytest plugin; run its CLI over the package sources. + # tox doesn't shell-glob, so expand the file list cross-platform via Python + # and drop test dirs (lazy-import hygiene is irrelevant there) plus the + # vendored/distutils trees (maintained upstream, not our lazy-import concern). + python -c "import glob, os, subprocess, sys; \ + skip = {'tests', '_distutils', '_vendor', '_validate_pyproject'}; \ + files = [f for f in glob.glob('setuptools/**/*.py', recursive=True) if not skip & set(f.split(os.sep))]; \ + subprocess.check_call([sys.executable, '-m', 'flake8_lazy', *files])" usedevelop = True extras = test From be82d657ff42056ec7a9e85273ccc67383140ece Mon Sep 17 00:00:00 2001 From: Avasam Date: Sat, 11 Jul 2026 18:02:00 -0400 Subject: [PATCH 2/2] Eager imports for `_importlib` --- ruff.toml | 1 + setuptools/_entry_points.py | 3 +-- setuptools/_importlib.py | 6 ++---- setuptools/_scripts.py | 3 +-- setuptools/command/egg_info.py | 3 +-- setuptools/command/sdist.py | 3 +-- setuptools/dist.py | 3 +-- setuptools/installer.py | 3 +-- setuptools/wheel.py | 3 +-- 9 files changed, 10 insertions(+), 18 deletions(-) diff --git a/ruff.toml b/ruff.toml index 9525996ab0..5393e263cd 100644 --- a/ruff.toml +++ b/ruff.toml @@ -5,6 +5,7 @@ exclude = [ ] [lint] +external=["LZY"] extend-select = [ # upstream diff --git a/setuptools/_entry_points.py b/setuptools/_entry_points.py index 93412267ef..c6b4e8f32e 100644 --- a/setuptools/_entry_points.py +++ b/setuptools/_entry_points.py @@ -1,5 +1,4 @@ __lazy_modules__ = { - f"{__spec__.parent}._importlib", f"{__spec__.parent}._itertools", f"{__spec__.parent}.errors", "itertools", @@ -17,7 +16,7 @@ from jaraco.text import yield_lines from more_itertools import consume -from ._importlib import metadata +from ._importlib import metadata # noqa: LZY102 from ._itertools import ensure_unique from .errors import OptionError diff --git a/setuptools/_importlib.py b/setuptools/_importlib.py index 69b2ee583b..e323e4adbb 100644 --- a/setuptools/_importlib.py +++ b/setuptools/_importlib.py @@ -1,4 +1,2 @@ -__lazy_modules__ = {"importlib", "importlib.metadata", "importlib.resources"} - -import importlib.metadata as metadata # noqa: F401 -import importlib.resources as resources # noqa: F401 +import importlib.metadata as metadata # noqa: F401,LZY101 +import importlib.resources as resources # noqa: F401,LZY101 diff --git a/setuptools/_scripts.py b/setuptools/_scripts.py index 08458f3183..ce4b810563 100644 --- a/setuptools/_scripts.py +++ b/setuptools/_scripts.py @@ -7,7 +7,6 @@ "distutils.command", "distutils.command.build_scripts", "distutils.util", - f"{__spec__.parent}._importlib", f"{__spec__.parent}.warnings", "re", "shlex", @@ -28,7 +27,7 @@ from collections.abc import Iterable from typing import TYPE_CHECKING, TypedDict -from ._importlib import metadata, resources +from ._importlib import metadata, resources # noqa: LZY102 if TYPE_CHECKING: from typing_extensions import Self diff --git a/setuptools/command/egg_info.py b/setuptools/command/egg_info.py index 4b84a4a127..815ad00233 100644 --- a/setuptools/command/egg_info.py +++ b/setuptools/command/egg_info.py @@ -10,7 +10,6 @@ "distutils", "distutils.errors", "distutils.util", - f"{(__spec__.parent or '').rsplit('.', 1)[0]}._importlib", "functools", "packaging", "packaging.requirements", @@ -40,7 +39,7 @@ from setuptools.glob import glob from .. import _entry_points, _normalization -from .._importlib import metadata +from .._importlib import metadata # noqa: LZY102 from ..warnings import SetuptoolsDeprecationWarning from . import _requirestxt diff --git a/setuptools/command/sdist.py b/setuptools/command/sdist.py index a01d7bf139..5b33010b74 100644 --- a/setuptools/command/sdist.py +++ b/setuptools/command/sdist.py @@ -5,7 +5,6 @@ "collections.abc", "contextlib", "distutils", - f"{(__spec__.parent or '').rsplit('.', 1)[0]}._importlib", f"{(__spec__.parent or '').rsplit('.', 1)[0]}.dist", f"{__spec__.parent}.build", "itertools", @@ -20,7 +19,7 @@ from itertools import chain from typing import ClassVar -from .._importlib import metadata +from .._importlib import metadata # noqa: LZY102 from ..dist import Distribution from .build import _ORIGINAL_SUBCOMMANDS diff --git a/setuptools/dist.py b/setuptools/dist.py index f2fab5ce1a..8f6337c676 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -9,7 +9,6 @@ "distutils.fancy_getopt", "distutils.log", "distutils.util", - f"{__spec__.parent}._importlib", f"{__spec__.parent}._normalization", f"{__spec__.parent}._path", f"{__spec__.parent}._reqs", @@ -52,7 +51,7 @@ _static, command as _, # noqa: F401 # imported for side-effects ) -from ._importlib import metadata +from ._importlib import metadata # noqa: LZY102 from ._normalization import _canonicalize_license_expression from ._path import StrPath from ._reqs import _StrOrIter diff --git a/setuptools/installer.py b/setuptools/installer.py index d96e39c08a..ca33db9543 100644 --- a/setuptools/installer.py +++ b/setuptools/installer.py @@ -3,7 +3,6 @@ __lazy_modules__ = { "distutils", "distutils.errors", - f"{__spec__.parent}._importlib", f"{__spec__.parent}.wheel", "glob", "itertools", @@ -25,7 +24,7 @@ import packaging.utils from . import _reqs -from ._importlib import metadata +from ._importlib import metadata # noqa: LZY102 from .warnings import SetuptoolsDeprecationWarning from .wheel import Wheel diff --git a/setuptools/wheel.py b/setuptools/wheel.py index d9f56f6eb9..5ba91e6ab4 100644 --- a/setuptools/wheel.py +++ b/setuptools/wheel.py @@ -7,7 +7,6 @@ "distutils.util", "email", f"{__spec__.parent}._discovery", - f"{__spec__.parent}._importlib", f"{__spec__.parent}.unicode_utils", "itertools", "packaging", @@ -41,7 +40,7 @@ from setuptools.command.egg_info import _egg_basename, write_requirements from ._discovery import extras_from_deps -from ._importlib import metadata +from ._importlib import metadata # noqa: LZY102 from .unicode_utils import _read_utf8_with_fallback from distutils.util import get_platform