Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vendor distutils stubs #4691

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ disable_error_code =

## local

# Use our custom stubs for distutils
mypy_path = $MYPY_CONFIG_FILE_DIR/typings
Comment on lines +21 to +22
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used pyright's default of typings so that I didn't have to configure it there. But that folder name can be arbitrary.


# CI should test for all versions, local development gets hints for oldest supported
# But our testing setup doesn't allow passing CLI arguments, so local devs have to set this manually.
# python_version = 3.8
Expand Down Expand Up @@ -46,20 +49,16 @@ disable_error_code = attr-defined
[mypy-pkg_resources.tests.*]
disable_error_code = import-not-found

# - distutils doesn't exist on Python 3.12, unfortunately, this means typing
# will be missing for subclasses of distutils on Python 3.12 until either:
# - support for `SETUPTOOLS_USE_DISTUTILS=stdlib` is dropped (#3625)
# for setuptools to import `_distutils` directly
# - or non-stdlib distutils typings are exposed
# - The following are not marked as py.typed:
# - jaraco: Since mypy 1.12, the root name of the untyped namespace package gets called-out too
# - jaraco.develop: https://github.com/jaraco/jaraco.develop/issues/22
# - jaraco.envs: https://github.com/jaraco/jaraco.envs/issues/7
# - jaraco.packaging: https://github.com/jaraco/jaraco.packaging/issues/20
# - jaraco.path: https://github.com/jaraco/jaraco.path/issues/2
# - jaraco.test: https://github.com/jaraco/jaraco.test/issues/7
# - jaraco.text: https://github.com/jaraco/jaraco.text/issues/17
# - wheel: does not intend on exposing a programmatic API https://github.com/pypa/wheel/pull/610#issuecomment-2081687671
[mypy-distutils.*,jaraco.develop,jaraco.envs,jaraco.packaging.*,jaraco.path,jaraco.test.*,jaraco.text,wheel.*]
[mypy-jaraco,jaraco.develop,jaraco.envs,jaraco.packaging.*,jaraco.path,jaraco.test.*,jaraco.text,wheel.*]
ignore_missing_imports = True

# Even when excluding a module, import issues can show up due to following import
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ type = [

# local

# Referenced in distutils-stubs
"types-docutils",
# pin mypy version so a new version doesn't suddenly cause the CI to fail,
# until types-setuptools is removed from typeshed.
# For help with static-typing issues, or mypy update, ping @Avasam
Expand Down Expand Up @@ -203,6 +205,8 @@ include-package-data = true
include = [
"setuptools*",
"pkg_resources*",
# TODO: Include distutils stubs with package once we're confident in them
# "typings/distutils-stubs",
Comment on lines +208 to +209
Copy link
Contributor Author

@Avasam Avasam Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to ship anything as long as typeshed provides stubs for setuptools/_distutils. We can synchronize once ready.
As I mentioned in the issue, there's also always the option to ship it as a different package (in which case it could live completely separately from setuptools and pypa/distutils)

"_distutils_hack*",
]
exclude = [
Expand Down
2 changes: 2 additions & 0 deletions pyrightconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
],
// Our testing setup doesn't allow passing CLI arguments, so local devs have to set this manually.
// "pythonVersion": "3.8",
// Allow using distutils-stubs on Python 3.12+
"reportMissingModuleSource": false,
// For now we don't mind if mypy's `type: ignore` comments accidentally suppresses pyright issues
"enableTypeIgnoreComments": true,
"typeCheckingMode": "basic",
Expand Down
3 changes: 3 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ ignore = [
# Only enforcing return type annotations for public functions
"ANN202", # missing-return-type-private-function
"ANN204", # missing-return-type-special-method
# Typeshed doesn't want complex or non-literal defaults for maintenance and testing reasons.
# This doesn't affect us, let's have more complete stubs.
"PYI011", # typed-argument-default-in-stub

# https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules
"W191",
Expand Down
3 changes: 2 additions & 1 deletion setuptools/command/sdist.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import os
import re
from itertools import chain
from typing import ClassVar

from .._importlib import metadata
from ..dist import Distribution
Expand Down Expand Up @@ -49,7 +50,7 @@ class sdist(orig.sdist):
]

distribution: Distribution # override distutils.dist.Distribution with setuptools.dist.Distribution
negative_opt: dict[str, str] = {}
negative_opt: ClassVar[dict[str, str]] = {}

README_EXTENSIONS = ['', '.rst', '.txt', '.md']
READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS)
Expand Down
Empty file.
25 changes: 25 additions & 0 deletions typings/distutils-stubs/_modified.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from collections.abc import Callable, Iterable
from typing import Literal, TypeVar

from _typeshed import StrOrBytesPath

_SourcesT = TypeVar("_SourcesT", bound=StrOrBytesPath)
_TargetsT = TypeVar("_TargetsT", bound=StrOrBytesPath)

def newer(source: StrOrBytesPath, target: StrOrBytesPath) -> bool: ...
def newer_pairwise(
sources: Iterable[_SourcesT],
targets: Iterable[_TargetsT],
newer: Callable[[_SourcesT, _TargetsT], bool] = newer,
) -> tuple[list[_SourcesT], list[_TargetsT]]: ...
def newer_group(
sources: Iterable[StrOrBytesPath],
target: StrOrBytesPath,
missing: Literal["error", "ignore", "newer"] = "error",
) -> bool: ...
def newer_pairwise_group(
sources: Iterable[_SourcesT],
targets: Iterable[_TargetsT],
*,
newer: Callable[[_SourcesT, _TargetsT], bool] = newer,
) -> tuple[list[_SourcesT], list[_TargetsT]]: ...
38 changes: 38 additions & 0 deletions typings/distutils-stubs/archive_util.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from typing import Literal, overload

from _typeshed import StrOrBytesPath, StrPath

@overload
def make_archive(
base_name: str,
format: str,
root_dir: StrOrBytesPath | None = None,
base_dir: str | None = None,
verbose: bool = False,
dry_run: bool = False,
owner: str | None = None,
group: str | None = None,
) -> str: ...
@overload
def make_archive(
base_name: StrPath,
format: str,
root_dir: StrOrBytesPath,
base_dir: str | None = None,
verbose: bool = False,
dry_run: bool = False,
owner: str | None = None,
group: str | None = None,
) -> str: ...
def make_tarball(
base_name: str,
base_dir: StrPath,
compress: Literal["gzip", "bzip2", "xz"] | None = "gzip",
verbose: bool = False,
dry_run: bool = False,
owner: str | None = None,
group: str | None = None,
) -> str: ...
def make_zipfile(
base_name: str, base_dir: str, verbose: bool = False, dry_run: bool = False
) -> str: ...
3 changes: 3 additions & 0 deletions typings/distutils-stubs/bcppcompiler.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .ccompiler import CCompiler

class BCPPCompiler(CCompiler): ...
215 changes: 215 additions & 0 deletions typings/distutils-stubs/ccompiler.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
from collections.abc import Callable, Iterable
from typing import ClassVar, Literal, TypeVar, overload

from _typeshed import BytesPath, StrPath, Unused
from typing_extensions import TypeAlias, TypeVarTuple, Unpack

_Macro: TypeAlias = tuple[str] | tuple[str, str | None]
_StrPathT = TypeVar("_StrPathT", bound=StrPath)
_BytesPathT = TypeVar("_BytesPathT", bound=BytesPath)
_Ts = TypeVarTuple("_Ts")

def gen_lib_options(
compiler: CCompiler,
library_dirs: list[str],
runtime_library_dirs: list[str],
libraries: list[str],
) -> list[str]: ...
def gen_preprocess_options(
macros: list[_Macro], include_dirs: list[str]
) -> list[str]: ...
def get_default_compiler(
osname: str | None = None, platform: str | None = None
) -> str: ...
def new_compiler(
plat: str | None = None,
compiler: str | None = None,
verbose: bool = False,
dry_run: bool = False,
force: bool = False,
) -> CCompiler: ...
def show_compilers() -> None: ...

class CCompiler:
src_extensions: ClassVar[list[str] | None]
obj_extension: ClassVar[str | None]
static_lib_extension: ClassVar[str | None]
shared_lib_extension: ClassVar[str | None]
static_lib_format: ClassVar[str | None]
shared_lib_format: ClassVar[str | None]
exe_extension: ClassVar[str | None]
language_map: ClassVar[dict[str, str]]
language_order: ClassVar[list[str]]
dry_run: bool
force: bool
verbose: bool
output_dir: str | None
macros: list[_Macro]
include_dirs: list[str]
libraries: list[str]
library_dirs: list[str]
runtime_library_dirs: list[str]
objects: list[str]
def __init__(
self, verbose: bool = False, dry_run: bool = False, force: bool = False
) -> None: ...
def add_include_dir(self, dir: str) -> None: ...
def set_include_dirs(self, dirs: list[str]) -> None: ...
def add_library(self, libname: str) -> None: ...
def set_libraries(self, libnames: list[str]) -> None: ...
def add_library_dir(self, dir: str) -> None: ...
def set_library_dirs(self, dirs: list[str]) -> None: ...
def add_runtime_library_dir(self, dir: str) -> None: ...
def set_runtime_library_dirs(self, dirs: list[str]) -> None: ...
def define_macro(self, name: str, value: str | None = None) -> None: ...
def undefine_macro(self, name: str) -> None: ...
def add_link_object(self, object: str) -> None: ...
def set_link_objects(self, objects: list[str]) -> None: ...
def detect_language(self, sources: str | list[str]) -> str | None: ...
def find_library_file(
self, dirs: list[str], lib: str, debug: bool = False
) -> str | None: ...
def has_function(
self,
funcname: str,
includes: list[str] | None = None,
include_dirs: list[str] | None = None,
libraries: list[str] | None = None,
library_dirs: list[str] | None = None,
) -> bool: ...
def library_dir_option(self, dir: str) -> str: ...
def library_option(self, lib: str) -> str: ...
def runtime_library_dir_option(self, dir: str) -> str: ...
def set_executables(self, **args: str) -> None: ...
def compile(
self,
sources: list[str],
output_dir: str | None = None,
macros: list[_Macro] | None = None,
include_dirs: list[str] | None = None,
debug: bool = False,
extra_preargs: list[str] | None = None,
extra_postargs: list[str] | None = None,
depends: list[str] | None = None,
) -> list[str]: ...
def create_static_lib(
self,
objects: list[str],
output_libname: str,
output_dir: str | None = None,
debug: bool = False,
target_lang: str | None = None,
) -> None: ...
def link(
self,
target_desc: str,
objects: list[str],
output_filename: str,
output_dir: str | None = None,
libraries: list[str] | None = None,
library_dirs: list[str] | None = None,
runtime_library_dirs: list[str] | None = None,
export_symbols: list[str] | None = None,
debug: bool = False,
extra_preargs: list[str] | None = None,
extra_postargs: list[str] | None = None,
build_temp: str | None = None,
target_lang: str | None = None,
) -> None: ...
def link_executable(
self,
objects: list[str],
output_progname: str,
output_dir: str | None = None,
libraries: list[str] | None = None,
library_dirs: list[str] | None = None,
runtime_library_dirs: list[str] | None = None,
debug: bool = False,
extra_preargs: list[str] | None = None,
extra_postargs: list[str] | None = None,
target_lang: str | None = None,
) -> None: ...
def link_shared_lib(
self,
objects: list[str],
output_libname: str,
output_dir: str | None = None,
libraries: list[str] | None = None,
library_dirs: list[str] | None = None,
runtime_library_dirs: list[str] | None = None,
export_symbols: list[str] | None = None,
debug: bool = False,
extra_preargs: list[str] | None = None,
extra_postargs: list[str] | None = None,
build_temp: str | None = None,
target_lang: str | None = None,
) -> None: ...
def link_shared_object(
self,
objects: list[str],
output_filename: str,
output_dir: str | None = None,
libraries: list[str] | None = None,
library_dirs: list[str] | None = None,
runtime_library_dirs: list[str] | None = None,
export_symbols: list[str] | None = None,
debug: bool = False,
extra_preargs: list[str] | None = None,
extra_postargs: list[str] | None = None,
build_temp: str | None = None,
target_lang: str | None = None,
) -> None: ...
def preprocess(
self,
source: str,
output_file: str | None = None,
macros: list[_Macro] | None = None,
include_dirs: list[str] | None = None,
extra_preargs: list[str] | None = None,
extra_postargs: list[str] | None = None,
) -> None: ...
@overload
def executable_filename(
self, basename: str, strip_dir: Literal[False] = False, output_dir: StrPath = ""
) -> str: ...
@overload
def executable_filename(
self, basename: StrPath, strip_dir: Literal[True], output_dir: StrPath = ""
) -> str: ...
def library_filename(
self,
libname: str,
lib_type: str = "static",
strip_dir: bool = False,
output_dir: StrPath = "",
) -> str: ...
def object_filenames(
self,
source_filenames: Iterable[StrPath],
strip_dir: bool = False,
output_dir: StrPath | None = '',
) -> list[str]: ...
@overload
def shared_object_filename(
self, basename: str, strip_dir: Literal[False] = False, output_dir: StrPath = ""
) -> str: ...
@overload
def shared_object_filename(
self, basename: StrPath, strip_dir: Literal[True], output_dir: StrPath = ""
) -> str: ...
def execute(
self,
func: Callable[[Unpack[_Ts]], Unused],
args: tuple[Unpack[_Ts]],
msg: str | None = None,
level: int = 1,
) -> None: ...
def spawn(self, cmd: list[str]) -> None: ...
def mkpath(self, name: str, mode: int = 0o777) -> None: ...
@overload
def move_file(self, src: StrPath, dst: _StrPathT) -> _StrPathT | str: ...
@overload
def move_file(self, src: BytesPath, dst: _BytesPathT) -> _BytesPathT | bytes: ...
def announce(self, msg: str, level: int = 1) -> None: ...
def warn(self, msg: str) -> None: ...
def debug_print(self, msg: str) -> None: ...
Loading
Loading