Skip to content

Commit

Permalink
Merge with pypa/distutils.
Browse files Browse the repository at this point in the history
  • Loading branch information
jaraco committed Jan 5, 2025
2 parents 0ebc351 + ff11eed commit e94ce0d
Show file tree
Hide file tree
Showing 44 changed files with 312 additions and 257 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ core = [

# for distutils
"jaraco.collections",
"jaraco.functools>=4",
"jaraco.functools >= 4",
"packaging",
"more_itertools",
]
Expand Down
39 changes: 23 additions & 16 deletions setuptools/_distutils/ccompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
for the Distutils compiler abstraction model."""

import os
import pathlib
import re
import sys
import types
Expand Down Expand Up @@ -969,27 +970,33 @@ def out_extensions(self):
return dict.fromkeys(self.src_extensions, self.obj_extension)

def _make_out_path(self, output_dir, strip_dir, src_name):
base, ext = os.path.splitext(src_name)
base = self._make_relative(base)
return self._make_out_path_exts(
output_dir, strip_dir, src_name, self.out_extensions
)

@classmethod
def _make_out_path_exts(cls, output_dir, strip_dir, src_name, extensions):
r"""
>>> exts = {'.c': '.o'}
>>> CCompiler._make_out_path_exts('.', False, '/foo/bar.c', exts).replace('\\', '/')
'./foo/bar.o'
>>> CCompiler._make_out_path_exts('.', True, '/foo/bar.c', exts).replace('\\', '/')
'./bar.o'
"""
src = pathlib.PurePath(src_name)
# Ensure base is relative to honor output_dir (python/cpython#37775).
base = cls._make_relative(src)
try:
new_ext = self.out_extensions[ext]
new_ext = extensions[src.suffix]
except LookupError:
raise UnknownFileError(f"unknown file type '{ext}' (from '{src_name}')")
raise UnknownFileError(f"unknown file type '{src.suffix}' (from '{src}')")
if strip_dir:
base = os.path.basename(base)
return os.path.join(output_dir, base + new_ext)
base = pathlib.PurePath(base.name)
return os.path.join(output_dir, base.with_suffix(new_ext))

@staticmethod
def _make_relative(base):
"""
In order to ensure that a filename always honors the
indicated output_dir, make sure it's relative.
Ref python/cpython#37775.
"""
# Chop off the drive
no_drive = os.path.splitdrive(base)[1]
# If abs, chop off leading /
return no_drive[os.path.isabs(no_drive) :]
def _make_relative(base: pathlib.Path):
return base.relative_to(base.anchor)

def shared_object_filename(self, basename, strip_dir=False, output_dir=''):
assert output_dir is not None
Expand Down
27 changes: 25 additions & 2 deletions setuptools/_distutils/cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@
in the distutils.command package.
"""

from __future__ import annotations

import logging
import os
import re
import sys
from collections.abc import Callable
from typing import Any, ClassVar, TypeVar, overload

from . import _modified, archive_util, dir_util, file_util, util
from ._log import log
from .errors import DistutilsOptionError

_CommandT = TypeVar("_CommandT", bound="Command")


class Command:
"""Abstract base class for defining command classes, the "worker bees"
Expand Down Expand Up @@ -44,7 +50,14 @@ class Command:
# 'sub_commands' is usually defined at the *end* of a class, because
# predicates can be unbound methods, so they must already have been
# defined. The canonical example is the "install" command.
sub_commands = []
sub_commands: ClassVar[ # Any to work around variance issues
list[tuple[str, Callable[[Any], bool] | None]]
] = []

user_options: ClassVar[
# Specifying both because list is invariant. Avoids mypy override assignment issues
list[tuple[str, str, str]] | list[tuple[str, str | None, str]]
] = []

# -- Creation/initialization methods -------------------------------

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

# XXX rename to 'get_reinitialized_command()'? (should do the
# same in dist.py, if so)
def reinitialize_command(self, command, reinit_subcommands=False):
@overload
def reinitialize_command(
self, command: str, reinit_subcommands: bool = False
) -> Command: ...
@overload
def reinitialize_command(
self, command: _CommandT, reinit_subcommands: bool = False
) -> _CommandT: ...
def reinitialize_command(
self, command: str | Command, reinit_subcommands=False
) -> Command:
return self.distribution.reinitialize_command(command, reinit_subcommands)

def run_command(self, command):
Expand Down
5 changes: 3 additions & 2 deletions setuptools/_distutils/command/bdist.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import os
import warnings
from typing import ClassVar

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


class ListCompat(dict):
class ListCompat(dict[str, tuple[str, str]]):
# adapter to allow for Setuptools compatibility in format_commands
def append(self, item):
warnings.warn(
Expand Down Expand Up @@ -70,7 +71,7 @@ class bdist(Command):
]

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

# This won't do in reality: will need to distinguish RPM-ish Linux,
# Debian-ish Linux, Solaris, FreeBSD, ..., Windows, Mac OS.
Expand Down
3 changes: 2 additions & 1 deletion setuptools/_distutils/command/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ def finalize_options(self): # noqa: C901
self.build_temp = os.path.join(self.build_base, 'temp' + plat_specifier)
if self.build_scripts is None:
self.build_scripts = os.path.join(
self.build_base, 'scripts-%d.%d' % sys.version_info[:2]
self.build_base,
f'scripts-{sys.version_info.major}.{sys.version_info.minor}',
)

if self.executable is None and sys.executable:
Expand Down
6 changes: 3 additions & 3 deletions setuptools/_distutils/command/build_clib.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import os
from distutils._log import log
from typing import ClassVar

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

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

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

if not isinstance(build_info, dict):
Expand Down
14 changes: 9 additions & 5 deletions setuptools/_distutils/command/build_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
)
from ..extension import Extension
from ..sysconfig import customize_compiler, get_config_h_filename, get_python_version
from ..util import get_platform, is_mingw
from ..util import get_platform, is_freethreaded, is_mingw

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

# The official Windows free threaded Python installer doesn't set
# Py_GIL_DISABLED because its pyconfig.h is shared with the
# default build, so define it here (pypa/setuptools#4662).
if os.name == 'nt' and is_freethreaded():
self.compiler.define_macro('Py_GIL_DISABLED', '1')

# And make sure that any compile/link-related options (which might
# come from the command-line or from the setup script) are set in
# that CCompiler object -- that way, they automatically apply to
Expand Down Expand Up @@ -437,8 +443,7 @@ def check_extensions_list(self, extensions): # noqa: C901
for macro in macros:
if not (isinstance(macro, tuple) and len(macro) in (1, 2)):
raise DistutilsSetupError(
"'macros' element of build info dict "
"must be 1- or 2-tuple"
"'macros' element of build info dict must be 1- or 2-tuple"
)
if len(macro) == 1:
ext.undef_macros.append(macro[0])
Expand Down Expand Up @@ -666,8 +671,7 @@ def find_swig(self):
return "swig.exe"
else:
raise DistutilsPlatformError(
"I don't know how to find (much less run) SWIG "
f"on platform '{os.name}'"
f"I don't know how to find (much less run) SWIG on platform '{os.name}'"
)

# -- Name generators -----------------------------------------------
Expand Down
3 changes: 2 additions & 1 deletion setuptools/_distutils/command/build_scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from distutils import sysconfig
from distutils._log import log
from stat import ST_MODE
from typing import ClassVar

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

user_options = [
user_options: ClassVar[list[tuple[str, str, str]]] = [
('build-dir=', 'd', "directory to \"build\" (copy) to"),
('force', 'f', "forcibly build everything (ignore file timestamps"),
('executable=', 'e', "specify final destination interpreter path"),
Expand Down
8 changes: 3 additions & 5 deletions setuptools/_distutils/command/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""

import contextlib
from typing import ClassVar

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

description = "perform some checks on the package"
user_options = [
user_options: ClassVar[list[tuple[str, str, str]]] = [
('metadata', 'm', 'Verify meta-data'),
(
'restructuredtext',
'r',
(
'Checks if long string meta-data syntax '
'are reStructuredText-compliant'
),
'Checks if long string meta-data syntax are reStructuredText-compliant',
),
('strict', 's', 'Will exit with an error if a check fails'),
]
Expand Down
8 changes: 4 additions & 4 deletions setuptools/_distutils/command/command_template
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ Implements the Distutils 'x' command.
__revision__ = "$Id$"

from distutils.core import Command
from typing import ClassVar


class x(Command):

# Brief (40-50 characters) description of the command
description = ""

# List of option tuples: long name, short name (None if no short
# name), and help string.
user_options = [('', '',
""),
]
user_options: ClassVar[list[tuple[str, str, str]]] = [
('', '', ""),
]

def initialize_options(self):
self. = None
Expand Down
4 changes: 2 additions & 2 deletions setuptools/_distutils/command/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,8 @@ def finalize_options(self): # noqa: C901
'dist_version': self.distribution.get_version(),
'dist_fullname': self.distribution.get_fullname(),
'py_version': py_version,
'py_version_short': '%d.%d' % sys.version_info[:2],
'py_version_nodot': '%d%d' % sys.version_info[:2],
'py_version_short': f'{sys.version_info.major}.{sys.version_info.minor}',
'py_version_nodot': f'{sys.version_info.major}{sys.version_info.minor}',
'sys_prefix': prefix,
'prefix': prefix,
'sys_exec_prefix': exec_prefix,
Expand Down
5 changes: 2 additions & 3 deletions setuptools/_distutils/command/install_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import functools
import os
from typing import Iterable
from collections.abc import Iterable

from ..core import Command
from ..util import change_root, convert_path
Expand All @@ -22,8 +22,7 @@ class install_data(Command):
(
'install-dir=',
'd',
"base directory for installing data files "
"[default: installation base dir]",
"base directory for installing data files [default: installation base dir]",
),
('root=', None, "install everything relative to this alternate root directory"),
('force', 'f', "force installation (overwrite existing files)"),
Expand Down
11 changes: 5 additions & 6 deletions setuptools/_distutils/command/install_egg_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import os
import re
import sys
from typing import ClassVar

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

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

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

def finalize_options(self):
self.set_undefined_options('install_lib', ('install_dir', 'install_dir'))
Expand Down
4 changes: 3 additions & 1 deletion setuptools/_distutils/command/install_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
Implements the Distutils 'install_headers' command, to install C/C++ header
files to the Python include directory."""

from typing import ClassVar

from ..core import Command


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

user_options = [
user_options: ClassVar[list[tuple[str, str, str]]] = [
('install-dir=', 'd', "directory to install header files to"),
('force', 'f', "force installation (overwrite existing files)"),
]
Expand Down
Loading

0 comments on commit e94ce0d

Please sign in to comment.