Skip to content

Commit 96e9a67

Browse files
authored
Merge branch 'main' into update-ruff
2 parents 79ae47e + 4d4efe5 commit 96e9a67

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+307
-250
lines changed

.github/workflows/main.yml

+3
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ jobs:
6363
- platform: ubuntu-latest
6464
python: "3.10"
6565
distutils: stdlib
66+
# TODO: Re-evaluate the need for the following workaround
67+
exclude:
68+
- {python: "3.9", platform: "macos-latest"} # actions/setup-python#981
6669
runs-on: ${{ matrix.platform }}
6770
continue-on-error: ${{ matrix.python == '3.14' }}
6871
env:

docs/userguide/quickstart.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ Package discovery
199199
-----------------
200200
For projects that follow a simple directory structure, ``setuptools`` should be
201201
able to automatically detect all :term:`packages <package>` and
202-
:term:`namespaces <namespace>`. However, complex projects might include
202+
:term:`namespaces <namespace package>`. However, complex projects might include
203203
additional folders and supporting files that not necessarily should be
204204
distributed (or that can confuse ``setuptools`` auto discovery algorithm).
205205

mypy.ini

+3-3
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,16 @@ ignore_missing_imports = True
5858

5959
# - wheel: does not intend on exposing a programmatic API https://github.com/pypa/wheel/pull/610#issuecomment-2081687671
6060
[mypy-wheel.*]
61-
ignore_missing_imports = True
61+
follow_untyped_imports = True
6262
# - The following are not marked as py.typed:
6363
# - jaraco: Since mypy 1.12, the root name of the untyped namespace package gets called-out too
6464
# - jaraco.develop: https://github.com/jaraco/jaraco.develop/issues/22
6565
# - jaraco.envs: https://github.com/jaraco/jaraco.envs/issues/7
6666
# - jaraco.packaging: https://github.com/jaraco/jaraco.packaging/issues/20
6767
# - jaraco.path: https://github.com/jaraco/jaraco.path/issues/2
6868
# - jaraco.text: https://github.com/jaraco/jaraco.text/issues/17
69-
[mypy-jaraco,jaraco.develop,jaraco.envs,jaraco.packaging.*,jaraco.path,jaraco.text]
70-
ignore_missing_imports = True
69+
[mypy-jaraco,jaraco.develop.*,jaraco.envs,jaraco.packaging.*,jaraco.path,jaraco.text]
70+
follow_untyped_imports = True
7171

7272
# Even when excluding a module, import issues can show up due to following import
7373
# https://github.com/python/mypy/issues/11936#issuecomment-1466764006

newsfragments/4478.feature.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Synced with pypa/distutils@c97a3db2f including better support for free threaded Python on Windows (pypa/distutils#310), improved typing support, and linter accommodations.

pyproject.toml

+7-3
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ test = [
4444
"packaging>=24.2",
4545
"jaraco.envs>=2.2",
4646
"pytest-xdist>=3", # Dropped dependency on pytest-fork and py
47-
"jaraco.path>=3.2.0",
47+
"jaraco.path>=3.7.2", # Typing fixes
4848
"build[virtualenv]>=1.0.3",
4949
"filelock>=3.4.0",
5050
"ini2toml[lite]>=0.14",
@@ -102,7 +102,7 @@ core = [
102102

103103
# for distutils
104104
"jaraco.collections",
105-
"jaraco.functools>=4",
105+
"jaraco.functools >= 4",
106106
"packaging",
107107
"more_itertools",
108108
]
@@ -135,7 +135,7 @@ type = [
135135
# pin mypy version so a new version doesn't suddenly cause the CI to fail,
136136
# until types-setuptools is removed from typeshed.
137137
# For help with static-typing issues, or mypy update, ping @Avasam
138-
"mypy>=1.12,<1.14",
138+
"mypy==1.14.*",
139139
# Typing fixes in version newer than we require at runtime
140140
"importlib_metadata>=7.0.2; python_version < '3.10'",
141141
# Imported unconditionally in tools/finalize.py
@@ -210,6 +210,10 @@ exclude = [
210210
]
211211
namespaces = true
212212

213+
[tool.setuptools.exclude-package-data]
214+
# Remove ruff.toml when installing vendored packages (#4652)
215+
"*" = ["ruff.toml"]
216+
213217
[tool.distutils.sdist]
214218
formats = "zip"
215219

setuptools/_distutils/cmd.py

+25-2
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,21 @@
44
in the distutils.command package.
55
"""
66

7+
from __future__ import annotations
8+
79
import logging
810
import os
911
import re
1012
import sys
13+
from collections.abc import Callable
14+
from typing import Any, ClassVar, TypeVar, overload
1115

1216
from . import _modified, archive_util, dir_util, file_util, util
1317
from ._log import log
1418
from .errors import DistutilsOptionError
1519

20+
_CommandT = TypeVar("_CommandT", bound="Command")
21+
1622

1723
class Command:
1824
"""Abstract base class for defining command classes, the "worker bees"
@@ -44,7 +50,14 @@ class Command:
4450
# 'sub_commands' is usually defined at the *end* of a class, because
4551
# predicates can be unbound methods, so they must already have been
4652
# defined. The canonical example is the "install" command.
47-
sub_commands = []
53+
sub_commands: ClassVar[ # Any to work around variance issues
54+
list[tuple[str, Callable[[Any], bool] | None]]
55+
] = []
56+
57+
user_options: ClassVar[
58+
# Specifying both because list is invariant. Avoids mypy override assignment issues
59+
list[tuple[str, str, str]] | list[tuple[str, str | None, str]]
60+
] = []
4861

4962
# -- Creation/initialization methods -------------------------------
5063

@@ -305,7 +318,17 @@ def get_finalized_command(self, command, create=True):
305318

306319
# XXX rename to 'get_reinitialized_command()'? (should do the
307320
# same in dist.py, if so)
308-
def reinitialize_command(self, command, reinit_subcommands=False):
321+
@overload
322+
def reinitialize_command(
323+
self, command: str, reinit_subcommands: bool = False
324+
) -> Command: ...
325+
@overload
326+
def reinitialize_command(
327+
self, command: _CommandT, reinit_subcommands: bool = False
328+
) -> _CommandT: ...
329+
def reinitialize_command(
330+
self, command: str | Command, reinit_subcommands=False
331+
) -> Command:
309332
return self.distribution.reinitialize_command(command, reinit_subcommands)
310333

311334
def run_command(self, command):

setuptools/_distutils/command/bdist.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import os
77
import warnings
8+
from typing import ClassVar
89

910
from ..core import Command
1011
from ..errors import DistutilsOptionError, DistutilsPlatformError
@@ -23,7 +24,7 @@ def show_formats():
2324
pretty_printer.print_help("List of available distribution formats:")
2425

2526

26-
class ListCompat(dict):
27+
class ListCompat(dict[str, tuple[str, str]]):
2728
# adapter to allow for Setuptools compatibility in format_commands
2829
def append(self, item):
2930
warnings.warn(
@@ -70,7 +71,7 @@ class bdist(Command):
7071
]
7172

7273
# The following commands do not take a format option from bdist
73-
no_format_option = ('bdist_rpm',)
74+
no_format_option: ClassVar[tuple[str, ...]] = ('bdist_rpm',)
7475

7576
# This won't do in reality: will need to distinguish RPM-ish Linux,
7677
# Debian-ish Linux, Solaris, FreeBSD, ..., Windows, Mac OS.

setuptools/_distutils/command/build.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ def finalize_options(self): # noqa: C901
113113
self.build_temp = os.path.join(self.build_base, 'temp' + plat_specifier)
114114
if self.build_scripts is None:
115115
self.build_scripts = os.path.join(
116-
self.build_base, 'scripts-%d.%d' % sys.version_info[:2]
116+
self.build_base,
117+
f'scripts-{sys.version_info.major}.{sys.version_info.minor}',
117118
)
118119

119120
if self.executable is None and sys.executable:

setuptools/_distutils/command/build_clib.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import os
1818
from distutils._log import log
19+
from typing import ClassVar
1920

2021
from ..core import Command
2122
from ..errors import DistutilsSetupError
@@ -31,7 +32,7 @@ def show_compilers():
3132
class build_clib(Command):
3233
description = "build C/C++ libraries used by Python extensions"
3334

34-
user_options = [
35+
user_options: ClassVar[list[tuple[str, str, str]]] = [
3536
('build-clib=', 'b', "directory to build C/C++ libraries to"),
3637
('build-temp=', 't', "directory to put temporary build by-products"),
3738
('debug', 'g', "compile with debugging information"),
@@ -138,8 +139,7 @@ def check_library_list(self, libraries):
138139

139140
if '/' in name or (os.sep != '/' and os.sep in name):
140141
raise DistutilsSetupError(
141-
f"bad library name '{lib[0]}': "
142-
"may not contain directory separators"
142+
f"bad library name '{lib[0]}': may not contain directory separators"
143143
)
144144

145145
if not isinstance(build_info, dict):

setuptools/_distutils/command/build_ext.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
)
2424
from ..extension import Extension
2525
from ..sysconfig import customize_compiler, get_config_h_filename, get_python_version
26-
from ..util import get_platform, is_mingw
26+
from ..util import get_platform, is_freethreaded, is_mingw
2727

2828
# An extension name is just a dot-separated list of Python NAMEs (ie.
2929
# the same as a fully-qualified module name).
@@ -333,6 +333,12 @@ def run(self): # noqa: C901
333333
if os.name == 'nt' and self.plat_name != get_platform():
334334
self.compiler.initialize(self.plat_name)
335335

336+
# The official Windows free threaded Python installer doesn't set
337+
# Py_GIL_DISABLED because its pyconfig.h is shared with the
338+
# default build, so define it here (pypa/setuptools#4662).
339+
if os.name == 'nt' and is_freethreaded():
340+
self.compiler.define_macro('Py_GIL_DISABLED', '1')
341+
336342
# And make sure that any compile/link-related options (which might
337343
# come from the command-line or from the setup script) are set in
338344
# that CCompiler object -- that way, they automatically apply to
@@ -437,8 +443,7 @@ def check_extensions_list(self, extensions): # noqa: C901
437443
for macro in macros:
438444
if not (isinstance(macro, tuple) and len(macro) in (1, 2)):
439445
raise DistutilsSetupError(
440-
"'macros' element of build info dict "
441-
"must be 1- or 2-tuple"
446+
"'macros' element of build info dict must be 1- or 2-tuple"
442447
)
443448
if len(macro) == 1:
444449
ext.undef_macros.append(macro[0])
@@ -666,8 +671,7 @@ def find_swig(self):
666671
return "swig.exe"
667672
else:
668673
raise DistutilsPlatformError(
669-
"I don't know how to find (much less run) SWIG "
670-
f"on platform '{os.name}'"
674+
f"I don't know how to find (much less run) SWIG on platform '{os.name}'"
671675
)
672676

673677
# -- Name generators -----------------------------------------------

setuptools/_distutils/command/build_scripts.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from distutils import sysconfig
99
from distutils._log import log
1010
from stat import ST_MODE
11+
from typing import ClassVar
1112

1213
from .._modified import newer
1314
from ..core import Command
@@ -25,7 +26,7 @@
2526
class build_scripts(Command):
2627
description = "\"build\" scripts (copy and fixup #! line)"
2728

28-
user_options = [
29+
user_options: ClassVar[list[tuple[str, str, str]]] = [
2930
('build-dir=', 'd', "directory to \"build\" (copy) to"),
3031
('force', 'f', "forcibly build everything (ignore file timestamps"),
3132
('executable=', 'e', "specify final destination interpreter path"),

setuptools/_distutils/command/check.py

+3-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""
55

66
import contextlib
7+
from typing import ClassVar
78

89
from ..core import Command
910
from ..errors import DistutilsSetupError
@@ -41,15 +42,12 @@ class check(Command):
4142
"""This command checks the meta-data of the package."""
4243

4344
description = "perform some checks on the package"
44-
user_options = [
45+
user_options: ClassVar[list[tuple[str, str, str]]] = [
4546
('metadata', 'm', 'Verify meta-data'),
4647
(
4748
'restructuredtext',
4849
'r',
49-
(
50-
'Checks if long string meta-data syntax '
51-
'are reStructuredText-compliant'
52-
),
50+
'Checks if long string meta-data syntax are reStructuredText-compliant',
5351
),
5452
('strict', 's', 'Will exit with an error if a check fails'),
5553
]

setuptools/_distutils/command/command_template

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,18 @@ Implements the Distutils 'x' command.
88
__revision__ = "$Id$"
99

1010
from distutils.core import Command
11+
from typing import ClassVar
1112

1213

1314
class x(Command):
14-
1515
# Brief (40-50 characters) description of the command
1616
description = ""
1717

1818
# List of option tuples: long name, short name (None if no short
1919
# name), and help string.
20-
user_options = [('', '',
21-
""),
22-
]
20+
user_options: ClassVar[list[tuple[str, str, str]]] = [
21+
('', '', ""),
22+
]
2323

2424
def initialize_options(self):
2525
self. = None

setuptools/_distutils/command/install.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -407,8 +407,8 @@ def finalize_options(self): # noqa: C901
407407
'dist_version': self.distribution.get_version(),
408408
'dist_fullname': self.distribution.get_fullname(),
409409
'py_version': py_version,
410-
'py_version_short': '%d.%d' % sys.version_info[:2],
411-
'py_version_nodot': '%d%d' % sys.version_info[:2],
410+
'py_version_short': f'{sys.version_info.major}.{sys.version_info.minor}',
411+
'py_version_nodot': f'{sys.version_info.major}{sys.version_info.minor}',
412412
'sys_prefix': prefix,
413413
'prefix': prefix,
414414
'sys_exec_prefix': exec_prefix,

setuptools/_distutils/command/install_data.py

+2-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import functools
1111
import os
12-
from typing import Iterable
12+
from collections.abc import Iterable
1313

1414
from ..core import Command
1515
from ..util import change_root, convert_path
@@ -22,8 +22,7 @@ class install_data(Command):
2222
(
2323
'install-dir=',
2424
'd',
25-
"base directory for installing data files "
26-
"[default: installation base dir]",
25+
"base directory for installing data files [default: installation base dir]",
2726
),
2827
('root=', None, "install everything relative to this alternate root directory"),
2928
('force', 'f', "force installation (overwrite existing files)"),

setuptools/_distutils/command/install_egg_info.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import os
99
import re
1010
import sys
11+
from typing import ClassVar
1112

1213
from .. import dir_util
1314
from .._log import log
@@ -18,7 +19,7 @@ class install_egg_info(Command):
1819
"""Install an .egg-info file for the package"""
1920

2021
description = "Install package's PKG-INFO metadata as an .egg-info file"
21-
user_options = [
22+
user_options: ClassVar[list[tuple[str, str, str]]] = [
2223
('install-dir=', 'd', "directory to install to"),
2324
]
2425

@@ -31,11 +32,9 @@ def basename(self):
3132
Allow basename to be overridden by child class.
3233
Ref pypa/distutils#2.
3334
"""
34-
return "%s-%s-py%d.%d.egg-info" % (
35-
to_filename(safe_name(self.distribution.get_name())),
36-
to_filename(safe_version(self.distribution.get_version())),
37-
*sys.version_info[:2],
38-
)
35+
name = to_filename(safe_name(self.distribution.get_name()))
36+
version = to_filename(safe_version(self.distribution.get_version()))
37+
return f"{name}-{version}-py{sys.version_info.major}.{sys.version_info.minor}.egg-info"
3938

4039
def finalize_options(self):
4140
self.set_undefined_options('install_lib', ('install_dir', 'install_dir'))

setuptools/_distutils/command/install_headers.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33
Implements the Distutils 'install_headers' command, to install C/C++ header
44
files to the Python include directory."""
55

6+
from typing import ClassVar
7+
68
from ..core import Command
79

810

911
# XXX force is never used
1012
class install_headers(Command):
1113
description = "install C/C++ header files"
1214

13-
user_options = [
15+
user_options: ClassVar[list[tuple[str, str, str]]] = [
1416
('install-dir=', 'd', "directory to install header files to"),
1517
('force', 'f', "force installation (overwrite existing files)"),
1618
]

0 commit comments

Comments
 (0)