Skip to content

Commit 6928048

Browse files
authored
Merge branch 'main' into debt/msvc-monkey
2 parents ac62989 + 11a6b59 commit 6928048

30 files changed

+155
-1780
lines changed

MANIFEST.in

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,3 @@ include tox.ini
1919
include setuptools/tests/config/setupcfg_examples.txt
2020
include setuptools/config/*.schema.json
2121
global-exclude *.py[cod] __pycache__
22-
prune .tox

newsfragments/4593.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Reraise error from ``setuptools.command.easy_install.auto_chmod`` instead of nonsensical ``TypeError: 'Exception' object is not subscriptable`` -- by :user:`Avasam`

newsfragments/4603.feature.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Automatically exclude ``.tox|.nox|.venv`` directories from ``sdist``.

newsfragments/4606.removal.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Synced with pypa/distutils@58fe058e4, including consolidating Visual Studio 2017 support (#4600, pypa/distutils#289), removal of deprecated legacy MSVC compiler modules (pypa/distutils#287), suppressing of errors when the home directory is missing (pypa/distutils#278), removal of wininst binaries (pypa/distutils#282).

setuptools/_distutils/_msvccompiler.py

Lines changed: 74 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
LibError,
3434
LinkError,
3535
)
36-
from .util import get_platform
36+
from .util import get_host_platform, get_platform
3737

3838

3939
def _find_vc2015():
@@ -79,32 +79,40 @@ def _find_vc2017():
7979
if not root:
8080
return None, None
8181

82-
try:
83-
path = subprocess.check_output(
84-
[
85-
os.path.join(
86-
root, "Microsoft Visual Studio", "Installer", "vswhere.exe"
87-
),
88-
"-latest",
89-
"-prerelease",
90-
"-requires",
91-
"Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
92-
"-property",
93-
"installationPath",
94-
"-products",
95-
"*",
96-
],
97-
encoding="mbcs",
98-
errors="strict",
99-
).strip()
100-
except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
101-
return None, None
82+
variant = 'arm64' if get_platform() == 'win-arm64' else 'x86.x64'
83+
suitable_components = (
84+
f"Microsoft.VisualStudio.Component.VC.Tools.{variant}",
85+
"Microsoft.VisualStudio.Workload.WDExpress",
86+
)
87+
88+
for component in suitable_components:
89+
# Workaround for `-requiresAny` (only available on VS 2017 > 15.6)
90+
with contextlib.suppress(
91+
subprocess.CalledProcessError, OSError, UnicodeDecodeError
92+
):
93+
path = (
94+
subprocess.check_output([
95+
os.path.join(
96+
root, "Microsoft Visual Studio", "Installer", "vswhere.exe"
97+
),
98+
"-latest",
99+
"-prerelease",
100+
"-requires",
101+
component,
102+
"-property",
103+
"installationPath",
104+
"-products",
105+
"*",
106+
])
107+
.decode(encoding="mbcs", errors="strict")
108+
.strip()
109+
)
102110

103-
path = os.path.join(path, "VC", "Auxiliary", "Build")
104-
if os.path.isdir(path):
105-
return 15, path
111+
path = os.path.join(path, "VC", "Auxiliary", "Build")
112+
if os.path.isdir(path):
113+
return 15, path
106114

107-
return None, None
115+
return None, None # no suitable component found
108116

109117

110118
PLAT_SPEC_TO_RUNTIME = {
@@ -140,7 +148,11 @@ def _get_vc_env(plat_spec):
140148

141149
vcvarsall, _ = _find_vcvarsall(plat_spec)
142150
if not vcvarsall:
143-
raise DistutilsPlatformError("Unable to find vcvarsall.bat")
151+
raise DistutilsPlatformError(
152+
'Microsoft Visual C++ 14.0 or greater is required. '
153+
'Get it with "Microsoft C++ Build Tools": '
154+
'https://visualstudio.microsoft.com/visual-cpp-build-tools/'
155+
)
144156

145157
try:
146158
out = subprocess.check_output(
@@ -178,17 +190,43 @@ def _find_exe(exe, paths=None):
178190
return exe
179191

180192

181-
# A map keyed by get_platform() return values to values accepted by
182-
# 'vcvarsall.bat'. Always cross-compile from x86 to work with the
183-
# lighter-weight MSVC installs that do not include native 64-bit tools.
184-
PLAT_TO_VCVARS = {
193+
_vcvars_names = {
185194
'win32': 'x86',
186-
'win-amd64': 'x86_amd64',
187-
'win-arm32': 'x86_arm',
188-
'win-arm64': 'x86_arm64',
195+
'win-amd64': 'amd64',
196+
'win-arm32': 'arm',
197+
'win-arm64': 'arm64',
189198
}
190199

191200

201+
def _get_vcvars_spec(host_platform, platform):
202+
"""
203+
Given a host platform and platform, determine the spec for vcvarsall.
204+
205+
Uses the native MSVC host if the host platform would need expensive
206+
emulation for x86.
207+
208+
>>> _get_vcvars_spec('win-arm64', 'win32')
209+
'arm64_x86'
210+
>>> _get_vcvars_spec('win-arm64', 'win-amd64')
211+
'arm64_amd64'
212+
213+
Otherwise, always cross-compile from x86 to work with the
214+
lighter-weight MSVC installs that do not include native 64-bit tools.
215+
216+
>>> _get_vcvars_spec('win32', 'win32')
217+
'x86'
218+
>>> _get_vcvars_spec('win-arm32', 'win-arm32')
219+
'x86_arm'
220+
>>> _get_vcvars_spec('win-amd64', 'win-arm64')
221+
'x86_arm64'
222+
"""
223+
if host_platform != 'win-arm64':
224+
host_platform = 'win32'
225+
vc_hp = _vcvars_names[host_platform]
226+
vc_plat = _vcvars_names[platform]
227+
return vc_hp if vc_hp == vc_plat else f'{vc_hp}_{vc_plat}'
228+
229+
192230
class MSVCCompiler(CCompiler):
193231
"""Concrete class that implements an interface to Microsoft Visual C++,
194232
as defined by the CCompiler abstract class."""
@@ -242,13 +280,12 @@ def initialize(self, plat_name=None):
242280
if plat_name is None:
243281
plat_name = get_platform()
244282
# sanity check for platforms to prevent obscure errors later.
245-
if plat_name not in PLAT_TO_VCVARS:
283+
if plat_name not in _vcvars_names:
246284
raise DistutilsPlatformError(
247-
f"--plat-name must be one of {tuple(PLAT_TO_VCVARS)}"
285+
f"--plat-name must be one of {tuple(_vcvars_names)}"
248286
)
249287

250-
# Get the vcvarsall.bat spec for the requested platform.
251-
plat_spec = PLAT_TO_VCVARS[plat_name]
288+
plat_spec = _get_vcvars_spec(get_host_platform(), get_platform())
252289

253290
vc_env = _get_vc_env(plat_spec)
254291
if not vc_env:

setuptools/_distutils/archive_util.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,8 +266,7 @@ def make_archive(
266266
raise ValueError(f"unknown archive format '{format}'")
267267

268268
func = format_info[0]
269-
for arg, val in format_info[1]:
270-
kwargs[arg] = val
269+
kwargs.update(format_info[1])
271270

272271
if format != 'zip':
273272
kwargs['owner'] = owner

setuptools/_distutils/command/build_ext.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,8 +638,7 @@ def swig_sources(self, sources, extension):
638638

639639
# Do not override commandline arguments
640640
if not self.swig_opts:
641-
for o in extension.swig_opts:
642-
swig_cmd.append(o)
641+
swig_cmd.extend(extension.swig_opts)
643642

644643
for source in swig_sources:
645644
target = swig_targets[source]

setuptools/_distutils/command/install.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ def create_home_path(self):
680680
if not self.user:
681681
return
682682
home = convert_path(os.path.expanduser("~"))
683-
for _name, path in self.config_vars.items():
683+
for path in self.config_vars.values():
684684
if str(path).startswith(home) and not os.path.isdir(path):
685685
self.debug_print(f"os.makedirs('{path}', 0o700)")
686686
os.makedirs(path, 0o700)

setuptools/_distutils/command/install_lib.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ def finalize_options(self):
8181
if not isinstance(self.optimize, int):
8282
try:
8383
self.optimize = int(self.optimize)
84-
if self.optimize not in (0, 1, 2):
85-
raise AssertionError
86-
except (ValueError, AssertionError):
84+
except ValueError:
85+
pass
86+
if self.optimize not in (0, 1, 2):
8787
raise DistutilsOptionError("optimize must be 0, 1, or 2")
8888

8989
def run(self):
Binary file not shown.
-187 KB
Binary file not shown.
Binary file not shown.
-448 KB
Binary file not shown.
-60 KB
Binary file not shown.
-64 KB
Binary file not shown.
-60 KB
Binary file not shown.
Binary file not shown.
-192 KB
Binary file not shown.

setuptools/_distutils/cygwinccompiler.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,7 @@ def link(
172172

173173
# Generate .def file
174174
contents = [f"LIBRARY {os.path.basename(output_filename)}", "EXPORTS"]
175-
for sym in export_symbols:
176-
contents.append(sym)
175+
contents.extend(export_symbols)
177176
self.execute(write_file, (def_file, contents), f"writing {def_file}")
178177

179178
# next add options for def-file
@@ -309,6 +308,9 @@ def check_config_h():
309308
fn = sysconfig.get_config_h_filename()
310309
try:
311310
config_h = pathlib.Path(fn).read_text(encoding='utf-8')
311+
except OSError as exc:
312+
return (CONFIG_H_UNCERTAIN, f"couldn't read '{fn}': {exc.strerror}")
313+
else:
312314
substring = '__GNUC__'
313315
if substring in config_h:
314316
code = CONFIG_H_OK
@@ -317,8 +319,6 @@ def check_config_h():
317319
code = CONFIG_H_NOTOK
318320
mention_inflected = 'does not mention'
319321
return code, f"{fn!r} {mention_inflected} {substring!r}"
320-
except OSError as exc:
321-
return (CONFIG_H_UNCERTAIN, f"couldn't read '{fn}': {exc.strerror}")
322322

323323

324324
def is_cygwincc(cc):

setuptools/_distutils/dist.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,12 @@
1010
import pathlib
1111
import re
1212
import sys
13+
import warnings
1314
from collections.abc import Iterable
1415
from email import message_from_file
1516

16-
from ._vendor.packaging.utils import canonicalize_name, canonicalize_version
17-
18-
try:
19-
import warnings
20-
except ImportError:
21-
warnings = None
22-
2317
from ._log import log
18+
from ._vendor.packaging.utils import canonicalize_name, canonicalize_version
2419
from .debug import DEBUG
2520
from .errors import (
2621
DistutilsArgError,
@@ -249,10 +244,7 @@ def __init__(self, attrs=None): # noqa: C901
249244
attrs['license'] = attrs['licence']
250245
del attrs['licence']
251246
msg = "'licence' distribution option is deprecated; use 'license'"
252-
if warnings is not None:
253-
warnings.warn(msg)
254-
else:
255-
sys.stderr.write(msg + "\n")
247+
warnings.warn(msg)
256248

257249
# Now work on the rest of the attributes. Any attribute that's
258250
# not already defined is invalid!
@@ -354,7 +346,8 @@ def _gen_paths(self):
354346
prefix = '.' * (os.name == 'posix')
355347
filename = prefix + 'pydistutils.cfg'
356348
if self.want_user_cfg:
357-
yield pathlib.Path('~').expanduser() / filename
349+
with contextlib.suppress(RuntimeError):
350+
yield pathlib.Path('~').expanduser() / filename
358351

359352
# All platforms support local setup.cfg
360353
yield pathlib.Path('setup.cfg')
@@ -741,9 +734,7 @@ def print_commands(self):
741734
import distutils.command
742735

743736
std_commands = distutils.command.__all__
744-
is_std = set()
745-
for cmd in std_commands:
746-
is_std.add(cmd)
737+
is_std = set(std_commands)
747738

748739
extra_commands = [cmd for cmd in self.cmdclass.keys() if cmd not in is_std]
749740

@@ -769,9 +760,7 @@ def get_command_list(self):
769760
import distutils.command
770761

771762
std_commands = distutils.command.__all__
772-
is_std = set()
773-
for cmd in std_commands:
774-
is_std.add(cmd)
763+
is_std = set(std_commands)
775764

776765
extra_commands = [cmd for cmd in self.cmdclass.keys() if cmd not in is_std]
777766

setuptools/_distutils/extension.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def __init__(
105105
**kw, # To catch unknown keywords
106106
):
107107
if not isinstance(name, str):
108-
raise AssertionError("'name' must be a string")
108+
raise AssertionError("'name' must be a string") # noqa: TRY004
109109
if not (
110110
isinstance(sources, list)
111111
and all(isinstance(v, (str, os.PathLike)) for v in sources)

setuptools/_distutils/file_util.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,13 @@ def copy_file( # noqa: C901
140140
if not (os.path.exists(dst) and os.path.samefile(src, dst)):
141141
try:
142142
os.link(src, dst)
143-
return (dst, 1)
144143
except OSError:
145144
# If hard linking fails, fall back on copying file
146145
# (some special filesystems don't support hard linking
147146
# even under Unix, see issue #8876).
148147
pass
148+
else:
149+
return (dst, 1)
149150
elif link == 'sym':
150151
if not (os.path.exists(dst) and os.path.samefile(src, dst)):
151152
os.symlink(src, dst)

0 commit comments

Comments
 (0)