update
This commit is contained in:
@@ -10,74 +10,74 @@ __ https://setuptools.pypa.io/en/latest/deprecated/easy_install.html
|
||||
|
||||
"""
|
||||
|
||||
from glob import glob
|
||||
from distutils.util import get_platform
|
||||
from distutils.util import convert_path, subst_vars
|
||||
from distutils.errors import (
|
||||
DistutilsArgError,
|
||||
DistutilsOptionError,
|
||||
DistutilsError,
|
||||
DistutilsPlatformError,
|
||||
)
|
||||
from distutils import log, dir_util
|
||||
from distutils.command.build_scripts import first_line_re
|
||||
from distutils.spawn import find_executable
|
||||
from distutils.command import install
|
||||
import sys
|
||||
from __future__ import annotations
|
||||
|
||||
import configparser
|
||||
import contextlib
|
||||
import io
|
||||
import os
|
||||
import zipimport
|
||||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
import re
|
||||
import stat
|
||||
import random
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import site
|
||||
import stat
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
import sysconfig
|
||||
import tempfile
|
||||
import textwrap
|
||||
import warnings
|
||||
import site
|
||||
import struct
|
||||
import contextlib
|
||||
import subprocess
|
||||
import shlex
|
||||
import io
|
||||
import configparser
|
||||
import sysconfig
|
||||
|
||||
|
||||
import zipfile
|
||||
import zipimport
|
||||
from collections.abc import Iterable
|
||||
from glob import glob
|
||||
from sysconfig import get_path
|
||||
from typing import TYPE_CHECKING, Callable, TypeVar
|
||||
|
||||
from setuptools import Command
|
||||
from setuptools.sandbox import run_setup
|
||||
from setuptools.command import setopt
|
||||
from setuptools.archive_util import unpack_archive
|
||||
from setuptools.package_index import (
|
||||
PackageIndex,
|
||||
parse_requirement_arg,
|
||||
URL_SCHEME,
|
||||
)
|
||||
from setuptools.command import bdist_egg, egg_info
|
||||
from setuptools.warnings import SetuptoolsDeprecationWarning, SetuptoolsWarning
|
||||
from setuptools.wheel import Wheel
|
||||
from jaraco.text import yield_lines
|
||||
|
||||
import pkg_resources
|
||||
from pkg_resources import (
|
||||
DEVELOP_DIST,
|
||||
Distribution,
|
||||
DistributionNotFound,
|
||||
EggMetadata,
|
||||
Environment,
|
||||
PathMetadata,
|
||||
Requirement,
|
||||
VersionConflict,
|
||||
WorkingSet,
|
||||
find_distributions,
|
||||
get_distribution,
|
||||
normalize_path,
|
||||
resource_string,
|
||||
get_distribution,
|
||||
find_distributions,
|
||||
Environment,
|
||||
Requirement,
|
||||
Distribution,
|
||||
PathMetadata,
|
||||
EggMetadata,
|
||||
WorkingSet,
|
||||
DistributionNotFound,
|
||||
VersionConflict,
|
||||
DEVELOP_DIST,
|
||||
)
|
||||
import pkg_resources
|
||||
from .. import py312compat
|
||||
from .._path import ensure_directory
|
||||
from ..extern.jaraco.text import yield_lines
|
||||
from setuptools import Command
|
||||
from setuptools.archive_util import unpack_archive
|
||||
from setuptools.command import bdist_egg, egg_info, setopt
|
||||
from setuptools.package_index import URL_SCHEME, PackageIndex, parse_requirement_arg
|
||||
from setuptools.sandbox import run_setup
|
||||
from setuptools.warnings import SetuptoolsDeprecationWarning, SetuptoolsWarning
|
||||
from setuptools.wheel import Wheel
|
||||
|
||||
from .._path import ensure_directory
|
||||
from ..compat import py39, py311, py312
|
||||
|
||||
from distutils import dir_util, log
|
||||
from distutils.command import install
|
||||
from distutils.command.build_scripts import first_line_re
|
||||
from distutils.errors import (
|
||||
DistutilsArgError,
|
||||
DistutilsError,
|
||||
DistutilsOptionError,
|
||||
DistutilsPlatformError,
|
||||
)
|
||||
from distutils.util import convert_path, get_platform, subst_vars
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing_extensions import Self
|
||||
|
||||
# Turn on PEP440Warnings
|
||||
warnings.filterwarnings("default", category=pkg_resources.PEP440Warning)
|
||||
@@ -89,6 +89,8 @@ __all__ = [
|
||||
'get_exe_prefixes',
|
||||
]
|
||||
|
||||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
def is_64bit():
|
||||
return struct.calcsize("P") == 8
|
||||
@@ -101,9 +103,9 @@ def _to_bytes(s):
|
||||
def isascii(s):
|
||||
try:
|
||||
s.encode('ascii')
|
||||
return True
|
||||
except UnicodeError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _one_liner(text):
|
||||
@@ -170,7 +172,7 @@ class easy_install(Command):
|
||||
|
||||
# the --user option seems to be an opt-in one,
|
||||
# so the default should be False.
|
||||
self.user = 0
|
||||
self.user = False
|
||||
self.zip_ok = self.local_snapshots_ok = None
|
||||
self.install_dir = self.script_dir = self.exclude_scripts = None
|
||||
self.index_url = None
|
||||
@@ -236,7 +238,7 @@ class easy_install(Command):
|
||||
dist = get_distribution('setuptools')
|
||||
tmpl = 'setuptools {dist.version} from {dist.location} (Python {ver})'
|
||||
print(tmpl.format(**locals()))
|
||||
raise SystemExit()
|
||||
raise SystemExit
|
||||
|
||||
def finalize_options(self): # noqa: C901 # is too complex (25) # FIXME
|
||||
self.version and self._render_version()
|
||||
@@ -245,31 +247,26 @@ class easy_install(Command):
|
||||
|
||||
self.config_vars = dict(sysconfig.get_config_vars())
|
||||
|
||||
self.config_vars.update(
|
||||
{
|
||||
'dist_name': self.distribution.get_name(),
|
||||
'dist_version': self.distribution.get_version(),
|
||||
'dist_fullname': self.distribution.get_fullname(),
|
||||
'py_version': py_version,
|
||||
'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': self.config_vars['prefix'],
|
||||
'sys_exec_prefix': self.config_vars['exec_prefix'],
|
||||
# Only python 3.2+ has abiflags
|
||||
'abiflags': getattr(sys, 'abiflags', ''),
|
||||
'platlibdir': getattr(sys, 'platlibdir', 'lib'),
|
||||
}
|
||||
)
|
||||
self.config_vars.update({
|
||||
'dist_name': self.distribution.get_name(),
|
||||
'dist_version': self.distribution.get_version(),
|
||||
'dist_fullname': self.distribution.get_fullname(),
|
||||
'py_version': py_version,
|
||||
'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': self.config_vars['prefix'],
|
||||
'sys_exec_prefix': self.config_vars['exec_prefix'],
|
||||
# Only POSIX systems have abiflags
|
||||
'abiflags': getattr(sys, 'abiflags', ''),
|
||||
# Only python 3.9+ has platlibdir
|
||||
'platlibdir': getattr(sys, 'platlibdir', 'lib'),
|
||||
})
|
||||
with contextlib.suppress(AttributeError):
|
||||
# only for distutils outside stdlib
|
||||
self.config_vars.update(
|
||||
{
|
||||
'implementation_lower': install._get_implementation().lower(),
|
||||
'implementation': install._get_implementation(),
|
||||
}
|
||||
)
|
||||
self.config_vars.update({
|
||||
'implementation_lower': install._get_implementation().lower(),
|
||||
'implementation': install._get_implementation(),
|
||||
})
|
||||
|
||||
# pypa/distutils#113 Python 3.9 compat
|
||||
self.config_vars.setdefault(
|
||||
@@ -471,7 +468,7 @@ class easy_install(Command):
|
||||
def warn_deprecated_options(self):
|
||||
pass
|
||||
|
||||
def check_site_dir(self): # noqa: C901 # is too complex (12) # FIXME
|
||||
def check_site_dir(self): # is too complex (12) # FIXME
|
||||
"""Verify that self.install_dir is .pth-capable dir, if needed"""
|
||||
|
||||
instdir = normalize_path(self.install_dir)
|
||||
@@ -480,7 +477,7 @@ class easy_install(Command):
|
||||
if not os.path.exists(instdir):
|
||||
try:
|
||||
os.makedirs(instdir)
|
||||
except (OSError, IOError):
|
||||
except OSError:
|
||||
self.cant_write_to_target()
|
||||
|
||||
# Is it a configured, PYTHONPATH, implicit, or explicit site dir?
|
||||
@@ -496,9 +493,9 @@ class easy_install(Command):
|
||||
try:
|
||||
if test_exists:
|
||||
os.unlink(testfile)
|
||||
open(testfile, 'w').close()
|
||||
open(testfile, 'wb').close()
|
||||
os.unlink(testfile)
|
||||
except (OSError, IOError):
|
||||
except OSError:
|
||||
self.cant_write_to_target()
|
||||
|
||||
if not is_site_dir and not self.multi_version:
|
||||
@@ -530,7 +527,7 @@ class easy_install(Command):
|
||||
|
||||
%s
|
||||
"""
|
||||
).lstrip() # noqa
|
||||
).lstrip()
|
||||
|
||||
__not_exists_id = textwrap.dedent(
|
||||
"""
|
||||
@@ -538,7 +535,7 @@ class easy_install(Command):
|
||||
choose a different installation directory (using the -d or --install-dir
|
||||
option).
|
||||
"""
|
||||
).lstrip() # noqa
|
||||
).lstrip()
|
||||
|
||||
__access_msg = textwrap.dedent(
|
||||
"""
|
||||
@@ -556,7 +553,7 @@ class easy_install(Command):
|
||||
|
||||
Please make the appropriate changes for your system and try again.
|
||||
"""
|
||||
).lstrip() # noqa
|
||||
).lstrip()
|
||||
|
||||
def cant_write_to_target(self):
|
||||
msg = self.__cant_write_msg % (
|
||||
@@ -570,7 +567,7 @@ class easy_install(Command):
|
||||
msg += '\n' + self.__access_msg
|
||||
raise DistutilsError(msg)
|
||||
|
||||
def check_pth_processing(self):
|
||||
def check_pth_processing(self): # noqa: C901
|
||||
"""Empirically verify whether .pth files are supported in inst. dir"""
|
||||
instdir = self.install_dir
|
||||
log.info("Checking .pth file support in %s", instdir)
|
||||
@@ -581,7 +578,7 @@ class easy_install(Command):
|
||||
_one_liner(
|
||||
"""
|
||||
import os
|
||||
f = open({ok_file!r}, 'w')
|
||||
f = open({ok_file!r}, 'w', encoding="utf-8")
|
||||
f.write('OK')
|
||||
f.close()
|
||||
"""
|
||||
@@ -593,8 +590,10 @@ class easy_install(Command):
|
||||
os.unlink(ok_file)
|
||||
dirname = os.path.dirname(ok_file)
|
||||
os.makedirs(dirname, exist_ok=True)
|
||||
f = open(pth_file, 'w')
|
||||
except (OSError, IOError):
|
||||
f = open(pth_file, 'w', encoding=py312.PTH_ENCODING)
|
||||
# ^-- Python<3.13 require encoding="locale" instead of "utf-8",
|
||||
# see python/cpython#77102.
|
||||
except OSError:
|
||||
self.cant_write_to_target()
|
||||
else:
|
||||
try:
|
||||
@@ -668,7 +667,7 @@ class easy_install(Command):
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _tmpdir(self):
|
||||
tmpdir = tempfile.mkdtemp(prefix=u"easy_install-")
|
||||
tmpdir = tempfile.mkdtemp(prefix="easy_install-")
|
||||
try:
|
||||
# cast to str as workaround for #709 and #710 and #712
|
||||
yield str(tmpdir)
|
||||
@@ -746,6 +745,7 @@ class easy_install(Command):
|
||||
for dist in dists:
|
||||
if dist in spec:
|
||||
return dist
|
||||
return None
|
||||
|
||||
def select_scheme(self, name):
|
||||
try:
|
||||
@@ -876,7 +876,9 @@ class easy_install(Command):
|
||||
ensure_directory(target)
|
||||
if os.path.exists(target):
|
||||
os.unlink(target)
|
||||
with open(target, "w" + mode) as f:
|
||||
|
||||
encoding = None if "b" in mode else "utf-8"
|
||||
with open(target, "w" + mode, encoding=encoding) as f:
|
||||
f.write(contents)
|
||||
chmod(target, 0o777 - mask)
|
||||
|
||||
@@ -939,7 +941,7 @@ class easy_install(Command):
|
||||
return Distribution.from_filename(egg_path, metadata=metadata)
|
||||
|
||||
# FIXME: 'easy_install.install_egg' is too complex (11)
|
||||
def install_egg(self, egg_path, tmpdir): # noqa: C901
|
||||
def install_egg(self, egg_path, tmpdir):
|
||||
destination = os.path.join(
|
||||
self.install_dir,
|
||||
os.path.basename(egg_path),
|
||||
@@ -1020,17 +1022,16 @@ class easy_install(Command):
|
||||
|
||||
# Write EGG-INFO/PKG-INFO
|
||||
if not os.path.exists(pkg_inf):
|
||||
f = open(pkg_inf, 'w')
|
||||
f.write('Metadata-Version: 1.0\n')
|
||||
for k, v in cfg.items('metadata'):
|
||||
if k != 'target_version':
|
||||
f.write('%s: %s\n' % (k.replace('_', '-').title(), v))
|
||||
f.close()
|
||||
with open(pkg_inf, 'w', encoding="utf-8") as f:
|
||||
f.write('Metadata-Version: 1.0\n')
|
||||
for k, v in cfg.items('metadata'):
|
||||
if k != 'target_version':
|
||||
f.write('%s: %s\n' % (k.replace('_', '-').title(), v))
|
||||
script_dir = os.path.join(_egg_info, 'scripts')
|
||||
# delete entry-point scripts to avoid duping
|
||||
self.delete_blockers(
|
||||
[os.path.join(script_dir, args[0]) for args in ScriptWriter.get_args(dist)]
|
||||
)
|
||||
self.delete_blockers([
|
||||
os.path.join(script_dir, args[0]) for args in ScriptWriter.get_args(dist)
|
||||
])
|
||||
# Build .egg file from tmpdir
|
||||
bdist_egg.make_zipfile(
|
||||
egg_path,
|
||||
@@ -1048,7 +1049,7 @@ class easy_install(Command):
|
||||
prefixes = get_exe_prefixes(dist_filename)
|
||||
to_compile = []
|
||||
native_libs = []
|
||||
top_level = {}
|
||||
top_level = set()
|
||||
|
||||
def process(src, dst):
|
||||
s = src.lower()
|
||||
@@ -1060,10 +1061,10 @@ class easy_install(Command):
|
||||
dl = dst.lower()
|
||||
if dl.endswith('.pyd') or dl.endswith('.dll'):
|
||||
parts[-1] = bdist_egg.strip_module(parts[-1])
|
||||
top_level[os.path.splitext(parts[0])[0]] = 1
|
||||
top_level.add([os.path.splitext(parts[0])[0]])
|
||||
native_libs.append(src)
|
||||
elif dl.endswith('.py') and old != 'SCRIPTS/':
|
||||
top_level[os.path.splitext(parts[0])[0]] = 1
|
||||
top_level.add([os.path.splitext(parts[0])[0]])
|
||||
to_compile.append(dst)
|
||||
return dst
|
||||
if not src.endswith('.pth'):
|
||||
@@ -1091,9 +1092,8 @@ class easy_install(Command):
|
||||
if locals()[name]:
|
||||
txt = os.path.join(egg_tmp, 'EGG-INFO', name + '.txt')
|
||||
if not os.path.exists(txt):
|
||||
f = open(txt, 'w')
|
||||
f.write('\n'.join(locals()[name]) + '\n')
|
||||
f.close()
|
||||
with open(txt, 'w', encoding="utf-8") as f:
|
||||
f.write('\n'.join(locals()[name]) + '\n')
|
||||
|
||||
def install_wheel(self, wheel_path, tmpdir):
|
||||
wheel = Wheel(wheel_path)
|
||||
@@ -1133,7 +1133,7 @@ class easy_install(Command):
|
||||
pkg_resources.require("%(name)s==%(version)s") # this exact version
|
||||
pkg_resources.require("%(name)s>=%(version)s") # this version or higher
|
||||
"""
|
||||
).lstrip() # noqa
|
||||
).lstrip()
|
||||
|
||||
__id_warning = textwrap.dedent(
|
||||
"""
|
||||
@@ -1141,7 +1141,7 @@ class easy_install(Command):
|
||||
this to work. (e.g. by being the application's script directory, by being on
|
||||
PYTHONPATH, or by being added to sys.path by your code.)
|
||||
"""
|
||||
) # noqa
|
||||
)
|
||||
|
||||
def installation_report(self, req, dist, what="Installed"):
|
||||
"""Helpful installation message for display to package users"""
|
||||
@@ -1168,7 +1168,7 @@ class easy_install(Command):
|
||||
|
||||
See the setuptools documentation for the "develop" command for more info.
|
||||
"""
|
||||
).lstrip() # noqa
|
||||
).lstrip()
|
||||
|
||||
def report_editable(self, spec, setup_script):
|
||||
dirname = os.path.dirname(setup_script)
|
||||
@@ -1205,10 +1205,11 @@ class easy_install(Command):
|
||||
|
||||
self.run_setup(setup_script, setup_base, args)
|
||||
all_eggs = Environment([dist_dir])
|
||||
eggs = []
|
||||
for key in all_eggs:
|
||||
for dist in all_eggs[key]:
|
||||
eggs.append(self.install_egg(dist.location, setup_base))
|
||||
eggs = [
|
||||
self.install_egg(dist.location, setup_base)
|
||||
for key in all_eggs
|
||||
for dist in all_eggs[key]
|
||||
]
|
||||
if not eggs and not self.dry_run:
|
||||
log.warn("No eggs found in %s (setup script problem?)", dist_dir)
|
||||
return eggs
|
||||
@@ -1281,7 +1282,10 @@ class easy_install(Command):
|
||||
filename = os.path.join(self.install_dir, 'setuptools.pth')
|
||||
if os.path.islink(filename):
|
||||
os.unlink(filename)
|
||||
with open(filename, 'wt') as f:
|
||||
|
||||
with open(filename, 'wt', encoding=py312.PTH_ENCODING) as f:
|
||||
# ^-- Python<3.13 require encoding="locale" instead of "utf-8",
|
||||
# see python/cpython#77102.
|
||||
f.write(self.pth_file.make_relative(dist.location) + '\n')
|
||||
|
||||
def unpack_progress(self, src, dst):
|
||||
@@ -1318,12 +1322,12 @@ class easy_install(Command):
|
||||
# try to make the byte compile messages quieter
|
||||
log.set_verbosity(self.verbose - 1)
|
||||
|
||||
byte_compile(to_compile, optimize=0, force=1, dry_run=self.dry_run)
|
||||
byte_compile(to_compile, optimize=0, force=True, dry_run=self.dry_run)
|
||||
if self.optimize:
|
||||
byte_compile(
|
||||
to_compile,
|
||||
optimize=self.optimize,
|
||||
force=1,
|
||||
force=True,
|
||||
dry_run=self.dry_run,
|
||||
)
|
||||
finally:
|
||||
@@ -1433,24 +1437,20 @@ def get_site_dirs():
|
||||
if sys.platform in ('os2emx', 'riscos'):
|
||||
sitedirs.append(os.path.join(prefix, "Lib", "site-packages"))
|
||||
elif os.sep == '/':
|
||||
sitedirs.extend(
|
||||
[
|
||||
os.path.join(
|
||||
prefix,
|
||||
"lib",
|
||||
"python{}.{}".format(*sys.version_info),
|
||||
"site-packages",
|
||||
),
|
||||
os.path.join(prefix, "lib", "site-python"),
|
||||
]
|
||||
)
|
||||
else:
|
||||
sitedirs.extend(
|
||||
[
|
||||
sitedirs.extend([
|
||||
os.path.join(
|
||||
prefix,
|
||||
os.path.join(prefix, "lib", "site-packages"),
|
||||
]
|
||||
)
|
||||
"lib",
|
||||
"python{}.{}".format(*sys.version_info),
|
||||
"site-packages",
|
||||
),
|
||||
os.path.join(prefix, "lib", "site-python"),
|
||||
])
|
||||
else:
|
||||
sitedirs.extend([
|
||||
prefix,
|
||||
os.path.join(prefix, "lib", "site-packages"),
|
||||
])
|
||||
if sys.platform != 'darwin':
|
||||
continue
|
||||
|
||||
@@ -1482,22 +1482,20 @@ def get_site_dirs():
|
||||
with contextlib.suppress(AttributeError):
|
||||
sitedirs.extend(site.getsitepackages())
|
||||
|
||||
sitedirs = list(map(normalize_path, sitedirs))
|
||||
|
||||
return sitedirs
|
||||
return list(map(normalize_path, sitedirs))
|
||||
|
||||
|
||||
def expand_paths(inputs): # noqa: C901 # is too complex (11) # FIXME
|
||||
"""Yield sys.path directories that might contain "old-style" packages"""
|
||||
|
||||
seen = {}
|
||||
seen = set()
|
||||
|
||||
for dirname in inputs:
|
||||
dirname = normalize_path(dirname)
|
||||
if dirname in seen:
|
||||
continue
|
||||
|
||||
seen[dirname] = 1
|
||||
seen.add(dirname)
|
||||
if not os.path.isdir(dirname):
|
||||
continue
|
||||
|
||||
@@ -1513,9 +1511,8 @@ def expand_paths(inputs): # noqa: C901 # is too complex (11) # FIXME
|
||||
continue
|
||||
|
||||
# Read the .pth file
|
||||
f = open(os.path.join(dirname, name))
|
||||
lines = list(yield_lines(f))
|
||||
f.close()
|
||||
content = _read_pth(os.path.join(dirname, name))
|
||||
lines = list(yield_lines(content))
|
||||
|
||||
# Yield existing non-dupe, non-import directory lines from it
|
||||
for line in lines:
|
||||
@@ -1526,7 +1523,7 @@ def expand_paths(inputs): # noqa: C901 # is too complex (11) # FIXME
|
||||
if line in seen:
|
||||
continue
|
||||
|
||||
seen[line] = 1
|
||||
seen.add(line)
|
||||
if not os.path.isdir(line):
|
||||
continue
|
||||
|
||||
@@ -1628,9 +1625,9 @@ class PthDistributions(Environment):
|
||||
def _load_raw(self):
|
||||
paths = []
|
||||
dirty = saw_import = False
|
||||
seen = dict.fromkeys(self.sitedirs)
|
||||
f = open(self.filename, 'rt')
|
||||
for line in f:
|
||||
seen = set(self.sitedirs)
|
||||
content = _read_pth(self.filename)
|
||||
for line in content.splitlines():
|
||||
path = line.rstrip()
|
||||
# still keep imports and empty/commented lines for formatting
|
||||
paths.append(path)
|
||||
@@ -1648,8 +1645,7 @@ class PthDistributions(Environment):
|
||||
dirty = True
|
||||
paths.pop()
|
||||
continue
|
||||
seen[normalized_path] = 1
|
||||
f.close()
|
||||
seen.add(normalized_path)
|
||||
# remove any trailing empty/blank line
|
||||
while paths and not paths[-1].strip():
|
||||
paths.pop()
|
||||
@@ -1678,9 +1674,11 @@ class PthDistributions(Environment):
|
||||
last_paths.remove(path)
|
||||
# also, re-check that all paths are still valid before saving them
|
||||
for path in self.paths[:]:
|
||||
if path not in last_paths and not path.startswith(
|
||||
('import ', 'from ', '#')
|
||||
):
|
||||
if path not in last_paths and not path.startswith((
|
||||
'import ',
|
||||
'from ',
|
||||
'#',
|
||||
)):
|
||||
absolute_path = os.path.join(self.basedir, path)
|
||||
if not os.path.exists(absolute_path):
|
||||
self.paths.remove(path)
|
||||
@@ -1698,7 +1696,9 @@ class PthDistributions(Environment):
|
||||
data = '\n'.join(lines) + '\n'
|
||||
if os.path.islink(self.filename):
|
||||
os.unlink(self.filename)
|
||||
with open(self.filename, 'wt') as f:
|
||||
with open(self.filename, 'wt', encoding=py312.PTH_ENCODING) as f:
|
||||
# ^-- Python<3.13 require encoding="locale" instead of "utf-8",
|
||||
# see python/cpython#77102.
|
||||
f.write(data)
|
||||
elif os.path.exists(self.filename):
|
||||
log.debug("Deleting empty %s", self.filename)
|
||||
@@ -1751,8 +1751,7 @@ class RewritePthDistributions(PthDistributions):
|
||||
@classmethod
|
||||
def _wrap_lines(cls, lines):
|
||||
yield cls.prelude
|
||||
for line in lines:
|
||||
yield line
|
||||
yield from lines
|
||||
yield cls.postlude
|
||||
|
||||
prelude = _one_liner(
|
||||
@@ -1774,7 +1773,7 @@ class RewritePthDistributions(PthDistributions):
|
||||
|
||||
|
||||
if os.environ.get('SETUPTOOLS_SYS_PATH_TECHNIQUE', 'raw') == 'rewrite':
|
||||
PthDistributions = RewritePthDistributions
|
||||
PthDistributions = RewritePthDistributions # type: ignore[misc] # Overwriting type
|
||||
|
||||
|
||||
def _first_line_re():
|
||||
@@ -1789,13 +1788,14 @@ def _first_line_re():
|
||||
return re.compile(first_line_re.pattern.decode())
|
||||
|
||||
|
||||
def auto_chmod(func, arg, exc):
|
||||
# Must match shutil._OnExcCallback
|
||||
def auto_chmod(func: Callable[..., _T], arg: str, exc: BaseException) -> _T:
|
||||
"""shutils onexc callback to automatically call chmod for certain functions."""
|
||||
# Only retry for scenarios known to have an issue
|
||||
if func in [os.unlink, os.remove] and os.name == 'nt':
|
||||
chmod(arg, stat.S_IWRITE)
|
||||
return func(arg)
|
||||
et, ev, _ = sys.exc_info()
|
||||
# TODO: This code doesn't make sense. What is it trying to do?
|
||||
raise (ev[0], ev[1] + (" %s %s" % (func, arg)))
|
||||
raise exc
|
||||
|
||||
|
||||
def update_dist_caches(dist_path, fix_zipimporter_caches):
|
||||
@@ -1995,9 +1995,9 @@ def is_python(text, filename='<string>'):
|
||||
def is_sh(executable):
|
||||
"""Determine if the specified executable is a .sh (contains a #! line)"""
|
||||
try:
|
||||
with io.open(executable, encoding='latin-1') as fp:
|
||||
with open(executable, encoding='latin-1') as fp:
|
||||
magic = fp.read(2)
|
||||
except (OSError, IOError):
|
||||
except OSError:
|
||||
return executable
|
||||
return magic == '#!'
|
||||
|
||||
@@ -2021,10 +2021,12 @@ def is_python_script(script_text, filename):
|
||||
|
||||
|
||||
try:
|
||||
from os import chmod as _chmod
|
||||
from os import (
|
||||
chmod as _chmod, # pyright: ignore[reportAssignmentType] # Losing type-safety w/ pyright, but that's ok
|
||||
)
|
||||
except ImportError:
|
||||
# Jython compatibility
|
||||
def _chmod(*args):
|
||||
def _chmod(*args: object, **kwargs: object) -> None: # type: ignore[misc] # Mypy reuses the imported definition anyway
|
||||
pass
|
||||
|
||||
|
||||
@@ -2032,7 +2034,7 @@ def chmod(path, mode):
|
||||
log.debug("changing mode of %s to %o", path, mode)
|
||||
try:
|
||||
_chmod(path, mode)
|
||||
except os.error as e:
|
||||
except OSError as e:
|
||||
log.debug("chmod failed: %s", e)
|
||||
|
||||
|
||||
@@ -2042,8 +2044,8 @@ class CommandSpec(list):
|
||||
those passed to Popen.
|
||||
"""
|
||||
|
||||
options = []
|
||||
split_args = dict()
|
||||
options: list[str] = []
|
||||
split_args: dict[str, bool] = dict()
|
||||
|
||||
@classmethod
|
||||
def best(cls):
|
||||
@@ -2058,19 +2060,20 @@ class CommandSpec(list):
|
||||
return os.environ.get('__PYVENV_LAUNCHER__', _default)
|
||||
|
||||
@classmethod
|
||||
def from_param(cls, param):
|
||||
def from_param(cls, param: Self | str | Iterable[str] | None) -> Self:
|
||||
"""
|
||||
Construct a CommandSpec from a parameter to build_scripts, which may
|
||||
be None.
|
||||
"""
|
||||
if isinstance(param, cls):
|
||||
return param
|
||||
if isinstance(param, list):
|
||||
if isinstance(param, str):
|
||||
return cls.from_string(param)
|
||||
if isinstance(param, Iterable):
|
||||
return cls(param)
|
||||
if param is None:
|
||||
return cls.from_environment()
|
||||
# otherwise, assume it's a string.
|
||||
return cls.from_string(param)
|
||||
raise TypeError(f"Argument has an unsupported type {type(param)}")
|
||||
|
||||
@classmethod
|
||||
def from_environment(cls):
|
||||
@@ -2188,8 +2191,7 @@ class ScriptWriter:
|
||||
cls._ensure_safe_name(name)
|
||||
script_text = cls.template % locals()
|
||||
args = cls._get_script_args(type_, name, header, script_text)
|
||||
for res in args:
|
||||
yield res
|
||||
yield from args
|
||||
|
||||
@staticmethod
|
||||
def _ensure_safe_name(name):
|
||||
@@ -2279,7 +2281,7 @@ class WindowsScriptWriter(ScriptWriter):
|
||||
to an executable on the system.
|
||||
"""
|
||||
clean_header = new_header[2:-1].strip('"')
|
||||
return sys.platform != 'win32' or find_executable(clean_header)
|
||||
return sys.platform != 'win32' or shutil.which(clean_header)
|
||||
|
||||
|
||||
class WindowsExecutableLauncherWriter(WindowsScriptWriter):
|
||||
@@ -2339,7 +2341,7 @@ def load_launcher_manifest(name):
|
||||
|
||||
|
||||
def _rmtree(path, ignore_errors=False, onexc=auto_chmod):
|
||||
return py312compat.shutil_rmtree(path, ignore_errors, onexc)
|
||||
return py311.shutil_rmtree(path, ignore_errors, onexc)
|
||||
|
||||
|
||||
def current_umask():
|
||||
@@ -2355,6 +2357,26 @@ def only_strs(values):
|
||||
return filter(lambda val: isinstance(val, str), values)
|
||||
|
||||
|
||||
def _read_pth(fullname: str) -> str:
|
||||
# Python<3.13 require encoding="locale" instead of "utf-8", see python/cpython#77102
|
||||
# In the case old versions of setuptools are producing `pth` files with
|
||||
# different encodings that might be problematic... So we fallback to "locale".
|
||||
|
||||
try:
|
||||
with open(fullname, encoding=py312.PTH_ENCODING) as f:
|
||||
return f.read()
|
||||
except UnicodeDecodeError: # pragma: no cover
|
||||
# This error may only happen for Python >= 3.13
|
||||
# TODO: Possible deprecation warnings to be added in the future:
|
||||
# ``.pth file {fullname!r} is not UTF-8.``
|
||||
# Your environment contain {fullname!r} that cannot be read as UTF-8.
|
||||
# This is likely to have been produced with an old version of setuptools.
|
||||
# Please be mindful that this is deprecated and in the future, non-utf8
|
||||
# .pth files may cause setuptools to fail.
|
||||
with open(fullname, encoding=py39.LOCALE_ENCODING) as f:
|
||||
return f.read()
|
||||
|
||||
|
||||
class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning):
|
||||
_SUMMARY = "easy_install command is deprecated."
|
||||
_DETAILS = """
|
||||
|
||||
Reference in New Issue
Block a user