From f15e80293781e98809ad84fa22a96065225c6748 Mon Sep 17 00:00:00 2001 From: Avasam Date: Sat, 31 May 2025 15:45:41 -0400 Subject: [PATCH] Merge commands overloads from typeshed --- setuptools/__init__.py | 221 ++++++++++++++++++++- setuptools/command/bdist_wheel.py | 3 +- setuptools/command/dist_info.py | 12 +- setuptools/command/editable_wheel.py | 27 +-- setuptools/dist.py | 274 ++++++++++++++++++++++++++- 5 files changed, 506 insertions(+), 31 deletions(-) diff --git a/setuptools/__init__.py b/setuptools/__init__.py index b3e78edab6..c7b182fe1b 100644 --- a/setuptools/__init__.py +++ b/setuptools/__init__.py @@ -12,7 +12,7 @@ import sys from abc import abstractmethod from collections.abc import Mapping -from typing import TYPE_CHECKING, TypeVar, overload +from typing import TYPE_CHECKING, Literal, TypeVar, overload sys.path.extend(((vendor_path := os.path.join(os.path.dirname(os.path.dirname(__file__)), 'setuptools', '_vendor')) not in sys.path) * [vendor_path]) # fmt: skip # workaround for #4476 @@ -30,6 +30,29 @@ import distutils.core +if TYPE_CHECKING: + from .command.alias import alias + from .command.bdist_egg import bdist_egg + from .command.bdist_rpm import bdist_rpm + from .command.bdist_wheel import bdist_wheel + from .command.build import build + from .command.build_clib import build_clib + from .command.build_ext import build_ext + from .command.build_py import build_py + from .command.develop import develop + from .command.dist_info import dist_info + from .command.easy_install import easy_install + from .command.editable_wheel import editable_wheel + from .command.egg_info import egg_info + from .command.install import install + from .command.install_egg_info import install_egg_info + from .command.install_lib import install_lib + from .command.install_scripts import install_scripts + from .command.rotate import rotate + from .command.saveopts import saveopts + from .command.sdist import sdist + from .command.setopt import setopt + __all__ = [ 'setup', 'Distribution', @@ -175,6 +198,200 @@ def __init__(self, dist: Distribution, **kw) -> None: super().__init__(dist) vars(self).update(kw) + if TYPE_CHECKING: + # Note: Commands that setuptools doesn't re-expose are considered deprecated (they must be imported from distutils directly) + # So we're not listing them here. This list comes directly from the setuptools/command folder. Minus the test command. + @overload # type: ignore[no-overload-impl] # This overrides from distutils + def get_finalized_command( # pyright: ignore[reportNoOverloadImplementation] # This overrides form distutils + self, command: Literal["alias"], create: bool = True + ) -> alias: ... + @overload + def get_finalized_command( + self, command: Literal["bdist_egg"], create: bool = True + ) -> bdist_egg: ... + @overload + def get_finalized_command( + self, command: Literal["bdist_rpm"], create: bool = True + ) -> bdist_rpm: ... + @overload + def get_finalized_command( + self, command: Literal["bdist_wheel"], create: bool = True + ) -> bdist_wheel: ... + @overload + def get_finalized_command( + self, command: Literal["build"], create: bool = True + ) -> build: ... + @overload + def get_finalized_command( + self, command: Literal["build_clib"], create: bool = True + ) -> build_clib: ... + @overload + def get_finalized_command( + self, command: Literal["build_ext"], create: bool = True + ) -> build_ext: ... + @overload + def get_finalized_command( + self, command: Literal["build_py"], create: bool = True + ) -> build_py: ... + @overload + def get_finalized_command( + self, command: Literal["develop"], create: bool = True + ) -> develop: ... + @overload + def get_finalized_command( + self, command: Literal["dist_info"], create: bool = True + ) -> dist_info: ... + @overload + def get_finalized_command( + self, command: Literal["easy_install"], create: bool = True + ) -> easy_install: ... + @overload + def get_finalized_command( + self, command: Literal["editable_wheel"], create: bool = True + ) -> editable_wheel: ... + @overload + def get_finalized_command( + self, command: Literal["egg_info"], create: bool = True + ) -> egg_info: ... + @overload + def get_finalized_command( + self, command: Literal["install"], create: bool = True + ) -> install: ... + @overload + def get_finalized_command( + self, command: Literal["install_egg_info"], create: bool = True + ) -> install_egg_info: ... + @overload + def get_finalized_command( + self, command: Literal["install_lib"], create: bool = True + ) -> install_lib: ... + @overload + def get_finalized_command( + self, command: Literal["install_scripts"], create: bool = True + ) -> install_scripts: ... + @overload + def get_finalized_command( + self, command: Literal["rotate"], create: bool = True + ) -> rotate: ... + @overload + def get_finalized_command( + self, command: Literal["saveopts"], create: bool = True + ) -> saveopts: ... + @overload + def get_finalized_command( + self, command: Literal["sdist"], create: bool = True + ) -> sdist: ... + @overload + def get_finalized_command( + self, command: Literal["setopt"], create: bool = True + ) -> setopt: ... + @overload + def get_finalized_command( + self, command: str, create: bool = True + ) -> Command: ... + + @overload + def reinitialize_command( + self, command: Literal["alias"], reinit_subcommands: bool = False, **kw + ) -> alias: ... + @overload + def reinitialize_command( + self, command: Literal["bdist_egg"], reinit_subcommands: bool = False, **kw + ) -> bdist_egg: ... + @overload + def reinitialize_command( + self, command: Literal["bdist_rpm"], reinit_subcommands: bool = False, **kw + ) -> bdist_rpm: ... + @overload + def reinitialize_command( + self, + command: Literal["bdist_wheel"], + reinit_subcommands: bool = False, + **kw, + ) -> bdist_wheel: ... + @overload + def reinitialize_command( + self, command: Literal["build"], reinit_subcommands: bool = False, **kw + ) -> build: ... + @overload + def reinitialize_command( + self, command: Literal["build_clib"], reinit_subcommands: bool = False, **kw + ) -> build_clib: ... + @overload + def reinitialize_command( + self, command: Literal["build_ext"], reinit_subcommands: bool = False, **kw + ) -> build_ext: ... + @overload + def reinitialize_command( + self, command: Literal["build_py"], reinit_subcommands: bool = False, **kw + ) -> build_py: ... + @overload + def reinitialize_command( + self, command: Literal["develop"], reinit_subcommands: bool = False, **kw + ) -> develop: ... + @overload + def reinitialize_command( + self, command: Literal["dist_info"], reinit_subcommands: bool = False, **kw + ) -> dist_info: ... + @overload + def reinitialize_command( + self, + command: Literal["easy_install"], + reinit_subcommands: bool = False, + **kw, + ) -> easy_install: ... + @overload + def reinitialize_command( + self, + command: Literal["editable_wheel"], + reinit_subcommands: bool = False, + **kw, + ) -> editable_wheel: ... + @overload + def reinitialize_command( + self, command: Literal["egg_info"], reinit_subcommands: bool = False, **kw + ) -> egg_info: ... + @overload + def reinitialize_command( + self, command: Literal["install"], reinit_subcommands: bool = False, **kw + ) -> install: ... + @overload + def reinitialize_command( + self, + command: Literal["install_egg_info"], + reinit_subcommands: bool = False, + **kw, + ) -> install_egg_info: ... + @overload + def reinitialize_command( + self, + command: Literal["install_lib"], + reinit_subcommands: bool = False, + **kw, + ) -> install_lib: ... + @overload + def reinitialize_command( + self, + command: Literal["install_scripts"], + reinit_subcommands: bool = False, + **kw, + ) -> install_scripts: ... + @overload + def reinitialize_command( + self, command: Literal["rotate"], reinit_subcommands: bool = False, **kw + ) -> rotate: ... + @overload + def reinitialize_command( + self, command: Literal["saveopts"], reinit_subcommands: bool = False, **kw + ) -> saveopts: ... + @overload + def reinitialize_command( + self, command: Literal["sdist"], reinit_subcommands: bool = False, **kw + ) -> sdist: ... + @overload + def reinitialize_command( + self, command: Literal["setopt"], reinit_subcommands: bool = False, **kw + ) -> setopt: ... @overload def reinitialize_command( self, command: str, reinit_subcommands: bool = False, **kw @@ -188,7 +405,7 @@ def reinitialize_command( ) -> Command | _Command: cmd = _Command.reinitialize_command(self, command, reinit_subcommands) vars(cmd).update(kw) - return cmd # pyright: ignore[reportReturnType] # pypa/distutils#307 + return cmd @abstractmethod def initialize_options(self) -> None: diff --git a/setuptools/command/bdist_wheel.py b/setuptools/command/bdist_wheel.py index 91ed00170e..cfd092040d 100644 --- a/setuptools/command/bdist_wheel.py +++ b/setuptools/command/bdist_wheel.py @@ -26,7 +26,6 @@ from .._core_metadata import _safe_license_file from .._normalization import safer_name from ..warnings import SetuptoolsDeprecationWarning -from .egg_info import egg_info as egg_info_cls from distutils import log @@ -233,7 +232,7 @@ def finalize_options(self) -> None: self.bdist_dir = os.path.join(bdist_base, "wheel") if self.dist_info_dir is None: - egg_info = cast(egg_info_cls, self.distribution.get_command_obj("egg_info")) + egg_info = self.distribution.get_command_obj("egg_info") egg_info.ensure_finalized() # needed for correct `wheel_dist_name` self.data_dir = self.wheel_dist_name + ".data" diff --git a/setuptools/command/dist_info.py b/setuptools/command/dist_info.py index dca01ff0ce..e5525251e3 100644 --- a/setuptools/command/dist_info.py +++ b/setuptools/command/dist_info.py @@ -7,14 +7,18 @@ import shutil from contextlib import contextmanager from pathlib import Path -from typing import cast +from typing import TYPE_CHECKING from .. import _normalization from .._shutil import rmdir as _rm -from .egg_info import egg_info as egg_info_cls from distutils import log -from distutils.core import Command + +# Pretend dist_info subclasses setuptools.Command so we get all overrides when type-checking +if TYPE_CHECKING: + from setuptools import Command +else: + from distutils.core import Command class dist_info(Command): @@ -54,7 +58,7 @@ def finalize_options(self) -> None: project_dir = dist.src_root or os.curdir self.output_dir = Path(self.output_dir or project_dir) - egg_info = cast(egg_info_cls, self.reinitialize_command("egg_info")) + egg_info = self.reinitialize_command("egg_info") egg_info.egg_base = str(self.output_dir) if self.tag_date: diff --git a/setuptools/command/editable_wheel.py b/setuptools/command/editable_wheel.py index d1d9e79b39..67a5524d94 100644 --- a/setuptools/command/editable_wheel.py +++ b/setuptools/command/editable_wheel.py @@ -26,7 +26,7 @@ from pathlib import Path from tempfile import TemporaryDirectory from types import TracebackType -from typing import TYPE_CHECKING, Protocol, TypeVar, cast +from typing import TYPE_CHECKING, Protocol, TypeVar from .. import Command, _normalization, _path, _shutil, errors, namespaces from .._path import StrPath @@ -34,12 +34,7 @@ from ..discovery import find_package_path from ..dist import Distribution from ..warnings import InformationOnly, SetuptoolsDeprecationWarning -from .build import build as build_cls from .build_py import build_py as build_py_cls -from .dist_info import dist_info as dist_info_cls -from .egg_info import egg_info as egg_info_cls -from .install import install as install_cls -from .install_scripts import install_scripts as install_scripts_cls if TYPE_CHECKING: from typing_extensions import Self @@ -150,7 +145,7 @@ def run(self) -> None: def _ensure_dist_info(self): if self.dist_info_dir is None: - dist_info = cast(dist_info_cls, self.reinitialize_command("dist_info")) + dist_info = self.reinitialize_command("dist_info") dist_info.output_dir = self.dist_dir dist_info.ensure_finalized() dist_info.run() @@ -197,18 +192,12 @@ def _configure_build( scripts = str(Path(unpacked_wheel, f"{name}.data", "scripts")) # egg-info may be generated again to create a manifest (used for package data) - egg_info = cast( - egg_info_cls, dist.reinitialize_command("egg_info", reinit_subcommands=True) - ) + egg_info = dist.reinitialize_command("egg_info", reinit_subcommands=True) egg_info.egg_base = str(tmp_dir) egg_info.ignore_egg_info_in_manifest = True - build = cast( - build_cls, dist.reinitialize_command("build", reinit_subcommands=True) - ) - install = cast( - install_cls, dist.reinitialize_command("install", reinit_subcommands=True) - ) + build = dist.reinitialize_command("build", reinit_subcommands=True) + install = dist.reinitialize_command("install", reinit_subcommands=True) build.build_platlib = build.build_purelib = build.build_lib = build_lib install.install_purelib = install.install_platlib = install.install_lib = wheel @@ -221,14 +210,12 @@ def _configure_build( build_scripts = dist.get_command_obj("build_scripts") build_scripts.executable = 'python' - install_scripts = cast( - install_scripts_cls, dist.get_command_obj("install_scripts") - ) + install_scripts = dist.get_command_obj("install_scripts") install_scripts.no_ep = True build.build_temp = str(tmp_dir) - build_py = cast(build_py_cls, dist.get_command_obj("build_py")) + build_py = dist.get_command_obj("build_py") build_py.compile = False build_py.existing_egg_info_dir = self._find_egg_info_dir() diff --git a/setuptools/dist.py b/setuptools/dist.py index d2d95b9854..28dc485da4 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -10,7 +10,7 @@ from collections.abc import Iterable, Iterator, MutableMapping, Sequence from glob import glob from pathlib import Path -from typing import TYPE_CHECKING, Any, Union +from typing import TYPE_CHECKING, Any, Literal, TypeVar, Union, overload from more_itertools import partition, unique_everseen from packaging.markers import InvalidMarker, Marker @@ -36,7 +36,6 @@ import distutils.cmd import distutils.command import distutils.core -import distutils.dist import distutils.log from distutils.debug import DEBUG from distutils.errors import DistutilsOptionError, DistutilsSetupError @@ -46,9 +45,32 @@ if TYPE_CHECKING: from typing_extensions import TypeAlias + from . import Command + from .command.alias import alias + from .command.bdist_egg import bdist_egg + from .command.bdist_rpm import bdist_rpm + from .command.bdist_wheel import bdist_wheel + from .command.build import build + from .command.build_clib import build_clib + from .command.build_ext import build_ext + from .command.build_py import build_py + from .command.develop import develop + from .command.dist_info import dist_info + from .command.easy_install import easy_install + from .command.editable_wheel import editable_wheel + from .command.egg_info import egg_info + from .command.install import install + from .command.install_egg_info import install_egg_info + from .command.install_lib import install_lib + from .command.install_scripts import install_scripts + from .command.rotate import rotate + from .command.saveopts import saveopts + from .command.sdist import sdist + from .command.setopt import setopt __all__ = ['Distribution'] +_CommandT = TypeVar("_CommandT", bound="Command") _sequence = tuple, list """ :meta private: @@ -836,7 +858,253 @@ def fetch_build_egg(self, req): return fetch_build_egg(self, req) - def get_command_class(self, command: str) -> type[distutils.cmd.Command]: # type: ignore[override] # Not doing complex overrides yet + if TYPE_CHECKING: + # NOTE: Commands that setuptools doesn't re-expose are considered deprecated (they must be imported from distutils directly) + # So we're not listing them here. This list comes directly from the setuptools/command folder. Minus the test command. + @overload # type: ignore[override, no-overload-impl] # This overrides from distutils + def get_command_obj( # pyright: ignore[reportNoOverloadImplementation] # This overrides form distutils + self, command: Literal["alias"], create: Literal[True] = True + ) -> alias: ... + @overload + def get_command_obj( + self, command: Literal["bdist_egg"], create: Literal[True] = True + ) -> bdist_egg: ... + @overload + def get_command_obj( + self, command: Literal["bdist_rpm"], create: Literal[True] = True + ) -> bdist_rpm: ... + @overload + def get_command_obj( + self, command: Literal["bdist_wheel"], create: Literal[True] = True + ) -> bdist_wheel: ... + @overload + def get_command_obj( + self, command: Literal["build"], create: Literal[True] = True + ) -> build: ... + @overload + def get_command_obj( + self, command: Literal["build_clib"], create: Literal[True] = True + ) -> build_clib: ... + @overload + def get_command_obj( + self, command: Literal["build_ext"], create: Literal[True] = True + ) -> build_ext: ... + @overload + def get_command_obj( + self, command: Literal["build_py"], create: Literal[True] = True + ) -> build_py: ... + @overload + def get_command_obj( + self, command: Literal["develop"], create: Literal[True] = True + ) -> develop: ... + @overload + def get_command_obj( + self, command: Literal["dist_info"], create: Literal[True] = True + ) -> dist_info: ... + @overload + def get_command_obj( + self, command: Literal["easy_install"], create: Literal[True] = True + ) -> easy_install: ... + @overload + def get_command_obj( + self, command: Literal["editable_wheel"], create: Literal[True] = True + ) -> editable_wheel: ... + @overload + def get_command_obj( + self, command: Literal["egg_info"], create: Literal[True] = True + ) -> egg_info: ... + @overload + def get_command_obj( + self, command: Literal["install"], create: Literal[True] = True + ) -> install: ... + @overload + def get_command_obj( + self, command: Literal["install_egg_info"], create: Literal[True] = True + ) -> install_egg_info: ... + @overload + def get_command_obj( + self, command: Literal["install_lib"], create: Literal[True] = True + ) -> install_lib: ... + @overload + def get_command_obj( + self, command: Literal["install_scripts"], create: Literal[True] = True + ) -> install_scripts: ... + @overload + def get_command_obj( + self, command: Literal["rotate"], create: Literal[True] = True + ) -> rotate: ... + @overload + def get_command_obj( + self, command: Literal["saveopts"], create: Literal[True] = True + ) -> saveopts: ... + @overload + def get_command_obj( + self, command: Literal["sdist"], create: Literal[True] = True + ) -> sdist: ... + @overload + def get_command_obj( + self, command: Literal["setopt"], create: Literal[True] = True + ) -> setopt: ... + @overload + def get_command_obj( + self, command: str, create: Literal[True] = True + ) -> Command: ... + # Not replicating the overloads for "Command | None", user may use "isinstance" + @overload + def get_command_obj( + self, command: str, create: Literal[False] + ) -> Command | None: ... + + @overload # type: ignore[override, no-overload-impl] # This overrides from distutils + def reinitialize_command( # pyright: ignore[reportNoOverloadImplementation] # This overrides form distutils + self, command: Literal["alias"], reinit_subcommands: bool = False + ) -> alias: ... + @overload + def reinitialize_command( + self, command: Literal["bdist_egg"], reinit_subcommands: bool = False + ) -> bdist_egg: ... + @overload + def reinitialize_command( + self, command: Literal["bdist_rpm"], reinit_subcommands: bool = False + ) -> bdist_rpm: ... + @overload + def reinitialize_command( + self, command: Literal["bdist_wheel"], reinit_subcommands: bool = False + ) -> bdist_wheel: ... + @overload + def reinitialize_command( + self, command: Literal["build"], reinit_subcommands: bool = False + ) -> build: ... + @overload + def reinitialize_command( + self, command: Literal["build_clib"], reinit_subcommands: bool = False + ) -> build_clib: ... + @overload + def reinitialize_command( + self, command: Literal["build_ext"], reinit_subcommands: bool = False + ) -> build_ext: ... + @overload + def reinitialize_command( + self, command: Literal["build_py"], reinit_subcommands: bool = False + ) -> build_py: ... + @overload + def reinitialize_command( + self, command: Literal["develop"], reinit_subcommands: bool = False + ) -> develop: ... + @overload + def reinitialize_command( + self, command: Literal["dist_info"], reinit_subcommands: bool = False + ) -> dist_info: ... + @overload + def reinitialize_command( + self, command: Literal["easy_install"], reinit_subcommands: bool = False + ) -> easy_install: ... + @overload + def reinitialize_command( + self, command: Literal["editable_wheel"], reinit_subcommands: bool = False + ) -> editable_wheel: ... + @overload + def reinitialize_command( + self, command: Literal["egg_info"], reinit_subcommands: bool = False + ) -> egg_info: ... + @overload + def reinitialize_command( + self, command: Literal["install"], reinit_subcommands: bool = False + ) -> install: ... + @overload + def reinitialize_command( + self, command: Literal["install_egg_info"], reinit_subcommands: bool = False + ) -> install_egg_info: ... + @overload + def reinitialize_command( + self, command: Literal["install_lib"], reinit_subcommands: bool = False + ) -> install_lib: ... + @overload + def reinitialize_command( + self, command: Literal["install_scripts"], reinit_subcommands: bool = False + ) -> install_scripts: ... + @overload + def reinitialize_command( + self, command: Literal["rotate"], reinit_subcommands: bool = False + ) -> rotate: ... + @overload + def reinitialize_command( + self, command: Literal["saveopts"], reinit_subcommands: bool = False + ) -> saveopts: ... + @overload + def reinitialize_command( + self, command: Literal["sdist"], reinit_subcommands: bool = False + ) -> sdist: ... + @overload + def reinitialize_command( + self, command: Literal["setopt"], reinit_subcommands: bool = False + ) -> setopt: ... + @overload + def reinitialize_command( + self, command: str, reinit_subcommands: bool = False + ) -> Command: ... + @overload + def reinitialize_command( + self, command: _CommandT, reinit_subcommands: bool = False + ) -> _CommandT: ... + + @overload # type: ignore[override] + def get_command_class(self, command: Literal["alias"]) -> type[alias]: ... + @overload + def get_command_class(self, command: Literal["bdist_egg"]) -> type[bdist_egg]: ... + @overload + def get_command_class(self, command: Literal["bdist_rpm"]) -> type[bdist_rpm]: ... + @overload + def get_command_class( + self, command: Literal["bdist_wheel"] + ) -> type[bdist_wheel]: ... + @overload + def get_command_class(self, command: Literal["build"]) -> type[build]: ... + @overload + def get_command_class(self, command: Literal["build_clib"]) -> type[build_clib]: ... + @overload + def get_command_class(self, command: Literal["build_ext"]) -> type[build_ext]: ... + @overload + def get_command_class(self, command: Literal["build_py"]) -> type[build_py]: ... + @overload + def get_command_class(self, command: Literal["develop"]) -> type[develop]: ... + @overload + def get_command_class(self, command: Literal["dist_info"]) -> type[dist_info]: ... + @overload + def get_command_class( + self, command: Literal["easy_install"] + ) -> type[easy_install]: ... + @overload + def get_command_class( + self, command: Literal["editable_wheel"] + ) -> type[editable_wheel]: ... + @overload + def get_command_class(self, command: Literal["egg_info"]) -> type[egg_info]: ... + @overload + def get_command_class(self, command: Literal["install"]) -> type[install]: ... + @overload + def get_command_class( + self, command: Literal["install_egg_info"] + ) -> type[install_egg_info]: ... + @overload + def get_command_class( + self, command: Literal["install_lib"] + ) -> type[install_lib]: ... + @overload + def get_command_class( + self, command: Literal["install_scripts"] + ) -> type[install_scripts]: ... + @overload + def get_command_class(self, command: Literal["rotate"]) -> type[rotate]: ... + @overload + def get_command_class(self, command: Literal["saveopts"]) -> type[saveopts]: ... + @overload + def get_command_class(self, command: Literal["sdist"]) -> type[sdist]: ... + @overload + def get_command_class(self, command: Literal["setopt"]) -> type[setopt]: ... + @overload + def get_command_class(self, command: str) -> type[Command]: ... + def get_command_class(self, command: str) -> type[distutils.cmd.Command]: """Pluggable version of get_command_class()""" if command in self.cmdclass: return self.cmdclass[command]