Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__init__.py +132 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/cache.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/check.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/completion.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/debug.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/download.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/hash.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/help.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/index.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/install.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/list.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/search.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/show.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/cache.py +225 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/check.py +54 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/completion.py +130 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/configuration.py +280 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/debug.py +201 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/download.py +147 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/freeze.py +108 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/hash.py +59 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/help.py +41 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/index.py +139 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/inspect.py +92 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/install.py +774 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/list.py +368 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/search.py +174 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/show.py +189 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/uninstall.py +113 -0
- .venv/lib/python3.11/site-packages/pip/_internal/commands/wheel.py +183 -0
- .venv/lib/python3.11/site-packages/pip/_internal/locations/__init__.py +467 -0
- .venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/base.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/locations/_distutils.py +172 -0
- .venv/lib/python3.11/site-packages/pip/_internal/locations/_sysconfig.py +213 -0
- .venv/lib/python3.11/site-packages/pip/_internal/locations/base.py +81 -0
- .venv/lib/python3.11/site-packages/pip/_internal/models/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/models/__pycache__/candidate.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/models/__pycache__/format_control.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/models/__pycache__/index.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-311.pyc +0 -0
.venv/lib/python3.11/site-packages/pip/_internal/commands/__init__.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Package containing all pip commands
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import importlib
|
| 6 |
+
from collections import namedtuple
|
| 7 |
+
from typing import Any, Dict, Optional
|
| 8 |
+
|
| 9 |
+
from pip._internal.cli.base_command import Command
|
| 10 |
+
|
| 11 |
+
CommandInfo = namedtuple("CommandInfo", "module_path, class_name, summary")
|
| 12 |
+
|
| 13 |
+
# This dictionary does a bunch of heavy lifting for help output:
|
| 14 |
+
# - Enables avoiding additional (costly) imports for presenting `--help`.
|
| 15 |
+
# - The ordering matters for help display.
|
| 16 |
+
#
|
| 17 |
+
# Even though the module path starts with the same "pip._internal.commands"
|
| 18 |
+
# prefix, the full path makes testing easier (specifically when modifying
|
| 19 |
+
# `commands_dict` in test setup / teardown).
|
| 20 |
+
commands_dict: Dict[str, CommandInfo] = {
|
| 21 |
+
"install": CommandInfo(
|
| 22 |
+
"pip._internal.commands.install",
|
| 23 |
+
"InstallCommand",
|
| 24 |
+
"Install packages.",
|
| 25 |
+
),
|
| 26 |
+
"download": CommandInfo(
|
| 27 |
+
"pip._internal.commands.download",
|
| 28 |
+
"DownloadCommand",
|
| 29 |
+
"Download packages.",
|
| 30 |
+
),
|
| 31 |
+
"uninstall": CommandInfo(
|
| 32 |
+
"pip._internal.commands.uninstall",
|
| 33 |
+
"UninstallCommand",
|
| 34 |
+
"Uninstall packages.",
|
| 35 |
+
),
|
| 36 |
+
"freeze": CommandInfo(
|
| 37 |
+
"pip._internal.commands.freeze",
|
| 38 |
+
"FreezeCommand",
|
| 39 |
+
"Output installed packages in requirements format.",
|
| 40 |
+
),
|
| 41 |
+
"inspect": CommandInfo(
|
| 42 |
+
"pip._internal.commands.inspect",
|
| 43 |
+
"InspectCommand",
|
| 44 |
+
"Inspect the python environment.",
|
| 45 |
+
),
|
| 46 |
+
"list": CommandInfo(
|
| 47 |
+
"pip._internal.commands.list",
|
| 48 |
+
"ListCommand",
|
| 49 |
+
"List installed packages.",
|
| 50 |
+
),
|
| 51 |
+
"show": CommandInfo(
|
| 52 |
+
"pip._internal.commands.show",
|
| 53 |
+
"ShowCommand",
|
| 54 |
+
"Show information about installed packages.",
|
| 55 |
+
),
|
| 56 |
+
"check": CommandInfo(
|
| 57 |
+
"pip._internal.commands.check",
|
| 58 |
+
"CheckCommand",
|
| 59 |
+
"Verify installed packages have compatible dependencies.",
|
| 60 |
+
),
|
| 61 |
+
"config": CommandInfo(
|
| 62 |
+
"pip._internal.commands.configuration",
|
| 63 |
+
"ConfigurationCommand",
|
| 64 |
+
"Manage local and global configuration.",
|
| 65 |
+
),
|
| 66 |
+
"search": CommandInfo(
|
| 67 |
+
"pip._internal.commands.search",
|
| 68 |
+
"SearchCommand",
|
| 69 |
+
"Search PyPI for packages.",
|
| 70 |
+
),
|
| 71 |
+
"cache": CommandInfo(
|
| 72 |
+
"pip._internal.commands.cache",
|
| 73 |
+
"CacheCommand",
|
| 74 |
+
"Inspect and manage pip's wheel cache.",
|
| 75 |
+
),
|
| 76 |
+
"index": CommandInfo(
|
| 77 |
+
"pip._internal.commands.index",
|
| 78 |
+
"IndexCommand",
|
| 79 |
+
"Inspect information available from package indexes.",
|
| 80 |
+
),
|
| 81 |
+
"wheel": CommandInfo(
|
| 82 |
+
"pip._internal.commands.wheel",
|
| 83 |
+
"WheelCommand",
|
| 84 |
+
"Build wheels from your requirements.",
|
| 85 |
+
),
|
| 86 |
+
"hash": CommandInfo(
|
| 87 |
+
"pip._internal.commands.hash",
|
| 88 |
+
"HashCommand",
|
| 89 |
+
"Compute hashes of package archives.",
|
| 90 |
+
),
|
| 91 |
+
"completion": CommandInfo(
|
| 92 |
+
"pip._internal.commands.completion",
|
| 93 |
+
"CompletionCommand",
|
| 94 |
+
"A helper command used for command completion.",
|
| 95 |
+
),
|
| 96 |
+
"debug": CommandInfo(
|
| 97 |
+
"pip._internal.commands.debug",
|
| 98 |
+
"DebugCommand",
|
| 99 |
+
"Show information useful for debugging.",
|
| 100 |
+
),
|
| 101 |
+
"help": CommandInfo(
|
| 102 |
+
"pip._internal.commands.help",
|
| 103 |
+
"HelpCommand",
|
| 104 |
+
"Show help for commands.",
|
| 105 |
+
),
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def create_command(name: str, **kwargs: Any) -> Command:
|
| 110 |
+
"""
|
| 111 |
+
Create an instance of the Command class with the given name.
|
| 112 |
+
"""
|
| 113 |
+
module_path, class_name, summary = commands_dict[name]
|
| 114 |
+
module = importlib.import_module(module_path)
|
| 115 |
+
command_class = getattr(module, class_name)
|
| 116 |
+
command = command_class(name=name, summary=summary, **kwargs)
|
| 117 |
+
|
| 118 |
+
return command
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def get_similar_commands(name: str) -> Optional[str]:
|
| 122 |
+
"""Command name auto-correct."""
|
| 123 |
+
from difflib import get_close_matches
|
| 124 |
+
|
| 125 |
+
name = name.lower()
|
| 126 |
+
|
| 127 |
+
close_commands = get_close_matches(name, commands_dict.keys())
|
| 128 |
+
|
| 129 |
+
if close_commands:
|
| 130 |
+
return close_commands[0]
|
| 131 |
+
else:
|
| 132 |
+
return None
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (4.45 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/cache.cpython-311.pyc
ADDED
|
Binary file (10.9 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/check.cpython-311.pyc
ADDED
|
Binary file (2.41 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/completion.cpython-311.pyc
ADDED
|
Binary file (5.62 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-311.pyc
ADDED
|
Binary file (14.8 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/debug.cpython-311.pyc
ADDED
|
Binary file (12.2 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/download.cpython-311.pyc
ADDED
|
Binary file (7.94 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-311.pyc
ADDED
|
Binary file (4.66 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/hash.cpython-311.pyc
ADDED
|
Binary file (3.35 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/help.cpython-311.pyc
ADDED
|
Binary file (1.97 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/index.cpython-311.pyc
ADDED
|
Binary file (7.72 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-311.pyc
ADDED
|
Binary file (4.44 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/install.cpython-311.pyc
ADDED
|
Binary file (31.1 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/list.cpython-311.pyc
ADDED
|
Binary file (17.2 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/search.cpython-311.pyc
ADDED
|
Binary file (8.95 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/show.cpython-311.pyc
ADDED
|
Binary file (11.3 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-311.pyc
ADDED
|
Binary file (5.14 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-311.pyc
ADDED
|
Binary file (9.4 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/cache.py
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import textwrap
|
| 3 |
+
from optparse import Values
|
| 4 |
+
from typing import Any, List
|
| 5 |
+
|
| 6 |
+
from pip._internal.cli.base_command import Command
|
| 7 |
+
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
| 8 |
+
from pip._internal.exceptions import CommandError, PipError
|
| 9 |
+
from pip._internal.utils import filesystem
|
| 10 |
+
from pip._internal.utils.logging import getLogger
|
| 11 |
+
|
| 12 |
+
logger = getLogger(__name__)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class CacheCommand(Command):
|
| 16 |
+
"""
|
| 17 |
+
Inspect and manage pip's wheel cache.
|
| 18 |
+
|
| 19 |
+
Subcommands:
|
| 20 |
+
|
| 21 |
+
- dir: Show the cache directory.
|
| 22 |
+
- info: Show information about the cache.
|
| 23 |
+
- list: List filenames of packages stored in the cache.
|
| 24 |
+
- remove: Remove one or more package from the cache.
|
| 25 |
+
- purge: Remove all items from the cache.
|
| 26 |
+
|
| 27 |
+
``<pattern>`` can be a glob expression or a package name.
|
| 28 |
+
"""
|
| 29 |
+
|
| 30 |
+
ignore_require_venv = True
|
| 31 |
+
usage = """
|
| 32 |
+
%prog dir
|
| 33 |
+
%prog info
|
| 34 |
+
%prog list [<pattern>] [--format=[human, abspath]]
|
| 35 |
+
%prog remove <pattern>
|
| 36 |
+
%prog purge
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
def add_options(self) -> None:
|
| 40 |
+
self.cmd_opts.add_option(
|
| 41 |
+
"--format",
|
| 42 |
+
action="store",
|
| 43 |
+
dest="list_format",
|
| 44 |
+
default="human",
|
| 45 |
+
choices=("human", "abspath"),
|
| 46 |
+
help="Select the output format among: human (default) or abspath",
|
| 47 |
+
)
|
| 48 |
+
|
| 49 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 50 |
+
|
| 51 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 52 |
+
handlers = {
|
| 53 |
+
"dir": self.get_cache_dir,
|
| 54 |
+
"info": self.get_cache_info,
|
| 55 |
+
"list": self.list_cache_items,
|
| 56 |
+
"remove": self.remove_cache_items,
|
| 57 |
+
"purge": self.purge_cache,
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
if not options.cache_dir:
|
| 61 |
+
logger.error("pip cache commands can not function since cache is disabled.")
|
| 62 |
+
return ERROR
|
| 63 |
+
|
| 64 |
+
# Determine action
|
| 65 |
+
if not args or args[0] not in handlers:
|
| 66 |
+
logger.error(
|
| 67 |
+
"Need an action (%s) to perform.",
|
| 68 |
+
", ".join(sorted(handlers)),
|
| 69 |
+
)
|
| 70 |
+
return ERROR
|
| 71 |
+
|
| 72 |
+
action = args[0]
|
| 73 |
+
|
| 74 |
+
# Error handling happens here, not in the action-handlers.
|
| 75 |
+
try:
|
| 76 |
+
handlers[action](options, args[1:])
|
| 77 |
+
except PipError as e:
|
| 78 |
+
logger.error(e.args[0])
|
| 79 |
+
return ERROR
|
| 80 |
+
|
| 81 |
+
return SUCCESS
|
| 82 |
+
|
| 83 |
+
def get_cache_dir(self, options: Values, args: List[Any]) -> None:
|
| 84 |
+
if args:
|
| 85 |
+
raise CommandError("Too many arguments")
|
| 86 |
+
|
| 87 |
+
logger.info(options.cache_dir)
|
| 88 |
+
|
| 89 |
+
def get_cache_info(self, options: Values, args: List[Any]) -> None:
|
| 90 |
+
if args:
|
| 91 |
+
raise CommandError("Too many arguments")
|
| 92 |
+
|
| 93 |
+
num_http_files = len(self._find_http_files(options))
|
| 94 |
+
num_packages = len(self._find_wheels(options, "*"))
|
| 95 |
+
|
| 96 |
+
http_cache_location = self._cache_dir(options, "http-v2")
|
| 97 |
+
old_http_cache_location = self._cache_dir(options, "http")
|
| 98 |
+
wheels_cache_location = self._cache_dir(options, "wheels")
|
| 99 |
+
http_cache_size = filesystem.format_size(
|
| 100 |
+
filesystem.directory_size(http_cache_location)
|
| 101 |
+
+ filesystem.directory_size(old_http_cache_location)
|
| 102 |
+
)
|
| 103 |
+
wheels_cache_size = filesystem.format_directory_size(wheels_cache_location)
|
| 104 |
+
|
| 105 |
+
message = (
|
| 106 |
+
textwrap.dedent(
|
| 107 |
+
"""
|
| 108 |
+
Package index page cache location (pip v23.3+): {http_cache_location}
|
| 109 |
+
Package index page cache location (older pips): {old_http_cache_location}
|
| 110 |
+
Package index page cache size: {http_cache_size}
|
| 111 |
+
Number of HTTP files: {num_http_files}
|
| 112 |
+
Locally built wheels location: {wheels_cache_location}
|
| 113 |
+
Locally built wheels size: {wheels_cache_size}
|
| 114 |
+
Number of locally built wheels: {package_count}
|
| 115 |
+
""" # noqa: E501
|
| 116 |
+
)
|
| 117 |
+
.format(
|
| 118 |
+
http_cache_location=http_cache_location,
|
| 119 |
+
old_http_cache_location=old_http_cache_location,
|
| 120 |
+
http_cache_size=http_cache_size,
|
| 121 |
+
num_http_files=num_http_files,
|
| 122 |
+
wheels_cache_location=wheels_cache_location,
|
| 123 |
+
package_count=num_packages,
|
| 124 |
+
wheels_cache_size=wheels_cache_size,
|
| 125 |
+
)
|
| 126 |
+
.strip()
|
| 127 |
+
)
|
| 128 |
+
|
| 129 |
+
logger.info(message)
|
| 130 |
+
|
| 131 |
+
def list_cache_items(self, options: Values, args: List[Any]) -> None:
|
| 132 |
+
if len(args) > 1:
|
| 133 |
+
raise CommandError("Too many arguments")
|
| 134 |
+
|
| 135 |
+
if args:
|
| 136 |
+
pattern = args[0]
|
| 137 |
+
else:
|
| 138 |
+
pattern = "*"
|
| 139 |
+
|
| 140 |
+
files = self._find_wheels(options, pattern)
|
| 141 |
+
if options.list_format == "human":
|
| 142 |
+
self.format_for_human(files)
|
| 143 |
+
else:
|
| 144 |
+
self.format_for_abspath(files)
|
| 145 |
+
|
| 146 |
+
def format_for_human(self, files: List[str]) -> None:
|
| 147 |
+
if not files:
|
| 148 |
+
logger.info("No locally built wheels cached.")
|
| 149 |
+
return
|
| 150 |
+
|
| 151 |
+
results = []
|
| 152 |
+
for filename in files:
|
| 153 |
+
wheel = os.path.basename(filename)
|
| 154 |
+
size = filesystem.format_file_size(filename)
|
| 155 |
+
results.append(f" - {wheel} ({size})")
|
| 156 |
+
logger.info("Cache contents:\n")
|
| 157 |
+
logger.info("\n".join(sorted(results)))
|
| 158 |
+
|
| 159 |
+
def format_for_abspath(self, files: List[str]) -> None:
|
| 160 |
+
if files:
|
| 161 |
+
logger.info("\n".join(sorted(files)))
|
| 162 |
+
|
| 163 |
+
def remove_cache_items(self, options: Values, args: List[Any]) -> None:
|
| 164 |
+
if len(args) > 1:
|
| 165 |
+
raise CommandError("Too many arguments")
|
| 166 |
+
|
| 167 |
+
if not args:
|
| 168 |
+
raise CommandError("Please provide a pattern")
|
| 169 |
+
|
| 170 |
+
files = self._find_wheels(options, args[0])
|
| 171 |
+
|
| 172 |
+
no_matching_msg = "No matching packages"
|
| 173 |
+
if args[0] == "*":
|
| 174 |
+
# Only fetch http files if no specific pattern given
|
| 175 |
+
files += self._find_http_files(options)
|
| 176 |
+
else:
|
| 177 |
+
# Add the pattern to the log message
|
| 178 |
+
no_matching_msg += f' for pattern "{args[0]}"'
|
| 179 |
+
|
| 180 |
+
if not files:
|
| 181 |
+
logger.warning(no_matching_msg)
|
| 182 |
+
|
| 183 |
+
for filename in files:
|
| 184 |
+
os.unlink(filename)
|
| 185 |
+
logger.verbose("Removed %s", filename)
|
| 186 |
+
logger.info("Files removed: %s", len(files))
|
| 187 |
+
|
| 188 |
+
def purge_cache(self, options: Values, args: List[Any]) -> None:
|
| 189 |
+
if args:
|
| 190 |
+
raise CommandError("Too many arguments")
|
| 191 |
+
|
| 192 |
+
return self.remove_cache_items(options, ["*"])
|
| 193 |
+
|
| 194 |
+
def _cache_dir(self, options: Values, subdir: str) -> str:
|
| 195 |
+
return os.path.join(options.cache_dir, subdir)
|
| 196 |
+
|
| 197 |
+
def _find_http_files(self, options: Values) -> List[str]:
|
| 198 |
+
old_http_dir = self._cache_dir(options, "http")
|
| 199 |
+
new_http_dir = self._cache_dir(options, "http-v2")
|
| 200 |
+
return filesystem.find_files(old_http_dir, "*") + filesystem.find_files(
|
| 201 |
+
new_http_dir, "*"
|
| 202 |
+
)
|
| 203 |
+
|
| 204 |
+
def _find_wheels(self, options: Values, pattern: str) -> List[str]:
|
| 205 |
+
wheel_dir = self._cache_dir(options, "wheels")
|
| 206 |
+
|
| 207 |
+
# The wheel filename format, as specified in PEP 427, is:
|
| 208 |
+
# {distribution}-{version}(-{build})?-{python}-{abi}-{platform}.whl
|
| 209 |
+
#
|
| 210 |
+
# Additionally, non-alphanumeric values in the distribution are
|
| 211 |
+
# normalized to underscores (_), meaning hyphens can never occur
|
| 212 |
+
# before `-{version}`.
|
| 213 |
+
#
|
| 214 |
+
# Given that information:
|
| 215 |
+
# - If the pattern we're given contains a hyphen (-), the user is
|
| 216 |
+
# providing at least the version. Thus, we can just append `*.whl`
|
| 217 |
+
# to match the rest of it.
|
| 218 |
+
# - If the pattern we're given doesn't contain a hyphen (-), the
|
| 219 |
+
# user is only providing the name. Thus, we append `-*.whl` to
|
| 220 |
+
# match the hyphen before the version, followed by anything else.
|
| 221 |
+
#
|
| 222 |
+
# PEP 427: https://www.python.org/dev/peps/pep-0427/
|
| 223 |
+
pattern = pattern + ("*.whl" if "-" in pattern else "-*.whl")
|
| 224 |
+
|
| 225 |
+
return filesystem.find_files(wheel_dir, pattern)
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/check.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
from optparse import Values
|
| 3 |
+
from typing import List
|
| 4 |
+
|
| 5 |
+
from pip._internal.cli.base_command import Command
|
| 6 |
+
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
| 7 |
+
from pip._internal.operations.check import (
|
| 8 |
+
check_package_set,
|
| 9 |
+
create_package_set_from_installed,
|
| 10 |
+
warn_legacy_versions_and_specifiers,
|
| 11 |
+
)
|
| 12 |
+
from pip._internal.utils.misc import write_output
|
| 13 |
+
|
| 14 |
+
logger = logging.getLogger(__name__)
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class CheckCommand(Command):
|
| 18 |
+
"""Verify installed packages have compatible dependencies."""
|
| 19 |
+
|
| 20 |
+
usage = """
|
| 21 |
+
%prog [options]"""
|
| 22 |
+
|
| 23 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 24 |
+
package_set, parsing_probs = create_package_set_from_installed()
|
| 25 |
+
warn_legacy_versions_and_specifiers(package_set)
|
| 26 |
+
missing, conflicting = check_package_set(package_set)
|
| 27 |
+
|
| 28 |
+
for project_name in missing:
|
| 29 |
+
version = package_set[project_name].version
|
| 30 |
+
for dependency in missing[project_name]:
|
| 31 |
+
write_output(
|
| 32 |
+
"%s %s requires %s, which is not installed.",
|
| 33 |
+
project_name,
|
| 34 |
+
version,
|
| 35 |
+
dependency[0],
|
| 36 |
+
)
|
| 37 |
+
|
| 38 |
+
for project_name in conflicting:
|
| 39 |
+
version = package_set[project_name].version
|
| 40 |
+
for dep_name, dep_version, req in conflicting[project_name]:
|
| 41 |
+
write_output(
|
| 42 |
+
"%s %s has requirement %s, but you have %s %s.",
|
| 43 |
+
project_name,
|
| 44 |
+
version,
|
| 45 |
+
req,
|
| 46 |
+
dep_name,
|
| 47 |
+
dep_version,
|
| 48 |
+
)
|
| 49 |
+
|
| 50 |
+
if missing or conflicting or parsing_probs:
|
| 51 |
+
return ERROR
|
| 52 |
+
else:
|
| 53 |
+
write_output("No broken requirements found.")
|
| 54 |
+
return SUCCESS
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/completion.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import textwrap
|
| 3 |
+
from optparse import Values
|
| 4 |
+
from typing import List
|
| 5 |
+
|
| 6 |
+
from pip._internal.cli.base_command import Command
|
| 7 |
+
from pip._internal.cli.status_codes import SUCCESS
|
| 8 |
+
from pip._internal.utils.misc import get_prog
|
| 9 |
+
|
| 10 |
+
BASE_COMPLETION = """
|
| 11 |
+
# pip {shell} completion start{script}# pip {shell} completion end
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
COMPLETION_SCRIPTS = {
|
| 15 |
+
"bash": """
|
| 16 |
+
_pip_completion()
|
| 17 |
+
{{
|
| 18 |
+
COMPREPLY=( $( COMP_WORDS="${{COMP_WORDS[*]}}" \\
|
| 19 |
+
COMP_CWORD=$COMP_CWORD \\
|
| 20 |
+
PIP_AUTO_COMPLETE=1 $1 2>/dev/null ) )
|
| 21 |
+
}}
|
| 22 |
+
complete -o default -F _pip_completion {prog}
|
| 23 |
+
""",
|
| 24 |
+
"zsh": """
|
| 25 |
+
#compdef -P pip[0-9.]#
|
| 26 |
+
__pip() {{
|
| 27 |
+
compadd $( COMP_WORDS="$words[*]" \\
|
| 28 |
+
COMP_CWORD=$((CURRENT-1)) \\
|
| 29 |
+
PIP_AUTO_COMPLETE=1 $words[1] 2>/dev/null )
|
| 30 |
+
}}
|
| 31 |
+
if [[ $zsh_eval_context[-1] == loadautofunc ]]; then
|
| 32 |
+
# autoload from fpath, call function directly
|
| 33 |
+
__pip "$@"
|
| 34 |
+
else
|
| 35 |
+
# eval/source/. command, register function for later
|
| 36 |
+
compdef __pip -P 'pip[0-9.]#'
|
| 37 |
+
fi
|
| 38 |
+
""",
|
| 39 |
+
"fish": """
|
| 40 |
+
function __fish_complete_pip
|
| 41 |
+
set -lx COMP_WORDS (commandline -o) ""
|
| 42 |
+
set -lx COMP_CWORD ( \\
|
| 43 |
+
math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\
|
| 44 |
+
)
|
| 45 |
+
set -lx PIP_AUTO_COMPLETE 1
|
| 46 |
+
string split \\ -- (eval $COMP_WORDS[1])
|
| 47 |
+
end
|
| 48 |
+
complete -fa "(__fish_complete_pip)" -c {prog}
|
| 49 |
+
""",
|
| 50 |
+
"powershell": """
|
| 51 |
+
if ((Test-Path Function:\\TabExpansion) -and -not `
|
| 52 |
+
(Test-Path Function:\\_pip_completeBackup)) {{
|
| 53 |
+
Rename-Item Function:\\TabExpansion _pip_completeBackup
|
| 54 |
+
}}
|
| 55 |
+
function TabExpansion($line, $lastWord) {{
|
| 56 |
+
$lastBlock = [regex]::Split($line, '[|;]')[-1].TrimStart()
|
| 57 |
+
if ($lastBlock.StartsWith("{prog} ")) {{
|
| 58 |
+
$Env:COMP_WORDS=$lastBlock
|
| 59 |
+
$Env:COMP_CWORD=$lastBlock.Split().Length - 1
|
| 60 |
+
$Env:PIP_AUTO_COMPLETE=1
|
| 61 |
+
(& {prog}).Split()
|
| 62 |
+
Remove-Item Env:COMP_WORDS
|
| 63 |
+
Remove-Item Env:COMP_CWORD
|
| 64 |
+
Remove-Item Env:PIP_AUTO_COMPLETE
|
| 65 |
+
}}
|
| 66 |
+
elseif (Test-Path Function:\\_pip_completeBackup) {{
|
| 67 |
+
# Fall back on existing tab expansion
|
| 68 |
+
_pip_completeBackup $line $lastWord
|
| 69 |
+
}}
|
| 70 |
+
}}
|
| 71 |
+
""",
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class CompletionCommand(Command):
|
| 76 |
+
"""A helper command to be used for command completion."""
|
| 77 |
+
|
| 78 |
+
ignore_require_venv = True
|
| 79 |
+
|
| 80 |
+
def add_options(self) -> None:
|
| 81 |
+
self.cmd_opts.add_option(
|
| 82 |
+
"--bash",
|
| 83 |
+
"-b",
|
| 84 |
+
action="store_const",
|
| 85 |
+
const="bash",
|
| 86 |
+
dest="shell",
|
| 87 |
+
help="Emit completion code for bash",
|
| 88 |
+
)
|
| 89 |
+
self.cmd_opts.add_option(
|
| 90 |
+
"--zsh",
|
| 91 |
+
"-z",
|
| 92 |
+
action="store_const",
|
| 93 |
+
const="zsh",
|
| 94 |
+
dest="shell",
|
| 95 |
+
help="Emit completion code for zsh",
|
| 96 |
+
)
|
| 97 |
+
self.cmd_opts.add_option(
|
| 98 |
+
"--fish",
|
| 99 |
+
"-f",
|
| 100 |
+
action="store_const",
|
| 101 |
+
const="fish",
|
| 102 |
+
dest="shell",
|
| 103 |
+
help="Emit completion code for fish",
|
| 104 |
+
)
|
| 105 |
+
self.cmd_opts.add_option(
|
| 106 |
+
"--powershell",
|
| 107 |
+
"-p",
|
| 108 |
+
action="store_const",
|
| 109 |
+
const="powershell",
|
| 110 |
+
dest="shell",
|
| 111 |
+
help="Emit completion code for powershell",
|
| 112 |
+
)
|
| 113 |
+
|
| 114 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 115 |
+
|
| 116 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 117 |
+
"""Prints the completion code of the given shell"""
|
| 118 |
+
shells = COMPLETION_SCRIPTS.keys()
|
| 119 |
+
shell_options = ["--" + shell for shell in sorted(shells)]
|
| 120 |
+
if options.shell in shells:
|
| 121 |
+
script = textwrap.dedent(
|
| 122 |
+
COMPLETION_SCRIPTS.get(options.shell, "").format(prog=get_prog())
|
| 123 |
+
)
|
| 124 |
+
print(BASE_COMPLETION.format(script=script, shell=options.shell))
|
| 125 |
+
return SUCCESS
|
| 126 |
+
else:
|
| 127 |
+
sys.stderr.write(
|
| 128 |
+
"ERROR: You must pass {}\n".format(" or ".join(shell_options))
|
| 129 |
+
)
|
| 130 |
+
return SUCCESS
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/configuration.py
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import os
|
| 3 |
+
import subprocess
|
| 4 |
+
from optparse import Values
|
| 5 |
+
from typing import Any, List, Optional
|
| 6 |
+
|
| 7 |
+
from pip._internal.cli.base_command import Command
|
| 8 |
+
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
| 9 |
+
from pip._internal.configuration import (
|
| 10 |
+
Configuration,
|
| 11 |
+
Kind,
|
| 12 |
+
get_configuration_files,
|
| 13 |
+
kinds,
|
| 14 |
+
)
|
| 15 |
+
from pip._internal.exceptions import PipError
|
| 16 |
+
from pip._internal.utils.logging import indent_log
|
| 17 |
+
from pip._internal.utils.misc import get_prog, write_output
|
| 18 |
+
|
| 19 |
+
logger = logging.getLogger(__name__)
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class ConfigurationCommand(Command):
|
| 23 |
+
"""
|
| 24 |
+
Manage local and global configuration.
|
| 25 |
+
|
| 26 |
+
Subcommands:
|
| 27 |
+
|
| 28 |
+
- list: List the active configuration (or from the file specified)
|
| 29 |
+
- edit: Edit the configuration file in an editor
|
| 30 |
+
- get: Get the value associated with command.option
|
| 31 |
+
- set: Set the command.option=value
|
| 32 |
+
- unset: Unset the value associated with command.option
|
| 33 |
+
- debug: List the configuration files and values defined under them
|
| 34 |
+
|
| 35 |
+
Configuration keys should be dot separated command and option name,
|
| 36 |
+
with the special prefix "global" affecting any command. For example,
|
| 37 |
+
"pip config set global.index-url https://example.org/" would configure
|
| 38 |
+
the index url for all commands, but "pip config set download.timeout 10"
|
| 39 |
+
would configure a 10 second timeout only for "pip download" commands.
|
| 40 |
+
|
| 41 |
+
If none of --user, --global and --site are passed, a virtual
|
| 42 |
+
environment configuration file is used if one is active and the file
|
| 43 |
+
exists. Otherwise, all modifications happen to the user file by
|
| 44 |
+
default.
|
| 45 |
+
"""
|
| 46 |
+
|
| 47 |
+
ignore_require_venv = True
|
| 48 |
+
usage = """
|
| 49 |
+
%prog [<file-option>] list
|
| 50 |
+
%prog [<file-option>] [--editor <editor-path>] edit
|
| 51 |
+
|
| 52 |
+
%prog [<file-option>] get command.option
|
| 53 |
+
%prog [<file-option>] set command.option value
|
| 54 |
+
%prog [<file-option>] unset command.option
|
| 55 |
+
%prog [<file-option>] debug
|
| 56 |
+
"""
|
| 57 |
+
|
| 58 |
+
def add_options(self) -> None:
|
| 59 |
+
self.cmd_opts.add_option(
|
| 60 |
+
"--editor",
|
| 61 |
+
dest="editor",
|
| 62 |
+
action="store",
|
| 63 |
+
default=None,
|
| 64 |
+
help=(
|
| 65 |
+
"Editor to use to edit the file. Uses VISUAL or EDITOR "
|
| 66 |
+
"environment variables if not provided."
|
| 67 |
+
),
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
self.cmd_opts.add_option(
|
| 71 |
+
"--global",
|
| 72 |
+
dest="global_file",
|
| 73 |
+
action="store_true",
|
| 74 |
+
default=False,
|
| 75 |
+
help="Use the system-wide configuration file only",
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
self.cmd_opts.add_option(
|
| 79 |
+
"--user",
|
| 80 |
+
dest="user_file",
|
| 81 |
+
action="store_true",
|
| 82 |
+
default=False,
|
| 83 |
+
help="Use the user configuration file only",
|
| 84 |
+
)
|
| 85 |
+
|
| 86 |
+
self.cmd_opts.add_option(
|
| 87 |
+
"--site",
|
| 88 |
+
dest="site_file",
|
| 89 |
+
action="store_true",
|
| 90 |
+
default=False,
|
| 91 |
+
help="Use the current environment configuration file only",
|
| 92 |
+
)
|
| 93 |
+
|
| 94 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 95 |
+
|
| 96 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 97 |
+
handlers = {
|
| 98 |
+
"list": self.list_values,
|
| 99 |
+
"edit": self.open_in_editor,
|
| 100 |
+
"get": self.get_name,
|
| 101 |
+
"set": self.set_name_value,
|
| 102 |
+
"unset": self.unset_name,
|
| 103 |
+
"debug": self.list_config_values,
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
# Determine action
|
| 107 |
+
if not args or args[0] not in handlers:
|
| 108 |
+
logger.error(
|
| 109 |
+
"Need an action (%s) to perform.",
|
| 110 |
+
", ".join(sorted(handlers)),
|
| 111 |
+
)
|
| 112 |
+
return ERROR
|
| 113 |
+
|
| 114 |
+
action = args[0]
|
| 115 |
+
|
| 116 |
+
# Determine which configuration files are to be loaded
|
| 117 |
+
# Depends on whether the command is modifying.
|
| 118 |
+
try:
|
| 119 |
+
load_only = self._determine_file(
|
| 120 |
+
options, need_value=(action in ["get", "set", "unset", "edit"])
|
| 121 |
+
)
|
| 122 |
+
except PipError as e:
|
| 123 |
+
logger.error(e.args[0])
|
| 124 |
+
return ERROR
|
| 125 |
+
|
| 126 |
+
# Load a new configuration
|
| 127 |
+
self.configuration = Configuration(
|
| 128 |
+
isolated=options.isolated_mode, load_only=load_only
|
| 129 |
+
)
|
| 130 |
+
self.configuration.load()
|
| 131 |
+
|
| 132 |
+
# Error handling happens here, not in the action-handlers.
|
| 133 |
+
try:
|
| 134 |
+
handlers[action](options, args[1:])
|
| 135 |
+
except PipError as e:
|
| 136 |
+
logger.error(e.args[0])
|
| 137 |
+
return ERROR
|
| 138 |
+
|
| 139 |
+
return SUCCESS
|
| 140 |
+
|
| 141 |
+
def _determine_file(self, options: Values, need_value: bool) -> Optional[Kind]:
|
| 142 |
+
file_options = [
|
| 143 |
+
key
|
| 144 |
+
for key, value in (
|
| 145 |
+
(kinds.USER, options.user_file),
|
| 146 |
+
(kinds.GLOBAL, options.global_file),
|
| 147 |
+
(kinds.SITE, options.site_file),
|
| 148 |
+
)
|
| 149 |
+
if value
|
| 150 |
+
]
|
| 151 |
+
|
| 152 |
+
if not file_options:
|
| 153 |
+
if not need_value:
|
| 154 |
+
return None
|
| 155 |
+
# Default to user, unless there's a site file.
|
| 156 |
+
elif any(
|
| 157 |
+
os.path.exists(site_config_file)
|
| 158 |
+
for site_config_file in get_configuration_files()[kinds.SITE]
|
| 159 |
+
):
|
| 160 |
+
return kinds.SITE
|
| 161 |
+
else:
|
| 162 |
+
return kinds.USER
|
| 163 |
+
elif len(file_options) == 1:
|
| 164 |
+
return file_options[0]
|
| 165 |
+
|
| 166 |
+
raise PipError(
|
| 167 |
+
"Need exactly one file to operate upon "
|
| 168 |
+
"(--user, --site, --global) to perform."
|
| 169 |
+
)
|
| 170 |
+
|
| 171 |
+
def list_values(self, options: Values, args: List[str]) -> None:
|
| 172 |
+
self._get_n_args(args, "list", n=0)
|
| 173 |
+
|
| 174 |
+
for key, value in sorted(self.configuration.items()):
|
| 175 |
+
write_output("%s=%r", key, value)
|
| 176 |
+
|
| 177 |
+
def get_name(self, options: Values, args: List[str]) -> None:
|
| 178 |
+
key = self._get_n_args(args, "get [name]", n=1)
|
| 179 |
+
value = self.configuration.get_value(key)
|
| 180 |
+
|
| 181 |
+
write_output("%s", value)
|
| 182 |
+
|
| 183 |
+
def set_name_value(self, options: Values, args: List[str]) -> None:
|
| 184 |
+
key, value = self._get_n_args(args, "set [name] [value]", n=2)
|
| 185 |
+
self.configuration.set_value(key, value)
|
| 186 |
+
|
| 187 |
+
self._save_configuration()
|
| 188 |
+
|
| 189 |
+
def unset_name(self, options: Values, args: List[str]) -> None:
|
| 190 |
+
key = self._get_n_args(args, "unset [name]", n=1)
|
| 191 |
+
self.configuration.unset_value(key)
|
| 192 |
+
|
| 193 |
+
self._save_configuration()
|
| 194 |
+
|
| 195 |
+
def list_config_values(self, options: Values, args: List[str]) -> None:
|
| 196 |
+
"""List config key-value pairs across different config files"""
|
| 197 |
+
self._get_n_args(args, "debug", n=0)
|
| 198 |
+
|
| 199 |
+
self.print_env_var_values()
|
| 200 |
+
# Iterate over config files and print if they exist, and the
|
| 201 |
+
# key-value pairs present in them if they do
|
| 202 |
+
for variant, files in sorted(self.configuration.iter_config_files()):
|
| 203 |
+
write_output("%s:", variant)
|
| 204 |
+
for fname in files:
|
| 205 |
+
with indent_log():
|
| 206 |
+
file_exists = os.path.exists(fname)
|
| 207 |
+
write_output("%s, exists: %r", fname, file_exists)
|
| 208 |
+
if file_exists:
|
| 209 |
+
self.print_config_file_values(variant)
|
| 210 |
+
|
| 211 |
+
def print_config_file_values(self, variant: Kind) -> None:
|
| 212 |
+
"""Get key-value pairs from the file of a variant"""
|
| 213 |
+
for name, value in self.configuration.get_values_in_config(variant).items():
|
| 214 |
+
with indent_log():
|
| 215 |
+
write_output("%s: %s", name, value)
|
| 216 |
+
|
| 217 |
+
def print_env_var_values(self) -> None:
|
| 218 |
+
"""Get key-values pairs present as environment variables"""
|
| 219 |
+
write_output("%s:", "env_var")
|
| 220 |
+
with indent_log():
|
| 221 |
+
for key, value in sorted(self.configuration.get_environ_vars()):
|
| 222 |
+
env_var = f"PIP_{key.upper()}"
|
| 223 |
+
write_output("%s=%r", env_var, value)
|
| 224 |
+
|
| 225 |
+
def open_in_editor(self, options: Values, args: List[str]) -> None:
|
| 226 |
+
editor = self._determine_editor(options)
|
| 227 |
+
|
| 228 |
+
fname = self.configuration.get_file_to_edit()
|
| 229 |
+
if fname is None:
|
| 230 |
+
raise PipError("Could not determine appropriate file.")
|
| 231 |
+
elif '"' in fname:
|
| 232 |
+
# This shouldn't happen, unless we see a username like that.
|
| 233 |
+
# If that happens, we'd appreciate a pull request fixing this.
|
| 234 |
+
raise PipError(
|
| 235 |
+
f'Can not open an editor for a file name containing "\n{fname}'
|
| 236 |
+
)
|
| 237 |
+
|
| 238 |
+
try:
|
| 239 |
+
subprocess.check_call(f'{editor} "{fname}"', shell=True)
|
| 240 |
+
except FileNotFoundError as e:
|
| 241 |
+
if not e.filename:
|
| 242 |
+
e.filename = editor
|
| 243 |
+
raise
|
| 244 |
+
except subprocess.CalledProcessError as e:
|
| 245 |
+
raise PipError(f"Editor Subprocess exited with exit code {e.returncode}")
|
| 246 |
+
|
| 247 |
+
def _get_n_args(self, args: List[str], example: str, n: int) -> Any:
|
| 248 |
+
"""Helper to make sure the command got the right number of arguments"""
|
| 249 |
+
if len(args) != n:
|
| 250 |
+
msg = (
|
| 251 |
+
f"Got unexpected number of arguments, expected {n}. "
|
| 252 |
+
f'(example: "{get_prog()} config {example}")'
|
| 253 |
+
)
|
| 254 |
+
raise PipError(msg)
|
| 255 |
+
|
| 256 |
+
if n == 1:
|
| 257 |
+
return args[0]
|
| 258 |
+
else:
|
| 259 |
+
return args
|
| 260 |
+
|
| 261 |
+
def _save_configuration(self) -> None:
|
| 262 |
+
# We successfully ran a modifying command. Need to save the
|
| 263 |
+
# configuration.
|
| 264 |
+
try:
|
| 265 |
+
self.configuration.save()
|
| 266 |
+
except Exception:
|
| 267 |
+
logger.exception(
|
| 268 |
+
"Unable to save configuration. Please report this as a bug."
|
| 269 |
+
)
|
| 270 |
+
raise PipError("Internal Error.")
|
| 271 |
+
|
| 272 |
+
def _determine_editor(self, options: Values) -> str:
|
| 273 |
+
if options.editor is not None:
|
| 274 |
+
return options.editor
|
| 275 |
+
elif "VISUAL" in os.environ:
|
| 276 |
+
return os.environ["VISUAL"]
|
| 277 |
+
elif "EDITOR" in os.environ:
|
| 278 |
+
return os.environ["EDITOR"]
|
| 279 |
+
else:
|
| 280 |
+
raise PipError("Could not determine editor to use.")
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/debug.py
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import importlib.resources
|
| 2 |
+
import locale
|
| 3 |
+
import logging
|
| 4 |
+
import os
|
| 5 |
+
import sys
|
| 6 |
+
from optparse import Values
|
| 7 |
+
from types import ModuleType
|
| 8 |
+
from typing import Any, Dict, List, Optional
|
| 9 |
+
|
| 10 |
+
import pip._vendor
|
| 11 |
+
from pip._vendor.certifi import where
|
| 12 |
+
from pip._vendor.packaging.version import parse as parse_version
|
| 13 |
+
|
| 14 |
+
from pip._internal.cli import cmdoptions
|
| 15 |
+
from pip._internal.cli.base_command import Command
|
| 16 |
+
from pip._internal.cli.cmdoptions import make_target_python
|
| 17 |
+
from pip._internal.cli.status_codes import SUCCESS
|
| 18 |
+
from pip._internal.configuration import Configuration
|
| 19 |
+
from pip._internal.metadata import get_environment
|
| 20 |
+
from pip._internal.utils.logging import indent_log
|
| 21 |
+
from pip._internal.utils.misc import get_pip_version
|
| 22 |
+
|
| 23 |
+
logger = logging.getLogger(__name__)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def show_value(name: str, value: Any) -> None:
|
| 27 |
+
logger.info("%s: %s", name, value)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def show_sys_implementation() -> None:
|
| 31 |
+
logger.info("sys.implementation:")
|
| 32 |
+
implementation_name = sys.implementation.name
|
| 33 |
+
with indent_log():
|
| 34 |
+
show_value("name", implementation_name)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def create_vendor_txt_map() -> Dict[str, str]:
|
| 38 |
+
with importlib.resources.open_text("pip._vendor", "vendor.txt") as f:
|
| 39 |
+
# Purge non version specifying lines.
|
| 40 |
+
# Also, remove any space prefix or suffixes (including comments).
|
| 41 |
+
lines = [
|
| 42 |
+
line.strip().split(" ", 1)[0] for line in f.readlines() if "==" in line
|
| 43 |
+
]
|
| 44 |
+
|
| 45 |
+
# Transform into "module" -> version dict.
|
| 46 |
+
return dict(line.split("==", 1) for line in lines)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def get_module_from_module_name(module_name: str) -> Optional[ModuleType]:
|
| 50 |
+
# Module name can be uppercase in vendor.txt for some reason...
|
| 51 |
+
module_name = module_name.lower().replace("-", "_")
|
| 52 |
+
# PATCH: setuptools is actually only pkg_resources.
|
| 53 |
+
if module_name == "setuptools":
|
| 54 |
+
module_name = "pkg_resources"
|
| 55 |
+
|
| 56 |
+
try:
|
| 57 |
+
__import__(f"pip._vendor.{module_name}", globals(), locals(), level=0)
|
| 58 |
+
return getattr(pip._vendor, module_name)
|
| 59 |
+
except ImportError:
|
| 60 |
+
# We allow 'truststore' to fail to import due
|
| 61 |
+
# to being unavailable on Python 3.9 and earlier.
|
| 62 |
+
if module_name == "truststore" and sys.version_info < (3, 10):
|
| 63 |
+
return None
|
| 64 |
+
raise
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def get_vendor_version_from_module(module_name: str) -> Optional[str]:
|
| 68 |
+
module = get_module_from_module_name(module_name)
|
| 69 |
+
version = getattr(module, "__version__", None)
|
| 70 |
+
|
| 71 |
+
if module and not version:
|
| 72 |
+
# Try to find version in debundled module info.
|
| 73 |
+
assert module.__file__ is not None
|
| 74 |
+
env = get_environment([os.path.dirname(module.__file__)])
|
| 75 |
+
dist = env.get_distribution(module_name)
|
| 76 |
+
if dist:
|
| 77 |
+
version = str(dist.version)
|
| 78 |
+
|
| 79 |
+
return version
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def show_actual_vendor_versions(vendor_txt_versions: Dict[str, str]) -> None:
|
| 83 |
+
"""Log the actual version and print extra info if there is
|
| 84 |
+
a conflict or if the actual version could not be imported.
|
| 85 |
+
"""
|
| 86 |
+
for module_name, expected_version in vendor_txt_versions.items():
|
| 87 |
+
extra_message = ""
|
| 88 |
+
actual_version = get_vendor_version_from_module(module_name)
|
| 89 |
+
if not actual_version:
|
| 90 |
+
extra_message = (
|
| 91 |
+
" (Unable to locate actual module version, using"
|
| 92 |
+
" vendor.txt specified version)"
|
| 93 |
+
)
|
| 94 |
+
actual_version = expected_version
|
| 95 |
+
elif parse_version(actual_version) != parse_version(expected_version):
|
| 96 |
+
extra_message = (
|
| 97 |
+
" (CONFLICT: vendor.txt suggests version should"
|
| 98 |
+
f" be {expected_version})"
|
| 99 |
+
)
|
| 100 |
+
logger.info("%s==%s%s", module_name, actual_version, extra_message)
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def show_vendor_versions() -> None:
|
| 104 |
+
logger.info("vendored library versions:")
|
| 105 |
+
|
| 106 |
+
vendor_txt_versions = create_vendor_txt_map()
|
| 107 |
+
with indent_log():
|
| 108 |
+
show_actual_vendor_versions(vendor_txt_versions)
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def show_tags(options: Values) -> None:
|
| 112 |
+
tag_limit = 10
|
| 113 |
+
|
| 114 |
+
target_python = make_target_python(options)
|
| 115 |
+
tags = target_python.get_sorted_tags()
|
| 116 |
+
|
| 117 |
+
# Display the target options that were explicitly provided.
|
| 118 |
+
formatted_target = target_python.format_given()
|
| 119 |
+
suffix = ""
|
| 120 |
+
if formatted_target:
|
| 121 |
+
suffix = f" (target: {formatted_target})"
|
| 122 |
+
|
| 123 |
+
msg = f"Compatible tags: {len(tags)}{suffix}"
|
| 124 |
+
logger.info(msg)
|
| 125 |
+
|
| 126 |
+
if options.verbose < 1 and len(tags) > tag_limit:
|
| 127 |
+
tags_limited = True
|
| 128 |
+
tags = tags[:tag_limit]
|
| 129 |
+
else:
|
| 130 |
+
tags_limited = False
|
| 131 |
+
|
| 132 |
+
with indent_log():
|
| 133 |
+
for tag in tags:
|
| 134 |
+
logger.info(str(tag))
|
| 135 |
+
|
| 136 |
+
if tags_limited:
|
| 137 |
+
msg = f"...\n[First {tag_limit} tags shown. Pass --verbose to show all.]"
|
| 138 |
+
logger.info(msg)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
def ca_bundle_info(config: Configuration) -> str:
|
| 142 |
+
levels = {key.split(".", 1)[0] for key, _ in config.items()}
|
| 143 |
+
if not levels:
|
| 144 |
+
return "Not specified"
|
| 145 |
+
|
| 146 |
+
levels_that_override_global = ["install", "wheel", "download"]
|
| 147 |
+
global_overriding_level = [
|
| 148 |
+
level for level in levels if level in levels_that_override_global
|
| 149 |
+
]
|
| 150 |
+
if not global_overriding_level:
|
| 151 |
+
return "global"
|
| 152 |
+
|
| 153 |
+
if "global" in levels:
|
| 154 |
+
levels.remove("global")
|
| 155 |
+
return ", ".join(levels)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
class DebugCommand(Command):
|
| 159 |
+
"""
|
| 160 |
+
Display debug information.
|
| 161 |
+
"""
|
| 162 |
+
|
| 163 |
+
usage = """
|
| 164 |
+
%prog <options>"""
|
| 165 |
+
ignore_require_venv = True
|
| 166 |
+
|
| 167 |
+
def add_options(self) -> None:
|
| 168 |
+
cmdoptions.add_target_python_options(self.cmd_opts)
|
| 169 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 170 |
+
self.parser.config.load()
|
| 171 |
+
|
| 172 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 173 |
+
logger.warning(
|
| 174 |
+
"This command is only meant for debugging. "
|
| 175 |
+
"Do not use this with automation for parsing and getting these "
|
| 176 |
+
"details, since the output and options of this command may "
|
| 177 |
+
"change without notice."
|
| 178 |
+
)
|
| 179 |
+
show_value("pip version", get_pip_version())
|
| 180 |
+
show_value("sys.version", sys.version)
|
| 181 |
+
show_value("sys.executable", sys.executable)
|
| 182 |
+
show_value("sys.getdefaultencoding", sys.getdefaultencoding())
|
| 183 |
+
show_value("sys.getfilesystemencoding", sys.getfilesystemencoding())
|
| 184 |
+
show_value(
|
| 185 |
+
"locale.getpreferredencoding",
|
| 186 |
+
locale.getpreferredencoding(),
|
| 187 |
+
)
|
| 188 |
+
show_value("sys.platform", sys.platform)
|
| 189 |
+
show_sys_implementation()
|
| 190 |
+
|
| 191 |
+
show_value("'cert' config value", ca_bundle_info(self.parser.config))
|
| 192 |
+
show_value("REQUESTS_CA_BUNDLE", os.environ.get("REQUESTS_CA_BUNDLE"))
|
| 193 |
+
show_value("CURL_CA_BUNDLE", os.environ.get("CURL_CA_BUNDLE"))
|
| 194 |
+
show_value("pip._vendor.certifi.where()", where())
|
| 195 |
+
show_value("pip._vendor.DEBUNDLED", pip._vendor.DEBUNDLED)
|
| 196 |
+
|
| 197 |
+
show_vendor_versions()
|
| 198 |
+
|
| 199 |
+
show_tags(options)
|
| 200 |
+
|
| 201 |
+
return SUCCESS
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/download.py
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import os
|
| 3 |
+
from optparse import Values
|
| 4 |
+
from typing import List
|
| 5 |
+
|
| 6 |
+
from pip._internal.cli import cmdoptions
|
| 7 |
+
from pip._internal.cli.cmdoptions import make_target_python
|
| 8 |
+
from pip._internal.cli.req_command import RequirementCommand, with_cleanup
|
| 9 |
+
from pip._internal.cli.status_codes import SUCCESS
|
| 10 |
+
from pip._internal.operations.build.build_tracker import get_build_tracker
|
| 11 |
+
from pip._internal.req.req_install import check_legacy_setup_py_options
|
| 12 |
+
from pip._internal.utils.misc import ensure_dir, normalize_path, write_output
|
| 13 |
+
from pip._internal.utils.temp_dir import TempDirectory
|
| 14 |
+
|
| 15 |
+
logger = logging.getLogger(__name__)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class DownloadCommand(RequirementCommand):
|
| 19 |
+
"""
|
| 20 |
+
Download packages from:
|
| 21 |
+
|
| 22 |
+
- PyPI (and other indexes) using requirement specifiers.
|
| 23 |
+
- VCS project urls.
|
| 24 |
+
- Local project directories.
|
| 25 |
+
- Local or remote source archives.
|
| 26 |
+
|
| 27 |
+
pip also supports downloading from "requirements files", which provide
|
| 28 |
+
an easy way to specify a whole environment to be downloaded.
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
usage = """
|
| 32 |
+
%prog [options] <requirement specifier> [package-index-options] ...
|
| 33 |
+
%prog [options] -r <requirements file> [package-index-options] ...
|
| 34 |
+
%prog [options] <vcs project url> ...
|
| 35 |
+
%prog [options] <local project path> ...
|
| 36 |
+
%prog [options] <archive url/path> ..."""
|
| 37 |
+
|
| 38 |
+
def add_options(self) -> None:
|
| 39 |
+
self.cmd_opts.add_option(cmdoptions.constraints())
|
| 40 |
+
self.cmd_opts.add_option(cmdoptions.requirements())
|
| 41 |
+
self.cmd_opts.add_option(cmdoptions.no_deps())
|
| 42 |
+
self.cmd_opts.add_option(cmdoptions.global_options())
|
| 43 |
+
self.cmd_opts.add_option(cmdoptions.no_binary())
|
| 44 |
+
self.cmd_opts.add_option(cmdoptions.only_binary())
|
| 45 |
+
self.cmd_opts.add_option(cmdoptions.prefer_binary())
|
| 46 |
+
self.cmd_opts.add_option(cmdoptions.src())
|
| 47 |
+
self.cmd_opts.add_option(cmdoptions.pre())
|
| 48 |
+
self.cmd_opts.add_option(cmdoptions.require_hashes())
|
| 49 |
+
self.cmd_opts.add_option(cmdoptions.progress_bar())
|
| 50 |
+
self.cmd_opts.add_option(cmdoptions.no_build_isolation())
|
| 51 |
+
self.cmd_opts.add_option(cmdoptions.use_pep517())
|
| 52 |
+
self.cmd_opts.add_option(cmdoptions.no_use_pep517())
|
| 53 |
+
self.cmd_opts.add_option(cmdoptions.check_build_deps())
|
| 54 |
+
self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
|
| 55 |
+
|
| 56 |
+
self.cmd_opts.add_option(
|
| 57 |
+
"-d",
|
| 58 |
+
"--dest",
|
| 59 |
+
"--destination-dir",
|
| 60 |
+
"--destination-directory",
|
| 61 |
+
dest="download_dir",
|
| 62 |
+
metavar="dir",
|
| 63 |
+
default=os.curdir,
|
| 64 |
+
help="Download packages into <dir>.",
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
cmdoptions.add_target_python_options(self.cmd_opts)
|
| 68 |
+
|
| 69 |
+
index_opts = cmdoptions.make_option_group(
|
| 70 |
+
cmdoptions.index_group,
|
| 71 |
+
self.parser,
|
| 72 |
+
)
|
| 73 |
+
|
| 74 |
+
self.parser.insert_option_group(0, index_opts)
|
| 75 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 76 |
+
|
| 77 |
+
@with_cleanup
|
| 78 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 79 |
+
options.ignore_installed = True
|
| 80 |
+
# editable doesn't really make sense for `pip download`, but the bowels
|
| 81 |
+
# of the RequirementSet code require that property.
|
| 82 |
+
options.editables = []
|
| 83 |
+
|
| 84 |
+
cmdoptions.check_dist_restriction(options)
|
| 85 |
+
|
| 86 |
+
options.download_dir = normalize_path(options.download_dir)
|
| 87 |
+
ensure_dir(options.download_dir)
|
| 88 |
+
|
| 89 |
+
session = self.get_default_session(options)
|
| 90 |
+
|
| 91 |
+
target_python = make_target_python(options)
|
| 92 |
+
finder = self._build_package_finder(
|
| 93 |
+
options=options,
|
| 94 |
+
session=session,
|
| 95 |
+
target_python=target_python,
|
| 96 |
+
ignore_requires_python=options.ignore_requires_python,
|
| 97 |
+
)
|
| 98 |
+
|
| 99 |
+
build_tracker = self.enter_context(get_build_tracker())
|
| 100 |
+
|
| 101 |
+
directory = TempDirectory(
|
| 102 |
+
delete=not options.no_clean,
|
| 103 |
+
kind="download",
|
| 104 |
+
globally_managed=True,
|
| 105 |
+
)
|
| 106 |
+
|
| 107 |
+
reqs = self.get_requirements(args, options, finder, session)
|
| 108 |
+
check_legacy_setup_py_options(options, reqs)
|
| 109 |
+
|
| 110 |
+
preparer = self.make_requirement_preparer(
|
| 111 |
+
temp_build_dir=directory,
|
| 112 |
+
options=options,
|
| 113 |
+
build_tracker=build_tracker,
|
| 114 |
+
session=session,
|
| 115 |
+
finder=finder,
|
| 116 |
+
download_dir=options.download_dir,
|
| 117 |
+
use_user_site=False,
|
| 118 |
+
verbosity=self.verbosity,
|
| 119 |
+
)
|
| 120 |
+
|
| 121 |
+
resolver = self.make_resolver(
|
| 122 |
+
preparer=preparer,
|
| 123 |
+
finder=finder,
|
| 124 |
+
options=options,
|
| 125 |
+
ignore_requires_python=options.ignore_requires_python,
|
| 126 |
+
use_pep517=options.use_pep517,
|
| 127 |
+
py_version_info=options.python_version,
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
self.trace_basic_info(finder)
|
| 131 |
+
|
| 132 |
+
requirement_set = resolver.resolve(reqs, check_supported_wheels=True)
|
| 133 |
+
|
| 134 |
+
downloaded: List[str] = []
|
| 135 |
+
for req in requirement_set.requirements.values():
|
| 136 |
+
if req.satisfied_by is None:
|
| 137 |
+
assert req.name is not None
|
| 138 |
+
preparer.save_linked_requirement(req)
|
| 139 |
+
downloaded.append(req.name)
|
| 140 |
+
|
| 141 |
+
preparer.prepare_linked_requirements_more(requirement_set.requirements.values())
|
| 142 |
+
requirement_set.warn_legacy_versions_and_specifiers()
|
| 143 |
+
|
| 144 |
+
if downloaded:
|
| 145 |
+
write_output("Successfully downloaded %s", " ".join(downloaded))
|
| 146 |
+
|
| 147 |
+
return SUCCESS
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/freeze.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
from optparse import Values
|
| 3 |
+
from typing import AbstractSet, List
|
| 4 |
+
|
| 5 |
+
from pip._internal.cli import cmdoptions
|
| 6 |
+
from pip._internal.cli.base_command import Command
|
| 7 |
+
from pip._internal.cli.status_codes import SUCCESS
|
| 8 |
+
from pip._internal.operations.freeze import freeze
|
| 9 |
+
from pip._internal.utils.compat import stdlib_pkgs
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def _should_suppress_build_backends() -> bool:
|
| 13 |
+
return sys.version_info < (3, 12)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def _dev_pkgs() -> AbstractSet[str]:
|
| 17 |
+
pkgs = {"pip"}
|
| 18 |
+
|
| 19 |
+
if _should_suppress_build_backends():
|
| 20 |
+
pkgs |= {"setuptools", "distribute", "wheel"}
|
| 21 |
+
|
| 22 |
+
return pkgs
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class FreezeCommand(Command):
|
| 26 |
+
"""
|
| 27 |
+
Output installed packages in requirements format.
|
| 28 |
+
|
| 29 |
+
packages are listed in a case-insensitive sorted order.
|
| 30 |
+
"""
|
| 31 |
+
|
| 32 |
+
usage = """
|
| 33 |
+
%prog [options]"""
|
| 34 |
+
log_streams = ("ext://sys.stderr", "ext://sys.stderr")
|
| 35 |
+
|
| 36 |
+
def add_options(self) -> None:
|
| 37 |
+
self.cmd_opts.add_option(
|
| 38 |
+
"-r",
|
| 39 |
+
"--requirement",
|
| 40 |
+
dest="requirements",
|
| 41 |
+
action="append",
|
| 42 |
+
default=[],
|
| 43 |
+
metavar="file",
|
| 44 |
+
help=(
|
| 45 |
+
"Use the order in the given requirements file and its "
|
| 46 |
+
"comments when generating output. This option can be "
|
| 47 |
+
"used multiple times."
|
| 48 |
+
),
|
| 49 |
+
)
|
| 50 |
+
self.cmd_opts.add_option(
|
| 51 |
+
"-l",
|
| 52 |
+
"--local",
|
| 53 |
+
dest="local",
|
| 54 |
+
action="store_true",
|
| 55 |
+
default=False,
|
| 56 |
+
help=(
|
| 57 |
+
"If in a virtualenv that has global access, do not output "
|
| 58 |
+
"globally-installed packages."
|
| 59 |
+
),
|
| 60 |
+
)
|
| 61 |
+
self.cmd_opts.add_option(
|
| 62 |
+
"--user",
|
| 63 |
+
dest="user",
|
| 64 |
+
action="store_true",
|
| 65 |
+
default=False,
|
| 66 |
+
help="Only output packages installed in user-site.",
|
| 67 |
+
)
|
| 68 |
+
self.cmd_opts.add_option(cmdoptions.list_path())
|
| 69 |
+
self.cmd_opts.add_option(
|
| 70 |
+
"--all",
|
| 71 |
+
dest="freeze_all",
|
| 72 |
+
action="store_true",
|
| 73 |
+
help=(
|
| 74 |
+
"Do not skip these packages in the output:"
|
| 75 |
+
" {}".format(", ".join(_dev_pkgs()))
|
| 76 |
+
),
|
| 77 |
+
)
|
| 78 |
+
self.cmd_opts.add_option(
|
| 79 |
+
"--exclude-editable",
|
| 80 |
+
dest="exclude_editable",
|
| 81 |
+
action="store_true",
|
| 82 |
+
help="Exclude editable package from output.",
|
| 83 |
+
)
|
| 84 |
+
self.cmd_opts.add_option(cmdoptions.list_exclude())
|
| 85 |
+
|
| 86 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 87 |
+
|
| 88 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 89 |
+
skip = set(stdlib_pkgs)
|
| 90 |
+
if not options.freeze_all:
|
| 91 |
+
skip.update(_dev_pkgs())
|
| 92 |
+
|
| 93 |
+
if options.excludes:
|
| 94 |
+
skip.update(options.excludes)
|
| 95 |
+
|
| 96 |
+
cmdoptions.check_list_path_option(options)
|
| 97 |
+
|
| 98 |
+
for line in freeze(
|
| 99 |
+
requirement=options.requirements,
|
| 100 |
+
local_only=options.local,
|
| 101 |
+
user_only=options.user,
|
| 102 |
+
paths=options.path,
|
| 103 |
+
isolated=options.isolated_mode,
|
| 104 |
+
skip=skip,
|
| 105 |
+
exclude_editable=options.exclude_editable,
|
| 106 |
+
):
|
| 107 |
+
sys.stdout.write(line + "\n")
|
| 108 |
+
return SUCCESS
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/hash.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import hashlib
|
| 2 |
+
import logging
|
| 3 |
+
import sys
|
| 4 |
+
from optparse import Values
|
| 5 |
+
from typing import List
|
| 6 |
+
|
| 7 |
+
from pip._internal.cli.base_command import Command
|
| 8 |
+
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
| 9 |
+
from pip._internal.utils.hashes import FAVORITE_HASH, STRONG_HASHES
|
| 10 |
+
from pip._internal.utils.misc import read_chunks, write_output
|
| 11 |
+
|
| 12 |
+
logger = logging.getLogger(__name__)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class HashCommand(Command):
|
| 16 |
+
"""
|
| 17 |
+
Compute a hash of a local package archive.
|
| 18 |
+
|
| 19 |
+
These can be used with --hash in a requirements file to do repeatable
|
| 20 |
+
installs.
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
usage = "%prog [options] <file> ..."
|
| 24 |
+
ignore_require_venv = True
|
| 25 |
+
|
| 26 |
+
def add_options(self) -> None:
|
| 27 |
+
self.cmd_opts.add_option(
|
| 28 |
+
"-a",
|
| 29 |
+
"--algorithm",
|
| 30 |
+
dest="algorithm",
|
| 31 |
+
choices=STRONG_HASHES,
|
| 32 |
+
action="store",
|
| 33 |
+
default=FAVORITE_HASH,
|
| 34 |
+
help="The hash algorithm to use: one of {}".format(
|
| 35 |
+
", ".join(STRONG_HASHES)
|
| 36 |
+
),
|
| 37 |
+
)
|
| 38 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 39 |
+
|
| 40 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 41 |
+
if not args:
|
| 42 |
+
self.parser.print_usage(sys.stderr)
|
| 43 |
+
return ERROR
|
| 44 |
+
|
| 45 |
+
algorithm = options.algorithm
|
| 46 |
+
for path in args:
|
| 47 |
+
write_output(
|
| 48 |
+
"%s:\n--hash=%s:%s", path, algorithm, _hash_of_file(path, algorithm)
|
| 49 |
+
)
|
| 50 |
+
return SUCCESS
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def _hash_of_file(path: str, algorithm: str) -> str:
|
| 54 |
+
"""Return the hash digest of a file."""
|
| 55 |
+
with open(path, "rb") as archive:
|
| 56 |
+
hash = hashlib.new(algorithm)
|
| 57 |
+
for chunk in read_chunks(archive):
|
| 58 |
+
hash.update(chunk)
|
| 59 |
+
return hash.hexdigest()
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/help.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from optparse import Values
|
| 2 |
+
from typing import List
|
| 3 |
+
|
| 4 |
+
from pip._internal.cli.base_command import Command
|
| 5 |
+
from pip._internal.cli.status_codes import SUCCESS
|
| 6 |
+
from pip._internal.exceptions import CommandError
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class HelpCommand(Command):
|
| 10 |
+
"""Show help for commands"""
|
| 11 |
+
|
| 12 |
+
usage = """
|
| 13 |
+
%prog <command>"""
|
| 14 |
+
ignore_require_venv = True
|
| 15 |
+
|
| 16 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 17 |
+
from pip._internal.commands import (
|
| 18 |
+
commands_dict,
|
| 19 |
+
create_command,
|
| 20 |
+
get_similar_commands,
|
| 21 |
+
)
|
| 22 |
+
|
| 23 |
+
try:
|
| 24 |
+
# 'pip help' with no args is handled by pip.__init__.parseopt()
|
| 25 |
+
cmd_name = args[0] # the command we need help for
|
| 26 |
+
except IndexError:
|
| 27 |
+
return SUCCESS
|
| 28 |
+
|
| 29 |
+
if cmd_name not in commands_dict:
|
| 30 |
+
guess = get_similar_commands(cmd_name)
|
| 31 |
+
|
| 32 |
+
msg = [f'unknown command "{cmd_name}"']
|
| 33 |
+
if guess:
|
| 34 |
+
msg.append(f'maybe you meant "{guess}"')
|
| 35 |
+
|
| 36 |
+
raise CommandError(" - ".join(msg))
|
| 37 |
+
|
| 38 |
+
command = create_command(cmd_name)
|
| 39 |
+
command.parser.print_help()
|
| 40 |
+
|
| 41 |
+
return SUCCESS
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/index.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
from optparse import Values
|
| 3 |
+
from typing import Any, Iterable, List, Optional, Union
|
| 4 |
+
|
| 5 |
+
from pip._vendor.packaging.version import LegacyVersion, Version
|
| 6 |
+
|
| 7 |
+
from pip._internal.cli import cmdoptions
|
| 8 |
+
from pip._internal.cli.req_command import IndexGroupCommand
|
| 9 |
+
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
| 10 |
+
from pip._internal.commands.search import print_dist_installation_info
|
| 11 |
+
from pip._internal.exceptions import CommandError, DistributionNotFound, PipError
|
| 12 |
+
from pip._internal.index.collector import LinkCollector
|
| 13 |
+
from pip._internal.index.package_finder import PackageFinder
|
| 14 |
+
from pip._internal.models.selection_prefs import SelectionPreferences
|
| 15 |
+
from pip._internal.models.target_python import TargetPython
|
| 16 |
+
from pip._internal.network.session import PipSession
|
| 17 |
+
from pip._internal.utils.misc import write_output
|
| 18 |
+
|
| 19 |
+
logger = logging.getLogger(__name__)
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class IndexCommand(IndexGroupCommand):
|
| 23 |
+
"""
|
| 24 |
+
Inspect information available from package indexes.
|
| 25 |
+
"""
|
| 26 |
+
|
| 27 |
+
ignore_require_venv = True
|
| 28 |
+
usage = """
|
| 29 |
+
%prog versions <package>
|
| 30 |
+
"""
|
| 31 |
+
|
| 32 |
+
def add_options(self) -> None:
|
| 33 |
+
cmdoptions.add_target_python_options(self.cmd_opts)
|
| 34 |
+
|
| 35 |
+
self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
|
| 36 |
+
self.cmd_opts.add_option(cmdoptions.pre())
|
| 37 |
+
self.cmd_opts.add_option(cmdoptions.no_binary())
|
| 38 |
+
self.cmd_opts.add_option(cmdoptions.only_binary())
|
| 39 |
+
|
| 40 |
+
index_opts = cmdoptions.make_option_group(
|
| 41 |
+
cmdoptions.index_group,
|
| 42 |
+
self.parser,
|
| 43 |
+
)
|
| 44 |
+
|
| 45 |
+
self.parser.insert_option_group(0, index_opts)
|
| 46 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 47 |
+
|
| 48 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 49 |
+
handlers = {
|
| 50 |
+
"versions": self.get_available_package_versions,
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
logger.warning(
|
| 54 |
+
"pip index is currently an experimental command. "
|
| 55 |
+
"It may be removed/changed in a future release "
|
| 56 |
+
"without prior warning."
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
# Determine action
|
| 60 |
+
if not args or args[0] not in handlers:
|
| 61 |
+
logger.error(
|
| 62 |
+
"Need an action (%s) to perform.",
|
| 63 |
+
", ".join(sorted(handlers)),
|
| 64 |
+
)
|
| 65 |
+
return ERROR
|
| 66 |
+
|
| 67 |
+
action = args[0]
|
| 68 |
+
|
| 69 |
+
# Error handling happens here, not in the action-handlers.
|
| 70 |
+
try:
|
| 71 |
+
handlers[action](options, args[1:])
|
| 72 |
+
except PipError as e:
|
| 73 |
+
logger.error(e.args[0])
|
| 74 |
+
return ERROR
|
| 75 |
+
|
| 76 |
+
return SUCCESS
|
| 77 |
+
|
| 78 |
+
def _build_package_finder(
|
| 79 |
+
self,
|
| 80 |
+
options: Values,
|
| 81 |
+
session: PipSession,
|
| 82 |
+
target_python: Optional[TargetPython] = None,
|
| 83 |
+
ignore_requires_python: Optional[bool] = None,
|
| 84 |
+
) -> PackageFinder:
|
| 85 |
+
"""
|
| 86 |
+
Create a package finder appropriate to the index command.
|
| 87 |
+
"""
|
| 88 |
+
link_collector = LinkCollector.create(session, options=options)
|
| 89 |
+
|
| 90 |
+
# Pass allow_yanked=False to ignore yanked versions.
|
| 91 |
+
selection_prefs = SelectionPreferences(
|
| 92 |
+
allow_yanked=False,
|
| 93 |
+
allow_all_prereleases=options.pre,
|
| 94 |
+
ignore_requires_python=ignore_requires_python,
|
| 95 |
+
)
|
| 96 |
+
|
| 97 |
+
return PackageFinder.create(
|
| 98 |
+
link_collector=link_collector,
|
| 99 |
+
selection_prefs=selection_prefs,
|
| 100 |
+
target_python=target_python,
|
| 101 |
+
)
|
| 102 |
+
|
| 103 |
+
def get_available_package_versions(self, options: Values, args: List[Any]) -> None:
|
| 104 |
+
if len(args) != 1:
|
| 105 |
+
raise CommandError("You need to specify exactly one argument")
|
| 106 |
+
|
| 107 |
+
target_python = cmdoptions.make_target_python(options)
|
| 108 |
+
query = args[0]
|
| 109 |
+
|
| 110 |
+
with self._build_session(options) as session:
|
| 111 |
+
finder = self._build_package_finder(
|
| 112 |
+
options=options,
|
| 113 |
+
session=session,
|
| 114 |
+
target_python=target_python,
|
| 115 |
+
ignore_requires_python=options.ignore_requires_python,
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
versions: Iterable[Union[LegacyVersion, Version]] = (
|
| 119 |
+
candidate.version for candidate in finder.find_all_candidates(query)
|
| 120 |
+
)
|
| 121 |
+
|
| 122 |
+
if not options.pre:
|
| 123 |
+
# Remove prereleases
|
| 124 |
+
versions = (
|
| 125 |
+
version for version in versions if not version.is_prerelease
|
| 126 |
+
)
|
| 127 |
+
versions = set(versions)
|
| 128 |
+
|
| 129 |
+
if not versions:
|
| 130 |
+
raise DistributionNotFound(
|
| 131 |
+
f"No matching distribution found for {query}"
|
| 132 |
+
)
|
| 133 |
+
|
| 134 |
+
formatted_versions = [str(ver) for ver in sorted(versions, reverse=True)]
|
| 135 |
+
latest = formatted_versions[0]
|
| 136 |
+
|
| 137 |
+
write_output(f"{query} ({latest})")
|
| 138 |
+
write_output("Available versions: {}".format(", ".join(formatted_versions)))
|
| 139 |
+
print_dist_installation_info(query, latest)
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/inspect.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
from optparse import Values
|
| 3 |
+
from typing import Any, Dict, List
|
| 4 |
+
|
| 5 |
+
from pip._vendor.packaging.markers import default_environment
|
| 6 |
+
from pip._vendor.rich import print_json
|
| 7 |
+
|
| 8 |
+
from pip import __version__
|
| 9 |
+
from pip._internal.cli import cmdoptions
|
| 10 |
+
from pip._internal.cli.req_command import Command
|
| 11 |
+
from pip._internal.cli.status_codes import SUCCESS
|
| 12 |
+
from pip._internal.metadata import BaseDistribution, get_environment
|
| 13 |
+
from pip._internal.utils.compat import stdlib_pkgs
|
| 14 |
+
from pip._internal.utils.urls import path_to_url
|
| 15 |
+
|
| 16 |
+
logger = logging.getLogger(__name__)
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class InspectCommand(Command):
|
| 20 |
+
"""
|
| 21 |
+
Inspect the content of a Python environment and produce a report in JSON format.
|
| 22 |
+
"""
|
| 23 |
+
|
| 24 |
+
ignore_require_venv = True
|
| 25 |
+
usage = """
|
| 26 |
+
%prog [options]"""
|
| 27 |
+
|
| 28 |
+
def add_options(self) -> None:
|
| 29 |
+
self.cmd_opts.add_option(
|
| 30 |
+
"--local",
|
| 31 |
+
action="store_true",
|
| 32 |
+
default=False,
|
| 33 |
+
help=(
|
| 34 |
+
"If in a virtualenv that has global access, do not list "
|
| 35 |
+
"globally-installed packages."
|
| 36 |
+
),
|
| 37 |
+
)
|
| 38 |
+
self.cmd_opts.add_option(
|
| 39 |
+
"--user",
|
| 40 |
+
dest="user",
|
| 41 |
+
action="store_true",
|
| 42 |
+
default=False,
|
| 43 |
+
help="Only output packages installed in user-site.",
|
| 44 |
+
)
|
| 45 |
+
self.cmd_opts.add_option(cmdoptions.list_path())
|
| 46 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 47 |
+
|
| 48 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 49 |
+
cmdoptions.check_list_path_option(options)
|
| 50 |
+
dists = get_environment(options.path).iter_installed_distributions(
|
| 51 |
+
local_only=options.local,
|
| 52 |
+
user_only=options.user,
|
| 53 |
+
skip=set(stdlib_pkgs),
|
| 54 |
+
)
|
| 55 |
+
output = {
|
| 56 |
+
"version": "1",
|
| 57 |
+
"pip_version": __version__,
|
| 58 |
+
"installed": [self._dist_to_dict(dist) for dist in dists],
|
| 59 |
+
"environment": default_environment(),
|
| 60 |
+
# TODO tags? scheme?
|
| 61 |
+
}
|
| 62 |
+
print_json(data=output)
|
| 63 |
+
return SUCCESS
|
| 64 |
+
|
| 65 |
+
def _dist_to_dict(self, dist: BaseDistribution) -> Dict[str, Any]:
|
| 66 |
+
res: Dict[str, Any] = {
|
| 67 |
+
"metadata": dist.metadata_dict,
|
| 68 |
+
"metadata_location": dist.info_location,
|
| 69 |
+
}
|
| 70 |
+
# direct_url. Note that we don't have download_info (as in the installation
|
| 71 |
+
# report) since it is not recorded in installed metadata.
|
| 72 |
+
direct_url = dist.direct_url
|
| 73 |
+
if direct_url is not None:
|
| 74 |
+
res["direct_url"] = direct_url.to_dict()
|
| 75 |
+
else:
|
| 76 |
+
# Emulate direct_url for legacy editable installs.
|
| 77 |
+
editable_project_location = dist.editable_project_location
|
| 78 |
+
if editable_project_location is not None:
|
| 79 |
+
res["direct_url"] = {
|
| 80 |
+
"url": path_to_url(editable_project_location),
|
| 81 |
+
"dir_info": {
|
| 82 |
+
"editable": True,
|
| 83 |
+
},
|
| 84 |
+
}
|
| 85 |
+
# installer
|
| 86 |
+
installer = dist.installer
|
| 87 |
+
if dist.installer:
|
| 88 |
+
res["installer"] = installer
|
| 89 |
+
# requested
|
| 90 |
+
if dist.installed_with_dist_info:
|
| 91 |
+
res["requested"] = dist.requested
|
| 92 |
+
return res
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/install.py
ADDED
|
@@ -0,0 +1,774 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import errno
|
| 2 |
+
import json
|
| 3 |
+
import operator
|
| 4 |
+
import os
|
| 5 |
+
import shutil
|
| 6 |
+
import site
|
| 7 |
+
from optparse import SUPPRESS_HELP, Values
|
| 8 |
+
from typing import List, Optional
|
| 9 |
+
|
| 10 |
+
from pip._vendor.rich import print_json
|
| 11 |
+
|
| 12 |
+
from pip._internal.cache import WheelCache
|
| 13 |
+
from pip._internal.cli import cmdoptions
|
| 14 |
+
from pip._internal.cli.cmdoptions import make_target_python
|
| 15 |
+
from pip._internal.cli.req_command import (
|
| 16 |
+
RequirementCommand,
|
| 17 |
+
warn_if_run_as_root,
|
| 18 |
+
with_cleanup,
|
| 19 |
+
)
|
| 20 |
+
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
| 21 |
+
from pip._internal.exceptions import CommandError, InstallationError
|
| 22 |
+
from pip._internal.locations import get_scheme
|
| 23 |
+
from pip._internal.metadata import get_environment
|
| 24 |
+
from pip._internal.models.installation_report import InstallationReport
|
| 25 |
+
from pip._internal.operations.build.build_tracker import get_build_tracker
|
| 26 |
+
from pip._internal.operations.check import ConflictDetails, check_install_conflicts
|
| 27 |
+
from pip._internal.req import install_given_reqs
|
| 28 |
+
from pip._internal.req.req_install import (
|
| 29 |
+
InstallRequirement,
|
| 30 |
+
check_legacy_setup_py_options,
|
| 31 |
+
)
|
| 32 |
+
from pip._internal.utils.compat import WINDOWS
|
| 33 |
+
from pip._internal.utils.filesystem import test_writable_dir
|
| 34 |
+
from pip._internal.utils.logging import getLogger
|
| 35 |
+
from pip._internal.utils.misc import (
|
| 36 |
+
check_externally_managed,
|
| 37 |
+
ensure_dir,
|
| 38 |
+
get_pip_version,
|
| 39 |
+
protect_pip_from_modification_on_windows,
|
| 40 |
+
write_output,
|
| 41 |
+
)
|
| 42 |
+
from pip._internal.utils.temp_dir import TempDirectory
|
| 43 |
+
from pip._internal.utils.virtualenv import (
|
| 44 |
+
running_under_virtualenv,
|
| 45 |
+
virtualenv_no_global,
|
| 46 |
+
)
|
| 47 |
+
from pip._internal.wheel_builder import build, should_build_for_install_command
|
| 48 |
+
|
| 49 |
+
logger = getLogger(__name__)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
class InstallCommand(RequirementCommand):
|
| 53 |
+
"""
|
| 54 |
+
Install packages from:
|
| 55 |
+
|
| 56 |
+
- PyPI (and other indexes) using requirement specifiers.
|
| 57 |
+
- VCS project urls.
|
| 58 |
+
- Local project directories.
|
| 59 |
+
- Local or remote source archives.
|
| 60 |
+
|
| 61 |
+
pip also supports installing from "requirements files", which provide
|
| 62 |
+
an easy way to specify a whole environment to be installed.
|
| 63 |
+
"""
|
| 64 |
+
|
| 65 |
+
usage = """
|
| 66 |
+
%prog [options] <requirement specifier> [package-index-options] ...
|
| 67 |
+
%prog [options] -r <requirements file> [package-index-options] ...
|
| 68 |
+
%prog [options] [-e] <vcs project url> ...
|
| 69 |
+
%prog [options] [-e] <local project path> ...
|
| 70 |
+
%prog [options] <archive url/path> ..."""
|
| 71 |
+
|
| 72 |
+
def add_options(self) -> None:
|
| 73 |
+
self.cmd_opts.add_option(cmdoptions.requirements())
|
| 74 |
+
self.cmd_opts.add_option(cmdoptions.constraints())
|
| 75 |
+
self.cmd_opts.add_option(cmdoptions.no_deps())
|
| 76 |
+
self.cmd_opts.add_option(cmdoptions.pre())
|
| 77 |
+
|
| 78 |
+
self.cmd_opts.add_option(cmdoptions.editable())
|
| 79 |
+
self.cmd_opts.add_option(
|
| 80 |
+
"--dry-run",
|
| 81 |
+
action="store_true",
|
| 82 |
+
dest="dry_run",
|
| 83 |
+
default=False,
|
| 84 |
+
help=(
|
| 85 |
+
"Don't actually install anything, just print what would be. "
|
| 86 |
+
"Can be used in combination with --ignore-installed "
|
| 87 |
+
"to 'resolve' the requirements."
|
| 88 |
+
),
|
| 89 |
+
)
|
| 90 |
+
self.cmd_opts.add_option(
|
| 91 |
+
"-t",
|
| 92 |
+
"--target",
|
| 93 |
+
dest="target_dir",
|
| 94 |
+
metavar="dir",
|
| 95 |
+
default=None,
|
| 96 |
+
help=(
|
| 97 |
+
"Install packages into <dir>. "
|
| 98 |
+
"By default this will not replace existing files/folders in "
|
| 99 |
+
"<dir>. Use --upgrade to replace existing packages in <dir> "
|
| 100 |
+
"with new versions."
|
| 101 |
+
),
|
| 102 |
+
)
|
| 103 |
+
cmdoptions.add_target_python_options(self.cmd_opts)
|
| 104 |
+
|
| 105 |
+
self.cmd_opts.add_option(
|
| 106 |
+
"--user",
|
| 107 |
+
dest="use_user_site",
|
| 108 |
+
action="store_true",
|
| 109 |
+
help=(
|
| 110 |
+
"Install to the Python user install directory for your "
|
| 111 |
+
"platform. Typically ~/.local/, or %APPDATA%\\Python on "
|
| 112 |
+
"Windows. (See the Python documentation for site.USER_BASE "
|
| 113 |
+
"for full details.)"
|
| 114 |
+
),
|
| 115 |
+
)
|
| 116 |
+
self.cmd_opts.add_option(
|
| 117 |
+
"--no-user",
|
| 118 |
+
dest="use_user_site",
|
| 119 |
+
action="store_false",
|
| 120 |
+
help=SUPPRESS_HELP,
|
| 121 |
+
)
|
| 122 |
+
self.cmd_opts.add_option(
|
| 123 |
+
"--root",
|
| 124 |
+
dest="root_path",
|
| 125 |
+
metavar="dir",
|
| 126 |
+
default=None,
|
| 127 |
+
help="Install everything relative to this alternate root directory.",
|
| 128 |
+
)
|
| 129 |
+
self.cmd_opts.add_option(
|
| 130 |
+
"--prefix",
|
| 131 |
+
dest="prefix_path",
|
| 132 |
+
metavar="dir",
|
| 133 |
+
default=None,
|
| 134 |
+
help=(
|
| 135 |
+
"Installation prefix where lib, bin and other top-level "
|
| 136 |
+
"folders are placed. Note that the resulting installation may "
|
| 137 |
+
"contain scripts and other resources which reference the "
|
| 138 |
+
"Python interpreter of pip, and not that of ``--prefix``. "
|
| 139 |
+
"See also the ``--python`` option if the intention is to "
|
| 140 |
+
"install packages into another (possibly pip-free) "
|
| 141 |
+
"environment."
|
| 142 |
+
),
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
self.cmd_opts.add_option(cmdoptions.src())
|
| 146 |
+
|
| 147 |
+
self.cmd_opts.add_option(
|
| 148 |
+
"-U",
|
| 149 |
+
"--upgrade",
|
| 150 |
+
dest="upgrade",
|
| 151 |
+
action="store_true",
|
| 152 |
+
help=(
|
| 153 |
+
"Upgrade all specified packages to the newest available "
|
| 154 |
+
"version. The handling of dependencies depends on the "
|
| 155 |
+
"upgrade-strategy used."
|
| 156 |
+
),
|
| 157 |
+
)
|
| 158 |
+
|
| 159 |
+
self.cmd_opts.add_option(
|
| 160 |
+
"--upgrade-strategy",
|
| 161 |
+
dest="upgrade_strategy",
|
| 162 |
+
default="only-if-needed",
|
| 163 |
+
choices=["only-if-needed", "eager"],
|
| 164 |
+
help=(
|
| 165 |
+
"Determines how dependency upgrading should be handled "
|
| 166 |
+
"[default: %default]. "
|
| 167 |
+
'"eager" - dependencies are upgraded regardless of '
|
| 168 |
+
"whether the currently installed version satisfies the "
|
| 169 |
+
"requirements of the upgraded package(s). "
|
| 170 |
+
'"only-if-needed" - are upgraded only when they do not '
|
| 171 |
+
"satisfy the requirements of the upgraded package(s)."
|
| 172 |
+
),
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
self.cmd_opts.add_option(
|
| 176 |
+
"--force-reinstall",
|
| 177 |
+
dest="force_reinstall",
|
| 178 |
+
action="store_true",
|
| 179 |
+
help="Reinstall all packages even if they are already up-to-date.",
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
self.cmd_opts.add_option(
|
| 183 |
+
"-I",
|
| 184 |
+
"--ignore-installed",
|
| 185 |
+
dest="ignore_installed",
|
| 186 |
+
action="store_true",
|
| 187 |
+
help=(
|
| 188 |
+
"Ignore the installed packages, overwriting them. "
|
| 189 |
+
"This can break your system if the existing package "
|
| 190 |
+
"is of a different version or was installed "
|
| 191 |
+
"with a different package manager!"
|
| 192 |
+
),
|
| 193 |
+
)
|
| 194 |
+
|
| 195 |
+
self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
|
| 196 |
+
self.cmd_opts.add_option(cmdoptions.no_build_isolation())
|
| 197 |
+
self.cmd_opts.add_option(cmdoptions.use_pep517())
|
| 198 |
+
self.cmd_opts.add_option(cmdoptions.no_use_pep517())
|
| 199 |
+
self.cmd_opts.add_option(cmdoptions.check_build_deps())
|
| 200 |
+
self.cmd_opts.add_option(cmdoptions.override_externally_managed())
|
| 201 |
+
|
| 202 |
+
self.cmd_opts.add_option(cmdoptions.config_settings())
|
| 203 |
+
self.cmd_opts.add_option(cmdoptions.global_options())
|
| 204 |
+
|
| 205 |
+
self.cmd_opts.add_option(
|
| 206 |
+
"--compile",
|
| 207 |
+
action="store_true",
|
| 208 |
+
dest="compile",
|
| 209 |
+
default=True,
|
| 210 |
+
help="Compile Python source files to bytecode",
|
| 211 |
+
)
|
| 212 |
+
|
| 213 |
+
self.cmd_opts.add_option(
|
| 214 |
+
"--no-compile",
|
| 215 |
+
action="store_false",
|
| 216 |
+
dest="compile",
|
| 217 |
+
help="Do not compile Python source files to bytecode",
|
| 218 |
+
)
|
| 219 |
+
|
| 220 |
+
self.cmd_opts.add_option(
|
| 221 |
+
"--no-warn-script-location",
|
| 222 |
+
action="store_false",
|
| 223 |
+
dest="warn_script_location",
|
| 224 |
+
default=True,
|
| 225 |
+
help="Do not warn when installing scripts outside PATH",
|
| 226 |
+
)
|
| 227 |
+
self.cmd_opts.add_option(
|
| 228 |
+
"--no-warn-conflicts",
|
| 229 |
+
action="store_false",
|
| 230 |
+
dest="warn_about_conflicts",
|
| 231 |
+
default=True,
|
| 232 |
+
help="Do not warn about broken dependencies",
|
| 233 |
+
)
|
| 234 |
+
self.cmd_opts.add_option(cmdoptions.no_binary())
|
| 235 |
+
self.cmd_opts.add_option(cmdoptions.only_binary())
|
| 236 |
+
self.cmd_opts.add_option(cmdoptions.prefer_binary())
|
| 237 |
+
self.cmd_opts.add_option(cmdoptions.require_hashes())
|
| 238 |
+
self.cmd_opts.add_option(cmdoptions.progress_bar())
|
| 239 |
+
self.cmd_opts.add_option(cmdoptions.root_user_action())
|
| 240 |
+
|
| 241 |
+
index_opts = cmdoptions.make_option_group(
|
| 242 |
+
cmdoptions.index_group,
|
| 243 |
+
self.parser,
|
| 244 |
+
)
|
| 245 |
+
|
| 246 |
+
self.parser.insert_option_group(0, index_opts)
|
| 247 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 248 |
+
|
| 249 |
+
self.cmd_opts.add_option(
|
| 250 |
+
"--report",
|
| 251 |
+
dest="json_report_file",
|
| 252 |
+
metavar="file",
|
| 253 |
+
default=None,
|
| 254 |
+
help=(
|
| 255 |
+
"Generate a JSON file describing what pip did to install "
|
| 256 |
+
"the provided requirements. "
|
| 257 |
+
"Can be used in combination with --dry-run and --ignore-installed "
|
| 258 |
+
"to 'resolve' the requirements. "
|
| 259 |
+
"When - is used as file name it writes to stdout. "
|
| 260 |
+
"When writing to stdout, please combine with the --quiet option "
|
| 261 |
+
"to avoid mixing pip logging output with JSON output."
|
| 262 |
+
),
|
| 263 |
+
)
|
| 264 |
+
|
| 265 |
+
@with_cleanup
|
| 266 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 267 |
+
if options.use_user_site and options.target_dir is not None:
|
| 268 |
+
raise CommandError("Can not combine '--user' and '--target'")
|
| 269 |
+
|
| 270 |
+
# Check whether the environment we're installing into is externally
|
| 271 |
+
# managed, as specified in PEP 668. Specifying --root, --target, or
|
| 272 |
+
# --prefix disables the check, since there's no reliable way to locate
|
| 273 |
+
# the EXTERNALLY-MANAGED file for those cases. An exception is also
|
| 274 |
+
# made specifically for "--dry-run --report" for convenience.
|
| 275 |
+
installing_into_current_environment = (
|
| 276 |
+
not (options.dry_run and options.json_report_file)
|
| 277 |
+
and options.root_path is None
|
| 278 |
+
and options.target_dir is None
|
| 279 |
+
and options.prefix_path is None
|
| 280 |
+
)
|
| 281 |
+
if (
|
| 282 |
+
installing_into_current_environment
|
| 283 |
+
and not options.override_externally_managed
|
| 284 |
+
):
|
| 285 |
+
check_externally_managed()
|
| 286 |
+
|
| 287 |
+
upgrade_strategy = "to-satisfy-only"
|
| 288 |
+
if options.upgrade:
|
| 289 |
+
upgrade_strategy = options.upgrade_strategy
|
| 290 |
+
|
| 291 |
+
cmdoptions.check_dist_restriction(options, check_target=True)
|
| 292 |
+
|
| 293 |
+
logger.verbose("Using %s", get_pip_version())
|
| 294 |
+
options.use_user_site = decide_user_install(
|
| 295 |
+
options.use_user_site,
|
| 296 |
+
prefix_path=options.prefix_path,
|
| 297 |
+
target_dir=options.target_dir,
|
| 298 |
+
root_path=options.root_path,
|
| 299 |
+
isolated_mode=options.isolated_mode,
|
| 300 |
+
)
|
| 301 |
+
|
| 302 |
+
target_temp_dir: Optional[TempDirectory] = None
|
| 303 |
+
target_temp_dir_path: Optional[str] = None
|
| 304 |
+
if options.target_dir:
|
| 305 |
+
options.ignore_installed = True
|
| 306 |
+
options.target_dir = os.path.abspath(options.target_dir)
|
| 307 |
+
if (
|
| 308 |
+
# fmt: off
|
| 309 |
+
os.path.exists(options.target_dir) and
|
| 310 |
+
not os.path.isdir(options.target_dir)
|
| 311 |
+
# fmt: on
|
| 312 |
+
):
|
| 313 |
+
raise CommandError(
|
| 314 |
+
"Target path exists but is not a directory, will not continue."
|
| 315 |
+
)
|
| 316 |
+
|
| 317 |
+
# Create a target directory for using with the target option
|
| 318 |
+
target_temp_dir = TempDirectory(kind="target")
|
| 319 |
+
target_temp_dir_path = target_temp_dir.path
|
| 320 |
+
self.enter_context(target_temp_dir)
|
| 321 |
+
|
| 322 |
+
global_options = options.global_options or []
|
| 323 |
+
|
| 324 |
+
session = self.get_default_session(options)
|
| 325 |
+
|
| 326 |
+
target_python = make_target_python(options)
|
| 327 |
+
finder = self._build_package_finder(
|
| 328 |
+
options=options,
|
| 329 |
+
session=session,
|
| 330 |
+
target_python=target_python,
|
| 331 |
+
ignore_requires_python=options.ignore_requires_python,
|
| 332 |
+
)
|
| 333 |
+
build_tracker = self.enter_context(get_build_tracker())
|
| 334 |
+
|
| 335 |
+
directory = TempDirectory(
|
| 336 |
+
delete=not options.no_clean,
|
| 337 |
+
kind="install",
|
| 338 |
+
globally_managed=True,
|
| 339 |
+
)
|
| 340 |
+
|
| 341 |
+
try:
|
| 342 |
+
reqs = self.get_requirements(args, options, finder, session)
|
| 343 |
+
check_legacy_setup_py_options(options, reqs)
|
| 344 |
+
|
| 345 |
+
wheel_cache = WheelCache(options.cache_dir)
|
| 346 |
+
|
| 347 |
+
# Only when installing is it permitted to use PEP 660.
|
| 348 |
+
# In other circumstances (pip wheel, pip download) we generate
|
| 349 |
+
# regular (i.e. non editable) metadata and wheels.
|
| 350 |
+
for req in reqs:
|
| 351 |
+
req.permit_editable_wheels = True
|
| 352 |
+
|
| 353 |
+
preparer = self.make_requirement_preparer(
|
| 354 |
+
temp_build_dir=directory,
|
| 355 |
+
options=options,
|
| 356 |
+
build_tracker=build_tracker,
|
| 357 |
+
session=session,
|
| 358 |
+
finder=finder,
|
| 359 |
+
use_user_site=options.use_user_site,
|
| 360 |
+
verbosity=self.verbosity,
|
| 361 |
+
)
|
| 362 |
+
resolver = self.make_resolver(
|
| 363 |
+
preparer=preparer,
|
| 364 |
+
finder=finder,
|
| 365 |
+
options=options,
|
| 366 |
+
wheel_cache=wheel_cache,
|
| 367 |
+
use_user_site=options.use_user_site,
|
| 368 |
+
ignore_installed=options.ignore_installed,
|
| 369 |
+
ignore_requires_python=options.ignore_requires_python,
|
| 370 |
+
force_reinstall=options.force_reinstall,
|
| 371 |
+
upgrade_strategy=upgrade_strategy,
|
| 372 |
+
use_pep517=options.use_pep517,
|
| 373 |
+
)
|
| 374 |
+
|
| 375 |
+
self.trace_basic_info(finder)
|
| 376 |
+
|
| 377 |
+
requirement_set = resolver.resolve(
|
| 378 |
+
reqs, check_supported_wheels=not options.target_dir
|
| 379 |
+
)
|
| 380 |
+
|
| 381 |
+
if options.json_report_file:
|
| 382 |
+
report = InstallationReport(requirement_set.requirements_to_install)
|
| 383 |
+
if options.json_report_file == "-":
|
| 384 |
+
print_json(data=report.to_dict())
|
| 385 |
+
else:
|
| 386 |
+
with open(options.json_report_file, "w", encoding="utf-8") as f:
|
| 387 |
+
json.dump(report.to_dict(), f, indent=2, ensure_ascii=False)
|
| 388 |
+
|
| 389 |
+
if options.dry_run:
|
| 390 |
+
# In non dry-run mode, the legacy versions and specifiers check
|
| 391 |
+
# will be done as part of conflict detection.
|
| 392 |
+
requirement_set.warn_legacy_versions_and_specifiers()
|
| 393 |
+
would_install_items = sorted(
|
| 394 |
+
(r.metadata["name"], r.metadata["version"])
|
| 395 |
+
for r in requirement_set.requirements_to_install
|
| 396 |
+
)
|
| 397 |
+
if would_install_items:
|
| 398 |
+
write_output(
|
| 399 |
+
"Would install %s",
|
| 400 |
+
" ".join("-".join(item) for item in would_install_items),
|
| 401 |
+
)
|
| 402 |
+
return SUCCESS
|
| 403 |
+
|
| 404 |
+
try:
|
| 405 |
+
pip_req = requirement_set.get_requirement("pip")
|
| 406 |
+
except KeyError:
|
| 407 |
+
modifying_pip = False
|
| 408 |
+
else:
|
| 409 |
+
# If we're not replacing an already installed pip,
|
| 410 |
+
# we're not modifying it.
|
| 411 |
+
modifying_pip = pip_req.satisfied_by is None
|
| 412 |
+
protect_pip_from_modification_on_windows(modifying_pip=modifying_pip)
|
| 413 |
+
|
| 414 |
+
reqs_to_build = [
|
| 415 |
+
r
|
| 416 |
+
for r in requirement_set.requirements.values()
|
| 417 |
+
if should_build_for_install_command(r)
|
| 418 |
+
]
|
| 419 |
+
|
| 420 |
+
_, build_failures = build(
|
| 421 |
+
reqs_to_build,
|
| 422 |
+
wheel_cache=wheel_cache,
|
| 423 |
+
verify=True,
|
| 424 |
+
build_options=[],
|
| 425 |
+
global_options=global_options,
|
| 426 |
+
)
|
| 427 |
+
|
| 428 |
+
if build_failures:
|
| 429 |
+
raise InstallationError(
|
| 430 |
+
"Could not build wheels for {}, which is required to "
|
| 431 |
+
"install pyproject.toml-based projects".format(
|
| 432 |
+
", ".join(r.name for r in build_failures) # type: ignore
|
| 433 |
+
)
|
| 434 |
+
)
|
| 435 |
+
|
| 436 |
+
to_install = resolver.get_installation_order(requirement_set)
|
| 437 |
+
|
| 438 |
+
# Check for conflicts in the package set we're installing.
|
| 439 |
+
conflicts: Optional[ConflictDetails] = None
|
| 440 |
+
should_warn_about_conflicts = (
|
| 441 |
+
not options.ignore_dependencies and options.warn_about_conflicts
|
| 442 |
+
)
|
| 443 |
+
if should_warn_about_conflicts:
|
| 444 |
+
conflicts = self._determine_conflicts(to_install)
|
| 445 |
+
|
| 446 |
+
# Don't warn about script install locations if
|
| 447 |
+
# --target or --prefix has been specified
|
| 448 |
+
warn_script_location = options.warn_script_location
|
| 449 |
+
if options.target_dir or options.prefix_path:
|
| 450 |
+
warn_script_location = False
|
| 451 |
+
|
| 452 |
+
installed = install_given_reqs(
|
| 453 |
+
to_install,
|
| 454 |
+
global_options,
|
| 455 |
+
root=options.root_path,
|
| 456 |
+
home=target_temp_dir_path,
|
| 457 |
+
prefix=options.prefix_path,
|
| 458 |
+
warn_script_location=warn_script_location,
|
| 459 |
+
use_user_site=options.use_user_site,
|
| 460 |
+
pycompile=options.compile,
|
| 461 |
+
)
|
| 462 |
+
|
| 463 |
+
lib_locations = get_lib_location_guesses(
|
| 464 |
+
user=options.use_user_site,
|
| 465 |
+
home=target_temp_dir_path,
|
| 466 |
+
root=options.root_path,
|
| 467 |
+
prefix=options.prefix_path,
|
| 468 |
+
isolated=options.isolated_mode,
|
| 469 |
+
)
|
| 470 |
+
env = get_environment(lib_locations)
|
| 471 |
+
|
| 472 |
+
installed.sort(key=operator.attrgetter("name"))
|
| 473 |
+
items = []
|
| 474 |
+
for result in installed:
|
| 475 |
+
item = result.name
|
| 476 |
+
try:
|
| 477 |
+
installed_dist = env.get_distribution(item)
|
| 478 |
+
if installed_dist is not None:
|
| 479 |
+
item = f"{item}-{installed_dist.version}"
|
| 480 |
+
except Exception:
|
| 481 |
+
pass
|
| 482 |
+
items.append(item)
|
| 483 |
+
|
| 484 |
+
if conflicts is not None:
|
| 485 |
+
self._warn_about_conflicts(
|
| 486 |
+
conflicts,
|
| 487 |
+
resolver_variant=self.determine_resolver_variant(options),
|
| 488 |
+
)
|
| 489 |
+
|
| 490 |
+
installed_desc = " ".join(items)
|
| 491 |
+
if installed_desc:
|
| 492 |
+
write_output(
|
| 493 |
+
"Successfully installed %s",
|
| 494 |
+
installed_desc,
|
| 495 |
+
)
|
| 496 |
+
except OSError as error:
|
| 497 |
+
show_traceback = self.verbosity >= 1
|
| 498 |
+
|
| 499 |
+
message = create_os_error_message(
|
| 500 |
+
error,
|
| 501 |
+
show_traceback,
|
| 502 |
+
options.use_user_site,
|
| 503 |
+
)
|
| 504 |
+
logger.error(message, exc_info=show_traceback)
|
| 505 |
+
|
| 506 |
+
return ERROR
|
| 507 |
+
|
| 508 |
+
if options.target_dir:
|
| 509 |
+
assert target_temp_dir
|
| 510 |
+
self._handle_target_dir(
|
| 511 |
+
options.target_dir, target_temp_dir, options.upgrade
|
| 512 |
+
)
|
| 513 |
+
if options.root_user_action == "warn":
|
| 514 |
+
warn_if_run_as_root()
|
| 515 |
+
return SUCCESS
|
| 516 |
+
|
| 517 |
+
def _handle_target_dir(
|
| 518 |
+
self, target_dir: str, target_temp_dir: TempDirectory, upgrade: bool
|
| 519 |
+
) -> None:
|
| 520 |
+
ensure_dir(target_dir)
|
| 521 |
+
|
| 522 |
+
# Checking both purelib and platlib directories for installed
|
| 523 |
+
# packages to be moved to target directory
|
| 524 |
+
lib_dir_list = []
|
| 525 |
+
|
| 526 |
+
# Checking both purelib and platlib directories for installed
|
| 527 |
+
# packages to be moved to target directory
|
| 528 |
+
scheme = get_scheme("", home=target_temp_dir.path)
|
| 529 |
+
purelib_dir = scheme.purelib
|
| 530 |
+
platlib_dir = scheme.platlib
|
| 531 |
+
data_dir = scheme.data
|
| 532 |
+
|
| 533 |
+
if os.path.exists(purelib_dir):
|
| 534 |
+
lib_dir_list.append(purelib_dir)
|
| 535 |
+
if os.path.exists(platlib_dir) and platlib_dir != purelib_dir:
|
| 536 |
+
lib_dir_list.append(platlib_dir)
|
| 537 |
+
if os.path.exists(data_dir):
|
| 538 |
+
lib_dir_list.append(data_dir)
|
| 539 |
+
|
| 540 |
+
for lib_dir in lib_dir_list:
|
| 541 |
+
for item in os.listdir(lib_dir):
|
| 542 |
+
if lib_dir == data_dir:
|
| 543 |
+
ddir = os.path.join(data_dir, item)
|
| 544 |
+
if any(s.startswith(ddir) for s in lib_dir_list[:-1]):
|
| 545 |
+
continue
|
| 546 |
+
target_item_dir = os.path.join(target_dir, item)
|
| 547 |
+
if os.path.exists(target_item_dir):
|
| 548 |
+
if not upgrade:
|
| 549 |
+
logger.warning(
|
| 550 |
+
"Target directory %s already exists. Specify "
|
| 551 |
+
"--upgrade to force replacement.",
|
| 552 |
+
target_item_dir,
|
| 553 |
+
)
|
| 554 |
+
continue
|
| 555 |
+
if os.path.islink(target_item_dir):
|
| 556 |
+
logger.warning(
|
| 557 |
+
"Target directory %s already exists and is "
|
| 558 |
+
"a link. pip will not automatically replace "
|
| 559 |
+
"links, please remove if replacement is "
|
| 560 |
+
"desired.",
|
| 561 |
+
target_item_dir,
|
| 562 |
+
)
|
| 563 |
+
continue
|
| 564 |
+
if os.path.isdir(target_item_dir):
|
| 565 |
+
shutil.rmtree(target_item_dir)
|
| 566 |
+
else:
|
| 567 |
+
os.remove(target_item_dir)
|
| 568 |
+
|
| 569 |
+
shutil.move(os.path.join(lib_dir, item), target_item_dir)
|
| 570 |
+
|
| 571 |
+
def _determine_conflicts(
|
| 572 |
+
self, to_install: List[InstallRequirement]
|
| 573 |
+
) -> Optional[ConflictDetails]:
|
| 574 |
+
try:
|
| 575 |
+
return check_install_conflicts(to_install)
|
| 576 |
+
except Exception:
|
| 577 |
+
logger.exception(
|
| 578 |
+
"Error while checking for conflicts. Please file an issue on "
|
| 579 |
+
"pip's issue tracker: https://github.com/pypa/pip/issues/new"
|
| 580 |
+
)
|
| 581 |
+
return None
|
| 582 |
+
|
| 583 |
+
def _warn_about_conflicts(
|
| 584 |
+
self, conflict_details: ConflictDetails, resolver_variant: str
|
| 585 |
+
) -> None:
|
| 586 |
+
package_set, (missing, conflicting) = conflict_details
|
| 587 |
+
if not missing and not conflicting:
|
| 588 |
+
return
|
| 589 |
+
|
| 590 |
+
parts: List[str] = []
|
| 591 |
+
if resolver_variant == "legacy":
|
| 592 |
+
parts.append(
|
| 593 |
+
"pip's legacy dependency resolver does not consider dependency "
|
| 594 |
+
"conflicts when selecting packages. This behaviour is the "
|
| 595 |
+
"source of the following dependency conflicts."
|
| 596 |
+
)
|
| 597 |
+
else:
|
| 598 |
+
assert resolver_variant == "resolvelib"
|
| 599 |
+
parts.append(
|
| 600 |
+
"pip's dependency resolver does not currently take into account "
|
| 601 |
+
"all the packages that are installed. This behaviour is the "
|
| 602 |
+
"source of the following dependency conflicts."
|
| 603 |
+
)
|
| 604 |
+
|
| 605 |
+
# NOTE: There is some duplication here, with commands/check.py
|
| 606 |
+
for project_name in missing:
|
| 607 |
+
version = package_set[project_name][0]
|
| 608 |
+
for dependency in missing[project_name]:
|
| 609 |
+
message = (
|
| 610 |
+
f"{project_name} {version} requires {dependency[1]}, "
|
| 611 |
+
"which is not installed."
|
| 612 |
+
)
|
| 613 |
+
parts.append(message)
|
| 614 |
+
|
| 615 |
+
for project_name in conflicting:
|
| 616 |
+
version = package_set[project_name][0]
|
| 617 |
+
for dep_name, dep_version, req in conflicting[project_name]:
|
| 618 |
+
message = (
|
| 619 |
+
"{name} {version} requires {requirement}, but {you} have "
|
| 620 |
+
"{dep_name} {dep_version} which is incompatible."
|
| 621 |
+
).format(
|
| 622 |
+
name=project_name,
|
| 623 |
+
version=version,
|
| 624 |
+
requirement=req,
|
| 625 |
+
dep_name=dep_name,
|
| 626 |
+
dep_version=dep_version,
|
| 627 |
+
you=("you" if resolver_variant == "resolvelib" else "you'll"),
|
| 628 |
+
)
|
| 629 |
+
parts.append(message)
|
| 630 |
+
|
| 631 |
+
logger.critical("\n".join(parts))
|
| 632 |
+
|
| 633 |
+
|
| 634 |
+
def get_lib_location_guesses(
|
| 635 |
+
user: bool = False,
|
| 636 |
+
home: Optional[str] = None,
|
| 637 |
+
root: Optional[str] = None,
|
| 638 |
+
isolated: bool = False,
|
| 639 |
+
prefix: Optional[str] = None,
|
| 640 |
+
) -> List[str]:
|
| 641 |
+
scheme = get_scheme(
|
| 642 |
+
"",
|
| 643 |
+
user=user,
|
| 644 |
+
home=home,
|
| 645 |
+
root=root,
|
| 646 |
+
isolated=isolated,
|
| 647 |
+
prefix=prefix,
|
| 648 |
+
)
|
| 649 |
+
return [scheme.purelib, scheme.platlib]
|
| 650 |
+
|
| 651 |
+
|
| 652 |
+
def site_packages_writable(root: Optional[str], isolated: bool) -> bool:
|
| 653 |
+
return all(
|
| 654 |
+
test_writable_dir(d)
|
| 655 |
+
for d in set(get_lib_location_guesses(root=root, isolated=isolated))
|
| 656 |
+
)
|
| 657 |
+
|
| 658 |
+
|
| 659 |
+
def decide_user_install(
|
| 660 |
+
use_user_site: Optional[bool],
|
| 661 |
+
prefix_path: Optional[str] = None,
|
| 662 |
+
target_dir: Optional[str] = None,
|
| 663 |
+
root_path: Optional[str] = None,
|
| 664 |
+
isolated_mode: bool = False,
|
| 665 |
+
) -> bool:
|
| 666 |
+
"""Determine whether to do a user install based on the input options.
|
| 667 |
+
|
| 668 |
+
If use_user_site is False, no additional checks are done.
|
| 669 |
+
If use_user_site is True, it is checked for compatibility with other
|
| 670 |
+
options.
|
| 671 |
+
If use_user_site is None, the default behaviour depends on the environment,
|
| 672 |
+
which is provided by the other arguments.
|
| 673 |
+
"""
|
| 674 |
+
# In some cases (config from tox), use_user_site can be set to an integer
|
| 675 |
+
# rather than a bool, which 'use_user_site is False' wouldn't catch.
|
| 676 |
+
if (use_user_site is not None) and (not use_user_site):
|
| 677 |
+
logger.debug("Non-user install by explicit request")
|
| 678 |
+
return False
|
| 679 |
+
|
| 680 |
+
if use_user_site:
|
| 681 |
+
if prefix_path:
|
| 682 |
+
raise CommandError(
|
| 683 |
+
"Can not combine '--user' and '--prefix' as they imply "
|
| 684 |
+
"different installation locations"
|
| 685 |
+
)
|
| 686 |
+
if virtualenv_no_global():
|
| 687 |
+
raise InstallationError(
|
| 688 |
+
"Can not perform a '--user' install. User site-packages "
|
| 689 |
+
"are not visible in this virtualenv."
|
| 690 |
+
)
|
| 691 |
+
logger.debug("User install by explicit request")
|
| 692 |
+
return True
|
| 693 |
+
|
| 694 |
+
# If we are here, user installs have not been explicitly requested/avoided
|
| 695 |
+
assert use_user_site is None
|
| 696 |
+
|
| 697 |
+
# user install incompatible with --prefix/--target
|
| 698 |
+
if prefix_path or target_dir:
|
| 699 |
+
logger.debug("Non-user install due to --prefix or --target option")
|
| 700 |
+
return False
|
| 701 |
+
|
| 702 |
+
# If user installs are not enabled, choose a non-user install
|
| 703 |
+
if not site.ENABLE_USER_SITE:
|
| 704 |
+
logger.debug("Non-user install because user site-packages disabled")
|
| 705 |
+
return False
|
| 706 |
+
|
| 707 |
+
# If we have permission for a non-user install, do that,
|
| 708 |
+
# otherwise do a user install.
|
| 709 |
+
if site_packages_writable(root=root_path, isolated=isolated_mode):
|
| 710 |
+
logger.debug("Non-user install because site-packages writeable")
|
| 711 |
+
return False
|
| 712 |
+
|
| 713 |
+
logger.info(
|
| 714 |
+
"Defaulting to user installation because normal site-packages "
|
| 715 |
+
"is not writeable"
|
| 716 |
+
)
|
| 717 |
+
return True
|
| 718 |
+
|
| 719 |
+
|
| 720 |
+
def create_os_error_message(
|
| 721 |
+
error: OSError, show_traceback: bool, using_user_site: bool
|
| 722 |
+
) -> str:
|
| 723 |
+
"""Format an error message for an OSError
|
| 724 |
+
|
| 725 |
+
It may occur anytime during the execution of the install command.
|
| 726 |
+
"""
|
| 727 |
+
parts = []
|
| 728 |
+
|
| 729 |
+
# Mention the error if we are not going to show a traceback
|
| 730 |
+
parts.append("Could not install packages due to an OSError")
|
| 731 |
+
if not show_traceback:
|
| 732 |
+
parts.append(": ")
|
| 733 |
+
parts.append(str(error))
|
| 734 |
+
else:
|
| 735 |
+
parts.append(".")
|
| 736 |
+
|
| 737 |
+
# Spilt the error indication from a helper message (if any)
|
| 738 |
+
parts[-1] += "\n"
|
| 739 |
+
|
| 740 |
+
# Suggest useful actions to the user:
|
| 741 |
+
# (1) using user site-packages or (2) verifying the permissions
|
| 742 |
+
if error.errno == errno.EACCES:
|
| 743 |
+
user_option_part = "Consider using the `--user` option"
|
| 744 |
+
permissions_part = "Check the permissions"
|
| 745 |
+
|
| 746 |
+
if not running_under_virtualenv() and not using_user_site:
|
| 747 |
+
parts.extend(
|
| 748 |
+
[
|
| 749 |
+
user_option_part,
|
| 750 |
+
" or ",
|
| 751 |
+
permissions_part.lower(),
|
| 752 |
+
]
|
| 753 |
+
)
|
| 754 |
+
else:
|
| 755 |
+
parts.append(permissions_part)
|
| 756 |
+
parts.append(".\n")
|
| 757 |
+
|
| 758 |
+
# Suggest the user to enable Long Paths if path length is
|
| 759 |
+
# more than 260
|
| 760 |
+
if (
|
| 761 |
+
WINDOWS
|
| 762 |
+
and error.errno == errno.ENOENT
|
| 763 |
+
and error.filename
|
| 764 |
+
and len(error.filename) > 260
|
| 765 |
+
):
|
| 766 |
+
parts.append(
|
| 767 |
+
"HINT: This error might have occurred since "
|
| 768 |
+
"this system does not have Windows Long Path "
|
| 769 |
+
"support enabled. You can find information on "
|
| 770 |
+
"how to enable this at "
|
| 771 |
+
"https://pip.pypa.io/warnings/enable-long-paths\n"
|
| 772 |
+
)
|
| 773 |
+
|
| 774 |
+
return "".join(parts).strip() + "\n"
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/list.py
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import logging
|
| 3 |
+
from optparse import Values
|
| 4 |
+
from typing import TYPE_CHECKING, Generator, List, Optional, Sequence, Tuple, cast
|
| 5 |
+
|
| 6 |
+
from pip._vendor.packaging.utils import canonicalize_name
|
| 7 |
+
|
| 8 |
+
from pip._internal.cli import cmdoptions
|
| 9 |
+
from pip._internal.cli.req_command import IndexGroupCommand
|
| 10 |
+
from pip._internal.cli.status_codes import SUCCESS
|
| 11 |
+
from pip._internal.exceptions import CommandError
|
| 12 |
+
from pip._internal.index.collector import LinkCollector
|
| 13 |
+
from pip._internal.index.package_finder import PackageFinder
|
| 14 |
+
from pip._internal.metadata import BaseDistribution, get_environment
|
| 15 |
+
from pip._internal.models.selection_prefs import SelectionPreferences
|
| 16 |
+
from pip._internal.network.session import PipSession
|
| 17 |
+
from pip._internal.utils.compat import stdlib_pkgs
|
| 18 |
+
from pip._internal.utils.misc import tabulate, write_output
|
| 19 |
+
|
| 20 |
+
if TYPE_CHECKING:
|
| 21 |
+
from pip._internal.metadata.base import DistributionVersion
|
| 22 |
+
|
| 23 |
+
class _DistWithLatestInfo(BaseDistribution):
|
| 24 |
+
"""Give the distribution object a couple of extra fields.
|
| 25 |
+
|
| 26 |
+
These will be populated during ``get_outdated()``. This is dirty but
|
| 27 |
+
makes the rest of the code much cleaner.
|
| 28 |
+
"""
|
| 29 |
+
|
| 30 |
+
latest_version: DistributionVersion
|
| 31 |
+
latest_filetype: str
|
| 32 |
+
|
| 33 |
+
_ProcessedDists = Sequence[_DistWithLatestInfo]
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
logger = logging.getLogger(__name__)
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
class ListCommand(IndexGroupCommand):
|
| 40 |
+
"""
|
| 41 |
+
List installed packages, including editables.
|
| 42 |
+
|
| 43 |
+
Packages are listed in a case-insensitive sorted order.
|
| 44 |
+
"""
|
| 45 |
+
|
| 46 |
+
ignore_require_venv = True
|
| 47 |
+
usage = """
|
| 48 |
+
%prog [options]"""
|
| 49 |
+
|
| 50 |
+
def add_options(self) -> None:
|
| 51 |
+
self.cmd_opts.add_option(
|
| 52 |
+
"-o",
|
| 53 |
+
"--outdated",
|
| 54 |
+
action="store_true",
|
| 55 |
+
default=False,
|
| 56 |
+
help="List outdated packages",
|
| 57 |
+
)
|
| 58 |
+
self.cmd_opts.add_option(
|
| 59 |
+
"-u",
|
| 60 |
+
"--uptodate",
|
| 61 |
+
action="store_true",
|
| 62 |
+
default=False,
|
| 63 |
+
help="List uptodate packages",
|
| 64 |
+
)
|
| 65 |
+
self.cmd_opts.add_option(
|
| 66 |
+
"-e",
|
| 67 |
+
"--editable",
|
| 68 |
+
action="store_true",
|
| 69 |
+
default=False,
|
| 70 |
+
help="List editable projects.",
|
| 71 |
+
)
|
| 72 |
+
self.cmd_opts.add_option(
|
| 73 |
+
"-l",
|
| 74 |
+
"--local",
|
| 75 |
+
action="store_true",
|
| 76 |
+
default=False,
|
| 77 |
+
help=(
|
| 78 |
+
"If in a virtualenv that has global access, do not list "
|
| 79 |
+
"globally-installed packages."
|
| 80 |
+
),
|
| 81 |
+
)
|
| 82 |
+
self.cmd_opts.add_option(
|
| 83 |
+
"--user",
|
| 84 |
+
dest="user",
|
| 85 |
+
action="store_true",
|
| 86 |
+
default=False,
|
| 87 |
+
help="Only output packages installed in user-site.",
|
| 88 |
+
)
|
| 89 |
+
self.cmd_opts.add_option(cmdoptions.list_path())
|
| 90 |
+
self.cmd_opts.add_option(
|
| 91 |
+
"--pre",
|
| 92 |
+
action="store_true",
|
| 93 |
+
default=False,
|
| 94 |
+
help=(
|
| 95 |
+
"Include pre-release and development versions. By default, "
|
| 96 |
+
"pip only finds stable versions."
|
| 97 |
+
),
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
self.cmd_opts.add_option(
|
| 101 |
+
"--format",
|
| 102 |
+
action="store",
|
| 103 |
+
dest="list_format",
|
| 104 |
+
default="columns",
|
| 105 |
+
choices=("columns", "freeze", "json"),
|
| 106 |
+
help=(
|
| 107 |
+
"Select the output format among: columns (default), freeze, or json. "
|
| 108 |
+
"The 'freeze' format cannot be used with the --outdated option."
|
| 109 |
+
),
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
self.cmd_opts.add_option(
|
| 113 |
+
"--not-required",
|
| 114 |
+
action="store_true",
|
| 115 |
+
dest="not_required",
|
| 116 |
+
help="List packages that are not dependencies of installed packages.",
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
self.cmd_opts.add_option(
|
| 120 |
+
"--exclude-editable",
|
| 121 |
+
action="store_false",
|
| 122 |
+
dest="include_editable",
|
| 123 |
+
help="Exclude editable package from output.",
|
| 124 |
+
)
|
| 125 |
+
self.cmd_opts.add_option(
|
| 126 |
+
"--include-editable",
|
| 127 |
+
action="store_true",
|
| 128 |
+
dest="include_editable",
|
| 129 |
+
help="Include editable package from output.",
|
| 130 |
+
default=True,
|
| 131 |
+
)
|
| 132 |
+
self.cmd_opts.add_option(cmdoptions.list_exclude())
|
| 133 |
+
index_opts = cmdoptions.make_option_group(cmdoptions.index_group, self.parser)
|
| 134 |
+
|
| 135 |
+
self.parser.insert_option_group(0, index_opts)
|
| 136 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 137 |
+
|
| 138 |
+
def _build_package_finder(
|
| 139 |
+
self, options: Values, session: PipSession
|
| 140 |
+
) -> PackageFinder:
|
| 141 |
+
"""
|
| 142 |
+
Create a package finder appropriate to this list command.
|
| 143 |
+
"""
|
| 144 |
+
link_collector = LinkCollector.create(session, options=options)
|
| 145 |
+
|
| 146 |
+
# Pass allow_yanked=False to ignore yanked versions.
|
| 147 |
+
selection_prefs = SelectionPreferences(
|
| 148 |
+
allow_yanked=False,
|
| 149 |
+
allow_all_prereleases=options.pre,
|
| 150 |
+
)
|
| 151 |
+
|
| 152 |
+
return PackageFinder.create(
|
| 153 |
+
link_collector=link_collector,
|
| 154 |
+
selection_prefs=selection_prefs,
|
| 155 |
+
)
|
| 156 |
+
|
| 157 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 158 |
+
if options.outdated and options.uptodate:
|
| 159 |
+
raise CommandError("Options --outdated and --uptodate cannot be combined.")
|
| 160 |
+
|
| 161 |
+
if options.outdated and options.list_format == "freeze":
|
| 162 |
+
raise CommandError(
|
| 163 |
+
"List format 'freeze' cannot be used with the --outdated option."
|
| 164 |
+
)
|
| 165 |
+
|
| 166 |
+
cmdoptions.check_list_path_option(options)
|
| 167 |
+
|
| 168 |
+
skip = set(stdlib_pkgs)
|
| 169 |
+
if options.excludes:
|
| 170 |
+
skip.update(canonicalize_name(n) for n in options.excludes)
|
| 171 |
+
|
| 172 |
+
packages: "_ProcessedDists" = [
|
| 173 |
+
cast("_DistWithLatestInfo", d)
|
| 174 |
+
for d in get_environment(options.path).iter_installed_distributions(
|
| 175 |
+
local_only=options.local,
|
| 176 |
+
user_only=options.user,
|
| 177 |
+
editables_only=options.editable,
|
| 178 |
+
include_editables=options.include_editable,
|
| 179 |
+
skip=skip,
|
| 180 |
+
)
|
| 181 |
+
]
|
| 182 |
+
|
| 183 |
+
# get_not_required must be called firstly in order to find and
|
| 184 |
+
# filter out all dependencies correctly. Otherwise a package
|
| 185 |
+
# can't be identified as requirement because some parent packages
|
| 186 |
+
# could be filtered out before.
|
| 187 |
+
if options.not_required:
|
| 188 |
+
packages = self.get_not_required(packages, options)
|
| 189 |
+
|
| 190 |
+
if options.outdated:
|
| 191 |
+
packages = self.get_outdated(packages, options)
|
| 192 |
+
elif options.uptodate:
|
| 193 |
+
packages = self.get_uptodate(packages, options)
|
| 194 |
+
|
| 195 |
+
self.output_package_listing(packages, options)
|
| 196 |
+
return SUCCESS
|
| 197 |
+
|
| 198 |
+
def get_outdated(
|
| 199 |
+
self, packages: "_ProcessedDists", options: Values
|
| 200 |
+
) -> "_ProcessedDists":
|
| 201 |
+
return [
|
| 202 |
+
dist
|
| 203 |
+
for dist in self.iter_packages_latest_infos(packages, options)
|
| 204 |
+
if dist.latest_version > dist.version
|
| 205 |
+
]
|
| 206 |
+
|
| 207 |
+
def get_uptodate(
|
| 208 |
+
self, packages: "_ProcessedDists", options: Values
|
| 209 |
+
) -> "_ProcessedDists":
|
| 210 |
+
return [
|
| 211 |
+
dist
|
| 212 |
+
for dist in self.iter_packages_latest_infos(packages, options)
|
| 213 |
+
if dist.latest_version == dist.version
|
| 214 |
+
]
|
| 215 |
+
|
| 216 |
+
def get_not_required(
|
| 217 |
+
self, packages: "_ProcessedDists", options: Values
|
| 218 |
+
) -> "_ProcessedDists":
|
| 219 |
+
dep_keys = {
|
| 220 |
+
canonicalize_name(dep.name)
|
| 221 |
+
for dist in packages
|
| 222 |
+
for dep in (dist.iter_dependencies() or ())
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
# Create a set to remove duplicate packages, and cast it to a list
|
| 226 |
+
# to keep the return type consistent with get_outdated and
|
| 227 |
+
# get_uptodate
|
| 228 |
+
return list({pkg for pkg in packages if pkg.canonical_name not in dep_keys})
|
| 229 |
+
|
| 230 |
+
def iter_packages_latest_infos(
|
| 231 |
+
self, packages: "_ProcessedDists", options: Values
|
| 232 |
+
) -> Generator["_DistWithLatestInfo", None, None]:
|
| 233 |
+
with self._build_session(options) as session:
|
| 234 |
+
finder = self._build_package_finder(options, session)
|
| 235 |
+
|
| 236 |
+
def latest_info(
|
| 237 |
+
dist: "_DistWithLatestInfo",
|
| 238 |
+
) -> Optional["_DistWithLatestInfo"]:
|
| 239 |
+
all_candidates = finder.find_all_candidates(dist.canonical_name)
|
| 240 |
+
if not options.pre:
|
| 241 |
+
# Remove prereleases
|
| 242 |
+
all_candidates = [
|
| 243 |
+
candidate
|
| 244 |
+
for candidate in all_candidates
|
| 245 |
+
if not candidate.version.is_prerelease
|
| 246 |
+
]
|
| 247 |
+
|
| 248 |
+
evaluator = finder.make_candidate_evaluator(
|
| 249 |
+
project_name=dist.canonical_name,
|
| 250 |
+
)
|
| 251 |
+
best_candidate = evaluator.sort_best_candidate(all_candidates)
|
| 252 |
+
if best_candidate is None:
|
| 253 |
+
return None
|
| 254 |
+
|
| 255 |
+
remote_version = best_candidate.version
|
| 256 |
+
if best_candidate.link.is_wheel:
|
| 257 |
+
typ = "wheel"
|
| 258 |
+
else:
|
| 259 |
+
typ = "sdist"
|
| 260 |
+
dist.latest_version = remote_version
|
| 261 |
+
dist.latest_filetype = typ
|
| 262 |
+
return dist
|
| 263 |
+
|
| 264 |
+
for dist in map(latest_info, packages):
|
| 265 |
+
if dist is not None:
|
| 266 |
+
yield dist
|
| 267 |
+
|
| 268 |
+
def output_package_listing(
|
| 269 |
+
self, packages: "_ProcessedDists", options: Values
|
| 270 |
+
) -> None:
|
| 271 |
+
packages = sorted(
|
| 272 |
+
packages,
|
| 273 |
+
key=lambda dist: dist.canonical_name,
|
| 274 |
+
)
|
| 275 |
+
if options.list_format == "columns" and packages:
|
| 276 |
+
data, header = format_for_columns(packages, options)
|
| 277 |
+
self.output_package_listing_columns(data, header)
|
| 278 |
+
elif options.list_format == "freeze":
|
| 279 |
+
for dist in packages:
|
| 280 |
+
if options.verbose >= 1:
|
| 281 |
+
write_output(
|
| 282 |
+
"%s==%s (%s)", dist.raw_name, dist.version, dist.location
|
| 283 |
+
)
|
| 284 |
+
else:
|
| 285 |
+
write_output("%s==%s", dist.raw_name, dist.version)
|
| 286 |
+
elif options.list_format == "json":
|
| 287 |
+
write_output(format_for_json(packages, options))
|
| 288 |
+
|
| 289 |
+
def output_package_listing_columns(
|
| 290 |
+
self, data: List[List[str]], header: List[str]
|
| 291 |
+
) -> None:
|
| 292 |
+
# insert the header first: we need to know the size of column names
|
| 293 |
+
if len(data) > 0:
|
| 294 |
+
data.insert(0, header)
|
| 295 |
+
|
| 296 |
+
pkg_strings, sizes = tabulate(data)
|
| 297 |
+
|
| 298 |
+
# Create and add a separator.
|
| 299 |
+
if len(data) > 0:
|
| 300 |
+
pkg_strings.insert(1, " ".join("-" * x for x in sizes))
|
| 301 |
+
|
| 302 |
+
for val in pkg_strings:
|
| 303 |
+
write_output(val)
|
| 304 |
+
|
| 305 |
+
|
| 306 |
+
def format_for_columns(
|
| 307 |
+
pkgs: "_ProcessedDists", options: Values
|
| 308 |
+
) -> Tuple[List[List[str]], List[str]]:
|
| 309 |
+
"""
|
| 310 |
+
Convert the package data into something usable
|
| 311 |
+
by output_package_listing_columns.
|
| 312 |
+
"""
|
| 313 |
+
header = ["Package", "Version"]
|
| 314 |
+
|
| 315 |
+
running_outdated = options.outdated
|
| 316 |
+
if running_outdated:
|
| 317 |
+
header.extend(["Latest", "Type"])
|
| 318 |
+
|
| 319 |
+
has_editables = any(x.editable for x in pkgs)
|
| 320 |
+
if has_editables:
|
| 321 |
+
header.append("Editable project location")
|
| 322 |
+
|
| 323 |
+
if options.verbose >= 1:
|
| 324 |
+
header.append("Location")
|
| 325 |
+
if options.verbose >= 1:
|
| 326 |
+
header.append("Installer")
|
| 327 |
+
|
| 328 |
+
data = []
|
| 329 |
+
for proj in pkgs:
|
| 330 |
+
# if we're working on the 'outdated' list, separate out the
|
| 331 |
+
# latest_version and type
|
| 332 |
+
row = [proj.raw_name, str(proj.version)]
|
| 333 |
+
|
| 334 |
+
if running_outdated:
|
| 335 |
+
row.append(str(proj.latest_version))
|
| 336 |
+
row.append(proj.latest_filetype)
|
| 337 |
+
|
| 338 |
+
if has_editables:
|
| 339 |
+
row.append(proj.editable_project_location or "")
|
| 340 |
+
|
| 341 |
+
if options.verbose >= 1:
|
| 342 |
+
row.append(proj.location or "")
|
| 343 |
+
if options.verbose >= 1:
|
| 344 |
+
row.append(proj.installer)
|
| 345 |
+
|
| 346 |
+
data.append(row)
|
| 347 |
+
|
| 348 |
+
return data, header
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
def format_for_json(packages: "_ProcessedDists", options: Values) -> str:
|
| 352 |
+
data = []
|
| 353 |
+
for dist in packages:
|
| 354 |
+
info = {
|
| 355 |
+
"name": dist.raw_name,
|
| 356 |
+
"version": str(dist.version),
|
| 357 |
+
}
|
| 358 |
+
if options.verbose >= 1:
|
| 359 |
+
info["location"] = dist.location or ""
|
| 360 |
+
info["installer"] = dist.installer
|
| 361 |
+
if options.outdated:
|
| 362 |
+
info["latest_version"] = str(dist.latest_version)
|
| 363 |
+
info["latest_filetype"] = dist.latest_filetype
|
| 364 |
+
editable_project_location = dist.editable_project_location
|
| 365 |
+
if editable_project_location:
|
| 366 |
+
info["editable_project_location"] = editable_project_location
|
| 367 |
+
data.append(info)
|
| 368 |
+
return json.dumps(data)
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/search.py
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import shutil
|
| 3 |
+
import sys
|
| 4 |
+
import textwrap
|
| 5 |
+
import xmlrpc.client
|
| 6 |
+
from collections import OrderedDict
|
| 7 |
+
from optparse import Values
|
| 8 |
+
from typing import TYPE_CHECKING, Dict, List, Optional
|
| 9 |
+
|
| 10 |
+
from pip._vendor.packaging.version import parse as parse_version
|
| 11 |
+
|
| 12 |
+
from pip._internal.cli.base_command import Command
|
| 13 |
+
from pip._internal.cli.req_command import SessionCommandMixin
|
| 14 |
+
from pip._internal.cli.status_codes import NO_MATCHES_FOUND, SUCCESS
|
| 15 |
+
from pip._internal.exceptions import CommandError
|
| 16 |
+
from pip._internal.metadata import get_default_environment
|
| 17 |
+
from pip._internal.models.index import PyPI
|
| 18 |
+
from pip._internal.network.xmlrpc import PipXmlrpcTransport
|
| 19 |
+
from pip._internal.utils.logging import indent_log
|
| 20 |
+
from pip._internal.utils.misc import write_output
|
| 21 |
+
|
| 22 |
+
if TYPE_CHECKING:
|
| 23 |
+
from typing import TypedDict
|
| 24 |
+
|
| 25 |
+
class TransformedHit(TypedDict):
|
| 26 |
+
name: str
|
| 27 |
+
summary: str
|
| 28 |
+
versions: List[str]
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
logger = logging.getLogger(__name__)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class SearchCommand(Command, SessionCommandMixin):
|
| 35 |
+
"""Search for PyPI packages whose name or summary contains <query>."""
|
| 36 |
+
|
| 37 |
+
usage = """
|
| 38 |
+
%prog [options] <query>"""
|
| 39 |
+
ignore_require_venv = True
|
| 40 |
+
|
| 41 |
+
def add_options(self) -> None:
|
| 42 |
+
self.cmd_opts.add_option(
|
| 43 |
+
"-i",
|
| 44 |
+
"--index",
|
| 45 |
+
dest="index",
|
| 46 |
+
metavar="URL",
|
| 47 |
+
default=PyPI.pypi_url,
|
| 48 |
+
help="Base URL of Python Package Index (default %default)",
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 52 |
+
|
| 53 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 54 |
+
if not args:
|
| 55 |
+
raise CommandError("Missing required argument (search query).")
|
| 56 |
+
query = args
|
| 57 |
+
pypi_hits = self.search(query, options)
|
| 58 |
+
hits = transform_hits(pypi_hits)
|
| 59 |
+
|
| 60 |
+
terminal_width = None
|
| 61 |
+
if sys.stdout.isatty():
|
| 62 |
+
terminal_width = shutil.get_terminal_size()[0]
|
| 63 |
+
|
| 64 |
+
print_results(hits, terminal_width=terminal_width)
|
| 65 |
+
if pypi_hits:
|
| 66 |
+
return SUCCESS
|
| 67 |
+
return NO_MATCHES_FOUND
|
| 68 |
+
|
| 69 |
+
def search(self, query: List[str], options: Values) -> List[Dict[str, str]]:
|
| 70 |
+
index_url = options.index
|
| 71 |
+
|
| 72 |
+
session = self.get_default_session(options)
|
| 73 |
+
|
| 74 |
+
transport = PipXmlrpcTransport(index_url, session)
|
| 75 |
+
pypi = xmlrpc.client.ServerProxy(index_url, transport)
|
| 76 |
+
try:
|
| 77 |
+
hits = pypi.search({"name": query, "summary": query}, "or")
|
| 78 |
+
except xmlrpc.client.Fault as fault:
|
| 79 |
+
message = "XMLRPC request failed [code: {code}]\n{string}".format(
|
| 80 |
+
code=fault.faultCode,
|
| 81 |
+
string=fault.faultString,
|
| 82 |
+
)
|
| 83 |
+
raise CommandError(message)
|
| 84 |
+
assert isinstance(hits, list)
|
| 85 |
+
return hits
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def transform_hits(hits: List[Dict[str, str]]) -> List["TransformedHit"]:
|
| 89 |
+
"""
|
| 90 |
+
The list from pypi is really a list of versions. We want a list of
|
| 91 |
+
packages with the list of versions stored inline. This converts the
|
| 92 |
+
list from pypi into one we can use.
|
| 93 |
+
"""
|
| 94 |
+
packages: Dict[str, "TransformedHit"] = OrderedDict()
|
| 95 |
+
for hit in hits:
|
| 96 |
+
name = hit["name"]
|
| 97 |
+
summary = hit["summary"]
|
| 98 |
+
version = hit["version"]
|
| 99 |
+
|
| 100 |
+
if name not in packages.keys():
|
| 101 |
+
packages[name] = {
|
| 102 |
+
"name": name,
|
| 103 |
+
"summary": summary,
|
| 104 |
+
"versions": [version],
|
| 105 |
+
}
|
| 106 |
+
else:
|
| 107 |
+
packages[name]["versions"].append(version)
|
| 108 |
+
|
| 109 |
+
# if this is the highest version, replace summary and score
|
| 110 |
+
if version == highest_version(packages[name]["versions"]):
|
| 111 |
+
packages[name]["summary"] = summary
|
| 112 |
+
|
| 113 |
+
return list(packages.values())
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def print_dist_installation_info(name: str, latest: str) -> None:
|
| 117 |
+
env = get_default_environment()
|
| 118 |
+
dist = env.get_distribution(name)
|
| 119 |
+
if dist is not None:
|
| 120 |
+
with indent_log():
|
| 121 |
+
if dist.version == latest:
|
| 122 |
+
write_output("INSTALLED: %s (latest)", dist.version)
|
| 123 |
+
else:
|
| 124 |
+
write_output("INSTALLED: %s", dist.version)
|
| 125 |
+
if parse_version(latest).pre:
|
| 126 |
+
write_output(
|
| 127 |
+
"LATEST: %s (pre-release; install"
|
| 128 |
+
" with `pip install --pre`)",
|
| 129 |
+
latest,
|
| 130 |
+
)
|
| 131 |
+
else:
|
| 132 |
+
write_output("LATEST: %s", latest)
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def print_results(
|
| 136 |
+
hits: List["TransformedHit"],
|
| 137 |
+
name_column_width: Optional[int] = None,
|
| 138 |
+
terminal_width: Optional[int] = None,
|
| 139 |
+
) -> None:
|
| 140 |
+
if not hits:
|
| 141 |
+
return
|
| 142 |
+
if name_column_width is None:
|
| 143 |
+
name_column_width = (
|
| 144 |
+
max(
|
| 145 |
+
[
|
| 146 |
+
len(hit["name"]) + len(highest_version(hit.get("versions", ["-"])))
|
| 147 |
+
for hit in hits
|
| 148 |
+
]
|
| 149 |
+
)
|
| 150 |
+
+ 4
|
| 151 |
+
)
|
| 152 |
+
|
| 153 |
+
for hit in hits:
|
| 154 |
+
name = hit["name"]
|
| 155 |
+
summary = hit["summary"] or ""
|
| 156 |
+
latest = highest_version(hit.get("versions", ["-"]))
|
| 157 |
+
if terminal_width is not None:
|
| 158 |
+
target_width = terminal_width - name_column_width - 5
|
| 159 |
+
if target_width > 10:
|
| 160 |
+
# wrap and indent summary to fit terminal
|
| 161 |
+
summary_lines = textwrap.wrap(summary, target_width)
|
| 162 |
+
summary = ("\n" + " " * (name_column_width + 3)).join(summary_lines)
|
| 163 |
+
|
| 164 |
+
name_latest = f"{name} ({latest})"
|
| 165 |
+
line = f"{name_latest:{name_column_width}} - {summary}"
|
| 166 |
+
try:
|
| 167 |
+
write_output(line)
|
| 168 |
+
print_dist_installation_info(name, latest)
|
| 169 |
+
except UnicodeEncodeError:
|
| 170 |
+
pass
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
def highest_version(versions: List[str]) -> str:
|
| 174 |
+
return max(versions, key=parse_version)
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/show.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
from optparse import Values
|
| 3 |
+
from typing import Generator, Iterable, Iterator, List, NamedTuple, Optional
|
| 4 |
+
|
| 5 |
+
from pip._vendor.packaging.utils import canonicalize_name
|
| 6 |
+
|
| 7 |
+
from pip._internal.cli.base_command import Command
|
| 8 |
+
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
| 9 |
+
from pip._internal.metadata import BaseDistribution, get_default_environment
|
| 10 |
+
from pip._internal.utils.misc import write_output
|
| 11 |
+
|
| 12 |
+
logger = logging.getLogger(__name__)
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class ShowCommand(Command):
|
| 16 |
+
"""
|
| 17 |
+
Show information about one or more installed packages.
|
| 18 |
+
|
| 19 |
+
The output is in RFC-compliant mail header format.
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
usage = """
|
| 23 |
+
%prog [options] <package> ..."""
|
| 24 |
+
ignore_require_venv = True
|
| 25 |
+
|
| 26 |
+
def add_options(self) -> None:
|
| 27 |
+
self.cmd_opts.add_option(
|
| 28 |
+
"-f",
|
| 29 |
+
"--files",
|
| 30 |
+
dest="files",
|
| 31 |
+
action="store_true",
|
| 32 |
+
default=False,
|
| 33 |
+
help="Show the full list of installed files for each package.",
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 37 |
+
|
| 38 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 39 |
+
if not args:
|
| 40 |
+
logger.warning("ERROR: Please provide a package name or names.")
|
| 41 |
+
return ERROR
|
| 42 |
+
query = args
|
| 43 |
+
|
| 44 |
+
results = search_packages_info(query)
|
| 45 |
+
if not print_results(
|
| 46 |
+
results, list_files=options.files, verbose=options.verbose
|
| 47 |
+
):
|
| 48 |
+
return ERROR
|
| 49 |
+
return SUCCESS
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
class _PackageInfo(NamedTuple):
|
| 53 |
+
name: str
|
| 54 |
+
version: str
|
| 55 |
+
location: str
|
| 56 |
+
editable_project_location: Optional[str]
|
| 57 |
+
requires: List[str]
|
| 58 |
+
required_by: List[str]
|
| 59 |
+
installer: str
|
| 60 |
+
metadata_version: str
|
| 61 |
+
classifiers: List[str]
|
| 62 |
+
summary: str
|
| 63 |
+
homepage: str
|
| 64 |
+
project_urls: List[str]
|
| 65 |
+
author: str
|
| 66 |
+
author_email: str
|
| 67 |
+
license: str
|
| 68 |
+
entry_points: List[str]
|
| 69 |
+
files: Optional[List[str]]
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def search_packages_info(query: List[str]) -> Generator[_PackageInfo, None, None]:
|
| 73 |
+
"""
|
| 74 |
+
Gather details from installed distributions. Print distribution name,
|
| 75 |
+
version, location, and installed files. Installed files requires a
|
| 76 |
+
pip generated 'installed-files.txt' in the distributions '.egg-info'
|
| 77 |
+
directory.
|
| 78 |
+
"""
|
| 79 |
+
env = get_default_environment()
|
| 80 |
+
|
| 81 |
+
installed = {dist.canonical_name: dist for dist in env.iter_all_distributions()}
|
| 82 |
+
query_names = [canonicalize_name(name) for name in query]
|
| 83 |
+
missing = sorted(
|
| 84 |
+
[name for name, pkg in zip(query, query_names) if pkg not in installed]
|
| 85 |
+
)
|
| 86 |
+
if missing:
|
| 87 |
+
logger.warning("Package(s) not found: %s", ", ".join(missing))
|
| 88 |
+
|
| 89 |
+
def _get_requiring_packages(current_dist: BaseDistribution) -> Iterator[str]:
|
| 90 |
+
return (
|
| 91 |
+
dist.metadata["Name"] or "UNKNOWN"
|
| 92 |
+
for dist in installed.values()
|
| 93 |
+
if current_dist.canonical_name
|
| 94 |
+
in {canonicalize_name(d.name) for d in dist.iter_dependencies()}
|
| 95 |
+
)
|
| 96 |
+
|
| 97 |
+
for query_name in query_names:
|
| 98 |
+
try:
|
| 99 |
+
dist = installed[query_name]
|
| 100 |
+
except KeyError:
|
| 101 |
+
continue
|
| 102 |
+
|
| 103 |
+
requires = sorted((req.name for req in dist.iter_dependencies()), key=str.lower)
|
| 104 |
+
required_by = sorted(_get_requiring_packages(dist), key=str.lower)
|
| 105 |
+
|
| 106 |
+
try:
|
| 107 |
+
entry_points_text = dist.read_text("entry_points.txt")
|
| 108 |
+
entry_points = entry_points_text.splitlines(keepends=False)
|
| 109 |
+
except FileNotFoundError:
|
| 110 |
+
entry_points = []
|
| 111 |
+
|
| 112 |
+
files_iter = dist.iter_declared_entries()
|
| 113 |
+
if files_iter is None:
|
| 114 |
+
files: Optional[List[str]] = None
|
| 115 |
+
else:
|
| 116 |
+
files = sorted(files_iter)
|
| 117 |
+
|
| 118 |
+
metadata = dist.metadata
|
| 119 |
+
|
| 120 |
+
yield _PackageInfo(
|
| 121 |
+
name=dist.raw_name,
|
| 122 |
+
version=str(dist.version),
|
| 123 |
+
location=dist.location or "",
|
| 124 |
+
editable_project_location=dist.editable_project_location,
|
| 125 |
+
requires=requires,
|
| 126 |
+
required_by=required_by,
|
| 127 |
+
installer=dist.installer,
|
| 128 |
+
metadata_version=dist.metadata_version or "",
|
| 129 |
+
classifiers=metadata.get_all("Classifier", []),
|
| 130 |
+
summary=metadata.get("Summary", ""),
|
| 131 |
+
homepage=metadata.get("Home-page", ""),
|
| 132 |
+
project_urls=metadata.get_all("Project-URL", []),
|
| 133 |
+
author=metadata.get("Author", ""),
|
| 134 |
+
author_email=metadata.get("Author-email", ""),
|
| 135 |
+
license=metadata.get("License", ""),
|
| 136 |
+
entry_points=entry_points,
|
| 137 |
+
files=files,
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
def print_results(
|
| 142 |
+
distributions: Iterable[_PackageInfo],
|
| 143 |
+
list_files: bool,
|
| 144 |
+
verbose: bool,
|
| 145 |
+
) -> bool:
|
| 146 |
+
"""
|
| 147 |
+
Print the information from installed distributions found.
|
| 148 |
+
"""
|
| 149 |
+
results_printed = False
|
| 150 |
+
for i, dist in enumerate(distributions):
|
| 151 |
+
results_printed = True
|
| 152 |
+
if i > 0:
|
| 153 |
+
write_output("---")
|
| 154 |
+
|
| 155 |
+
write_output("Name: %s", dist.name)
|
| 156 |
+
write_output("Version: %s", dist.version)
|
| 157 |
+
write_output("Summary: %s", dist.summary)
|
| 158 |
+
write_output("Home-page: %s", dist.homepage)
|
| 159 |
+
write_output("Author: %s", dist.author)
|
| 160 |
+
write_output("Author-email: %s", dist.author_email)
|
| 161 |
+
write_output("License: %s", dist.license)
|
| 162 |
+
write_output("Location: %s", dist.location)
|
| 163 |
+
if dist.editable_project_location is not None:
|
| 164 |
+
write_output(
|
| 165 |
+
"Editable project location: %s", dist.editable_project_location
|
| 166 |
+
)
|
| 167 |
+
write_output("Requires: %s", ", ".join(dist.requires))
|
| 168 |
+
write_output("Required-by: %s", ", ".join(dist.required_by))
|
| 169 |
+
|
| 170 |
+
if verbose:
|
| 171 |
+
write_output("Metadata-Version: %s", dist.metadata_version)
|
| 172 |
+
write_output("Installer: %s", dist.installer)
|
| 173 |
+
write_output("Classifiers:")
|
| 174 |
+
for classifier in dist.classifiers:
|
| 175 |
+
write_output(" %s", classifier)
|
| 176 |
+
write_output("Entry-points:")
|
| 177 |
+
for entry in dist.entry_points:
|
| 178 |
+
write_output(" %s", entry.strip())
|
| 179 |
+
write_output("Project-URLs:")
|
| 180 |
+
for project_url in dist.project_urls:
|
| 181 |
+
write_output(" %s", project_url)
|
| 182 |
+
if list_files:
|
| 183 |
+
write_output("Files:")
|
| 184 |
+
if dist.files is None:
|
| 185 |
+
write_output("Cannot locate RECORD or installed-files.txt")
|
| 186 |
+
else:
|
| 187 |
+
for line in dist.files:
|
| 188 |
+
write_output(" %s", line.strip())
|
| 189 |
+
return results_printed
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/uninstall.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
from optparse import Values
|
| 3 |
+
from typing import List
|
| 4 |
+
|
| 5 |
+
from pip._vendor.packaging.utils import canonicalize_name
|
| 6 |
+
|
| 7 |
+
from pip._internal.cli import cmdoptions
|
| 8 |
+
from pip._internal.cli.base_command import Command
|
| 9 |
+
from pip._internal.cli.req_command import SessionCommandMixin, warn_if_run_as_root
|
| 10 |
+
from pip._internal.cli.status_codes import SUCCESS
|
| 11 |
+
from pip._internal.exceptions import InstallationError
|
| 12 |
+
from pip._internal.req import parse_requirements
|
| 13 |
+
from pip._internal.req.constructors import (
|
| 14 |
+
install_req_from_line,
|
| 15 |
+
install_req_from_parsed_requirement,
|
| 16 |
+
)
|
| 17 |
+
from pip._internal.utils.misc import (
|
| 18 |
+
check_externally_managed,
|
| 19 |
+
protect_pip_from_modification_on_windows,
|
| 20 |
+
)
|
| 21 |
+
|
| 22 |
+
logger = logging.getLogger(__name__)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class UninstallCommand(Command, SessionCommandMixin):
|
| 26 |
+
"""
|
| 27 |
+
Uninstall packages.
|
| 28 |
+
|
| 29 |
+
pip is able to uninstall most installed packages. Known exceptions are:
|
| 30 |
+
|
| 31 |
+
- Pure distutils packages installed with ``python setup.py install``, which
|
| 32 |
+
leave behind no metadata to determine what files were installed.
|
| 33 |
+
- Script wrappers installed by ``python setup.py develop``.
|
| 34 |
+
"""
|
| 35 |
+
|
| 36 |
+
usage = """
|
| 37 |
+
%prog [options] <package> ...
|
| 38 |
+
%prog [options] -r <requirements file> ..."""
|
| 39 |
+
|
| 40 |
+
def add_options(self) -> None:
|
| 41 |
+
self.cmd_opts.add_option(
|
| 42 |
+
"-r",
|
| 43 |
+
"--requirement",
|
| 44 |
+
dest="requirements",
|
| 45 |
+
action="append",
|
| 46 |
+
default=[],
|
| 47 |
+
metavar="file",
|
| 48 |
+
help=(
|
| 49 |
+
"Uninstall all the packages listed in the given requirements "
|
| 50 |
+
"file. This option can be used multiple times."
|
| 51 |
+
),
|
| 52 |
+
)
|
| 53 |
+
self.cmd_opts.add_option(
|
| 54 |
+
"-y",
|
| 55 |
+
"--yes",
|
| 56 |
+
dest="yes",
|
| 57 |
+
action="store_true",
|
| 58 |
+
help="Don't ask for confirmation of uninstall deletions.",
|
| 59 |
+
)
|
| 60 |
+
self.cmd_opts.add_option(cmdoptions.root_user_action())
|
| 61 |
+
self.cmd_opts.add_option(cmdoptions.override_externally_managed())
|
| 62 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 63 |
+
|
| 64 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 65 |
+
session = self.get_default_session(options)
|
| 66 |
+
|
| 67 |
+
reqs_to_uninstall = {}
|
| 68 |
+
for name in args:
|
| 69 |
+
req = install_req_from_line(
|
| 70 |
+
name,
|
| 71 |
+
isolated=options.isolated_mode,
|
| 72 |
+
)
|
| 73 |
+
if req.name:
|
| 74 |
+
reqs_to_uninstall[canonicalize_name(req.name)] = req
|
| 75 |
+
else:
|
| 76 |
+
logger.warning(
|
| 77 |
+
"Invalid requirement: %r ignored -"
|
| 78 |
+
" the uninstall command expects named"
|
| 79 |
+
" requirements.",
|
| 80 |
+
name,
|
| 81 |
+
)
|
| 82 |
+
for filename in options.requirements:
|
| 83 |
+
for parsed_req in parse_requirements(
|
| 84 |
+
filename, options=options, session=session
|
| 85 |
+
):
|
| 86 |
+
req = install_req_from_parsed_requirement(
|
| 87 |
+
parsed_req, isolated=options.isolated_mode
|
| 88 |
+
)
|
| 89 |
+
if req.name:
|
| 90 |
+
reqs_to_uninstall[canonicalize_name(req.name)] = req
|
| 91 |
+
if not reqs_to_uninstall:
|
| 92 |
+
raise InstallationError(
|
| 93 |
+
f"You must give at least one requirement to {self.name} (see "
|
| 94 |
+
f'"pip help {self.name}")'
|
| 95 |
+
)
|
| 96 |
+
|
| 97 |
+
if not options.override_externally_managed:
|
| 98 |
+
check_externally_managed()
|
| 99 |
+
|
| 100 |
+
protect_pip_from_modification_on_windows(
|
| 101 |
+
modifying_pip="pip" in reqs_to_uninstall
|
| 102 |
+
)
|
| 103 |
+
|
| 104 |
+
for req in reqs_to_uninstall.values():
|
| 105 |
+
uninstall_pathset = req.uninstall(
|
| 106 |
+
auto_confirm=options.yes,
|
| 107 |
+
verbose=self.verbosity > 0,
|
| 108 |
+
)
|
| 109 |
+
if uninstall_pathset:
|
| 110 |
+
uninstall_pathset.commit()
|
| 111 |
+
if options.root_user_action == "warn":
|
| 112 |
+
warn_if_run_as_root()
|
| 113 |
+
return SUCCESS
|
.venv/lib/python3.11/site-packages/pip/_internal/commands/wheel.py
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import os
|
| 3 |
+
import shutil
|
| 4 |
+
from optparse import Values
|
| 5 |
+
from typing import List
|
| 6 |
+
|
| 7 |
+
from pip._internal.cache import WheelCache
|
| 8 |
+
from pip._internal.cli import cmdoptions
|
| 9 |
+
from pip._internal.cli.req_command import RequirementCommand, with_cleanup
|
| 10 |
+
from pip._internal.cli.status_codes import SUCCESS
|
| 11 |
+
from pip._internal.exceptions import CommandError
|
| 12 |
+
from pip._internal.operations.build.build_tracker import get_build_tracker
|
| 13 |
+
from pip._internal.req.req_install import (
|
| 14 |
+
InstallRequirement,
|
| 15 |
+
check_legacy_setup_py_options,
|
| 16 |
+
)
|
| 17 |
+
from pip._internal.utils.misc import ensure_dir, normalize_path
|
| 18 |
+
from pip._internal.utils.temp_dir import TempDirectory
|
| 19 |
+
from pip._internal.wheel_builder import build, should_build_for_wheel_command
|
| 20 |
+
|
| 21 |
+
logger = logging.getLogger(__name__)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class WheelCommand(RequirementCommand):
|
| 25 |
+
"""
|
| 26 |
+
Build Wheel archives for your requirements and dependencies.
|
| 27 |
+
|
| 28 |
+
Wheel is a built-package format, and offers the advantage of not
|
| 29 |
+
recompiling your software during every install. For more details, see the
|
| 30 |
+
wheel docs: https://wheel.readthedocs.io/en/latest/
|
| 31 |
+
|
| 32 |
+
'pip wheel' uses the build system interface as described here:
|
| 33 |
+
https://pip.pypa.io/en/stable/reference/build-system/
|
| 34 |
+
|
| 35 |
+
"""
|
| 36 |
+
|
| 37 |
+
usage = """
|
| 38 |
+
%prog [options] <requirement specifier> ...
|
| 39 |
+
%prog [options] -r <requirements file> ...
|
| 40 |
+
%prog [options] [-e] <vcs project url> ...
|
| 41 |
+
%prog [options] [-e] <local project path> ...
|
| 42 |
+
%prog [options] <archive url/path> ..."""
|
| 43 |
+
|
| 44 |
+
def add_options(self) -> None:
|
| 45 |
+
self.cmd_opts.add_option(
|
| 46 |
+
"-w",
|
| 47 |
+
"--wheel-dir",
|
| 48 |
+
dest="wheel_dir",
|
| 49 |
+
metavar="dir",
|
| 50 |
+
default=os.curdir,
|
| 51 |
+
help=(
|
| 52 |
+
"Build wheels into <dir>, where the default is the "
|
| 53 |
+
"current working directory."
|
| 54 |
+
),
|
| 55 |
+
)
|
| 56 |
+
self.cmd_opts.add_option(cmdoptions.no_binary())
|
| 57 |
+
self.cmd_opts.add_option(cmdoptions.only_binary())
|
| 58 |
+
self.cmd_opts.add_option(cmdoptions.prefer_binary())
|
| 59 |
+
self.cmd_opts.add_option(cmdoptions.no_build_isolation())
|
| 60 |
+
self.cmd_opts.add_option(cmdoptions.use_pep517())
|
| 61 |
+
self.cmd_opts.add_option(cmdoptions.no_use_pep517())
|
| 62 |
+
self.cmd_opts.add_option(cmdoptions.check_build_deps())
|
| 63 |
+
self.cmd_opts.add_option(cmdoptions.constraints())
|
| 64 |
+
self.cmd_opts.add_option(cmdoptions.editable())
|
| 65 |
+
self.cmd_opts.add_option(cmdoptions.requirements())
|
| 66 |
+
self.cmd_opts.add_option(cmdoptions.src())
|
| 67 |
+
self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
|
| 68 |
+
self.cmd_opts.add_option(cmdoptions.no_deps())
|
| 69 |
+
self.cmd_opts.add_option(cmdoptions.progress_bar())
|
| 70 |
+
|
| 71 |
+
self.cmd_opts.add_option(
|
| 72 |
+
"--no-verify",
|
| 73 |
+
dest="no_verify",
|
| 74 |
+
action="store_true",
|
| 75 |
+
default=False,
|
| 76 |
+
help="Don't verify if built wheel is valid.",
|
| 77 |
+
)
|
| 78 |
+
|
| 79 |
+
self.cmd_opts.add_option(cmdoptions.config_settings())
|
| 80 |
+
self.cmd_opts.add_option(cmdoptions.build_options())
|
| 81 |
+
self.cmd_opts.add_option(cmdoptions.global_options())
|
| 82 |
+
|
| 83 |
+
self.cmd_opts.add_option(
|
| 84 |
+
"--pre",
|
| 85 |
+
action="store_true",
|
| 86 |
+
default=False,
|
| 87 |
+
help=(
|
| 88 |
+
"Include pre-release and development versions. By default, "
|
| 89 |
+
"pip only finds stable versions."
|
| 90 |
+
),
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
self.cmd_opts.add_option(cmdoptions.require_hashes())
|
| 94 |
+
|
| 95 |
+
index_opts = cmdoptions.make_option_group(
|
| 96 |
+
cmdoptions.index_group,
|
| 97 |
+
self.parser,
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
self.parser.insert_option_group(0, index_opts)
|
| 101 |
+
self.parser.insert_option_group(0, self.cmd_opts)
|
| 102 |
+
|
| 103 |
+
@with_cleanup
|
| 104 |
+
def run(self, options: Values, args: List[str]) -> int:
|
| 105 |
+
session = self.get_default_session(options)
|
| 106 |
+
|
| 107 |
+
finder = self._build_package_finder(options, session)
|
| 108 |
+
|
| 109 |
+
options.wheel_dir = normalize_path(options.wheel_dir)
|
| 110 |
+
ensure_dir(options.wheel_dir)
|
| 111 |
+
|
| 112 |
+
build_tracker = self.enter_context(get_build_tracker())
|
| 113 |
+
|
| 114 |
+
directory = TempDirectory(
|
| 115 |
+
delete=not options.no_clean,
|
| 116 |
+
kind="wheel",
|
| 117 |
+
globally_managed=True,
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
reqs = self.get_requirements(args, options, finder, session)
|
| 121 |
+
check_legacy_setup_py_options(options, reqs)
|
| 122 |
+
|
| 123 |
+
wheel_cache = WheelCache(options.cache_dir)
|
| 124 |
+
|
| 125 |
+
preparer = self.make_requirement_preparer(
|
| 126 |
+
temp_build_dir=directory,
|
| 127 |
+
options=options,
|
| 128 |
+
build_tracker=build_tracker,
|
| 129 |
+
session=session,
|
| 130 |
+
finder=finder,
|
| 131 |
+
download_dir=options.wheel_dir,
|
| 132 |
+
use_user_site=False,
|
| 133 |
+
verbosity=self.verbosity,
|
| 134 |
+
)
|
| 135 |
+
|
| 136 |
+
resolver = self.make_resolver(
|
| 137 |
+
preparer=preparer,
|
| 138 |
+
finder=finder,
|
| 139 |
+
options=options,
|
| 140 |
+
wheel_cache=wheel_cache,
|
| 141 |
+
ignore_requires_python=options.ignore_requires_python,
|
| 142 |
+
use_pep517=options.use_pep517,
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
self.trace_basic_info(finder)
|
| 146 |
+
|
| 147 |
+
requirement_set = resolver.resolve(reqs, check_supported_wheels=True)
|
| 148 |
+
|
| 149 |
+
reqs_to_build: List[InstallRequirement] = []
|
| 150 |
+
for req in requirement_set.requirements.values():
|
| 151 |
+
if req.is_wheel:
|
| 152 |
+
preparer.save_linked_requirement(req)
|
| 153 |
+
elif should_build_for_wheel_command(req):
|
| 154 |
+
reqs_to_build.append(req)
|
| 155 |
+
|
| 156 |
+
preparer.prepare_linked_requirements_more(requirement_set.requirements.values())
|
| 157 |
+
requirement_set.warn_legacy_versions_and_specifiers()
|
| 158 |
+
|
| 159 |
+
# build wheels
|
| 160 |
+
build_successes, build_failures = build(
|
| 161 |
+
reqs_to_build,
|
| 162 |
+
wheel_cache=wheel_cache,
|
| 163 |
+
verify=(not options.no_verify),
|
| 164 |
+
build_options=options.build_options or [],
|
| 165 |
+
global_options=options.global_options or [],
|
| 166 |
+
)
|
| 167 |
+
for req in build_successes:
|
| 168 |
+
assert req.link and req.link.is_wheel
|
| 169 |
+
assert req.local_file_path
|
| 170 |
+
# copy from cache to target directory
|
| 171 |
+
try:
|
| 172 |
+
shutil.copy(req.local_file_path, options.wheel_dir)
|
| 173 |
+
except OSError as e:
|
| 174 |
+
logger.warning(
|
| 175 |
+
"Building wheel for %s failed: %s",
|
| 176 |
+
req.name,
|
| 177 |
+
e,
|
| 178 |
+
)
|
| 179 |
+
build_failures.append(req)
|
| 180 |
+
if len(build_failures) != 0:
|
| 181 |
+
raise CommandError("Failed to build one or more wheels")
|
| 182 |
+
|
| 183 |
+
return SUCCESS
|
.venv/lib/python3.11/site-packages/pip/_internal/locations/__init__.py
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import functools
|
| 2 |
+
import logging
|
| 3 |
+
import os
|
| 4 |
+
import pathlib
|
| 5 |
+
import sys
|
| 6 |
+
import sysconfig
|
| 7 |
+
from typing import Any, Dict, Generator, Optional, Tuple
|
| 8 |
+
|
| 9 |
+
from pip._internal.models.scheme import SCHEME_KEYS, Scheme
|
| 10 |
+
from pip._internal.utils.compat import WINDOWS
|
| 11 |
+
from pip._internal.utils.deprecation import deprecated
|
| 12 |
+
from pip._internal.utils.virtualenv import running_under_virtualenv
|
| 13 |
+
|
| 14 |
+
from . import _sysconfig
|
| 15 |
+
from .base import (
|
| 16 |
+
USER_CACHE_DIR,
|
| 17 |
+
get_major_minor_version,
|
| 18 |
+
get_src_prefix,
|
| 19 |
+
is_osx_framework,
|
| 20 |
+
site_packages,
|
| 21 |
+
user_site,
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
__all__ = [
|
| 25 |
+
"USER_CACHE_DIR",
|
| 26 |
+
"get_bin_prefix",
|
| 27 |
+
"get_bin_user",
|
| 28 |
+
"get_major_minor_version",
|
| 29 |
+
"get_platlib",
|
| 30 |
+
"get_purelib",
|
| 31 |
+
"get_scheme",
|
| 32 |
+
"get_src_prefix",
|
| 33 |
+
"site_packages",
|
| 34 |
+
"user_site",
|
| 35 |
+
]
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
logger = logging.getLogger(__name__)
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
_PLATLIBDIR: str = getattr(sys, "platlibdir", "lib")
|
| 42 |
+
|
| 43 |
+
_USE_SYSCONFIG_DEFAULT = sys.version_info >= (3, 10)
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def _should_use_sysconfig() -> bool:
|
| 47 |
+
"""This function determines the value of _USE_SYSCONFIG.
|
| 48 |
+
|
| 49 |
+
By default, pip uses sysconfig on Python 3.10+.
|
| 50 |
+
But Python distributors can override this decision by setting:
|
| 51 |
+
sysconfig._PIP_USE_SYSCONFIG = True / False
|
| 52 |
+
Rationale in https://github.com/pypa/pip/issues/10647
|
| 53 |
+
|
| 54 |
+
This is a function for testability, but should be constant during any one
|
| 55 |
+
run.
|
| 56 |
+
"""
|
| 57 |
+
return bool(getattr(sysconfig, "_PIP_USE_SYSCONFIG", _USE_SYSCONFIG_DEFAULT))
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
_USE_SYSCONFIG = _should_use_sysconfig()
|
| 61 |
+
|
| 62 |
+
if not _USE_SYSCONFIG:
|
| 63 |
+
# Import distutils lazily to avoid deprecation warnings,
|
| 64 |
+
# but import it soon enough that it is in memory and available during
|
| 65 |
+
# a pip reinstall.
|
| 66 |
+
from . import _distutils
|
| 67 |
+
|
| 68 |
+
# Be noisy about incompatibilities if this platforms "should" be using
|
| 69 |
+
# sysconfig, but is explicitly opting out and using distutils instead.
|
| 70 |
+
if _USE_SYSCONFIG_DEFAULT and not _USE_SYSCONFIG:
|
| 71 |
+
_MISMATCH_LEVEL = logging.WARNING
|
| 72 |
+
else:
|
| 73 |
+
_MISMATCH_LEVEL = logging.DEBUG
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def _looks_like_bpo_44860() -> bool:
|
| 77 |
+
"""The resolution to bpo-44860 will change this incorrect platlib.
|
| 78 |
+
|
| 79 |
+
See <https://bugs.python.org/issue44860>.
|
| 80 |
+
"""
|
| 81 |
+
from distutils.command.install import INSTALL_SCHEMES
|
| 82 |
+
|
| 83 |
+
try:
|
| 84 |
+
unix_user_platlib = INSTALL_SCHEMES["unix_user"]["platlib"]
|
| 85 |
+
except KeyError:
|
| 86 |
+
return False
|
| 87 |
+
return unix_user_platlib == "$usersite"
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def _looks_like_red_hat_patched_platlib_purelib(scheme: Dict[str, str]) -> bool:
|
| 91 |
+
platlib = scheme["platlib"]
|
| 92 |
+
if "/$platlibdir/" in platlib:
|
| 93 |
+
platlib = platlib.replace("/$platlibdir/", f"/{_PLATLIBDIR}/")
|
| 94 |
+
if "/lib64/" not in platlib:
|
| 95 |
+
return False
|
| 96 |
+
unpatched = platlib.replace("/lib64/", "/lib/")
|
| 97 |
+
return unpatched.replace("$platbase/", "$base/") == scheme["purelib"]
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
@functools.lru_cache(maxsize=None)
|
| 101 |
+
def _looks_like_red_hat_lib() -> bool:
|
| 102 |
+
"""Red Hat patches platlib in unix_prefix and unix_home, but not purelib.
|
| 103 |
+
|
| 104 |
+
This is the only way I can see to tell a Red Hat-patched Python.
|
| 105 |
+
"""
|
| 106 |
+
from distutils.command.install import INSTALL_SCHEMES
|
| 107 |
+
|
| 108 |
+
return all(
|
| 109 |
+
k in INSTALL_SCHEMES
|
| 110 |
+
and _looks_like_red_hat_patched_platlib_purelib(INSTALL_SCHEMES[k])
|
| 111 |
+
for k in ("unix_prefix", "unix_home")
|
| 112 |
+
)
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
@functools.lru_cache(maxsize=None)
|
| 116 |
+
def _looks_like_debian_scheme() -> bool:
|
| 117 |
+
"""Debian adds two additional schemes."""
|
| 118 |
+
from distutils.command.install import INSTALL_SCHEMES
|
| 119 |
+
|
| 120 |
+
return "deb_system" in INSTALL_SCHEMES and "unix_local" in INSTALL_SCHEMES
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
@functools.lru_cache(maxsize=None)
|
| 124 |
+
def _looks_like_red_hat_scheme() -> bool:
|
| 125 |
+
"""Red Hat patches ``sys.prefix`` and ``sys.exec_prefix``.
|
| 126 |
+
|
| 127 |
+
Red Hat's ``00251-change-user-install-location.patch`` changes the install
|
| 128 |
+
command's ``prefix`` and ``exec_prefix`` to append ``"/local"``. This is
|
| 129 |
+
(fortunately?) done quite unconditionally, so we create a default command
|
| 130 |
+
object without any configuration to detect this.
|
| 131 |
+
"""
|
| 132 |
+
from distutils.command.install import install
|
| 133 |
+
from distutils.dist import Distribution
|
| 134 |
+
|
| 135 |
+
cmd: Any = install(Distribution())
|
| 136 |
+
cmd.finalize_options()
|
| 137 |
+
return (
|
| 138 |
+
cmd.exec_prefix == f"{os.path.normpath(sys.exec_prefix)}/local"
|
| 139 |
+
and cmd.prefix == f"{os.path.normpath(sys.prefix)}/local"
|
| 140 |
+
)
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
@functools.lru_cache(maxsize=None)
|
| 144 |
+
def _looks_like_slackware_scheme() -> bool:
|
| 145 |
+
"""Slackware patches sysconfig but fails to patch distutils and site.
|
| 146 |
+
|
| 147 |
+
Slackware changes sysconfig's user scheme to use ``"lib64"`` for the lib
|
| 148 |
+
path, but does not do the same to the site module.
|
| 149 |
+
"""
|
| 150 |
+
if user_site is None: # User-site not available.
|
| 151 |
+
return False
|
| 152 |
+
try:
|
| 153 |
+
paths = sysconfig.get_paths(scheme="posix_user", expand=False)
|
| 154 |
+
except KeyError: # User-site not available.
|
| 155 |
+
return False
|
| 156 |
+
return "/lib64/" in paths["purelib"] and "/lib64/" not in user_site
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
@functools.lru_cache(maxsize=None)
|
| 160 |
+
def _looks_like_msys2_mingw_scheme() -> bool:
|
| 161 |
+
"""MSYS2 patches distutils and sysconfig to use a UNIX-like scheme.
|
| 162 |
+
|
| 163 |
+
However, MSYS2 incorrectly patches sysconfig ``nt`` scheme. The fix is
|
| 164 |
+
likely going to be included in their 3.10 release, so we ignore the warning.
|
| 165 |
+
See msys2/MINGW-packages#9319.
|
| 166 |
+
|
| 167 |
+
MSYS2 MINGW's patch uses lowercase ``"lib"`` instead of the usual uppercase,
|
| 168 |
+
and is missing the final ``"site-packages"``.
|
| 169 |
+
"""
|
| 170 |
+
paths = sysconfig.get_paths("nt", expand=False)
|
| 171 |
+
return all(
|
| 172 |
+
"Lib" not in p and "lib" in p and not p.endswith("site-packages")
|
| 173 |
+
for p in (paths[key] for key in ("platlib", "purelib"))
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
def _fix_abiflags(parts: Tuple[str]) -> Generator[str, None, None]:
|
| 178 |
+
ldversion = sysconfig.get_config_var("LDVERSION")
|
| 179 |
+
abiflags = getattr(sys, "abiflags", None)
|
| 180 |
+
|
| 181 |
+
# LDVERSION does not end with sys.abiflags. Just return the path unchanged.
|
| 182 |
+
if not ldversion or not abiflags or not ldversion.endswith(abiflags):
|
| 183 |
+
yield from parts
|
| 184 |
+
return
|
| 185 |
+
|
| 186 |
+
# Strip sys.abiflags from LDVERSION-based path components.
|
| 187 |
+
for part in parts:
|
| 188 |
+
if part.endswith(ldversion):
|
| 189 |
+
part = part[: (0 - len(abiflags))]
|
| 190 |
+
yield part
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
@functools.lru_cache(maxsize=None)
|
| 194 |
+
def _warn_mismatched(old: pathlib.Path, new: pathlib.Path, *, key: str) -> None:
|
| 195 |
+
issue_url = "https://github.com/pypa/pip/issues/10151"
|
| 196 |
+
message = (
|
| 197 |
+
"Value for %s does not match. Please report this to <%s>"
|
| 198 |
+
"\ndistutils: %s"
|
| 199 |
+
"\nsysconfig: %s"
|
| 200 |
+
)
|
| 201 |
+
logger.log(_MISMATCH_LEVEL, message, key, issue_url, old, new)
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
def _warn_if_mismatch(old: pathlib.Path, new: pathlib.Path, *, key: str) -> bool:
|
| 205 |
+
if old == new:
|
| 206 |
+
return False
|
| 207 |
+
_warn_mismatched(old, new, key=key)
|
| 208 |
+
return True
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
@functools.lru_cache(maxsize=None)
|
| 212 |
+
def _log_context(
|
| 213 |
+
*,
|
| 214 |
+
user: bool = False,
|
| 215 |
+
home: Optional[str] = None,
|
| 216 |
+
root: Optional[str] = None,
|
| 217 |
+
prefix: Optional[str] = None,
|
| 218 |
+
) -> None:
|
| 219 |
+
parts = [
|
| 220 |
+
"Additional context:",
|
| 221 |
+
"user = %r",
|
| 222 |
+
"home = %r",
|
| 223 |
+
"root = %r",
|
| 224 |
+
"prefix = %r",
|
| 225 |
+
]
|
| 226 |
+
|
| 227 |
+
logger.log(_MISMATCH_LEVEL, "\n".join(parts), user, home, root, prefix)
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
def get_scheme(
|
| 231 |
+
dist_name: str,
|
| 232 |
+
user: bool = False,
|
| 233 |
+
home: Optional[str] = None,
|
| 234 |
+
root: Optional[str] = None,
|
| 235 |
+
isolated: bool = False,
|
| 236 |
+
prefix: Optional[str] = None,
|
| 237 |
+
) -> Scheme:
|
| 238 |
+
new = _sysconfig.get_scheme(
|
| 239 |
+
dist_name,
|
| 240 |
+
user=user,
|
| 241 |
+
home=home,
|
| 242 |
+
root=root,
|
| 243 |
+
isolated=isolated,
|
| 244 |
+
prefix=prefix,
|
| 245 |
+
)
|
| 246 |
+
if _USE_SYSCONFIG:
|
| 247 |
+
return new
|
| 248 |
+
|
| 249 |
+
old = _distutils.get_scheme(
|
| 250 |
+
dist_name,
|
| 251 |
+
user=user,
|
| 252 |
+
home=home,
|
| 253 |
+
root=root,
|
| 254 |
+
isolated=isolated,
|
| 255 |
+
prefix=prefix,
|
| 256 |
+
)
|
| 257 |
+
|
| 258 |
+
warning_contexts = []
|
| 259 |
+
for k in SCHEME_KEYS:
|
| 260 |
+
old_v = pathlib.Path(getattr(old, k))
|
| 261 |
+
new_v = pathlib.Path(getattr(new, k))
|
| 262 |
+
|
| 263 |
+
if old_v == new_v:
|
| 264 |
+
continue
|
| 265 |
+
|
| 266 |
+
# distutils incorrectly put PyPy packages under ``site-packages/python``
|
| 267 |
+
# in the ``posix_home`` scheme, but PyPy devs said they expect the
|
| 268 |
+
# directory name to be ``pypy`` instead. So we treat this as a bug fix
|
| 269 |
+
# and not warn about it. See bpo-43307 and python/cpython#24628.
|
| 270 |
+
skip_pypy_special_case = (
|
| 271 |
+
sys.implementation.name == "pypy"
|
| 272 |
+
and home is not None
|
| 273 |
+
and k in ("platlib", "purelib")
|
| 274 |
+
and old_v.parent == new_v.parent
|
| 275 |
+
and old_v.name.startswith("python")
|
| 276 |
+
and new_v.name.startswith("pypy")
|
| 277 |
+
)
|
| 278 |
+
if skip_pypy_special_case:
|
| 279 |
+
continue
|
| 280 |
+
|
| 281 |
+
# sysconfig's ``osx_framework_user`` does not include ``pythonX.Y`` in
|
| 282 |
+
# the ``include`` value, but distutils's ``headers`` does. We'll let
|
| 283 |
+
# CPython decide whether this is a bug or feature. See bpo-43948.
|
| 284 |
+
skip_osx_framework_user_special_case = (
|
| 285 |
+
user
|
| 286 |
+
and is_osx_framework()
|
| 287 |
+
and k == "headers"
|
| 288 |
+
and old_v.parent.parent == new_v.parent
|
| 289 |
+
and old_v.parent.name.startswith("python")
|
| 290 |
+
)
|
| 291 |
+
if skip_osx_framework_user_special_case:
|
| 292 |
+
continue
|
| 293 |
+
|
| 294 |
+
# On Red Hat and derived Linux distributions, distutils is patched to
|
| 295 |
+
# use "lib64" instead of "lib" for platlib.
|
| 296 |
+
if k == "platlib" and _looks_like_red_hat_lib():
|
| 297 |
+
continue
|
| 298 |
+
|
| 299 |
+
# On Python 3.9+, sysconfig's posix_user scheme sets platlib against
|
| 300 |
+
# sys.platlibdir, but distutils's unix_user incorrectly coninutes
|
| 301 |
+
# using the same $usersite for both platlib and purelib. This creates a
|
| 302 |
+
# mismatch when sys.platlibdir is not "lib".
|
| 303 |
+
skip_bpo_44860 = (
|
| 304 |
+
user
|
| 305 |
+
and k == "platlib"
|
| 306 |
+
and not WINDOWS
|
| 307 |
+
and sys.version_info >= (3, 9)
|
| 308 |
+
and _PLATLIBDIR != "lib"
|
| 309 |
+
and _looks_like_bpo_44860()
|
| 310 |
+
)
|
| 311 |
+
if skip_bpo_44860:
|
| 312 |
+
continue
|
| 313 |
+
|
| 314 |
+
# Slackware incorrectly patches posix_user to use lib64 instead of lib,
|
| 315 |
+
# but not usersite to match the location.
|
| 316 |
+
skip_slackware_user_scheme = (
|
| 317 |
+
user
|
| 318 |
+
and k in ("platlib", "purelib")
|
| 319 |
+
and not WINDOWS
|
| 320 |
+
and _looks_like_slackware_scheme()
|
| 321 |
+
)
|
| 322 |
+
if skip_slackware_user_scheme:
|
| 323 |
+
continue
|
| 324 |
+
|
| 325 |
+
# Both Debian and Red Hat patch Python to place the system site under
|
| 326 |
+
# /usr/local instead of /usr. Debian also places lib in dist-packages
|
| 327 |
+
# instead of site-packages, but the /usr/local check should cover it.
|
| 328 |
+
skip_linux_system_special_case = (
|
| 329 |
+
not (user or home or prefix or running_under_virtualenv())
|
| 330 |
+
and old_v.parts[1:3] == ("usr", "local")
|
| 331 |
+
and len(new_v.parts) > 1
|
| 332 |
+
and new_v.parts[1] == "usr"
|
| 333 |
+
and (len(new_v.parts) < 3 or new_v.parts[2] != "local")
|
| 334 |
+
and (_looks_like_red_hat_scheme() or _looks_like_debian_scheme())
|
| 335 |
+
)
|
| 336 |
+
if skip_linux_system_special_case:
|
| 337 |
+
continue
|
| 338 |
+
|
| 339 |
+
# On Python 3.7 and earlier, sysconfig does not include sys.abiflags in
|
| 340 |
+
# the "pythonX.Y" part of the path, but distutils does.
|
| 341 |
+
skip_sysconfig_abiflag_bug = (
|
| 342 |
+
sys.version_info < (3, 8)
|
| 343 |
+
and not WINDOWS
|
| 344 |
+
and k in ("headers", "platlib", "purelib")
|
| 345 |
+
and tuple(_fix_abiflags(old_v.parts)) == new_v.parts
|
| 346 |
+
)
|
| 347 |
+
if skip_sysconfig_abiflag_bug:
|
| 348 |
+
continue
|
| 349 |
+
|
| 350 |
+
# MSYS2 MINGW's sysconfig patch does not include the "site-packages"
|
| 351 |
+
# part of the path. This is incorrect and will be fixed in MSYS.
|
| 352 |
+
skip_msys2_mingw_bug = (
|
| 353 |
+
WINDOWS and k in ("platlib", "purelib") and _looks_like_msys2_mingw_scheme()
|
| 354 |
+
)
|
| 355 |
+
if skip_msys2_mingw_bug:
|
| 356 |
+
continue
|
| 357 |
+
|
| 358 |
+
# CPython's POSIX install script invokes pip (via ensurepip) against the
|
| 359 |
+
# interpreter located in the source tree, not the install site. This
|
| 360 |
+
# triggers special logic in sysconfig that's not present in distutils.
|
| 361 |
+
# https://github.com/python/cpython/blob/8c21941ddaf/Lib/sysconfig.py#L178-L194
|
| 362 |
+
skip_cpython_build = (
|
| 363 |
+
sysconfig.is_python_build(check_home=True)
|
| 364 |
+
and not WINDOWS
|
| 365 |
+
and k in ("headers", "include", "platinclude")
|
| 366 |
+
)
|
| 367 |
+
if skip_cpython_build:
|
| 368 |
+
continue
|
| 369 |
+
|
| 370 |
+
warning_contexts.append((old_v, new_v, f"scheme.{k}"))
|
| 371 |
+
|
| 372 |
+
if not warning_contexts:
|
| 373 |
+
return old
|
| 374 |
+
|
| 375 |
+
# Check if this path mismatch is caused by distutils config files. Those
|
| 376 |
+
# files will no longer work once we switch to sysconfig, so this raises a
|
| 377 |
+
# deprecation message for them.
|
| 378 |
+
default_old = _distutils.distutils_scheme(
|
| 379 |
+
dist_name,
|
| 380 |
+
user,
|
| 381 |
+
home,
|
| 382 |
+
root,
|
| 383 |
+
isolated,
|
| 384 |
+
prefix,
|
| 385 |
+
ignore_config_files=True,
|
| 386 |
+
)
|
| 387 |
+
if any(default_old[k] != getattr(old, k) for k in SCHEME_KEYS):
|
| 388 |
+
deprecated(
|
| 389 |
+
reason=(
|
| 390 |
+
"Configuring installation scheme with distutils config files "
|
| 391 |
+
"is deprecated and will no longer work in the near future. If you "
|
| 392 |
+
"are using a Homebrew or Linuxbrew Python, please see discussion "
|
| 393 |
+
"at https://github.com/Homebrew/homebrew-core/issues/76621"
|
| 394 |
+
),
|
| 395 |
+
replacement=None,
|
| 396 |
+
gone_in=None,
|
| 397 |
+
)
|
| 398 |
+
return old
|
| 399 |
+
|
| 400 |
+
# Post warnings about this mismatch so user can report them back.
|
| 401 |
+
for old_v, new_v, key in warning_contexts:
|
| 402 |
+
_warn_mismatched(old_v, new_v, key=key)
|
| 403 |
+
_log_context(user=user, home=home, root=root, prefix=prefix)
|
| 404 |
+
|
| 405 |
+
return old
|
| 406 |
+
|
| 407 |
+
|
| 408 |
+
def get_bin_prefix() -> str:
|
| 409 |
+
new = _sysconfig.get_bin_prefix()
|
| 410 |
+
if _USE_SYSCONFIG:
|
| 411 |
+
return new
|
| 412 |
+
|
| 413 |
+
old = _distutils.get_bin_prefix()
|
| 414 |
+
if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="bin_prefix"):
|
| 415 |
+
_log_context()
|
| 416 |
+
return old
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
def get_bin_user() -> str:
|
| 420 |
+
return _sysconfig.get_scheme("", user=True).scripts
|
| 421 |
+
|
| 422 |
+
|
| 423 |
+
def _looks_like_deb_system_dist_packages(value: str) -> bool:
|
| 424 |
+
"""Check if the value is Debian's APT-controlled dist-packages.
|
| 425 |
+
|
| 426 |
+
Debian's ``distutils.sysconfig.get_python_lib()`` implementation returns the
|
| 427 |
+
default package path controlled by APT, but does not patch ``sysconfig`` to
|
| 428 |
+
do the same. This is similar to the bug worked around in ``get_scheme()``,
|
| 429 |
+
but here the default is ``deb_system`` instead of ``unix_local``. Ultimately
|
| 430 |
+
we can't do anything about this Debian bug, and this detection allows us to
|
| 431 |
+
skip the warning when needed.
|
| 432 |
+
"""
|
| 433 |
+
if not _looks_like_debian_scheme():
|
| 434 |
+
return False
|
| 435 |
+
if value == "/usr/lib/python3/dist-packages":
|
| 436 |
+
return True
|
| 437 |
+
return False
|
| 438 |
+
|
| 439 |
+
|
| 440 |
+
def get_purelib() -> str:
|
| 441 |
+
"""Return the default pure-Python lib location."""
|
| 442 |
+
new = _sysconfig.get_purelib()
|
| 443 |
+
if _USE_SYSCONFIG:
|
| 444 |
+
return new
|
| 445 |
+
|
| 446 |
+
old = _distutils.get_purelib()
|
| 447 |
+
if _looks_like_deb_system_dist_packages(old):
|
| 448 |
+
return old
|
| 449 |
+
if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="purelib"):
|
| 450 |
+
_log_context()
|
| 451 |
+
return old
|
| 452 |
+
|
| 453 |
+
|
| 454 |
+
def get_platlib() -> str:
|
| 455 |
+
"""Return the default platform-shared lib location."""
|
| 456 |
+
new = _sysconfig.get_platlib()
|
| 457 |
+
if _USE_SYSCONFIG:
|
| 458 |
+
return new
|
| 459 |
+
|
| 460 |
+
from . import _distutils
|
| 461 |
+
|
| 462 |
+
old = _distutils.get_platlib()
|
| 463 |
+
if _looks_like_deb_system_dist_packages(old):
|
| 464 |
+
return old
|
| 465 |
+
if _warn_if_mismatch(pathlib.Path(old), pathlib.Path(new), key="platlib"):
|
| 466 |
+
_log_context()
|
| 467 |
+
return old
|
.venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (18.2 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-311.pyc
ADDED
|
Binary file (7.55 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-311.pyc
ADDED
|
Binary file (8.88 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/locations/__pycache__/base.cpython-311.pyc
ADDED
|
Binary file (4 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/locations/_distutils.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Locations where we look for configs, install stuff, etc"""
|
| 2 |
+
|
| 3 |
+
# The following comment should be removed at some point in the future.
|
| 4 |
+
# mypy: strict-optional=False
|
| 5 |
+
|
| 6 |
+
# If pip's going to use distutils, it should not be using the copy that setuptools
|
| 7 |
+
# might have injected into the environment. This is done by removing the injected
|
| 8 |
+
# shim, if it's injected.
|
| 9 |
+
#
|
| 10 |
+
# See https://github.com/pypa/pip/issues/8761 for the original discussion and
|
| 11 |
+
# rationale for why this is done within pip.
|
| 12 |
+
try:
|
| 13 |
+
__import__("_distutils_hack").remove_shim()
|
| 14 |
+
except (ImportError, AttributeError):
|
| 15 |
+
pass
|
| 16 |
+
|
| 17 |
+
import logging
|
| 18 |
+
import os
|
| 19 |
+
import sys
|
| 20 |
+
from distutils.cmd import Command as DistutilsCommand
|
| 21 |
+
from distutils.command.install import SCHEME_KEYS
|
| 22 |
+
from distutils.command.install import install as distutils_install_command
|
| 23 |
+
from distutils.sysconfig import get_python_lib
|
| 24 |
+
from typing import Dict, List, Optional, Union, cast
|
| 25 |
+
|
| 26 |
+
from pip._internal.models.scheme import Scheme
|
| 27 |
+
from pip._internal.utils.compat import WINDOWS
|
| 28 |
+
from pip._internal.utils.virtualenv import running_under_virtualenv
|
| 29 |
+
|
| 30 |
+
from .base import get_major_minor_version
|
| 31 |
+
|
| 32 |
+
logger = logging.getLogger(__name__)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def distutils_scheme(
|
| 36 |
+
dist_name: str,
|
| 37 |
+
user: bool = False,
|
| 38 |
+
home: Optional[str] = None,
|
| 39 |
+
root: Optional[str] = None,
|
| 40 |
+
isolated: bool = False,
|
| 41 |
+
prefix: Optional[str] = None,
|
| 42 |
+
*,
|
| 43 |
+
ignore_config_files: bool = False,
|
| 44 |
+
) -> Dict[str, str]:
|
| 45 |
+
"""
|
| 46 |
+
Return a distutils install scheme
|
| 47 |
+
"""
|
| 48 |
+
from distutils.dist import Distribution
|
| 49 |
+
|
| 50 |
+
dist_args: Dict[str, Union[str, List[str]]] = {"name": dist_name}
|
| 51 |
+
if isolated:
|
| 52 |
+
dist_args["script_args"] = ["--no-user-cfg"]
|
| 53 |
+
|
| 54 |
+
d = Distribution(dist_args)
|
| 55 |
+
if not ignore_config_files:
|
| 56 |
+
try:
|
| 57 |
+
d.parse_config_files()
|
| 58 |
+
except UnicodeDecodeError:
|
| 59 |
+
paths = d.find_config_files()
|
| 60 |
+
logger.warning(
|
| 61 |
+
"Ignore distutils configs in %s due to encoding errors.",
|
| 62 |
+
", ".join(os.path.basename(p) for p in paths),
|
| 63 |
+
)
|
| 64 |
+
obj: Optional[DistutilsCommand] = None
|
| 65 |
+
obj = d.get_command_obj("install", create=True)
|
| 66 |
+
assert obj is not None
|
| 67 |
+
i = cast(distutils_install_command, obj)
|
| 68 |
+
# NOTE: setting user or home has the side-effect of creating the home dir
|
| 69 |
+
# or user base for installations during finalize_options()
|
| 70 |
+
# ideally, we'd prefer a scheme class that has no side-effects.
|
| 71 |
+
assert not (user and prefix), f"user={user} prefix={prefix}"
|
| 72 |
+
assert not (home and prefix), f"home={home} prefix={prefix}"
|
| 73 |
+
i.user = user or i.user
|
| 74 |
+
if user or home:
|
| 75 |
+
i.prefix = ""
|
| 76 |
+
i.prefix = prefix or i.prefix
|
| 77 |
+
i.home = home or i.home
|
| 78 |
+
i.root = root or i.root
|
| 79 |
+
i.finalize_options()
|
| 80 |
+
|
| 81 |
+
scheme = {}
|
| 82 |
+
for key in SCHEME_KEYS:
|
| 83 |
+
scheme[key] = getattr(i, "install_" + key)
|
| 84 |
+
|
| 85 |
+
# install_lib specified in setup.cfg should install *everything*
|
| 86 |
+
# into there (i.e. it takes precedence over both purelib and
|
| 87 |
+
# platlib). Note, i.install_lib is *always* set after
|
| 88 |
+
# finalize_options(); we only want to override here if the user
|
| 89 |
+
# has explicitly requested it hence going back to the config
|
| 90 |
+
if "install_lib" in d.get_option_dict("install"):
|
| 91 |
+
scheme.update({"purelib": i.install_lib, "platlib": i.install_lib})
|
| 92 |
+
|
| 93 |
+
if running_under_virtualenv():
|
| 94 |
+
if home:
|
| 95 |
+
prefix = home
|
| 96 |
+
elif user:
|
| 97 |
+
prefix = i.install_userbase
|
| 98 |
+
else:
|
| 99 |
+
prefix = i.prefix
|
| 100 |
+
scheme["headers"] = os.path.join(
|
| 101 |
+
prefix,
|
| 102 |
+
"include",
|
| 103 |
+
"site",
|
| 104 |
+
f"python{get_major_minor_version()}",
|
| 105 |
+
dist_name,
|
| 106 |
+
)
|
| 107 |
+
|
| 108 |
+
if root is not None:
|
| 109 |
+
path_no_drive = os.path.splitdrive(os.path.abspath(scheme["headers"]))[1]
|
| 110 |
+
scheme["headers"] = os.path.join(root, path_no_drive[1:])
|
| 111 |
+
|
| 112 |
+
return scheme
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
def get_scheme(
|
| 116 |
+
dist_name: str,
|
| 117 |
+
user: bool = False,
|
| 118 |
+
home: Optional[str] = None,
|
| 119 |
+
root: Optional[str] = None,
|
| 120 |
+
isolated: bool = False,
|
| 121 |
+
prefix: Optional[str] = None,
|
| 122 |
+
) -> Scheme:
|
| 123 |
+
"""
|
| 124 |
+
Get the "scheme" corresponding to the input parameters. The distutils
|
| 125 |
+
documentation provides the context for the available schemes:
|
| 126 |
+
https://docs.python.org/3/install/index.html#alternate-installation
|
| 127 |
+
|
| 128 |
+
:param dist_name: the name of the package to retrieve the scheme for, used
|
| 129 |
+
in the headers scheme path
|
| 130 |
+
:param user: indicates to use the "user" scheme
|
| 131 |
+
:param home: indicates to use the "home" scheme and provides the base
|
| 132 |
+
directory for the same
|
| 133 |
+
:param root: root under which other directories are re-based
|
| 134 |
+
:param isolated: equivalent to --no-user-cfg, i.e. do not consider
|
| 135 |
+
~/.pydistutils.cfg (posix) or ~/pydistutils.cfg (non-posix) for
|
| 136 |
+
scheme paths
|
| 137 |
+
:param prefix: indicates to use the "prefix" scheme and provides the
|
| 138 |
+
base directory for the same
|
| 139 |
+
"""
|
| 140 |
+
scheme = distutils_scheme(dist_name, user, home, root, isolated, prefix)
|
| 141 |
+
return Scheme(
|
| 142 |
+
platlib=scheme["platlib"],
|
| 143 |
+
purelib=scheme["purelib"],
|
| 144 |
+
headers=scheme["headers"],
|
| 145 |
+
scripts=scheme["scripts"],
|
| 146 |
+
data=scheme["data"],
|
| 147 |
+
)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def get_bin_prefix() -> str:
|
| 151 |
+
# XXX: In old virtualenv versions, sys.prefix can contain '..' components,
|
| 152 |
+
# so we need to call normpath to eliminate them.
|
| 153 |
+
prefix = os.path.normpath(sys.prefix)
|
| 154 |
+
if WINDOWS:
|
| 155 |
+
bin_py = os.path.join(prefix, "Scripts")
|
| 156 |
+
# buildout uses 'bin' on Windows too?
|
| 157 |
+
if not os.path.exists(bin_py):
|
| 158 |
+
bin_py = os.path.join(prefix, "bin")
|
| 159 |
+
return bin_py
|
| 160 |
+
# Forcing to use /usr/local/bin for standard macOS framework installs
|
| 161 |
+
# Also log to ~/Library/Logs/ for use with the Console.app log viewer
|
| 162 |
+
if sys.platform[:6] == "darwin" and prefix[:16] == "/System/Library/":
|
| 163 |
+
return "/usr/local/bin"
|
| 164 |
+
return os.path.join(prefix, "bin")
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
def get_purelib() -> str:
|
| 168 |
+
return get_python_lib(plat_specific=False)
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
def get_platlib() -> str:
|
| 172 |
+
return get_python_lib(plat_specific=True)
|
.venv/lib/python3.11/site-packages/pip/_internal/locations/_sysconfig.py
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import os
|
| 3 |
+
import sys
|
| 4 |
+
import sysconfig
|
| 5 |
+
import typing
|
| 6 |
+
|
| 7 |
+
from pip._internal.exceptions import InvalidSchemeCombination, UserInstallationInvalid
|
| 8 |
+
from pip._internal.models.scheme import SCHEME_KEYS, Scheme
|
| 9 |
+
from pip._internal.utils.virtualenv import running_under_virtualenv
|
| 10 |
+
|
| 11 |
+
from .base import change_root, get_major_minor_version, is_osx_framework
|
| 12 |
+
|
| 13 |
+
logger = logging.getLogger(__name__)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
# Notes on _infer_* functions.
|
| 17 |
+
# Unfortunately ``get_default_scheme()`` didn't exist before 3.10, so there's no
|
| 18 |
+
# way to ask things like "what is the '_prefix' scheme on this platform". These
|
| 19 |
+
# functions try to answer that with some heuristics while accounting for ad-hoc
|
| 20 |
+
# platforms not covered by CPython's default sysconfig implementation. If the
|
| 21 |
+
# ad-hoc implementation does not fully implement sysconfig, we'll fall back to
|
| 22 |
+
# a POSIX scheme.
|
| 23 |
+
|
| 24 |
+
_AVAILABLE_SCHEMES = set(sysconfig.get_scheme_names())
|
| 25 |
+
|
| 26 |
+
_PREFERRED_SCHEME_API = getattr(sysconfig, "get_preferred_scheme", None)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _should_use_osx_framework_prefix() -> bool:
|
| 30 |
+
"""Check for Apple's ``osx_framework_library`` scheme.
|
| 31 |
+
|
| 32 |
+
Python distributed by Apple's Command Line Tools has this special scheme
|
| 33 |
+
that's used when:
|
| 34 |
+
|
| 35 |
+
* This is a framework build.
|
| 36 |
+
* We are installing into the system prefix.
|
| 37 |
+
|
| 38 |
+
This does not account for ``pip install --prefix`` (also means we're not
|
| 39 |
+
installing to the system prefix), which should use ``posix_prefix``, but
|
| 40 |
+
logic here means ``_infer_prefix()`` outputs ``osx_framework_library``. But
|
| 41 |
+
since ``prefix`` is not available for ``sysconfig.get_default_scheme()``,
|
| 42 |
+
which is the stdlib replacement for ``_infer_prefix()``, presumably Apple
|
| 43 |
+
wouldn't be able to magically switch between ``osx_framework_library`` and
|
| 44 |
+
``posix_prefix``. ``_infer_prefix()`` returning ``osx_framework_library``
|
| 45 |
+
means its behavior is consistent whether we use the stdlib implementation
|
| 46 |
+
or our own, and we deal with this special case in ``get_scheme()`` instead.
|
| 47 |
+
"""
|
| 48 |
+
return (
|
| 49 |
+
"osx_framework_library" in _AVAILABLE_SCHEMES
|
| 50 |
+
and not running_under_virtualenv()
|
| 51 |
+
and is_osx_framework()
|
| 52 |
+
)
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def _infer_prefix() -> str:
|
| 56 |
+
"""Try to find a prefix scheme for the current platform.
|
| 57 |
+
|
| 58 |
+
This tries:
|
| 59 |
+
|
| 60 |
+
* A special ``osx_framework_library`` for Python distributed by Apple's
|
| 61 |
+
Command Line Tools, when not running in a virtual environment.
|
| 62 |
+
* Implementation + OS, used by PyPy on Windows (``pypy_nt``).
|
| 63 |
+
* Implementation without OS, used by PyPy on POSIX (``pypy``).
|
| 64 |
+
* OS + "prefix", used by CPython on POSIX (``posix_prefix``).
|
| 65 |
+
* Just the OS name, used by CPython on Windows (``nt``).
|
| 66 |
+
|
| 67 |
+
If none of the above works, fall back to ``posix_prefix``.
|
| 68 |
+
"""
|
| 69 |
+
if _PREFERRED_SCHEME_API:
|
| 70 |
+
return _PREFERRED_SCHEME_API("prefix")
|
| 71 |
+
if _should_use_osx_framework_prefix():
|
| 72 |
+
return "osx_framework_library"
|
| 73 |
+
implementation_suffixed = f"{sys.implementation.name}_{os.name}"
|
| 74 |
+
if implementation_suffixed in _AVAILABLE_SCHEMES:
|
| 75 |
+
return implementation_suffixed
|
| 76 |
+
if sys.implementation.name in _AVAILABLE_SCHEMES:
|
| 77 |
+
return sys.implementation.name
|
| 78 |
+
suffixed = f"{os.name}_prefix"
|
| 79 |
+
if suffixed in _AVAILABLE_SCHEMES:
|
| 80 |
+
return suffixed
|
| 81 |
+
if os.name in _AVAILABLE_SCHEMES: # On Windows, prefx is just called "nt".
|
| 82 |
+
return os.name
|
| 83 |
+
return "posix_prefix"
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def _infer_user() -> str:
|
| 87 |
+
"""Try to find a user scheme for the current platform."""
|
| 88 |
+
if _PREFERRED_SCHEME_API:
|
| 89 |
+
return _PREFERRED_SCHEME_API("user")
|
| 90 |
+
if is_osx_framework() and not running_under_virtualenv():
|
| 91 |
+
suffixed = "osx_framework_user"
|
| 92 |
+
else:
|
| 93 |
+
suffixed = f"{os.name}_user"
|
| 94 |
+
if suffixed in _AVAILABLE_SCHEMES:
|
| 95 |
+
return suffixed
|
| 96 |
+
if "posix_user" not in _AVAILABLE_SCHEMES: # User scheme unavailable.
|
| 97 |
+
raise UserInstallationInvalid()
|
| 98 |
+
return "posix_user"
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def _infer_home() -> str:
|
| 102 |
+
"""Try to find a home for the current platform."""
|
| 103 |
+
if _PREFERRED_SCHEME_API:
|
| 104 |
+
return _PREFERRED_SCHEME_API("home")
|
| 105 |
+
suffixed = f"{os.name}_home"
|
| 106 |
+
if suffixed in _AVAILABLE_SCHEMES:
|
| 107 |
+
return suffixed
|
| 108 |
+
return "posix_home"
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
# Update these keys if the user sets a custom home.
|
| 112 |
+
_HOME_KEYS = [
|
| 113 |
+
"installed_base",
|
| 114 |
+
"base",
|
| 115 |
+
"installed_platbase",
|
| 116 |
+
"platbase",
|
| 117 |
+
"prefix",
|
| 118 |
+
"exec_prefix",
|
| 119 |
+
]
|
| 120 |
+
if sysconfig.get_config_var("userbase") is not None:
|
| 121 |
+
_HOME_KEYS.append("userbase")
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
def get_scheme(
|
| 125 |
+
dist_name: str,
|
| 126 |
+
user: bool = False,
|
| 127 |
+
home: typing.Optional[str] = None,
|
| 128 |
+
root: typing.Optional[str] = None,
|
| 129 |
+
isolated: bool = False,
|
| 130 |
+
prefix: typing.Optional[str] = None,
|
| 131 |
+
) -> Scheme:
|
| 132 |
+
"""
|
| 133 |
+
Get the "scheme" corresponding to the input parameters.
|
| 134 |
+
|
| 135 |
+
:param dist_name: the name of the package to retrieve the scheme for, used
|
| 136 |
+
in the headers scheme path
|
| 137 |
+
:param user: indicates to use the "user" scheme
|
| 138 |
+
:param home: indicates to use the "home" scheme
|
| 139 |
+
:param root: root under which other directories are re-based
|
| 140 |
+
:param isolated: ignored, but kept for distutils compatibility (where
|
| 141 |
+
this controls whether the user-site pydistutils.cfg is honored)
|
| 142 |
+
:param prefix: indicates to use the "prefix" scheme and provides the
|
| 143 |
+
base directory for the same
|
| 144 |
+
"""
|
| 145 |
+
if user and prefix:
|
| 146 |
+
raise InvalidSchemeCombination("--user", "--prefix")
|
| 147 |
+
if home and prefix:
|
| 148 |
+
raise InvalidSchemeCombination("--home", "--prefix")
|
| 149 |
+
|
| 150 |
+
if home is not None:
|
| 151 |
+
scheme_name = _infer_home()
|
| 152 |
+
elif user:
|
| 153 |
+
scheme_name = _infer_user()
|
| 154 |
+
else:
|
| 155 |
+
scheme_name = _infer_prefix()
|
| 156 |
+
|
| 157 |
+
# Special case: When installing into a custom prefix, use posix_prefix
|
| 158 |
+
# instead of osx_framework_library. See _should_use_osx_framework_prefix()
|
| 159 |
+
# docstring for details.
|
| 160 |
+
if prefix is not None and scheme_name == "osx_framework_library":
|
| 161 |
+
scheme_name = "posix_prefix"
|
| 162 |
+
|
| 163 |
+
if home is not None:
|
| 164 |
+
variables = {k: home for k in _HOME_KEYS}
|
| 165 |
+
elif prefix is not None:
|
| 166 |
+
variables = {k: prefix for k in _HOME_KEYS}
|
| 167 |
+
else:
|
| 168 |
+
variables = {}
|
| 169 |
+
|
| 170 |
+
paths = sysconfig.get_paths(scheme=scheme_name, vars=variables)
|
| 171 |
+
|
| 172 |
+
# Logic here is very arbitrary, we're doing it for compatibility, don't ask.
|
| 173 |
+
# 1. Pip historically uses a special header path in virtual environments.
|
| 174 |
+
# 2. If the distribution name is not known, distutils uses 'UNKNOWN'. We
|
| 175 |
+
# only do the same when not running in a virtual environment because
|
| 176 |
+
# pip's historical header path logic (see point 1) did not do this.
|
| 177 |
+
if running_under_virtualenv():
|
| 178 |
+
if user:
|
| 179 |
+
base = variables.get("userbase", sys.prefix)
|
| 180 |
+
else:
|
| 181 |
+
base = variables.get("base", sys.prefix)
|
| 182 |
+
python_xy = f"python{get_major_minor_version()}"
|
| 183 |
+
paths["include"] = os.path.join(base, "include", "site", python_xy)
|
| 184 |
+
elif not dist_name:
|
| 185 |
+
dist_name = "UNKNOWN"
|
| 186 |
+
|
| 187 |
+
scheme = Scheme(
|
| 188 |
+
platlib=paths["platlib"],
|
| 189 |
+
purelib=paths["purelib"],
|
| 190 |
+
headers=os.path.join(paths["include"], dist_name),
|
| 191 |
+
scripts=paths["scripts"],
|
| 192 |
+
data=paths["data"],
|
| 193 |
+
)
|
| 194 |
+
if root is not None:
|
| 195 |
+
for key in SCHEME_KEYS:
|
| 196 |
+
value = change_root(root, getattr(scheme, key))
|
| 197 |
+
setattr(scheme, key, value)
|
| 198 |
+
return scheme
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
def get_bin_prefix() -> str:
|
| 202 |
+
# Forcing to use /usr/local/bin for standard macOS framework installs.
|
| 203 |
+
if sys.platform[:6] == "darwin" and sys.prefix[:16] == "/System/Library/":
|
| 204 |
+
return "/usr/local/bin"
|
| 205 |
+
return sysconfig.get_paths()["scripts"]
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
def get_purelib() -> str:
|
| 209 |
+
return sysconfig.get_paths()["purelib"]
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
def get_platlib() -> str:
|
| 213 |
+
return sysconfig.get_paths()["platlib"]
|
.venv/lib/python3.11/site-packages/pip/_internal/locations/base.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import functools
|
| 2 |
+
import os
|
| 3 |
+
import site
|
| 4 |
+
import sys
|
| 5 |
+
import sysconfig
|
| 6 |
+
import typing
|
| 7 |
+
|
| 8 |
+
from pip._internal.exceptions import InstallationError
|
| 9 |
+
from pip._internal.utils import appdirs
|
| 10 |
+
from pip._internal.utils.virtualenv import running_under_virtualenv
|
| 11 |
+
|
| 12 |
+
# Application Directories
|
| 13 |
+
USER_CACHE_DIR = appdirs.user_cache_dir("pip")
|
| 14 |
+
|
| 15 |
+
# FIXME doesn't account for venv linked to global site-packages
|
| 16 |
+
site_packages: str = sysconfig.get_path("purelib")
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def get_major_minor_version() -> str:
|
| 20 |
+
"""
|
| 21 |
+
Return the major-minor version of the current Python as a string, e.g.
|
| 22 |
+
"3.7" or "3.10".
|
| 23 |
+
"""
|
| 24 |
+
return "{}.{}".format(*sys.version_info)
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def change_root(new_root: str, pathname: str) -> str:
|
| 28 |
+
"""Return 'pathname' with 'new_root' prepended.
|
| 29 |
+
|
| 30 |
+
If 'pathname' is relative, this is equivalent to os.path.join(new_root, pathname).
|
| 31 |
+
Otherwise, it requires making 'pathname' relative and then joining the
|
| 32 |
+
two, which is tricky on DOS/Windows and Mac OS.
|
| 33 |
+
|
| 34 |
+
This is borrowed from Python's standard library's distutils module.
|
| 35 |
+
"""
|
| 36 |
+
if os.name == "posix":
|
| 37 |
+
if not os.path.isabs(pathname):
|
| 38 |
+
return os.path.join(new_root, pathname)
|
| 39 |
+
else:
|
| 40 |
+
return os.path.join(new_root, pathname[1:])
|
| 41 |
+
|
| 42 |
+
elif os.name == "nt":
|
| 43 |
+
(drive, path) = os.path.splitdrive(pathname)
|
| 44 |
+
if path[0] == "\\":
|
| 45 |
+
path = path[1:]
|
| 46 |
+
return os.path.join(new_root, path)
|
| 47 |
+
|
| 48 |
+
else:
|
| 49 |
+
raise InstallationError(
|
| 50 |
+
f"Unknown platform: {os.name}\n"
|
| 51 |
+
"Can not change root path prefix on unknown platform."
|
| 52 |
+
)
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def get_src_prefix() -> str:
|
| 56 |
+
if running_under_virtualenv():
|
| 57 |
+
src_prefix = os.path.join(sys.prefix, "src")
|
| 58 |
+
else:
|
| 59 |
+
# FIXME: keep src in cwd for now (it is not a temporary folder)
|
| 60 |
+
try:
|
| 61 |
+
src_prefix = os.path.join(os.getcwd(), "src")
|
| 62 |
+
except OSError:
|
| 63 |
+
# In case the current working directory has been renamed or deleted
|
| 64 |
+
sys.exit("The folder you are executing pip from can no longer be found.")
|
| 65 |
+
|
| 66 |
+
# under macOS + virtualenv sys.prefix is not properly resolved
|
| 67 |
+
# it is something like /path/to/python/bin/..
|
| 68 |
+
return os.path.abspath(src_prefix)
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
try:
|
| 72 |
+
# Use getusersitepackages if this is present, as it ensures that the
|
| 73 |
+
# value is initialised properly.
|
| 74 |
+
user_site: typing.Optional[str] = site.getusersitepackages()
|
| 75 |
+
except AttributeError:
|
| 76 |
+
user_site = site.USER_SITE
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
@functools.lru_cache(maxsize=None)
|
| 80 |
+
def is_osx_framework() -> bool:
|
| 81 |
+
return bool(sysconfig.get_config_var("PYTHONFRAMEWORK"))
|
.venv/lib/python3.11/site-packages/pip/_internal/models/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (271 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/models/__pycache__/candidate.cpython-311.pyc
ADDED
|
Binary file (2.08 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-311.pyc
ADDED
|
Binary file (12.8 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/models/__pycache__/format_control.cpython-311.pyc
ADDED
|
Binary file (4.63 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/models/__pycache__/index.cpython-311.pyc
ADDED
|
Binary file (1.9 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-311.pyc
ADDED
|
Binary file (2.6 kB). View file
|
|
|