Skip to content

Commit

Permalink
Type-check with mypy on Python 3.12
Browse files Browse the repository at this point in the history
  • Loading branch information
Avasam committed Aug 10, 2024
1 parent a6f7484 commit 50407ee
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 31 deletions.
14 changes: 9 additions & 5 deletions mypy.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[mypy]
# CI should test for all versions, local development gets hints for oldest supported
# Some upstream typeshed distutils stubs fixes are necessary before we can start testing on Python 3.12
python_version = 3.8
# But our testing setup doesn't allow passing CLI arguments, so local devs have to set this manually.
# python_version = 3.8
strict = False
warn_unused_ignores = True
warn_redundant_casts = True
Expand Down Expand Up @@ -30,15 +30,19 @@ disable_error_code = attr-defined
[mypy-pkg_resources.tests.*]
disable_error_code = import-not-found

# - distutils._modified has different errors on Python 3.8 [import-untyped], on Python 3.9+ [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
# - All jaraco modules are still untyped
# - _validate_project sometimes complains about trove_classifiers (#4296)
# - wheel appears to be untyped
[mypy-distutils._modified,jaraco.*,trove_classifiers,wheel.*]
[mypy-distutils.*,jaraco.*,trove_classifiers,wheel.*]
ignore_missing_imports = True

# Even when excluding a module, import issues can show up due to following import
# https://github.com/python/mypy/issues/11936#issuecomment-1466764006
[mypy-setuptools.config._validate_pyproject.*]
[mypy-setuptools.config._validate_pyproject.*,setuptools._distutils.*]
follow_imports = silent
# silent => ignore errors when following imports
11 changes: 9 additions & 2 deletions setuptools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
"""Extensions to the 'distutils' for large or complex distributions"""
# mypy: disable_error_code=override
# Command.reinitialize_command has an extra **kw param that distutils doesn't have
# Can't disable on the exact line because distutils doesn't exists on Python 3.12
# and mypy isn't aware of distutils_hack, causing distutils.core.Command to be Any,
# and a [unused-ignore] to be raised on 3.12+

from __future__ import annotations

Expand Down Expand Up @@ -114,8 +119,10 @@ def setup(**attrs):
setup.__doc__ = distutils.core.setup.__doc__

if TYPE_CHECKING:
from typing_extensions import TypeAlias

# Work around a mypy issue where type[T] can't be used as a base: https://github.com/python/mypy/issues/10962
_Command = distutils.core.Command
_Command: TypeAlias = distutils.core.Command
else:
_Command = monkey.get_unpatched(distutils.core.Command)

Expand Down Expand Up @@ -207,7 +214,7 @@ def ensure_string_list(self, option):
"'%s' must be a list of strings (got %r)" % (option, val)
)

@overload # type:ignore[override] # Extra **kw param
@overload
def reinitialize_command(
self, command: str, reinit_subcommands: bool = False, **kw
) -> _Command: ...
Expand Down
5 changes: 3 additions & 2 deletions setuptools/build_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,9 +385,10 @@ def _build_with_temp_dir(

# Build in a temporary directory, then copy to the target.
os.makedirs(result_directory, exist_ok=True)
temp_opts = {"prefix": ".tmp-", "dir": result_directory}

with tempfile.TemporaryDirectory(**temp_opts) as tmp_dist_dir:
with tempfile.TemporaryDirectory(
prefix=".tmp-", dir=result_directory
) as tmp_dist_dir:
sys.argv = [
*sys.argv[:1],
*self._global_args(config_settings),
Expand Down
2 changes: 1 addition & 1 deletion setuptools/command/build_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
get_config_var("LDSHARED")
# Not publicly exposed in typeshed distutils stubs, but this is done on purpose
# See https://github.com/pypa/setuptools/pull/4228#issuecomment-1959856400
from distutils.sysconfig import _config_vars as _CONFIG_VARS # type: ignore # noqa
from distutils.sysconfig import _config_vars as _CONFIG_VARS # noqa: E402


def _customize_compiler_for_shlib(compiler):
Expand Down
4 changes: 3 additions & 1 deletion setuptools/command/sdist.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from __future__ import annotations
from distutils import log
import distutils.command.sdist as orig
import os
import contextlib
from itertools import chain
from typing import ClassVar

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

distribution: Distribution # override distutils.dist.Distribution with setuptools.dist.Distribution
negative_opt = {}
negative_opt: ClassVar[dict[str, str]] = {} # type: ignore[misc] # Fixed upstream in typeshed to be a ClassVar. Should be included in mypy 1.12

README_EXTENSIONS = ['', '.rst', '.txt', '.md']
READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS)
Expand Down
2 changes: 1 addition & 1 deletion setuptools/config/setupcfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def _apply(
filenames = [*other_files, filepath]

try:
_Distribution.parse_config_files(dist, filenames=filenames) # type: ignore[arg-type] # TODO: fix in distutils stubs
_Distribution.parse_config_files(dist, filenames=filenames)
handlers = parse_configuration(
dist, dist.command_options, ignore_option_errors=ignore_option_errors
)
Expand Down
4 changes: 3 additions & 1 deletion setuptools/dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,10 @@ def check_packages(dist, attr, value):


if TYPE_CHECKING:
from typing_extensions import TypeAlias

# Work around a mypy issue where type[T] can't be used as a base: https://github.com/python/mypy/issues/10962
_Distribution = distutils.core.Distribution
_Distribution: TypeAlias = distutils.core.Distribution
else:
_Distribution = get_unpatched(distutils.core.Distribution)

Expand Down
39 changes: 22 additions & 17 deletions setuptools/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,35 @@
Provides exceptions used by setuptools modules.
"""

from __future__ import annotations

from typing import TYPE_CHECKING
from distutils import errors as _distutils_errors

if TYPE_CHECKING:
from typing_extensions import TypeAlias

# Re-export errors from distutils to facilitate the migration to PEP632

ByteCompileError = _distutils_errors.DistutilsByteCompileError
CCompilerError = _distutils_errors.CCompilerError
ClassError = _distutils_errors.DistutilsClassError
CompileError = _distutils_errors.CompileError
ExecError = _distutils_errors.DistutilsExecError
FileError = _distutils_errors.DistutilsFileError
InternalError = _distutils_errors.DistutilsInternalError
LibError = _distutils_errors.LibError
LinkError = _distutils_errors.LinkError
ModuleError = _distutils_errors.DistutilsModuleError
OptionError = _distutils_errors.DistutilsOptionError
PlatformError = _distutils_errors.DistutilsPlatformError
PreprocessError = _distutils_errors.PreprocessError
SetupError = _distutils_errors.DistutilsSetupError
TemplateError = _distutils_errors.DistutilsTemplateError
UnknownFileError = _distutils_errors.UnknownFileError
ByteCompileError: TypeAlias = _distutils_errors.DistutilsByteCompileError
CCompilerError: TypeAlias = _distutils_errors.CCompilerError
ClassError: TypeAlias = _distutils_errors.DistutilsClassError
CompileError: TypeAlias = _distutils_errors.CompileError
ExecError: TypeAlias = _distutils_errors.DistutilsExecError
FileError: TypeAlias = _distutils_errors.DistutilsFileError
InternalError: TypeAlias = _distutils_errors.DistutilsInternalError
LibError: TypeAlias = _distutils_errors.LibError
LinkError: TypeAlias = _distutils_errors.LinkError
ModuleError: TypeAlias = _distutils_errors.DistutilsModuleError
OptionError: TypeAlias = _distutils_errors.DistutilsOptionError
PlatformError: TypeAlias = _distutils_errors.DistutilsPlatformError
PreprocessError: TypeAlias = _distutils_errors.PreprocessError
SetupError: TypeAlias = _distutils_errors.DistutilsSetupError
TemplateError: TypeAlias = _distutils_errors.DistutilsTemplateError
UnknownFileError: TypeAlias = _distutils_errors.UnknownFileError

# The root error class in the hierarchy
BaseError = _distutils_errors.DistutilsError
BaseError: TypeAlias = _distutils_errors.DistutilsError


class InvalidConfigError(OptionError):
Expand Down
4 changes: 3 additions & 1 deletion setuptools/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ def _have_cython():
# for compatibility
have_pyrex = _have_cython
if TYPE_CHECKING:
from typing_extensions import TypeAlias

# Work around a mypy issue where type[T] can't be used as a base: https://github.com/python/mypy/issues/10962
_Extension = distutils.core.Extension
_Extension: TypeAlias = distutils.core.Extension
else:
_Extension = get_unpatched(distutils.core.Extension)

Expand Down

0 comments on commit 50407ee

Please sign in to comment.