summaryrefslogtreecommitdiff
path: root/venv/lib/python3.11/site-packages/pip/_internal/operations
diff options
context:
space:
mode:
authorcyfraeviolae <cyfraeviolae>2024-04-03 03:17:55 -0400
committercyfraeviolae <cyfraeviolae>2024-04-03 03:17:55 -0400
commit12cf076118570eebbff08c6b3090e0d4798447a1 (patch)
tree3ba25e17e3c3a5e82316558ba3864b955919ff72 /venv/lib/python3.11/site-packages/pip/_internal/operations
parentc45662ff3923b34614ddcc8feb9195541166dcc5 (diff)
no venv
Diffstat (limited to 'venv/lib/python3.11/site-packages/pip/_internal/operations')
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/__init__.py0
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-311.pycbin208 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/check.cpython-311.pycbin8471 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-311.pycbin11604 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-311.pycbin27833 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/__init__.py0
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-311.pycbin214 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-311.pycbin8935 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-311.pycbin2285 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-311.pycbin2321 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-311.pycbin3721 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-311.pycbin1951 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-311.pycbin2395 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-311.pycbin4502 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/build_tracker.py139
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/metadata.py39
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/metadata_editable.py41
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/metadata_legacy.py74
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/wheel.py37
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/wheel_editable.py46
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/build/wheel_legacy.py102
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/check.py187
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/freeze.py255
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/install/__init__.py2
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-311.pycbin282 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-311.pycbin2195 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-311.pycbin40176 -> 0 bytes
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/install/editable_legacy.py46
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/install/wheel.py734
-rw-r--r--venv/lib/python3.11/site-packages/pip/_internal/operations/prepare.py730
30 files changed, 0 insertions, 2432 deletions
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/__init__.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/__init__.py
+++ /dev/null
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-311.pyc
deleted file mode 100644
index 4439be7..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/check.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/check.cpython-311.pyc
deleted file mode 100644
index 5678f8f..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/check.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-311.pyc
deleted file mode 100644
index 2c850cd..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-311.pyc
deleted file mode 100644
index 07536cf..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__init__.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__init__.py
+++ /dev/null
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-311.pyc
deleted file mode 100644
index aa8b9b4..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-311.pyc
deleted file mode 100644
index 9fa988b..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-311.pyc
deleted file mode 100644
index 4f895a1..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-311.pyc
deleted file mode 100644
index 064dcf5..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-311.pyc
deleted file mode 100644
index 6843880..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-311.pyc
deleted file mode 100644
index dfe9cb2..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-311.pyc
deleted file mode 100644
index 8c85fb0..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-311.pyc
deleted file mode 100644
index 918e730..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/build_tracker.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/build_tracker.py
deleted file mode 100644
index 3791932..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/build_tracker.py
+++ /dev/null
@@ -1,139 +0,0 @@
-import contextlib
-import hashlib
-import logging
-import os
-from types import TracebackType
-from typing import Dict, Generator, Optional, Set, Type, Union
-
-from pip._internal.models.link import Link
-from pip._internal.req.req_install import InstallRequirement
-from pip._internal.utils.temp_dir import TempDirectory
-
-logger = logging.getLogger(__name__)
-
-
-@contextlib.contextmanager
-def update_env_context_manager(**changes: str) -> Generator[None, None, None]:
- target = os.environ
-
- # Save values from the target and change them.
- non_existent_marker = object()
- saved_values: Dict[str, Union[object, str]] = {}
- for name, new_value in changes.items():
- try:
- saved_values[name] = target[name]
- except KeyError:
- saved_values[name] = non_existent_marker
- target[name] = new_value
-
- try:
- yield
- finally:
- # Restore original values in the target.
- for name, original_value in saved_values.items():
- if original_value is non_existent_marker:
- del target[name]
- else:
- assert isinstance(original_value, str) # for mypy
- target[name] = original_value
-
-
-@contextlib.contextmanager
-def get_build_tracker() -> Generator["BuildTracker", None, None]:
- root = os.environ.get("PIP_BUILD_TRACKER")
- with contextlib.ExitStack() as ctx:
- if root is None:
- root = ctx.enter_context(TempDirectory(kind="build-tracker")).path
- ctx.enter_context(update_env_context_manager(PIP_BUILD_TRACKER=root))
- logger.debug("Initialized build tracking at %s", root)
-
- with BuildTracker(root) as tracker:
- yield tracker
-
-
-class TrackerId(str):
- """Uniquely identifying string provided to the build tracker."""
-
-
-class BuildTracker:
- """Ensure that an sdist cannot request itself as a setup requirement.
-
- When an sdist is prepared, it identifies its setup requirements in the
- context of ``BuildTracker.track()``. If a requirement shows up recursively, this
- raises an exception.
-
- This stops fork bombs embedded in malicious packages."""
-
- def __init__(self, root: str) -> None:
- self._root = root
- self._entries: Dict[TrackerId, InstallRequirement] = {}
- logger.debug("Created build tracker: %s", self._root)
-
- def __enter__(self) -> "BuildTracker":
- logger.debug("Entered build tracker: %s", self._root)
- return self
-
- def __exit__(
- self,
- exc_type: Optional[Type[BaseException]],
- exc_val: Optional[BaseException],
- exc_tb: Optional[TracebackType],
- ) -> None:
- self.cleanup()
-
- def _entry_path(self, key: TrackerId) -> str:
- hashed = hashlib.sha224(key.encode()).hexdigest()
- return os.path.join(self._root, hashed)
-
- def add(self, req: InstallRequirement, key: TrackerId) -> None:
- """Add an InstallRequirement to build tracking."""
-
- # Get the file to write information about this requirement.
- entry_path = self._entry_path(key)
-
- # Try reading from the file. If it exists and can be read from, a build
- # is already in progress, so a LookupError is raised.
- try:
- with open(entry_path) as fp:
- contents = fp.read()
- except FileNotFoundError:
- pass
- else:
- message = "{} is already being built: {}".format(req.link, contents)
- raise LookupError(message)
-
- # If we're here, req should really not be building already.
- assert key not in self._entries
-
- # Start tracking this requirement.
- with open(entry_path, "w", encoding="utf-8") as fp:
- fp.write(str(req))
- self._entries[key] = req
-
- logger.debug("Added %s to build tracker %r", req, self._root)
-
- def remove(self, req: InstallRequirement, key: TrackerId) -> None:
- """Remove an InstallRequirement from build tracking."""
-
- # Delete the created file and the corresponding entry.
- os.unlink(self._entry_path(key))
- del self._entries[key]
-
- logger.debug("Removed %s from build tracker %r", req, self._root)
-
- def cleanup(self) -> None:
- for key, req in list(self._entries.items()):
- self.remove(req, key)
-
- logger.debug("Removed build tracker: %r", self._root)
-
- @contextlib.contextmanager
- def track(self, req: InstallRequirement, key: str) -> Generator[None, None, None]:
- """Ensure that `key` cannot install itself as a setup requirement.
-
- :raises LookupError: If `key` was already provided in a parent invocation of
- the context introduced by this method."""
- tracker_id = TrackerId(key)
- self.add(req, tracker_id)
- yield
- self.remove(req, tracker_id)
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/metadata.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/metadata.py
deleted file mode 100644
index c66ac35..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/metadata.py
+++ /dev/null
@@ -1,39 +0,0 @@
-"""Metadata generation logic for source distributions.
-"""
-
-import os
-
-from pip._vendor.pyproject_hooks import BuildBackendHookCaller
-
-from pip._internal.build_env import BuildEnvironment
-from pip._internal.exceptions import (
- InstallationSubprocessError,
- MetadataGenerationFailed,
-)
-from pip._internal.utils.subprocess import runner_with_spinner_message
-from pip._internal.utils.temp_dir import TempDirectory
-
-
-def generate_metadata(
- build_env: BuildEnvironment, backend: BuildBackendHookCaller, details: str
-) -> str:
- """Generate metadata using mechanisms described in PEP 517.
-
- Returns the generated metadata directory.
- """
- metadata_tmpdir = TempDirectory(kind="modern-metadata", globally_managed=True)
-
- metadata_dir = metadata_tmpdir.path
-
- with build_env:
- # Note that BuildBackendHookCaller implements a fallback for
- # prepare_metadata_for_build_wheel, so we don't have to
- # consider the possibility that this hook doesn't exist.
- runner = runner_with_spinner_message("Preparing metadata (pyproject.toml)")
- with backend.subprocess_runner(runner):
- try:
- distinfo_dir = backend.prepare_metadata_for_build_wheel(metadata_dir)
- except InstallationSubprocessError as error:
- raise MetadataGenerationFailed(package_details=details) from error
-
- return os.path.join(metadata_dir, distinfo_dir)
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/metadata_editable.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/metadata_editable.py
deleted file mode 100644
index 27c69f0..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/metadata_editable.py
+++ /dev/null
@@ -1,41 +0,0 @@
-"""Metadata generation logic for source distributions.
-"""
-
-import os
-
-from pip._vendor.pyproject_hooks import BuildBackendHookCaller
-
-from pip._internal.build_env import BuildEnvironment
-from pip._internal.exceptions import (
- InstallationSubprocessError,
- MetadataGenerationFailed,
-)
-from pip._internal.utils.subprocess import runner_with_spinner_message
-from pip._internal.utils.temp_dir import TempDirectory
-
-
-def generate_editable_metadata(
- build_env: BuildEnvironment, backend: BuildBackendHookCaller, details: str
-) -> str:
- """Generate metadata using mechanisms described in PEP 660.
-
- Returns the generated metadata directory.
- """
- metadata_tmpdir = TempDirectory(kind="modern-metadata", globally_managed=True)
-
- metadata_dir = metadata_tmpdir.path
-
- with build_env:
- # Note that BuildBackendHookCaller implements a fallback for
- # prepare_metadata_for_build_wheel/editable, so we don't have to
- # consider the possibility that this hook doesn't exist.
- runner = runner_with_spinner_message(
- "Preparing editable metadata (pyproject.toml)"
- )
- with backend.subprocess_runner(runner):
- try:
- distinfo_dir = backend.prepare_metadata_for_build_editable(metadata_dir)
- except InstallationSubprocessError as error:
- raise MetadataGenerationFailed(package_details=details) from error
-
- return os.path.join(metadata_dir, distinfo_dir)
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/metadata_legacy.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/metadata_legacy.py
deleted file mode 100644
index e60988d..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/metadata_legacy.py
+++ /dev/null
@@ -1,74 +0,0 @@
-"""Metadata generation logic for legacy source distributions.
-"""
-
-import logging
-import os
-
-from pip._internal.build_env import BuildEnvironment
-from pip._internal.cli.spinners import open_spinner
-from pip._internal.exceptions import (
- InstallationError,
- InstallationSubprocessError,
- MetadataGenerationFailed,
-)
-from pip._internal.utils.setuptools_build import make_setuptools_egg_info_args
-from pip._internal.utils.subprocess import call_subprocess
-from pip._internal.utils.temp_dir import TempDirectory
-
-logger = logging.getLogger(__name__)
-
-
-def _find_egg_info(directory: str) -> str:
- """Find an .egg-info subdirectory in `directory`."""
- filenames = [f for f in os.listdir(directory) if f.endswith(".egg-info")]
-
- if not filenames:
- raise InstallationError(f"No .egg-info directory found in {directory}")
-
- if len(filenames) > 1:
- raise InstallationError(
- "More than one .egg-info directory found in {}".format(directory)
- )
-
- return os.path.join(directory, filenames[0])
-
-
-def generate_metadata(
- build_env: BuildEnvironment,
- setup_py_path: str,
- source_dir: str,
- isolated: bool,
- details: str,
-) -> str:
- """Generate metadata using setup.py-based defacto mechanisms.
-
- Returns the generated metadata directory.
- """
- logger.debug(
- "Running setup.py (path:%s) egg_info for package %s",
- setup_py_path,
- details,
- )
-
- egg_info_dir = TempDirectory(kind="pip-egg-info", globally_managed=True).path
-
- args = make_setuptools_egg_info_args(
- setup_py_path,
- egg_info_dir=egg_info_dir,
- no_user_config=isolated,
- )
-
- with build_env:
- with open_spinner("Preparing metadata (setup.py)") as spinner:
- try:
- call_subprocess(
- args,
- cwd=source_dir,
- command_desc="python setup.py egg_info",
- spinner=spinner,
- )
- except InstallationSubprocessError as error:
- raise MetadataGenerationFailed(package_details=details) from error
-
- # Return the .egg-info directory.
- return _find_egg_info(egg_info_dir)
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/wheel.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/wheel.py
deleted file mode 100644
index 064811a..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/wheel.py
+++ /dev/null
@@ -1,37 +0,0 @@
-import logging
-import os
-from typing import Optional
-
-from pip._vendor.pyproject_hooks import BuildBackendHookCaller
-
-from pip._internal.utils.subprocess import runner_with_spinner_message
-
-logger = logging.getLogger(__name__)
-
-
-def build_wheel_pep517(
- name: str,
- backend: BuildBackendHookCaller,
- metadata_directory: str,
- tempd: str,
-) -> Optional[str]:
- """Build one InstallRequirement using the PEP 517 build process.
-
- Returns path to wheel if successfully built. Otherwise, returns None.
- """
- assert metadata_directory is not None
- try:
- logger.debug("Destination directory: %s", tempd)
-
- runner = runner_with_spinner_message(
- f"Building wheel for {name} (pyproject.toml)"
- )
- with backend.subprocess_runner(runner):
- wheel_name = backend.build_wheel(
- tempd,
- metadata_directory=metadata_directory,
- )
- except Exception:
- logger.error("Failed building wheel for %s", name)
- return None
- return os.path.join(tempd, wheel_name)
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/wheel_editable.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/wheel_editable.py
deleted file mode 100644
index 719d69d..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/wheel_editable.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import logging
-import os
-from typing import Optional
-
-from pip._vendor.pyproject_hooks import BuildBackendHookCaller, HookMissing
-
-from pip._internal.utils.subprocess import runner_with_spinner_message
-
-logger = logging.getLogger(__name__)
-
-
-def build_wheel_editable(
- name: str,
- backend: BuildBackendHookCaller,
- metadata_directory: str,
- tempd: str,
-) -> Optional[str]:
- """Build one InstallRequirement using the PEP 660 build process.
-
- Returns path to wheel if successfully built. Otherwise, returns None.
- """
- assert metadata_directory is not None
- try:
- logger.debug("Destination directory: %s", tempd)
-
- runner = runner_with_spinner_message(
- f"Building editable for {name} (pyproject.toml)"
- )
- with backend.subprocess_runner(runner):
- try:
- wheel_name = backend.build_editable(
- tempd,
- metadata_directory=metadata_directory,
- )
- except HookMissing as e:
- logger.error(
- "Cannot build editable %s because the build "
- "backend does not have the %s hook",
- name,
- e,
- )
- return None
- except Exception:
- logger.error("Failed building editable for %s", name)
- return None
- return os.path.join(tempd, wheel_name)
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/wheel_legacy.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/build/wheel_legacy.py
deleted file mode 100644
index c5f0492..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/build/wheel_legacy.py
+++ /dev/null
@@ -1,102 +0,0 @@
-import logging
-import os.path
-from typing import List, Optional
-
-from pip._internal.cli.spinners import open_spinner
-from pip._internal.utils.setuptools_build import make_setuptools_bdist_wheel_args
-from pip._internal.utils.subprocess import call_subprocess, format_command_args
-
-logger = logging.getLogger(__name__)
-
-
-def format_command_result(
- command_args: List[str],
- command_output: str,
-) -> str:
- """Format command information for logging."""
- command_desc = format_command_args(command_args)
- text = f"Command arguments: {command_desc}\n"
-
- if not command_output:
- text += "Command output: None"
- elif logger.getEffectiveLevel() > logging.DEBUG:
- text += "Command output: [use --verbose to show]"
- else:
- if not command_output.endswith("\n"):
- command_output += "\n"
- text += f"Command output:\n{command_output}"
-
- return text
-
-
-def get_legacy_build_wheel_path(
- names: List[str],
- temp_dir: str,
- name: str,
- command_args: List[str],
- command_output: str,
-) -> Optional[str]:
- """Return the path to the wheel in the temporary build directory."""
- # Sort for determinism.
- names = sorted(names)
- if not names:
- msg = ("Legacy build of wheel for {!r} created no files.\n").format(name)
- msg += format_command_result(command_args, command_output)
- logger.warning(msg)
- return None
-
- if len(names) > 1:
- msg = (
- "Legacy build of wheel for {!r} created more than one file.\n"
- "Filenames (choosing first): {}\n"
- ).format(name, names)
- msg += format_command_result(command_args, command_output)
- logger.warning(msg)
-
- return os.path.join(temp_dir, names[0])
-
-
-def build_wheel_legacy(
- name: str,
- setup_py_path: str,
- source_dir: str,
- global_options: List[str],
- build_options: List[str],
- tempd: str,
-) -> Optional[str]:
- """Build one unpacked package using the "legacy" build process.
-
- Returns path to wheel if successfully built. Otherwise, returns None.
- """
- wheel_args = make_setuptools_bdist_wheel_args(
- setup_py_path,
- global_options=global_options,
- build_options=build_options,
- destination_dir=tempd,
- )
-
- spin_message = f"Building wheel for {name} (setup.py)"
- with open_spinner(spin_message) as spinner:
- logger.debug("Destination directory: %s", tempd)
-
- try:
- output = call_subprocess(
- wheel_args,
- command_desc="python setup.py bdist_wheel",
- cwd=source_dir,
- spinner=spinner,
- )
- except Exception:
- spinner.finish("error")
- logger.error("Failed building wheel for %s", name)
- return None
-
- names = os.listdir(tempd)
- wheel_path = get_legacy_build_wheel_path(
- names=names,
- temp_dir=tempd,
- name=name,
- command_args=wheel_args,
- command_output=output,
- )
- return wheel_path
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/check.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/check.py
deleted file mode 100644
index 90c6a58..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/check.py
+++ /dev/null
@@ -1,187 +0,0 @@
-"""Validation of dependencies of packages
-"""
-
-import logging
-from typing import Callable, Dict, List, NamedTuple, Optional, Set, Tuple
-
-from pip._vendor.packaging.requirements import Requirement
-from pip._vendor.packaging.specifiers import LegacySpecifier
-from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
-from pip._vendor.packaging.version import LegacyVersion
-
-from pip._internal.distributions import make_distribution_for_install_requirement
-from pip._internal.metadata import get_default_environment
-from pip._internal.metadata.base import DistributionVersion
-from pip._internal.req.req_install import InstallRequirement
-from pip._internal.utils.deprecation import deprecated
-
-logger = logging.getLogger(__name__)
-
-
-class PackageDetails(NamedTuple):
- version: DistributionVersion
- dependencies: List[Requirement]
-
-
-# Shorthands
-PackageSet = Dict[NormalizedName, PackageDetails]
-Missing = Tuple[NormalizedName, Requirement]
-Conflicting = Tuple[NormalizedName, DistributionVersion, Requirement]
-
-MissingDict = Dict[NormalizedName, List[Missing]]
-ConflictingDict = Dict[NormalizedName, List[Conflicting]]
-CheckResult = Tuple[MissingDict, ConflictingDict]
-ConflictDetails = Tuple[PackageSet, CheckResult]
-
-
-def create_package_set_from_installed() -> Tuple[PackageSet, bool]:
- """Converts a list of distributions into a PackageSet."""
- package_set = {}
- problems = False
- env = get_default_environment()
- for dist in env.iter_installed_distributions(local_only=False, skip=()):
- name = dist.canonical_name
- try:
- dependencies = list(dist.iter_dependencies())
- package_set[name] = PackageDetails(dist.version, dependencies)
- except (OSError, ValueError) as e:
- # Don't crash on unreadable or broken metadata.
- logger.warning("Error parsing requirements for %s: %s", name, e)
- problems = True
- return package_set, problems
-
-
-def check_package_set(
- package_set: PackageSet, should_ignore: Optional[Callable[[str], bool]] = None
-) -> CheckResult:
- """Check if a package set is consistent
-
- If should_ignore is passed, it should be a callable that takes a
- package name and returns a boolean.
- """
-
- warn_legacy_versions_and_specifiers(package_set)
-
- missing = {}
- conflicting = {}
-
- for package_name, package_detail in package_set.items():
- # Info about dependencies of package_name
- missing_deps: Set[Missing] = set()
- conflicting_deps: Set[Conflicting] = set()
-
- if should_ignore and should_ignore(package_name):
- continue
-
- for req in package_detail.dependencies:
- name = canonicalize_name(req.name)
-
- # Check if it's missing
- if name not in package_set:
- missed = True
- if req.marker is not None:
- missed = req.marker.evaluate({"extra": ""})
- if missed:
- missing_deps.add((name, req))
- continue
-
- # Check if there's a conflict
- version = package_set[name].version
- if not req.specifier.contains(version, prereleases=True):
- conflicting_deps.add((name, version, req))
-
- if missing_deps:
- missing[package_name] = sorted(missing_deps, key=str)
- if conflicting_deps:
- conflicting[package_name] = sorted(conflicting_deps, key=str)
-
- return missing, conflicting
-
-
-def check_install_conflicts(to_install: List[InstallRequirement]) -> ConflictDetails:
- """For checking if the dependency graph would be consistent after \
- installing given requirements
- """
- # Start from the current state
- package_set, _ = create_package_set_from_installed()
- # Install packages
- would_be_installed = _simulate_installation_of(to_install, package_set)
-
- # Only warn about directly-dependent packages; create a whitelist of them
- whitelist = _create_whitelist(would_be_installed, package_set)
-
- return (
- package_set,
- check_package_set(
- package_set, should_ignore=lambda name: name not in whitelist
- ),
- )
-
-
-def _simulate_installation_of(
- to_install: List[InstallRequirement], package_set: PackageSet
-) -> Set[NormalizedName]:
- """Computes the version of packages after installing to_install."""
- # Keep track of packages that were installed
- installed = set()
-
- # Modify it as installing requirement_set would (assuming no errors)
- for inst_req in to_install:
- abstract_dist = make_distribution_for_install_requirement(inst_req)
- dist = abstract_dist.get_metadata_distribution()
- name = dist.canonical_name
- package_set[name] = PackageDetails(dist.version, list(dist.iter_dependencies()))
-
- installed.add(name)
-
- return installed
-
-
-def _create_whitelist(
- would_be_installed: Set[NormalizedName], package_set: PackageSet
-) -> Set[NormalizedName]:
- packages_affected = set(would_be_installed)
-
- for package_name in package_set:
- if package_name in packages_affected:
- continue
-
- for req in package_set[package_name].dependencies:
- if canonicalize_name(req.name) in packages_affected:
- packages_affected.add(package_name)
- break
-
- return packages_affected
-
-
-def warn_legacy_versions_and_specifiers(package_set: PackageSet) -> None:
- for project_name, package_details in package_set.items():
- if isinstance(package_details.version, LegacyVersion):
- deprecated(
- reason=(
- f"{project_name} {package_details.version} "
- f"has a non-standard version number."
- ),
- replacement=(
- f"to upgrade to a newer version of {project_name} "
- f"or contact the author to suggest that they "
- f"release a version with a conforming version number"
- ),
- issue=12063,
- gone_in="24.1",
- )
- for dep in package_details.dependencies:
- if any(isinstance(spec, LegacySpecifier) for spec in dep.specifier):
- deprecated(
- reason=(
- f"{project_name} {package_details.version} "
- f"has a non-standard dependency specifier {dep}."
- ),
- replacement=(
- f"to upgrade to a newer version of {project_name} "
- f"or contact the author to suggest that they "
- f"release a version with a conforming dependency specifiers"
- ),
- issue=12063,
- gone_in="24.1",
- )
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/freeze.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/freeze.py
deleted file mode 100644
index 3544568..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/freeze.py
+++ /dev/null
@@ -1,255 +0,0 @@
-import collections
-import logging
-import os
-from typing import Container, Dict, Generator, Iterable, List, NamedTuple, Optional, Set
-
-from pip._vendor.packaging.utils import canonicalize_name
-from pip._vendor.packaging.version import Version
-
-from pip._internal.exceptions import BadCommand, InstallationError
-from pip._internal.metadata import BaseDistribution, get_environment
-from pip._internal.req.constructors import (
- install_req_from_editable,
- install_req_from_line,
-)
-from pip._internal.req.req_file import COMMENT_RE
-from pip._internal.utils.direct_url_helpers import direct_url_as_pep440_direct_reference
-
-logger = logging.getLogger(__name__)
-
-
-class _EditableInfo(NamedTuple):
- requirement: str
- comments: List[str]
-
-
-def freeze(
- requirement: Optional[List[str]] = None,
- local_only: bool = False,
- user_only: bool = False,
- paths: Optional[List[str]] = None,
- isolated: bool = False,
- exclude_editable: bool = False,
- skip: Container[str] = (),
-) -> Generator[str, None, None]:
- installations: Dict[str, FrozenRequirement] = {}
-
- dists = get_environment(paths).iter_installed_distributions(
- local_only=local_only,
- skip=(),
- user_only=user_only,
- )
- for dist in dists:
- req = FrozenRequirement.from_dist(dist)
- if exclude_editable and req.editable:
- continue
- installations[req.canonical_name] = req
-
- if requirement:
- # the options that don't get turned into an InstallRequirement
- # should only be emitted once, even if the same option is in multiple
- # requirements files, so we need to keep track of what has been emitted
- # so that we don't emit it again if it's seen again
- emitted_options: Set[str] = set()
- # keep track of which files a requirement is in so that we can
- # give an accurate warning if a requirement appears multiple times.
- req_files: Dict[str, List[str]] = collections.defaultdict(list)
- for req_file_path in requirement:
- with open(req_file_path) as req_file:
- for line in req_file:
- if (
- not line.strip()
- or line.strip().startswith("#")
- or line.startswith(
- (
- "-r",
- "--requirement",
- "-f",
- "--find-links",
- "-i",
- "--index-url",
- "--pre",
- "--trusted-host",
- "--process-dependency-links",
- "--extra-index-url",
- "--use-feature",
- )
- )
- ):
- line = line.rstrip()
- if line not in emitted_options:
- emitted_options.add(line)
- yield line
- continue
-
- if line.startswith("-e") or line.startswith("--editable"):
- if line.startswith("-e"):
- line = line[2:].strip()
- else:
- line = line[len("--editable") :].strip().lstrip("=")
- line_req = install_req_from_editable(
- line,
- isolated=isolated,
- )
- else:
- line_req = install_req_from_line(
- COMMENT_RE.sub("", line).strip(),
- isolated=isolated,
- )
-
- if not line_req.name:
- logger.info(
- "Skipping line in requirement file [%s] because "
- "it's not clear what it would install: %s",
- req_file_path,
- line.strip(),
- )
- logger.info(
- " (add #egg=PackageName to the URL to avoid"
- " this warning)"
- )
- else:
- line_req_canonical_name = canonicalize_name(line_req.name)
- if line_req_canonical_name not in installations:
- # either it's not installed, or it is installed
- # but has been processed already
- if not req_files[line_req.name]:
- logger.warning(
- "Requirement file [%s] contains %s, but "
- "package %r is not installed",
- req_file_path,
- COMMENT_RE.sub("", line).strip(),
- line_req.name,
- )
- else:
- req_files[line_req.name].append(req_file_path)
- else:
- yield str(installations[line_req_canonical_name]).rstrip()
- del installations[line_req_canonical_name]
- req_files[line_req.name].append(req_file_path)
-
- # Warn about requirements that were included multiple times (in a
- # single requirements file or in different requirements files).
- for name, files in req_files.items():
- if len(files) > 1:
- logger.warning(
- "Requirement %s included multiple times [%s]",
- name,
- ", ".join(sorted(set(files))),
- )
-
- yield ("## The following requirements were added by pip freeze:")
- for installation in sorted(installations.values(), key=lambda x: x.name.lower()):
- if installation.canonical_name not in skip:
- yield str(installation).rstrip()
-
-
-def _format_as_name_version(dist: BaseDistribution) -> str:
- dist_version = dist.version
- if isinstance(dist_version, Version):
- return f"{dist.raw_name}=={dist_version}"
- return f"{dist.raw_name}==={dist_version}"
-
-
-def _get_editable_info(dist: BaseDistribution) -> _EditableInfo:
- """
- Compute and return values (req, comments) for use in
- FrozenRequirement.from_dist().
- """
- editable_project_location = dist.editable_project_location
- assert editable_project_location
- location = os.path.normcase(os.path.abspath(editable_project_location))
-
- from pip._internal.vcs import RemoteNotFoundError, RemoteNotValidError, vcs
-
- vcs_backend = vcs.get_backend_for_dir(location)
-
- if vcs_backend is None:
- display = _format_as_name_version(dist)
- logger.debug(
- 'No VCS found for editable requirement "%s" in: %r',
- display,
- location,
- )
- return _EditableInfo(
- requirement=location,
- comments=[f"# Editable install with no version control ({display})"],
- )
-
- vcs_name = type(vcs_backend).__name__
-
- try:
- req = vcs_backend.get_src_requirement(location, dist.raw_name)
- except RemoteNotFoundError:
- display = _format_as_name_version(dist)
- return _EditableInfo(
- requirement=location,
- comments=[f"# Editable {vcs_name} install with no remote ({display})"],
- )
- except RemoteNotValidError as ex:
- display = _format_as_name_version(dist)
- return _EditableInfo(
- requirement=location,
- comments=[
- f"# Editable {vcs_name} install ({display}) with either a deleted "
- f"local remote or invalid URI:",
- f"# '{ex.url}'",
- ],
- )
- except BadCommand:
- logger.warning(
- "cannot determine version of editable source in %s "
- "(%s command not found in path)",
- location,
- vcs_backend.name,
- )
- return _EditableInfo(requirement=location, comments=[])
- except InstallationError as exc:
- logger.warning("Error when trying to get requirement for VCS system %s", exc)
- else:
- return _EditableInfo(requirement=req, comments=[])
-
- logger.warning("Could not determine repository location of %s", location)
-
- return _EditableInfo(
- requirement=location,
- comments=["## !! Could not determine repository location"],
- )
-
-
-class FrozenRequirement:
- def __init__(
- self,
- name: str,
- req: str,
- editable: bool,
- comments: Iterable[str] = (),
- ) -> None:
- self.name = name
- self.canonical_name = canonicalize_name(name)
- self.req = req
- self.editable = editable
- self.comments = comments
-
- @classmethod
- def from_dist(cls, dist: BaseDistribution) -> "FrozenRequirement":
- editable = dist.editable
- if editable:
- req, comments = _get_editable_info(dist)
- else:
- comments = []
- direct_url = dist.direct_url
- if direct_url:
- # if PEP 610 metadata is present, use it
- req = direct_url_as_pep440_direct_reference(direct_url, dist.raw_name)
- else:
- # name==version requirement
- req = _format_as_name_version(dist)
-
- return cls(dist.raw_name, req, editable, comments=comments)
-
- def __str__(self) -> str:
- req = self.req
- if self.editable:
- req = f"-e {req}"
- return "\n".join(list(self.comments) + [str(req)]) + "\n"
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/install/__init__.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/install/__init__.py
deleted file mode 100644
index 24d6a5d..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/install/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-"""For modules related to installing packages.
-"""
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-311.pyc
deleted file mode 100644
index b8a5965..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-311.pyc
deleted file mode 100644
index f62cb29..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-311.pyc
deleted file mode 100644
index 88b5111..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-311.pyc
+++ /dev/null
Binary files differ
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/install/editable_legacy.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/install/editable_legacy.py
deleted file mode 100644
index bebe24e..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/install/editable_legacy.py
+++ /dev/null
@@ -1,46 +0,0 @@
-"""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,
- )
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/install/wheel.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/install/wheel.py
deleted file mode 100644
index f67180c..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/install/wheel.py
+++ /dev/null
@@ -1,734 +0,0 @@
-"""Support for installing and building the "wheel" binary package format.
-"""
-
-import collections
-import compileall
-import contextlib
-import csv
-import importlib
-import logging
-import os.path
-import re
-import shutil
-import sys
-import warnings
-from base64 import urlsafe_b64encode
-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,
- Optional,
- Sequence,
- Set,
- Tuple,
- Union,
- cast,
-)
-from zipfile import ZipFile, ZipInfo
-
-from pip._vendor.distlib.scripts import ScriptMaker
-from pip._vendor.distlib.util import get_export_entry
-from pip._vendor.packaging.utils import canonicalize_name
-
-from pip._internal.exceptions import InstallationError
-from pip._internal.locations import get_major_minor_version
-from pip._internal.metadata import (
- BaseDistribution,
- FilesystemWheel,
- get_wheel_distribution,
-)
-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 captured_stdout, ensure_dir, hash_file, partition
-from pip._internal.utils.unpacking import (
- current_umask,
- is_within_directory,
- set_extracted_file_to_default_mode_plus_executable,
- zip_item_is_executable,
-)
-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
-
- def save(self) -> None:
- pass
-
-
-logger = logging.getLogger(__name__)
-
-RecordPath = NewType("RecordPath", str)
-InstalledCSVRow = Tuple[RecordPath, str, Union[int, 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]:
- """Return keyword arguments to properly open a CSV file
- in the given mode.
- """
- return {"mode": mode, "newline": "", "encoding": "utf-8"}
-
-
-def fix_script(path: str) -> bool:
- """Replace #!python with #!/path/to/python
- Return True if file was changed.
- """
- # XXX RECORD hashes will need to be updated
- assert os.path.isfile(path)
-
- with open(path, "rb") as script:
- firstline = script.readline()
- if not firstline.startswith(b"#!python"):
- return False
- exename = sys.executable.encode(sys.getfilesystemencoding())
- firstline = b"#!" + exename + os.linesep.encode("ascii")
- rest = script.read()
- with open(path, "wb") as script:
- script.write(firstline)
- script.write(rest)
- return True
-
-
-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]]:
- console_scripts = {}
- gui_scripts = {}
- for entry_point in dist.iter_entry_points():
- if entry_point.group == "console_scripts":
- console_scripts[entry_point.name] = entry_point.value
- elif entry_point.group == "gui_scripts":
- gui_scripts[entry_point.name] = entry_point.value
- return console_scripts, gui_scripts
-
-
-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.
- """
- if not scripts:
- return None
-
- # Group scripts by the path they were installed in
- 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)
- grouped_by_dir[parent_dir].add(script_name)
-
- # We don't want to warn for directories that are on PATH.
- not_warn_dirs = [
- os.path.normcase(os.path.normpath(i)).rstrip(os.sep)
- for i in os.environ.get("PATH", "").split(os.pathsep)
- ]
- # If an executable sits with sys.executable, we don't warn for it.
- # This covers the case of venv invocations without activating the venv.
- not_warn_dirs.append(
- os.path.normcase(os.path.normpath(os.path.dirname(sys.executable)))
- )
- 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
- }
- if not warn_for:
- return None
-
- # Format a message
- msg_lines = []
- for parent_dir, dir_scripts in warn_for.items():
- sorted_scripts: List[str] = sorted(dir_scripts)
- if len(sorted_scripts) == 1:
- start_text = f"script {sorted_scripts[0]} is"
- else:
- start_text = "scripts {} are".format(
- ", ".join(sorted_scripts[:-1]) + " and " + sorted_scripts[-1]
- )
-
- msg_lines.append(
- f"The {start_text} installed in '{parent_dir}' which is not on PATH."
- )
-
- last_line_fmt = (
- "Consider adding {} to PATH or, if you prefer "
- "to suppress this warning, use --no-warn-script-location."
- )
- if len(msg_lines) == 1:
- msg_lines.append(last_line_fmt.format("this directory"))
- else:
- msg_lines.append(last_line_fmt.format("these directories"))
-
- # Add a note if any directory starts with ~
- warn_for_tilde = any(
- i[0] == "~" for i in os.environ.get("PATH", "").split(os.pathsep) if i
- )
- if warn_for_tilde:
- tilde_warning_msg = (
- "NOTE: The current PATH contains path(s) starting with `~`, "
- "which may not be expanded by all applications."
- )
- msg_lines.append(tilde_warning_msg)
-
- # Returns the formatted multiline message
- return "\n".join(msg_lines)
-
-
-def _normalized_outrows(
- outrows: Iterable[InstalledCSVRow],
-) -> 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
- the value more predictable for tests.
-
- Each row is a 3-tuple (path, hash, size) and corresponds to a record of
- a RECORD file (see PEP 376 and PEP 427 for details). For the rows
- passed to this function, the size can be an integer as an int or string,
- or the empty string.
- """
- # Normally, there should only be one row per path, in which case the
- # second and third elements don't come into play when sorting.
- # However, in cases in the wild where a path might happen to occur twice,
- # we don't want the sort operation to trigger an error (but still want
- # determinism). Since the third element can be an int or string, we
- # coerce each element to a string to avoid a TypeError in this case.
- # For additional background, see--
- # https://github.com/pypa/pip/issues/5868
- return sorted(
- (record_path, hash_, str(size)) for record_path, hash_, size in outrows
- )
-
-
-def _record_to_fs_path(record_path: RecordPath, lib_dir: str) -> str:
- return os.path.join(lib_dir, record_path)
-
-
-def _fs_to_record_path(path: str, lib_dir: str) -> RecordPath:
- # On Windows, do not handle relative paths if they belong to different
- # logical disks
- if os.path.splitdrive(path)[0].lower() == os.path.splitdrive(lib_dir)[0].lower():
- path = os.path.relpath(path, lib_dir)
-
- path = path.replace(os.path.sep, "/")
- return cast("RecordPath", path)
-
-
-def get_csv_rows_for_installed(
- old_csv_rows: List[List[str]],
- installed: Dict[RecordPath, RecordPath],
- changed: Set[RecordPath],
- generated: List[str],
- lib_dir: str,
-) -> List[InstalledCSVRow]:
- """
- :param installed: A map from archive RECORD path to installation RECORD
- path.
- """
- 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)
- old_record_path = cast("RecordPath", row[0])
- new_record_path = installed.pop(old_record_path, old_record_path)
- if new_record_path in changed:
- digest, length = rehash(_record_to_fs_path(new_record_path, lib_dir))
- else:
- digest = row[1] if len(row) > 1 else ""
- length = row[2] if len(row) > 2 else ""
- installed_rows.append((new_record_path, digest, length))
- for f in generated:
- path = _fs_to_record_path(f, lib_dir)
- digest, length = rehash(f)
- installed_rows.append((path, digest, length))
- return installed_rows + [
- (installed_record_path, "", "") for installed_record_path in installed.values()
- ]
-
-
-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.
- """
- # Don't mutate caller's version
- console = console.copy()
-
- scripts_to_generate = []
-
- # Special case pip and setuptools to generate versioned wrappers
- #
- # The issue is that some projects (specifically, pip and setuptools) use
- # code in setup.py to create "versioned" entry points - pip2.7 on Python
- # 2.7, pip3.3 on Python 3.3, etc. But these entry points are baked into
- # 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, 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. So, as a stopgap until Metadata 2.0, we
- # override the versioned entry points in the wheel and generate the
- # 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
- # variable which will control which version scripts get installed.
- #
- # ENSUREPIP_OPTIONS=altinstall
- # - Only pipX.Y and easy_install-X.Y will be generated and installed
- # ENSUREPIP_OPTIONS=install
- # - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note
- # that this option is technically if ENSUREPIP_OPTIONS is set and is
- # not altinstall
- # DEFAULT
- # - The default behavior is to install pip, pipX, pipX.Y, easy_install
- # and easy_install-X.Y.
- pip_script = console.pop("pip", None)
- if pip_script:
- if "ENSUREPIP_OPTIONS" not in os.environ:
- scripts_to_generate.append("pip = " + pip_script)
-
- if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall":
- scripts_to_generate.append(f"pip{sys.version_info[0]} = {pip_script}")
-
- scripts_to_generate.append(f"pip{get_major_minor_version()} = {pip_script}")
- # Delete any other versioned pip entry points
- pip_ep = [k for k in console if re.match(r"pip(\d+(\.\d+)?)?$", k)]
- for k in pip_ep:
- del console[k]
- easy_install_script = console.pop("easy_install", None)
- if easy_install_script:
- if "ENSUREPIP_OPTIONS" not in os.environ:
- scripts_to_generate.append("easy_install = " + easy_install_script)
-
- scripts_to_generate.append(
- f"easy_install-{get_major_minor_version()} = {easy_install_script}"
- )
- # Delete any other versioned easy_install entry points
- easy_install_ep = [
- k for k in console if re.match(r"easy_install(-\d+\.\d+)?$", k)
- ]
- for k in easy_install_ep:
- del console[k]
-
- # Generate the console entry points specified in the wheel
- scripts_to_generate.extend(starmap("{} = {}".format, console.items()))
-
- return scripts_to_generate
-
-
-class ZipBackedFile:
- def __init__(
- self, src_record_path: RecordPath, dest_path: str, zip_file: ZipFile
- ) -> None:
- self.src_record_path = src_record_path
- self.dest_path = dest_path
- self._zip_file = zip_file
- self.changed = False
-
- def _getinfo(self) -> ZipInfo:
- 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
- # object (e.g. from pyopenssl through its vendored urllib3)
- # Since the shared object is mmap'd an attempt to call a
- # symbol in it will then cause a segfault. Unlinking the file
- # allows writing of new contents while allowing the process to
- # continue to use the old copy.
- if os.path.exists(self.dest_path):
- os.unlink(self.dest_path)
-
- zipinfo = self._getinfo()
-
- 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:
- self._file = file
- self.src_record_path = self._file.src_record_path
- self.dest_path = self._file.dest_path
- self.changed = False
-
- def save(self) -> None:
- self._file.save()
- self.changed = fix_script(self.dest_path)
-
-
-class MissingCallableSuffix(InstallationError):
- def __init__(self, entry_point: str) -> None:
- super().__init__(
- f"Invalid script entry point: {entry_point} - A callable "
- "suffix is required. Cf https://packaging.python.org/"
- "specifications/entry-points/#use-for-scripts for more "
- "information."
- )
-
-
-def _raise_for_invalid_entrypoint(specification: str) -> None:
- entry = get_export_entry(specification)
- if entry is not None and entry.suffix is None:
- raise MissingCallableSuffix(str(entry))
-
-
-class PipScriptMaker(ScriptMaker):
- def make(
- self, specification: str, options: Optional[Dict[str, Any]] = None
- ) -> List[str]:
- _raise_for_invalid_entrypoint(specification)
- return super().make(specification, options)
-
-
-def _install_wheel(
- name: str,
- wheel_zip: ZipFile,
- wheel_path: str,
- scheme: Scheme,
- pycompile: bool = True,
- warn_script_location: bool = True,
- direct_url: Optional[DirectUrl] = None,
- requested: bool = False,
-) -> None:
- """Install a wheel.
-
- :param name: Name of the project to install
- :param wheel_zip: open ZipFile for wheel being installed
- :param scheme: Distutils scheme dictating the install directories
- :param req_description: String used in place of the requirement, for
- logging
- :param pycompile: Whether to byte-compile installed Python files
- :param warn_script_location: Whether to check that scripts are installed
- into a directory on PATH
- :raises UnsupportedWheel:
- * when the directory holds an unpacked wheel with incompatible
- Wheel-Version
- * when the .dist-info dir does not match the wheel
- """
- info_dir, metadata = parse_wheel(wheel_zip, name)
-
- if wheel_root_is_purelib(metadata):
- lib_dir = scheme.purelib
- else:
- lib_dir = scheme.platlib
-
- # Record details of the files moved
- # 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] = []
-
- def record_installed(
- srcfile: RecordPath, destfile: str, modified: bool = False
- ) -> None:
- """Map archive RECORD paths to installation RECORD paths."""
- newpath = _fs_to_record_path(destfile, lib_dir)
- installed[srcfile] = newpath
- if modified:
- changed.add(newpath)
-
- def is_dir_path(path: RecordPath) -> bool:
- return path.endswith("/")
-
- def assert_no_path_traversal(dest_dir_path: str, target_path: str) -> None:
- if not is_within_directory(dest_dir_path, target_path):
- message = (
- "The wheel {!r} has a file {!r} trying to install"
- " outside the target directory {!r}"
- )
- raise InstallationError(
- message.format(wheel_path, target_path, dest_dir_path)
- )
-
- def root_scheme_file_maker(
- zip_file: ZipFile, dest: str
- ) -> 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)
- return ZipBackedFile(record_path, dest_path, zip_file)
-
- return make_root_scheme_file
-
- def data_scheme_file_maker(
- zip_file: ZipFile, scheme: Scheme
- ) -> Callable[[RecordPath], "File"]:
- scheme_paths = {key: getattr(scheme, key) for key in SCHEME_KEYS}
-
- 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 = (
- "Unexpected file in {}: {!r}. .data directory contents"
- " should be named like: '<scheme key>/<path>'."
- ).format(wheel_path, record_path)
- raise InstallationError(message)
-
- try:
- scheme_path = scheme_paths[scheme_key]
- except KeyError:
- valid_scheme_keys = ", ".join(sorted(scheme_paths))
- message = (
- "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)
- assert_no_path_traversal(scheme_path, dest_path)
- return ZipBackedFile(record_path, dest_path, zip_file)
-
- return make_data_scheme_file
-
- def is_data_scheme_path(path: RecordPath) -> bool:
- return path.split("/", 1)[0].endswith(".data")
-
- 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)
-
- make_root_scheme_file = root_scheme_file_maker(wheel_zip, lib_dir)
- files: Iterator[File] = map(make_root_scheme_file, root_scheme_paths)
-
- def is_script_scheme_path(path: RecordPath) -> bool:
- parts = path.split("/", 2)
- return len(parts) > 2 and parts[0].endswith(".data") and parts[1] == "scripts"
-
- other_scheme_paths, script_scheme_paths = partition(
- is_script_scheme_path, data_scheme_paths
- )
-
- make_data_scheme_file = data_scheme_file_maker(wheel_zip, scheme)
- other_scheme_files = map(make_data_scheme_file, other_scheme_paths)
- files = chain(files, other_scheme_files)
-
- # Get the defined entry points
- distribution = get_wheel_distribution(
- FilesystemWheel(wheel_path),
- canonicalize_name(name),
- )
- console, gui = get_entrypoints(distribution)
-
- 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
- name = os.path.basename(path)
- if name.lower().endswith(".exe"):
- matchname = name[:-4]
- elif name.lower().endswith("-script.py"):
- matchname = name[:-10]
- elif name.lower().endswith(".pya"):
- matchname = name[:-4]
- else:
- matchname = name
- # Ignore setuptools-generated scripts
- return matchname in console or matchname in gui
-
- script_scheme_files: Iterator[File] = map(
- make_data_scheme_file, script_scheme_paths
- )
- script_scheme_files = filterfalse(is_entrypoint_wrapper, script_scheme_files)
- script_scheme_files = map(ScriptFile, script_scheme_files)
- files = chain(files, script_scheme_files)
-
- for file in files:
- file.save()
- record_installed(file.src_record_path, file.dest_path, file.changed)
-
- def pyc_source_file_paths() -> Generator[str, None, None]:
- # We de-duplicate installation paths, since there can be overlap (e.g.
- # file in .data maps to same location as file in wheel root).
- # Sorting installation paths makes it easier to reproduce and debug
- # issues related to permissions on existing files.
- for installed_path in sorted(set(installed.values())):
- full_installed_path = os.path.join(lib_dir, installed_path)
- if not os.path.isfile(full_installed_path):
- continue
- if not full_installed_path.endswith(".py"):
- continue
- yield full_installed_path
-
- def pyc_output_path(path: str) -> str:
- """Return the path the pyc file would have been written to."""
- return importlib.util.cache_from_source(path)
-
- # Compile all of the pyc files for the installed files
- if pycompile:
- with captured_stdout() as stdout:
- with warnings.catch_warnings():
- warnings.filterwarnings("ignore")
- for path in pyc_source_file_paths():
- success = compileall.compile_file(path, force=True, quiet=True)
- if success:
- pyc_path = pyc_output_path(path)
- assert os.path.exists(pyc_path)
- pyc_record_path = cast(
- "RecordPath", pyc_path.replace(os.path.sep, "/")
- )
- record_installed(pyc_record_path, pyc_path)
- logger.debug(stdout.getvalue())
-
- maker = PipScriptMaker(None, scheme.scripts)
-
- # Ensure old scripts are overwritten.
- # See https://github.com/pypa/pip/issues/1800
- maker.clobber = True
-
- # Ensure we don't generate any variants for scripts because this is almost
- # never what somebody wants.
- # See https://bitbucket.org/pypa/distlib/issue/35/
- maker.variants = {""}
-
- # This is required because otherwise distlib creates scripts that are not
- # executable.
- # See https://bitbucket.org/pypa/distlib/issue/32/
- maker.set_mode = True
-
- # Generate the console and GUI entry points specified in the wheel
- scripts_to_generate = get_console_script_specs(console)
-
- gui_scripts_to_generate = list(starmap("{} = {}".format, gui.items()))
-
- generated_console_scripts = maker.make_multiple(scripts_to_generate)
- generated.extend(generated_console_scripts)
-
- generated.extend(maker.make_multiple(gui_scripts_to_generate, {"gui": True}))
-
- if warn_script_location:
- msg = message_about_scripts_not_on_PATH(generated_console_scripts)
- if msg is not None:
- logger.warning(msg)
-
- generated_file_mode = 0o666 & ~current_umask()
-
- @contextlib.contextmanager
- def _generate_file(path: str, **kwargs: Any) -> Generator[BinaryIO, None, None]:
- with adjacent_tmp_file(path, **kwargs) as f:
- yield f
- os.chmod(f.name, generated_file_mode)
- replace(f.name, path)
-
- dest_info_dir = os.path.join(lib_dir, info_dir)
-
- # Record pip as the installer
- installer_path = os.path.join(dest_info_dir, "INSTALLER")
- with _generate_file(installer_path) as installer_file:
- installer_file.write(b"pip\n")
- generated.append(installer_path)
-
- # Record the PEP 610 direct URL reference
- if direct_url is not None:
- direct_url_path = os.path.join(dest_info_dir, DIRECT_URL_METADATA_NAME)
- with _generate_file(direct_url_path) as direct_url_file:
- direct_url_file.write(direct_url.to_json().encode("utf-8"))
- generated.append(direct_url_path)
-
- # Record the REQUESTED file
- if requested:
- requested_path = os.path.join(dest_info_dir, "REQUESTED")
- with open(requested_path, "wb"):
- pass
- generated.append(requested_path)
-
- record_text = distribution.read_text("RECORD")
- record_rows = list(csv.reader(record_text.splitlines()))
-
- rows = get_csv_rows_for_installed(
- record_rows,
- installed=installed,
- changed=changed,
- generated=generated,
- lib_dir=lib_dir,
- )
-
- # Record details of all files installed
- record_path = os.path.join(dest_info_dir, "RECORD")
-
- with _generate_file(record_path, **csv_io_kwargs("w")) as record_file:
- # Explicitly cast to typing.IO[str] as a workaround for the mypy error:
- # "writer" has incompatible type "BinaryIO"; expected "_Writer"
- writer = csv.writer(cast("IO[str]", record_file))
- writer.writerows(_normalized_outrows(rows))
-
-
-@contextlib.contextmanager
-def req_error_context(req_description: str) -> Generator[None, None, None]:
- try:
- yield
- except InstallationError as e:
- message = f"For req: {req_description}. {e.args[0]}"
- raise InstallationError(message) from e
-
-
-def install_wheel(
- name: str,
- wheel_path: str,
- scheme: Scheme,
- req_description: str,
- pycompile: bool = True,
- warn_script_location: bool = True,
- direct_url: Optional[DirectUrl] = None,
- requested: bool = False,
-) -> None:
- with ZipFile(wheel_path, allowZip64=True) as z:
- with req_error_context(req_description):
- _install_wheel(
- name=name,
- wheel_zip=z,
- wheel_path=wheel_path,
- scheme=scheme,
- pycompile=pycompile,
- warn_script_location=warn_script_location,
- direct_url=direct_url,
- requested=requested,
- )
diff --git a/venv/lib/python3.11/site-packages/pip/_internal/operations/prepare.py b/venv/lib/python3.11/site-packages/pip/_internal/operations/prepare.py
deleted file mode 100644
index 956717d..0000000
--- a/venv/lib/python3.11/site-packages/pip/_internal/operations/prepare.py
+++ /dev/null
@@ -1,730 +0,0 @@
-"""Prepares a distribution for installation
-"""
-
-# The following comment should be removed at some point in the future.
-# mypy: strict-optional=False
-
-import mimetypes
-import os
-import shutil
-from pathlib import Path
-from typing import Dict, Iterable, List, Optional
-
-from pip._vendor.packaging.utils import canonicalize_name
-
-from pip._internal.distributions import make_distribution_for_install_requirement
-from pip._internal.distributions.installed import InstalledDistribution
-from pip._internal.exceptions import (
- DirectoryUrlHashUnsupported,
- HashMismatch,
- HashUnpinned,
- InstallationError,
- MetadataInconsistent,
- NetworkConnectionError,
- VcsHashUnsupported,
-)
-from pip._internal.index.package_finder import PackageFinder
-from pip._internal.metadata import BaseDistribution, get_metadata_distribution
-from pip._internal.models.direct_url import ArchiveInfo
-from pip._internal.models.link import Link
-from pip._internal.models.wheel import Wheel
-from pip._internal.network.download import BatchDownloader, Downloader
-from pip._internal.network.lazy_wheel import (
- HTTPRangeRequestUnsupported,
- dist_from_wheel_url,
-)
-from pip._internal.network.session import PipSession
-from pip._internal.operations.build.build_tracker import BuildTracker
-from pip._internal.req.req_install import InstallRequirement
-from pip._internal.utils._log import getLogger
-from pip._internal.utils.direct_url_helpers import (
- direct_url_for_editable,
- direct_url_from_link,
-)
-from pip._internal.utils.hashes import Hashes, MissingHashes
-from pip._internal.utils.logging import indent_log
-from pip._internal.utils.misc import (
- display_path,
- hash_file,
- hide_url,
- redact_auth_from_requirement,
-)
-from pip._internal.utils.temp_dir import TempDirectory
-from pip._internal.utils.unpacking import unpack_file
-from pip._internal.vcs import vcs
-
-logger = getLogger(__name__)
-
-
-def _get_prepared_distribution(
- req: InstallRequirement,
- build_tracker: BuildTracker,
- finder: PackageFinder,
- build_isolation: bool,
- check_build_deps: bool,
-) -> BaseDistribution:
- """Prepare a distribution for installation."""
- abstract_dist = make_distribution_for_install_requirement(req)
- tracker_id = abstract_dist.build_tracker_id
- if tracker_id is not None:
- with build_tracker.track(req, tracker_id):
- abstract_dist.prepare_distribution_metadata(
- finder, build_isolation, check_build_deps
- )
- return abstract_dist.get_metadata_distribution()
-
-
-def unpack_vcs_link(link: Link, location: str, verbosity: int) -> None:
- vcs_backend = vcs.get_backend_for_scheme(link.scheme)
- assert vcs_backend is not None
- vcs_backend.unpack(location, url=hide_url(link.url), verbosity=verbosity)
-
-
-class File:
- def __init__(self, path: str, content_type: Optional[str]) -> None:
- self.path = path
- if content_type is None:
- self.content_type = mimetypes.guess_type(path)[0]
- else:
- self.content_type = content_type
-
-
-def get_http_url(
- link: Link,
- download: Downloader,
- download_dir: Optional[str] = None,
- hashes: Optional[Hashes] = None,
-) -> File:
- temp_dir = TempDirectory(kind="unpack", globally_managed=True)
- # If a download dir is specified, is the file already downloaded there?
- already_downloaded_path = None
- if download_dir:
- already_downloaded_path = _check_download_dir(link, download_dir, hashes)
-
- if already_downloaded_path:
- from_path = already_downloaded_path
- content_type = None
- else:
- # let's download to a tmp dir
- from_path, content_type = download(link, temp_dir.path)
- if hashes:
- hashes.check_against_path(from_path)
-
- return File(from_path, content_type)
-
-
-def get_file_url(
- link: Link, download_dir: Optional[str] = None, hashes: Optional[Hashes] = None
-) -> File:
- """Get file and optionally check its hash."""
- # If a download dir is specified, is the file already there and valid?
- already_downloaded_path = None
- if download_dir:
- already_downloaded_path = _check_download_dir(link, download_dir, hashes)
-
- if already_downloaded_path:
- from_path = already_downloaded_path
- else:
- from_path = link.file_path
-
- # If --require-hashes is off, `hashes` is either empty, the
- # link's embedded hash, or MissingHashes; it is required to
- # match. If --require-hashes is on, we are satisfied by any
- # hash in `hashes` matching: a URL-based or an option-based
- # one; no internet-sourced hash will be in `hashes`.
- if hashes:
- hashes.check_against_path(from_path)
- return File(from_path, None)
-
-
-def unpack_url(
- link: Link,
- location: str,
- download: Downloader,
- verbosity: int,
- download_dir: Optional[str] = None,
- hashes: Optional[Hashes] = None,
-) -> Optional[File]:
- """Unpack link into location, downloading if required.
-
- :param hashes: A Hashes object, one of whose embedded hashes must match,
- or HashMismatch will be raised. If the Hashes is empty, no matches are
- required, and unhashable types of requirements (like VCS ones, which
- would ordinarily raise HashUnsupported) are allowed.
- """
- # non-editable vcs urls
- if link.is_vcs:
- unpack_vcs_link(link, location, verbosity=verbosity)
- return None
-
- assert not link.is_existing_dir()
-
- # file urls
- if link.is_file:
- file = get_file_url(link, download_dir, hashes=hashes)
-
- # http urls
- else:
- file = get_http_url(
- link,
- download,
- download_dir,
- hashes=hashes,
- )
-
- # unpack the archive to the build dir location. even when only downloading
- # archives, they have to be unpacked to parse dependencies, except wheels
- if not link.is_wheel:
- unpack_file(file.path, location, file.content_type)
-
- return file
-
-
-def _check_download_dir(
- link: Link,
- download_dir: str,
- hashes: Optional[Hashes],
- warn_on_hash_mismatch: bool = True,
-) -> Optional[str]:
- """Check download_dir for previously downloaded file with correct hash
- If a correct file is found return its path else None
- """
- download_path = os.path.join(download_dir, link.filename)
-
- if not os.path.exists(download_path):
- return None
-
- # If already downloaded, does its hash match?
- logger.info("File was already downloaded %s", download_path)
- if hashes:
- try:
- hashes.check_against_path(download_path)
- except HashMismatch:
- if warn_on_hash_mismatch:
- logger.warning(
- "Previously-downloaded file %s has bad hash. Re-downloading.",
- download_path,
- )
- os.unlink(download_path)
- return None
- return download_path
-
-
-class RequirementPreparer:
- """Prepares a Requirement"""
-
- def __init__(
- self,
- build_dir: str,
- download_dir: Optional[str],
- src_dir: str,
- build_isolation: bool,
- check_build_deps: bool,
- build_tracker: BuildTracker,
- session: PipSession,
- progress_bar: str,
- finder: PackageFinder,
- require_hashes: bool,
- use_user_site: bool,
- lazy_wheel: bool,
- verbosity: int,
- legacy_resolver: bool,
- ) -> None:
- super().__init__()
-
- self.src_dir = src_dir
- self.build_dir = build_dir
- self.build_tracker = build_tracker
- self._session = session
- self._download = Downloader(session, progress_bar)
- self._batch_download = BatchDownloader(session, progress_bar)
- self.finder = finder
-
- # Where still-packed archives should be written to. If None, they are
- # not saved, and are deleted immediately after unpacking.
- self.download_dir = download_dir
-
- # Is build isolation allowed?
- self.build_isolation = build_isolation
-
- # Should check build dependencies?
- self.check_build_deps = check_build_deps
-
- # Should hash-checking be required?
- self.require_hashes = require_hashes
-
- # Should install in user site-packages?
- self.use_user_site = use_user_site
-
- # Should wheels be downloaded lazily?
- self.use_lazy_wheel = lazy_wheel
-
- # How verbose should underlying tooling be?
- self.verbosity = verbosity
-
- # Are we using the legacy resolver?
- self.legacy_resolver = legacy_resolver
-
- # Memoized downloaded files, as mapping of url: path.
- self._downloaded: Dict[str, str] = {}
-
- # Previous "header" printed for a link-based InstallRequirement
- self._previous_requirement_header = ("", "")
-
- def _log_preparing_link(self, req: InstallRequirement) -> None:
- """Provide context for the requirement being prepared."""
- if req.link.is_file and not req.is_wheel_from_cache:
- message = "Processing %s"
- information = str(display_path(req.link.file_path))
- else:
- message = "Collecting %s"
- information = redact_auth_from_requirement(req.req) if req.req else str(req)
-
- # If we used req.req, inject requirement source if available (this
- # would already be included if we used req directly)
- if req.req and req.comes_from:
- if isinstance(req.comes_from, str):
- comes_from: Optional[str] = req.comes_from
- else:
- comes_from = req.comes_from.from_path()
- if comes_from:
- information += f" (from {comes_from})"
-
- if (message, information) != self._previous_requirement_header:
- self._previous_requirement_header = (message, information)
- logger.info(message, information)
-
- if req.is_wheel_from_cache:
- with indent_log():
- logger.info("Using cached %s", req.link.filename)
-
- def _ensure_link_req_src_dir(
- self, req: InstallRequirement, parallel_builds: bool
- ) -> None:
- """Ensure source_dir of a linked InstallRequirement."""
- # Since source_dir is only set for editable requirements.
- if req.link.is_wheel:
- # We don't need to unpack wheels, so no need for a source
- # directory.
- return
- assert req.source_dir is None
- if req.link.is_existing_dir():
- # build local directories in-tree
- req.source_dir = req.link.file_path
- return
-
- # We always delete unpacked sdists after pip runs.
- req.ensure_has_source_dir(
- self.build_dir,
- autodelete=True,
- parallel_builds=parallel_builds,
- )
- req.ensure_pristine_source_checkout()
-
- def _get_linked_req_hashes(self, req: InstallRequirement) -> Hashes:
- # By the time this is called, the requirement's link should have
- # been checked so we can tell what kind of requirements req is
- # and raise some more informative errors than otherwise.
- # (For example, we can raise VcsHashUnsupported for a VCS URL
- # rather than HashMissing.)
- if not self.require_hashes:
- return req.hashes(trust_internet=True)
-
- # We could check these first 2 conditions inside unpack_url
- # and save repetition of conditions, but then we would
- # report less-useful error messages for unhashable
- # requirements, complaining that there's no hash provided.
- if req.link.is_vcs:
- raise VcsHashUnsupported()
- if req.link.is_existing_dir():
- raise DirectoryUrlHashUnsupported()
-
- # Unpinned packages are asking for trouble when a new version
- # is uploaded. This isn't a security check, but it saves users
- # a surprising hash mismatch in the future.
- # file:/// URLs aren't pinnable, so don't complain about them
- # not being pinned.
- if not req.is_direct and not req.is_pinned:
- raise HashUnpinned()
-
- # If known-good hashes are missing for this requirement,
- # shim it with a facade object that will provoke hash
- # computation and then raise a HashMissing exception
- # showing the user what the hash should be.
- return req.hashes(trust_internet=False) or MissingHashes()
-
- def _fetch_metadata_only(
- self,
- req: InstallRequirement,
- ) -> Optional[BaseDistribution]:
- if self.legacy_resolver:
- logger.debug(
- "Metadata-only fetching is not used in the legacy resolver",
- )
- return None
- if self.require_hashes:
- logger.debug(
- "Metadata-only fetching is not used as hash checking is required",
- )
- return None
- # Try PEP 658 metadata first, then fall back to lazy wheel if unavailable.
- return self._fetch_metadata_using_link_data_attr(
- req
- ) or self._fetch_metadata_using_lazy_wheel(req.link)
-
- def _fetch_metadata_using_link_data_attr(
- self,
- req: InstallRequirement,
- ) -> Optional[BaseDistribution]:
- """Fetch metadata from the data-dist-info-metadata attribute, if possible."""
- # (1) Get the link to the metadata file, if provided by the backend.
- metadata_link = req.link.metadata_link()
- if metadata_link is None:
- return None
- assert req.req is not None
- logger.verbose(
- "Obtaining dependency information for %s from %s",
- req.req,
- metadata_link,
- )
- # (2) Download the contents of the METADATA file, separate from the dist itself.
- metadata_file = get_http_url(
- metadata_link,
- self._download,
- hashes=metadata_link.as_hashes(),
- )
- with open(metadata_file.path, "rb") as f:
- metadata_contents = f.read()
- # (3) Generate a dist just from those file contents.
- metadata_dist = get_metadata_distribution(
- metadata_contents,
- req.link.filename,
- req.req.name,
- )
- # (4) Ensure the Name: field from the METADATA file matches the name from the
- # install requirement.
- #
- # NB: raw_name will fall back to the name from the install requirement if
- # the Name: field is not present, but it's noted in the raw_name docstring
- # that that should NEVER happen anyway.
- if canonicalize_name(metadata_dist.raw_name) != canonicalize_name(req.req.name):
- raise MetadataInconsistent(
- req, "Name", req.req.name, metadata_dist.raw_name
- )
- return metadata_dist
-
- def _fetch_metadata_using_lazy_wheel(
- self,
- link: Link,
- ) -> Optional[BaseDistribution]:
- """Fetch metadata using lazy wheel, if possible."""
- # --use-feature=fast-deps must be provided.
- if not self.use_lazy_wheel:
- return None
- if link.is_file or not link.is_wheel:
- logger.debug(
- "Lazy wheel is not used as %r does not point to a remote wheel",
- link,
- )
- return None
-
- wheel = Wheel(link.filename)
- name = canonicalize_name(wheel.name)
- logger.info(
- "Obtaining dependency information from %s %s",
- name,
- wheel.version,
- )
- url = link.url.split("#", 1)[0]
- try:
- return dist_from_wheel_url(name, url, self._session)
- except HTTPRangeRequestUnsupported:
- logger.debug("%s does not support range requests", url)
- return None
-
- def _complete_partial_requirements(
- self,
- partially_downloaded_reqs: Iterable[InstallRequirement],
- parallel_builds: bool = False,
- ) -> None:
- """Download any requirements which were only fetched by metadata."""
- # Download to a temporary directory. These will be copied over as
- # needed for downstream 'download', 'wheel', and 'install' commands.
- temp_dir = TempDirectory(kind="unpack", globally_managed=True).path
-
- # Map each link to the requirement that owns it. This allows us to set
- # `req.local_file_path` on the appropriate requirement after passing
- # all the links at once into BatchDownloader.
- links_to_fully_download: Dict[Link, InstallRequirement] = {}
- for req in partially_downloaded_reqs:
- assert req.link
- links_to_fully_download[req.link] = req
-
- batch_download = self._batch_download(
- links_to_fully_download.keys(),
- temp_dir,
- )
- for link, (filepath, _) in batch_download:
- logger.debug("Downloading link %s to %s", link, filepath)
- req = links_to_fully_download[link]
- # Record the downloaded file path so wheel reqs can extract a Distribution
- # in .get_dist().
- req.local_file_path = filepath
- # Record that the file is downloaded so we don't do it again in
- # _prepare_linked_requirement().
- self._downloaded[req.link.url] = filepath
-
- # If this is an sdist, we need to unpack it after downloading, but the
- # .source_dir won't be set up until we are in _prepare_linked_requirement().
- # Add the downloaded archive to the install requirement to unpack after
- # preparing the source dir.
- if not req.is_wheel:
- req.needs_unpacked_archive(Path(filepath))
-
- # This step is necessary to ensure all lazy wheels are processed
- # successfully by the 'download', 'wheel', and 'install' commands.
- for req in partially_downloaded_reqs:
- self._prepare_linked_requirement(req, parallel_builds)
-
- def prepare_linked_requirement(
- self, req: InstallRequirement, parallel_builds: bool = False
- ) -> BaseDistribution:
- """Prepare a requirement to be obtained from req.link."""
- assert req.link
- self._log_preparing_link(req)
- with indent_log():
- # Check if the relevant file is already available
- # in the download directory
- file_path = None
- if self.download_dir is not None and req.link.is_wheel:
- hashes = self._get_linked_req_hashes(req)
- file_path = _check_download_dir(
- req.link,
- self.download_dir,
- hashes,
- # When a locally built wheel has been found in cache, we don't warn
- # about re-downloading when the already downloaded wheel hash does
- # not match. This is because the hash must be checked against the
- # original link, not the cached link. It that case the already
- # downloaded file will be removed and re-fetched from cache (which
- # implies a hash check against the cache entry's origin.json).
- warn_on_hash_mismatch=not req.is_wheel_from_cache,
- )
-
- if file_path is not None:
- # The file is already available, so mark it as downloaded
- self._downloaded[req.link.url] = file_path
- else:
- # The file is not available, attempt to fetch only metadata
- metadata_dist = self._fetch_metadata_only(req)
- if metadata_dist is not None:
- req.needs_more_preparation = True
- return metadata_dist
-
- # None of the optimizations worked, fully prepare the requirement
- return self._prepare_linked_requirement(req, parallel_builds)
-
- def prepare_linked_requirements_more(
- self, reqs: Iterable[InstallRequirement], parallel_builds: bool = False
- ) -> None:
- """Prepare linked requirements more, if needed."""
- reqs = [req for req in reqs if req.needs_more_preparation]
- for req in reqs:
- # Determine if any of these requirements were already downloaded.
- if self.download_dir is not None and req.link.is_wheel:
- hashes = self._get_linked_req_hashes(req)
- file_path = _check_download_dir(req.link, self.download_dir, hashes)
- if file_path is not None:
- self._downloaded[req.link.url] = file_path
- req.needs_more_preparation = False
-
- # Prepare requirements we found were already downloaded for some
- # reason. The other downloads will be completed separately.
- partially_downloaded_reqs: List[InstallRequirement] = []
- for req in reqs:
- if req.needs_more_preparation:
- partially_downloaded_reqs.append(req)
- else:
- self._prepare_linked_requirement(req, parallel_builds)
-
- # TODO: separate this part out from RequirementPreparer when the v1
- # resolver can be removed!
- self._complete_partial_requirements(
- partially_downloaded_reqs,
- parallel_builds=parallel_builds,
- )
-
- def _prepare_linked_requirement(
- self, req: InstallRequirement, parallel_builds: bool
- ) -> BaseDistribution:
- assert req.link
- link = req.link
-
- hashes = self._get_linked_req_hashes(req)
-
- if hashes and req.is_wheel_from_cache:
- assert req.download_info is not None
- assert link.is_wheel
- assert link.is_file
- # We need to verify hashes, and we have found the requirement in the cache
- # of locally built wheels.
- if (
- isinstance(req.download_info.info, ArchiveInfo)
- and req.download_info.info.hashes
- and hashes.has_one_of(req.download_info.info.hashes)
- ):
- # At this point we know the requirement was built from a hashable source
- # artifact, and we verified that the cache entry's hash of the original
- # artifact matches one of the hashes we expect. We don't verify hashes
- # against the cached wheel, because the wheel is not the original.
- hashes = None
- else:
- logger.warning(
- "The hashes of the source archive found in cache entry "
- "don't match, ignoring cached built wheel "
- "and re-downloading source."
- )
- req.link = req.cached_wheel_source_link
- link = req.link
-
- self._ensure_link_req_src_dir(req, parallel_builds)
-
- if link.is_existing_dir():
- local_file = None
- elif link.url not in self._downloaded:
- try:
- local_file = unpack_url(
- link,
- req.source_dir,
- self._download,
- self.verbosity,
- self.download_dir,
- hashes,
- )
- except NetworkConnectionError as exc:
- raise InstallationError(
- f"Could not install requirement {req} because of HTTP "
- f"error {exc} for URL {link}"
- )
- else:
- file_path = self._downloaded[link.url]
- if hashes:
- hashes.check_against_path(file_path)
- local_file = File(file_path, content_type=None)
-
- # If download_info is set, we got it from the wheel cache.
- if req.download_info is None:
- # Editables don't go through this function (see
- # prepare_editable_requirement).
- assert not req.editable
- req.download_info = direct_url_from_link(link, req.source_dir)
- # Make sure we have a hash in download_info. If we got it as part of the
- # URL, it will have been verified and we can rely on it. Otherwise we
- # compute it from the downloaded file.
- # FIXME: https://github.com/pypa/pip/issues/11943
- if (
- isinstance(req.download_info.info, ArchiveInfo)
- and not req.download_info.info.hashes
- and local_file
- ):
- hash = hash_file(local_file.path)[0].hexdigest()
- # We populate info.hash for backward compatibility.
- # This will automatically populate info.hashes.
- req.download_info.info.hash = f"sha256={hash}"
-
- # For use in later processing,
- # preserve the file path on the requirement.
- if local_file:
- req.local_file_path = local_file.path
-
- dist = _get_prepared_distribution(
- req,
- self.build_tracker,
- self.finder,
- self.build_isolation,
- self.check_build_deps,
- )
- return dist
-
- def save_linked_requirement(self, req: InstallRequirement) -> None:
- assert self.download_dir is not None
- assert req.link is not None
- link = req.link
- if link.is_vcs or (link.is_existing_dir() and req.editable):
- # Make a .zip of the source_dir we already created.
- req.archive(self.download_dir)
- return
-
- if link.is_existing_dir():
- logger.debug(
- "Not copying link to destination directory "
- "since it is a directory: %s",
- link,
- )
- return
- if req.local_file_path is None:
- # No distribution was downloaded for this requirement.
- return
-
- download_location = os.path.join(self.download_dir, link.filename)
- if not os.path.exists(download_location):
- shutil.copy(req.local_file_path, download_location)
- download_path = display_path(download_location)
- logger.info("Saved %s", download_path)
-
- def prepare_editable_requirement(
- self,
- req: InstallRequirement,
- ) -> BaseDistribution:
- """Prepare an editable requirement."""
- assert req.editable, "cannot prepare a non-editable req as editable"
-
- logger.info("Obtaining %s", req)
-
- with indent_log():
- if self.require_hashes:
- raise InstallationError(
- f"The editable requirement {req} cannot be installed when "
- "requiring hashes, because there is no single file to "
- "hash."
- )
- req.ensure_has_source_dir(self.src_dir)
- req.update_editable()
- assert req.source_dir
- req.download_info = direct_url_for_editable(req.unpacked_source_directory)
-
- dist = _get_prepared_distribution(
- req,
- self.build_tracker,
- self.finder,
- self.build_isolation,
- self.check_build_deps,
- )
-
- req.check_if_exists(self.use_user_site)
-
- return dist
-
- def prepare_installed_requirement(
- self,
- req: InstallRequirement,
- skip_reason: str,
- ) -> BaseDistribution:
- """Prepare an already-installed requirement."""
- assert req.satisfied_by, "req should have been satisfied but isn't"
- assert skip_reason is not None, (
- "did not get skip reason skipped but req.satisfied_by "
- f"is set to {req.satisfied_by}"
- )
- logger.info(
- "Requirement %s: %s (%s)", skip_reason, req, req.satisfied_by.version
- )
- with indent_log():
- if self.require_hashes:
- logger.debug(
- "Since it is already installed, we are trusting this "
- "package without checking its hash. To ensure a "
- "completely repeatable environment, install into an "
- "empty virtualenv."
- )
- return InstalledDistribution(req).get_metadata_distribution()