Skip to content

Add distutils as a top-level package included with types-setuptools #10948

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

Merged
merged 13 commits into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from 12 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
96 changes: 94 additions & 2 deletions stubs/setuptools/@tests/stubtest_allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,103 @@ setuptools._distutils.dist.Distribution.get_requires
setuptools._distutils.dist.Distribution.get_provides
setuptools._distutils.dist.Distribution.get_obsoletes

# Missing objects from setuptools._distutils
setuptools._distutils.archive_util.ARCHIVE_FORMATS
setuptools._distutils.archive_util.check_archive_formats
setuptools._distutils.ccompiler.CCompiler.EXECUTABLE
setuptools._distutils.ccompiler.CCompiler.SHARED_LIBRARY
setuptools._distutils.ccompiler.CCompiler.SHARED_OBJECT
setuptools._distutils.ccompiler.CCompiler.compiler_type
setuptools._distutils.ccompiler.CCompiler.out_extensions
setuptools._distutils.ccompiler.CCompiler.set_executable
setuptools._distutils.ccompiler.compiler_class
setuptools._distutils.cmd.Command.dump_options
setuptools._distutils.command.bdist
setuptools._distutils.command.bdist_rpm
setuptools._distutils.command.build
setuptools._distutils.command.build_clib
setuptools._distutils.command.build_clib.show_compilers
setuptools._distutils.command.build_ext.extension_name_re
setuptools._distutils.command.build_ext.show_compilers
setuptools._distutils.command.build_ext
setuptools._distutils.command.build_py
setuptools._distutils.command.build_scripts
setuptools._distutils.command.check
setuptools._distutils.command.clean
setuptools._distutils.command.install
setuptools._distutils.command.install_data
setuptools._distutils.command.install_headers
setuptools._distutils.command.install_lib
setuptools._distutils.command.install_scripts
setuptools._distutils.command.install.HAS_USER_SITE
setuptools._distutils.command.install.INSTALL_SCHEMES
setuptools._distutils.command.install.SCHEME_KEYS
setuptools._distutils.command.install.WINDOWS_SCHEME
setuptools._distutils.command.install_lib.PYTHON_SOURCE_EXTENSION
setuptools._distutils.command.sdist
setuptools._distutils.command.sdist.show_formats
setuptools._distutils.command.register
setuptools._distutils.command.upload
setuptools._distutils.config.DEFAULT_PYPIRC
setuptools._distutils.dist.DistributionMetadata.set_classifiers
setuptools._distutils.dist.DistributionMetadata.set_keywords
setuptools._distutils.dist.DistributionMetadata.set_platforms
setuptools._distutils.dist.fix_help_options
setuptools._distutils.extension.read_setup_file
setuptools._distutils.filelist.findall
setuptools._distutils.filelist.glob_to_re
setuptools._distutils.filelist.translate_pattern
setuptools._distutils.sysconfig.BASE_EXEC_PREFIX
setuptools._distutils.sysconfig.BASE_PREFIX
setuptools._distutils.sysconfig.IS_PYPY
setuptools._distutils.sysconfig.build_flags
setuptools._distutils.sysconfig.expand_makefile_vars
setuptools._distutils.sysconfig.get_python_version
setuptools._distutils.sysconfig.parse_config_h
setuptools._distutils.sysconfig.parse_makefile
setuptools._distutils.sysconfig.project_base
setuptools._distutils.sysconfig.python_build
setuptools._distutils.util.MACOSX_VERSION_VAR

# Missing submodules from setuptools._distutils
# (Many of these may be implementation details,
# but they can be added if people ask for them)
setuptools._distutils.bcppcompiler
setuptools._distutils.command.bdist
setuptools._distutils.command.bdist_dumb
setuptools._distutils.command.build_scripts
setuptools._distutils.command.check
setuptools._distutils.command.clean
setuptools._distutils.command.config
setuptools._distutils.command.install_data
setuptools._distutils.command.install_egg_info
setuptools._distutils.command.install_headers
setuptools._distutils.command.py37compat
setuptools._distutils.core
setuptools._distutils.cygwinccompiler
setuptools._distutils.debug
setuptools._distutils.dir_util
setuptools._distutils.fancy_getopt
setuptools._distutils.file_util
setuptools._distutils.log
setuptools._distutils.msvc9compiler
setuptools._distutils.msvccompiler
setuptools._distutils.py38compat
setuptools._distutils.py39compat
setuptools._distutils.spawn
setuptools._distutils.text_file
setuptools._distutils.unixccompiler
setuptools._distutils.version
setuptools._distutils.versionpredicate

# Reexported from setuptools._distutils; problems should be fixed there
distutils\..+
Copy link
Collaborator

Choose a reason for hiding this comment

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

Good call. Should make stubtest errors clearer and contributors will be less tempted to try to apply a fix in stdlib/distutils (I know I have in the past)


# Is a functools.partial, so stubtest says "is not a function"
setuptools.dep_util.newer_pairwise_group
setuptools._distutils.dep_util.newer_pairwise
setuptools.modified.newer_pairwise_group
setuptools._distutils._modified.newer_pairwise_group

# Private modules
setuptools.config._validate_pyproject.*
Expand All @@ -40,8 +134,6 @@ setuptools.command.build_py.build_py.existing_egg_info_dir
# Loop variable leak
setuptools.sandbox.AbstractSandbox.name

# Vendored and modified version of stdlib's distutils. Basically implementation details
setuptools._distutils.*
# Other vendored code
setuptools._vendor.*
pkg_resources._vendor.*
5 changes: 5 additions & 0 deletions stubs/setuptools/@tests/test_cases/check_distutils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import distutils.command.sdist
import distutils.config

Copy link
Collaborator

@Avasam Avasam Mar 16, 2024

Choose a reason for hiding this comment

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

Maybe we should also try to use something exclusive to setuptool's version?

For example (the first one I found):

Suggested change
from distutils.util import split_version
s = split_version("")

Copy link
Collaborator

@Avasam Avasam Mar 16, 2024

Choose a reason for hiding this comment

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

Whelp, it showed that checkers (at least within the context of test_cases) still prefer the stdlib if it's found. (this now only passes on 3.12).

Since those weren't in stdlib anyway, I can live with not supporting them rather than adding more hacky workarounds to the test suite. But that's up to you.

Copy link
Member Author

@AlexWaygood AlexWaygood Mar 16, 2024

Choose a reason for hiding this comment

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

That fails mypy/pyright on Python <3.12, because both of them choose the stdlib distutils stubs over the third-party distutils stubs. That's the correct behaviour for any normal case where two packages of the same name are simultaneously provided by the stdlib and a third-party distribution; setuptools only does its "override the stdlib distutils if we're installed" magic through some importlib hacks, and unfortunately I think it's unreasonable to expect type checkers to add support for that

Copy link
Member

Choose a reason for hiding this comment

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

You could write this as if sys.version_info >= (3, 12): split_version(""). No opinion on whether it's needed though.

Copy link
Member Author

Choose a reason for hiding this comment

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

You could write this as if sys.version_info >= (3, 12): split_version("").

Eh, I feel like that could be more confusing than clarifying, since it is actually available on <py312 if you have setuptools installed, there's just no way of reasonably getting type checkers to understand that

d = distutils.config.PyPIRCCommand
c = distutils.command.sdist.sdist
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/archive_util.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.archive_util import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/ccompiler.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.ccompiler import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/cmd.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.cmd import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/command/bdist_rpm.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.command.bdist_rpm import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/command/build.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.command.build import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/command/build_clib.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.command.build_clib import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/command/build_ext.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.command.build_ext import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/command/build_py.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.command.build_py import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/command/install.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.command.install import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/command/install_scripts.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.command.install_scripts import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/command/register.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.command.register import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/command/sdist.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.command.sdist import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/command/upload.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.command.upload import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/config.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.config import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/dep_util.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.dep_util import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/dist.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.dist import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/errors.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.errors import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/extension.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.extension import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/filelist.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.filelist import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/sysconfig.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.sysconfig import *
1 change: 1 addition & 0 deletions stubs/setuptools/distutils/util.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from setuptools._distutils.util import *
30 changes: 25 additions & 5 deletions tests/stubtest_third_party.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
from __future__ import annotations

import argparse
import contextlib
import os
import shutil
import subprocess
import sys
import tempfile
from collections.abc import Iterator
from pathlib import Path
from textwrap import dedent
from typing import NoReturn
Expand All @@ -16,10 +19,23 @@
from utils import PYTHON_VERSION, colored, get_mypy_req, print_error, print_success_msg


@contextlib.contextmanager
def temporarily_delete_stdlib_distutils(typeshed_dir: Path) -> Iterator[None]:
stdlib_distutils_dir = typeshed_dir / "stdlib" / "distutils"
with tempfile.TemporaryDirectory() as td:
shutil.copytree(stdlib_distutils_dir, td, dirs_exist_ok=True)
try:
shutil.rmtree(stdlib_distutils_dir)
yield
finally:
shutil.copytree(td, stdlib_distutils_dir, dirs_exist_ok=True)


def run_stubtest(
dist: Path, *, parser: argparse.ArgumentParser, verbose: bool = False, specified_platforms_only: bool = False
) -> bool:
dist_name = dist.name
typeshed_dir = dist.parent.parent
try:
metadata = read_metadata(dist_name)
except NoSuchStubError as e:
Expand All @@ -41,8 +57,8 @@ def run_stubtest(
print(colored(f"skipping (requires Python {metadata.requires_python})", "yellow"))
return True

with tempfile.TemporaryDirectory() as tmp:
venv_dir = Path(tmp)
with contextlib.ExitStack() as stack:
venv_dir = Path(stack.enter_context(tempfile.TemporaryDirectory()))
try:
subprocess.run(["uv", "venv", venv_dir, "--seed"], capture_output=True, check=True)
except subprocess.CalledProcessError as e:
Expand Down Expand Up @@ -89,7 +105,7 @@ def run_stubtest(
"mypy.stubtest",
# Use --custom-typeshed-dir in case we make linked changes to stdlib or _typeshed
"--custom-typeshed-dir",
str(dist.parent.parent),
str(typeshed_dir),
*ignore_missing_stub,
*packages_to_check,
*modules_to_check,
Expand Down Expand Up @@ -117,6 +133,10 @@ def run_stubtest(
if dist_name == "uWSGI":
if not setup_uwsgi_stubtest_command(dist, venv_dir, stubtest_cmd):
return False
# setuptools also requires special-casing, or stubtest gets confused
# between stdlib-distutils and setuptools-distutils
elif dist_name == "setuptools":
stack.enter_context(temporarily_delete_stdlib_distutils(typeshed_dir))

try:
subprocess.run(stubtest_cmd, env=stubtest_env, check=True, capture_output=True)
Expand Down Expand Up @@ -147,8 +167,8 @@ def run_stubtest(
else:
print_success_msg()

if verbose:
print_commands(dist, pip_cmd, stubtest_cmd, mypypath)
if verbose:
print_commands(dist, pip_cmd, stubtest_cmd, mypypath)

return True

Expand Down