Voice et bot modif
This commit is contained in:
parent
189d56026b
commit
7333a22bcd
10774 changed files with 634644 additions and 933308 deletions
|
|
@ -1 +1,2 @@
|
|||
"""For modules related to installing packages."""
|
||||
"""For modules related to installing packages.
|
||||
"""
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,46 @@
|
|||
"""Legacy editable installation process, i.e. `setup.py develop`.
|
||||
"""
|
||||
import logging
|
||||
from typing import Optional, Sequence
|
||||
|
||||
from pip._internal.build_env import BuildEnvironment
|
||||
from pip._internal.utils.logging import indent_log
|
||||
from pip._internal.utils.setuptools_build import make_setuptools_develop_args
|
||||
from pip._internal.utils.subprocess import call_subprocess
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def install_editable(
|
||||
*,
|
||||
global_options: Sequence[str],
|
||||
prefix: Optional[str],
|
||||
home: Optional[str],
|
||||
use_user_site: bool,
|
||||
name: str,
|
||||
setup_py_path: str,
|
||||
isolated: bool,
|
||||
build_env: BuildEnvironment,
|
||||
unpacked_source_directory: str,
|
||||
) -> None:
|
||||
"""Install a package in editable mode. Most arguments are pass-through
|
||||
to setuptools.
|
||||
"""
|
||||
logger.info("Running setup.py develop for %s", name)
|
||||
|
||||
args = make_setuptools_develop_args(
|
||||
setup_py_path,
|
||||
global_options=global_options,
|
||||
no_user_config=isolated,
|
||||
prefix=prefix,
|
||||
home=home,
|
||||
use_user_site=use_user_site,
|
||||
)
|
||||
|
||||
with indent_log():
|
||||
with build_env:
|
||||
call_subprocess(
|
||||
args,
|
||||
command_desc="python setup.py develop",
|
||||
cwd=unpacked_source_directory,
|
||||
)
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
"""Support for installing and building the "wheel" binary package format."""
|
||||
|
||||
from __future__ import annotations
|
||||
"""Support for installing and building the "wheel" binary package format.
|
||||
"""
|
||||
|
||||
import collections
|
||||
import compileall
|
||||
|
|
@ -12,19 +11,26 @@ import os.path
|
|||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import textwrap
|
||||
import warnings
|
||||
from base64 import urlsafe_b64encode
|
||||
from collections.abc import Generator, Iterable, Iterator, Sequence
|
||||
from email.message import Message
|
||||
from itertools import chain, filterfalse, starmap
|
||||
from typing import (
|
||||
IO,
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
BinaryIO,
|
||||
Callable,
|
||||
Dict,
|
||||
Generator,
|
||||
Iterable,
|
||||
Iterator,
|
||||
List,
|
||||
NewType,
|
||||
Protocol,
|
||||
Optional,
|
||||
Sequence,
|
||||
Set,
|
||||
Tuple,
|
||||
Union,
|
||||
cast,
|
||||
)
|
||||
|
|
@ -44,7 +50,7 @@ from pip._internal.metadata import (
|
|||
from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl
|
||||
from pip._internal.models.scheme import SCHEME_KEYS, Scheme
|
||||
from pip._internal.utils.filesystem import adjacent_tmp_file, replace
|
||||
from pip._internal.utils.misc import StreamWrapper, ensure_dir, hash_file, partition
|
||||
from pip._internal.utils.misc import captured_stdout, ensure_dir, hash_file, partition
|
||||
from pip._internal.utils.unpacking import (
|
||||
current_umask,
|
||||
is_within_directory,
|
||||
|
|
@ -53,30 +59,32 @@ from pip._internal.utils.unpacking import (
|
|||
)
|
||||
from pip._internal.utils.wheel import parse_wheel
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Protocol
|
||||
|
||||
class File(Protocol):
|
||||
src_record_path: RecordPath
|
||||
dest_path: str
|
||||
changed: bool
|
||||
class File(Protocol):
|
||||
src_record_path: "RecordPath"
|
||||
dest_path: str
|
||||
changed: bool
|
||||
|
||||
def save(self) -> None:
|
||||
pass
|
||||
def save(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
RecordPath = NewType("RecordPath", str)
|
||||
InstalledCSVRow = tuple[RecordPath, str, Union[int, str]]
|
||||
InstalledCSVRow = Tuple[RecordPath, str, Union[int, str]]
|
||||
|
||||
|
||||
def rehash(path: str, blocksize: int = 1 << 20) -> tuple[str, str]:
|
||||
def rehash(path: str, blocksize: int = 1 << 20) -> Tuple[str, str]:
|
||||
"""Return (encoded_digest, length) for path using hashlib.sha256()"""
|
||||
h, length = hash_file(path, blocksize)
|
||||
digest = "sha256=" + urlsafe_b64encode(h.digest()).decode("latin1").rstrip("=")
|
||||
return (digest, str(length))
|
||||
|
||||
|
||||
def csv_io_kwargs(mode: str) -> dict[str, Any]:
|
||||
def csv_io_kwargs(mode: str) -> Dict[str, Any]:
|
||||
"""Return keyword arguments to properly open a CSV file
|
||||
in the given mode.
|
||||
"""
|
||||
|
|
@ -107,7 +115,7 @@ def wheel_root_is_purelib(metadata: Message) -> bool:
|
|||
return metadata.get("Root-Is-Purelib", "").lower() == "true"
|
||||
|
||||
|
||||
def get_entrypoints(dist: BaseDistribution) -> tuple[dict[str, str], dict[str, str]]:
|
||||
def get_entrypoints(dist: BaseDistribution) -> Tuple[Dict[str, str], Dict[str, str]]:
|
||||
console_scripts = {}
|
||||
gui_scripts = {}
|
||||
for entry_point in dist.iter_entry_points():
|
||||
|
|
@ -118,7 +126,7 @@ def get_entrypoints(dist: BaseDistribution) -> tuple[dict[str, str], dict[str, s
|
|||
return console_scripts, gui_scripts
|
||||
|
||||
|
||||
def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> str | None:
|
||||
def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> Optional[str]:
|
||||
"""Determine if any scripts are not on PATH and format a warning.
|
||||
Returns a warning message if one or more scripts are not on PATH,
|
||||
otherwise None.
|
||||
|
|
@ -127,7 +135,7 @@ def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> str | None:
|
|||
return None
|
||||
|
||||
# Group scripts by the path they were installed in
|
||||
grouped_by_dir: dict[str, set[str]] = collections.defaultdict(set)
|
||||
grouped_by_dir: Dict[str, Set[str]] = collections.defaultdict(set)
|
||||
for destfile in scripts:
|
||||
parent_dir = os.path.dirname(destfile)
|
||||
script_name = os.path.basename(destfile)
|
||||
|
|
@ -143,7 +151,7 @@ def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> str | None:
|
|||
not_warn_dirs.append(
|
||||
os.path.normcase(os.path.normpath(os.path.dirname(sys.executable)))
|
||||
)
|
||||
warn_for: dict[str, set[str]] = {
|
||||
warn_for: Dict[str, Set[str]] = {
|
||||
parent_dir: scripts
|
||||
for parent_dir, scripts in grouped_by_dir.items()
|
||||
if os.path.normcase(os.path.normpath(parent_dir)) not in not_warn_dirs
|
||||
|
|
@ -154,7 +162,7 @@ def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> str | None:
|
|||
# Format a message
|
||||
msg_lines = []
|
||||
for parent_dir, dir_scripts in warn_for.items():
|
||||
sorted_scripts: list[str] = sorted(dir_scripts)
|
||||
sorted_scripts: List[str] = sorted(dir_scripts)
|
||||
if len(sorted_scripts) == 1:
|
||||
start_text = f"script {sorted_scripts[0]} is"
|
||||
else:
|
||||
|
|
@ -192,7 +200,7 @@ def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> str | None:
|
|||
|
||||
def _normalized_outrows(
|
||||
outrows: Iterable[InstalledCSVRow],
|
||||
) -> list[tuple[str, str, str]]:
|
||||
) -> List[Tuple[str, str, str]]:
|
||||
"""Normalize the given rows of a RECORD file.
|
||||
|
||||
Items in each row are converted into str. Rows are then sorted to make
|
||||
|
|
@ -231,17 +239,17 @@ def _fs_to_record_path(path: str, lib_dir: str) -> RecordPath:
|
|||
|
||||
|
||||
def get_csv_rows_for_installed(
|
||||
old_csv_rows: list[list[str]],
|
||||
installed: dict[RecordPath, RecordPath],
|
||||
changed: set[RecordPath],
|
||||
generated: list[str],
|
||||
old_csv_rows: List[List[str]],
|
||||
installed: Dict[RecordPath, RecordPath],
|
||||
changed: Set[RecordPath],
|
||||
generated: List[str],
|
||||
lib_dir: str,
|
||||
) -> list[InstalledCSVRow]:
|
||||
) -> List[InstalledCSVRow]:
|
||||
"""
|
||||
:param installed: A map from archive RECORD path to installation RECORD
|
||||
path.
|
||||
"""
|
||||
installed_rows: list[InstalledCSVRow] = []
|
||||
installed_rows: List[InstalledCSVRow] = []
|
||||
for row in old_csv_rows:
|
||||
if len(row) > 3:
|
||||
logger.warning("RECORD line has more than three elements: %s", row)
|
||||
|
|
@ -262,7 +270,7 @@ def get_csv_rows_for_installed(
|
|||
]
|
||||
|
||||
|
||||
def get_console_script_specs(console: dict[str, str]) -> list[str]:
|
||||
def get_console_script_specs(console: Dict[str, str]) -> List[str]:
|
||||
"""
|
||||
Given the mapping from entrypoint name to callable, return the relevant
|
||||
console script specs.
|
||||
|
|
@ -280,15 +288,17 @@ def get_console_script_specs(console: dict[str, str]) -> list[str]:
|
|||
# the wheel metadata at build time, and so if the wheel is installed with
|
||||
# a *different* version of Python the entry points will be wrong. The
|
||||
# correct fix for this is to enhance the metadata to be able to describe
|
||||
# such versioned entry points.
|
||||
# Currently, projects using versioned entry points will either have
|
||||
# such versioned entry points, but that won't happen till Metadata 2.0 is
|
||||
# available.
|
||||
# In the meantime, projects using versioned entry points will either have
|
||||
# incorrect versioned entry points, or they will not be able to distribute
|
||||
# "universal" wheels (i.e., they will need a wheel per Python version).
|
||||
#
|
||||
# Because setuptools and pip are bundled with _ensurepip and virtualenv,
|
||||
# we need to use universal wheels. As a workaround, we
|
||||
# we need to use universal wheels. So, as a stopgap until Metadata 2.0, we
|
||||
# override the versioned entry points in the wheel and generate the
|
||||
# correct ones.
|
||||
# correct ones. This code is purely a short-term measure until Metadata 2.0
|
||||
# is available.
|
||||
#
|
||||
# To add the level of hack in this section of code, in order to support
|
||||
# ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment
|
||||
|
|
@ -350,6 +360,12 @@ class ZipBackedFile:
|
|||
return self._zip_file.getinfo(self.src_record_path)
|
||||
|
||||
def save(self) -> None:
|
||||
# directory creation is lazy and after file filtering
|
||||
# to ensure we don't install empty dirs; empty dirs can't be
|
||||
# uninstalled.
|
||||
parent_dir = os.path.dirname(self.dest_path)
|
||||
ensure_dir(parent_dir)
|
||||
|
||||
# When we open the output file below, any existing file is truncated
|
||||
# before we start writing the new contents. This is fine in most
|
||||
# cases, but can cause a segfault if pip has loaded a shared
|
||||
|
|
@ -363,20 +379,16 @@ class ZipBackedFile:
|
|||
|
||||
zipinfo = self._getinfo()
|
||||
|
||||
# optimization: the file is created by open(),
|
||||
# skip the decompression when there is 0 bytes to decompress.
|
||||
with open(self.dest_path, "wb") as dest:
|
||||
if zipinfo.file_size > 0:
|
||||
with self._zip_file.open(zipinfo) as f:
|
||||
blocksize = min(zipinfo.file_size, 1024 * 1024)
|
||||
shutil.copyfileobj(f, dest, blocksize)
|
||||
with self._zip_file.open(zipinfo) as f:
|
||||
with open(self.dest_path, "wb") as dest:
|
||||
shutil.copyfileobj(f, dest)
|
||||
|
||||
if zip_item_is_executable(zipinfo):
|
||||
set_extracted_file_to_default_mode_plus_executable(self.dest_path)
|
||||
|
||||
|
||||
class ScriptFile:
|
||||
def __init__(self, file: File) -> None:
|
||||
def __init__(self, file: "File") -> None:
|
||||
self._file = file
|
||||
self.src_record_path = self._file.src_record_path
|
||||
self.dest_path = self._file.dest_path
|
||||
|
|
@ -391,7 +403,7 @@ class MissingCallableSuffix(InstallationError):
|
|||
def __init__(self, entry_point: str) -> None:
|
||||
super().__init__(
|
||||
f"Invalid script entry point: {entry_point} - A callable "
|
||||
"suffix is required. See https://packaging.python.org/"
|
||||
"suffix is required. Cf https://packaging.python.org/"
|
||||
"specifications/entry-points/#use-for-scripts for more "
|
||||
"information."
|
||||
)
|
||||
|
|
@ -404,34 +416,21 @@ def _raise_for_invalid_entrypoint(specification: str) -> None:
|
|||
|
||||
|
||||
class PipScriptMaker(ScriptMaker):
|
||||
# Override distlib's default script template with one that
|
||||
# doesn't import `re` module, allowing scripts to load faster.
|
||||
script_template = textwrap.dedent(
|
||||
"""\
|
||||
import sys
|
||||
from %(module)s import %(import_name)s
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(%(func)s())
|
||||
"""
|
||||
)
|
||||
|
||||
def make(
|
||||
self, specification: str, options: dict[str, Any] | None = None
|
||||
) -> list[str]:
|
||||
self, specification: str, options: Optional[Dict[str, Any]] = None
|
||||
) -> List[str]:
|
||||
_raise_for_invalid_entrypoint(specification)
|
||||
return super().make(specification, options)
|
||||
|
||||
|
||||
def _install_wheel( # noqa: C901, PLR0915 function is too long
|
||||
def _install_wheel(
|
||||
name: str,
|
||||
wheel_zip: ZipFile,
|
||||
wheel_path: str,
|
||||
scheme: Scheme,
|
||||
pycompile: bool = True,
|
||||
warn_script_location: bool = True,
|
||||
direct_url: DirectUrl | None = None,
|
||||
direct_url: Optional[DirectUrl] = None,
|
||||
requested: bool = False,
|
||||
) -> None:
|
||||
"""Install a wheel.
|
||||
|
|
@ -460,9 +459,9 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|||
# installed = files copied from the wheel to the destination
|
||||
# changed = files changed while installing (scripts #! line typically)
|
||||
# generated = files newly generated during the install (script wrappers)
|
||||
installed: dict[RecordPath, RecordPath] = {}
|
||||
changed: set[RecordPath] = set()
|
||||
generated: list[str] = []
|
||||
installed: Dict[RecordPath, RecordPath] = {}
|
||||
changed: Set[RecordPath] = set()
|
||||
generated: List[str] = []
|
||||
|
||||
def record_installed(
|
||||
srcfile: RecordPath, destfile: str, modified: bool = False
|
||||
|
|
@ -488,8 +487,8 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|||
|
||||
def root_scheme_file_maker(
|
||||
zip_file: ZipFile, dest: str
|
||||
) -> Callable[[RecordPath], File]:
|
||||
def make_root_scheme_file(record_path: RecordPath) -> File:
|
||||
) -> Callable[[RecordPath], "File"]:
|
||||
def make_root_scheme_file(record_path: RecordPath) -> "File":
|
||||
normed_path = os.path.normpath(record_path)
|
||||
dest_path = os.path.join(dest, normed_path)
|
||||
assert_no_path_traversal(dest, dest_path)
|
||||
|
|
@ -499,18 +498,18 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|||
|
||||
def data_scheme_file_maker(
|
||||
zip_file: ZipFile, scheme: Scheme
|
||||
) -> Callable[[RecordPath], File]:
|
||||
) -> Callable[[RecordPath], "File"]:
|
||||
scheme_paths = {key: getattr(scheme, key) for key in SCHEME_KEYS}
|
||||
|
||||
def make_data_scheme_file(record_path: RecordPath) -> File:
|
||||
def make_data_scheme_file(record_path: RecordPath) -> "File":
|
||||
normed_path = os.path.normpath(record_path)
|
||||
try:
|
||||
_, scheme_key, dest_subpath = normed_path.split(os.path.sep, 2)
|
||||
except ValueError:
|
||||
message = (
|
||||
f"Unexpected file in {wheel_path}: {record_path!r}. .data directory"
|
||||
" contents should be named like: '<scheme key>/<path>'."
|
||||
)
|
||||
"Unexpected file in {}: {!r}. .data directory contents"
|
||||
" should be named like: '<scheme key>/<path>'."
|
||||
).format(wheel_path, record_path)
|
||||
raise InstallationError(message)
|
||||
|
||||
try:
|
||||
|
|
@ -518,11 +517,10 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|||
except KeyError:
|
||||
valid_scheme_keys = ", ".join(sorted(scheme_paths))
|
||||
message = (
|
||||
f"Unknown scheme key used in {wheel_path}: {scheme_key} "
|
||||
f"(for file {record_path!r}). .data directory contents "
|
||||
f"should be in subdirectories named with a valid scheme "
|
||||
f"key ({valid_scheme_keys})"
|
||||
)
|
||||
"Unknown scheme key used in {}: {} (for file {!r}). .data"
|
||||
" directory contents should be in subdirectories named"
|
||||
" with a valid scheme key ({})"
|
||||
).format(wheel_path, scheme_key, record_path, valid_scheme_keys)
|
||||
raise InstallationError(message)
|
||||
|
||||
dest_path = os.path.join(scheme_path, dest_subpath)
|
||||
|
|
@ -534,7 +532,7 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|||
def is_data_scheme_path(path: RecordPath) -> bool:
|
||||
return path.split("/", 1)[0].endswith(".data")
|
||||
|
||||
paths = cast(list[RecordPath], wheel_zip.namelist())
|
||||
paths = cast(List[RecordPath], wheel_zip.namelist())
|
||||
file_paths = filterfalse(is_dir_path, paths)
|
||||
root_scheme_paths, data_scheme_paths = partition(is_data_scheme_path, file_paths)
|
||||
|
||||
|
|
@ -560,7 +558,7 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|||
)
|
||||
console, gui = get_entrypoints(distribution)
|
||||
|
||||
def is_entrypoint_wrapper(file: File) -> bool:
|
||||
def is_entrypoint_wrapper(file: "File") -> bool:
|
||||
# EP, EP.exe and EP-script.py are scripts generated for
|
||||
# entry point EP by setuptools
|
||||
path = file.dest_path
|
||||
|
|
@ -583,15 +581,7 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|||
script_scheme_files = map(ScriptFile, script_scheme_files)
|
||||
files = chain(files, script_scheme_files)
|
||||
|
||||
existing_parents = set()
|
||||
for file in files:
|
||||
# directory creation is lazy and after file filtering
|
||||
# to ensure we don't install empty dirs; empty dirs can't be
|
||||
# uninstalled.
|
||||
parent_dir = os.path.dirname(file.dest_path)
|
||||
if parent_dir not in existing_parents:
|
||||
ensure_dir(parent_dir)
|
||||
existing_parents.add(parent_dir)
|
||||
file.save()
|
||||
record_installed(file.src_record_path, file.dest_path, file.changed)
|
||||
|
||||
|
|
@ -614,9 +604,7 @@ def _install_wheel( # noqa: C901, PLR0915 function is too long
|
|||
|
||||
# Compile all of the pyc files for the installed files
|
||||
if pycompile:
|
||||
with contextlib.redirect_stdout(
|
||||
StreamWrapper.from_stream(sys.stdout)
|
||||
) as stdout:
|
||||
with captured_stdout() as stdout:
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings("ignore")
|
||||
for path in pyc_source_file_paths():
|
||||
|
|
@ -729,7 +717,7 @@ def install_wheel(
|
|||
req_description: str,
|
||||
pycompile: bool = True,
|
||||
warn_script_location: bool = True,
|
||||
direct_url: DirectUrl | None = None,
|
||||
direct_url: Optional[DirectUrl] = None,
|
||||
requested: bool = False,
|
||||
) -> None:
|
||||
with ZipFile(wheel_path, allowZip64=True) as z:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue