Загрузить файлы в «venv/Lib/site-packages/pip/_internal/commands»
This commit is contained in:
139
venv/Lib/site-packages/pip/_internal/commands/__init__.py
Normal file
139
venv/Lib/site-packages/pip/_internal/commands/__init__.py
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
"""
|
||||||
|
Package containing all pip commands
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import importlib
|
||||||
|
from collections import namedtuple
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from pip._internal.cli.base_command import Command
|
||||||
|
|
||||||
|
CommandInfo = namedtuple("CommandInfo", "module_path, class_name, summary")
|
||||||
|
|
||||||
|
# This dictionary does a bunch of heavy lifting for help output:
|
||||||
|
# - Enables avoiding additional (costly) imports for presenting `--help`.
|
||||||
|
# - The ordering matters for help display.
|
||||||
|
#
|
||||||
|
# Even though the module path starts with the same "pip._internal.commands"
|
||||||
|
# prefix, the full path makes testing easier (specifically when modifying
|
||||||
|
# `commands_dict` in test setup / teardown).
|
||||||
|
commands_dict: dict[str, CommandInfo] = {
|
||||||
|
"install": CommandInfo(
|
||||||
|
"pip._internal.commands.install",
|
||||||
|
"InstallCommand",
|
||||||
|
"Install packages.",
|
||||||
|
),
|
||||||
|
"lock": CommandInfo(
|
||||||
|
"pip._internal.commands.lock",
|
||||||
|
"LockCommand",
|
||||||
|
"Generate a lock file.",
|
||||||
|
),
|
||||||
|
"download": CommandInfo(
|
||||||
|
"pip._internal.commands.download",
|
||||||
|
"DownloadCommand",
|
||||||
|
"Download packages.",
|
||||||
|
),
|
||||||
|
"uninstall": CommandInfo(
|
||||||
|
"pip._internal.commands.uninstall",
|
||||||
|
"UninstallCommand",
|
||||||
|
"Uninstall packages.",
|
||||||
|
),
|
||||||
|
"freeze": CommandInfo(
|
||||||
|
"pip._internal.commands.freeze",
|
||||||
|
"FreezeCommand",
|
||||||
|
"Output installed packages in requirements format.",
|
||||||
|
),
|
||||||
|
"inspect": CommandInfo(
|
||||||
|
"pip._internal.commands.inspect",
|
||||||
|
"InspectCommand",
|
||||||
|
"Inspect the python environment.",
|
||||||
|
),
|
||||||
|
"list": CommandInfo(
|
||||||
|
"pip._internal.commands.list",
|
||||||
|
"ListCommand",
|
||||||
|
"List installed packages.",
|
||||||
|
),
|
||||||
|
"show": CommandInfo(
|
||||||
|
"pip._internal.commands.show",
|
||||||
|
"ShowCommand",
|
||||||
|
"Show information about installed packages.",
|
||||||
|
),
|
||||||
|
"check": CommandInfo(
|
||||||
|
"pip._internal.commands.check",
|
||||||
|
"CheckCommand",
|
||||||
|
"Verify installed packages have compatible dependencies.",
|
||||||
|
),
|
||||||
|
"config": CommandInfo(
|
||||||
|
"pip._internal.commands.configuration",
|
||||||
|
"ConfigurationCommand",
|
||||||
|
"Manage local and global configuration.",
|
||||||
|
),
|
||||||
|
"search": CommandInfo(
|
||||||
|
"pip._internal.commands.search",
|
||||||
|
"SearchCommand",
|
||||||
|
"Search PyPI for packages.",
|
||||||
|
),
|
||||||
|
"cache": CommandInfo(
|
||||||
|
"pip._internal.commands.cache",
|
||||||
|
"CacheCommand",
|
||||||
|
"Inspect and manage pip's wheel cache.",
|
||||||
|
),
|
||||||
|
"index": CommandInfo(
|
||||||
|
"pip._internal.commands.index",
|
||||||
|
"IndexCommand",
|
||||||
|
"Inspect information available from package indexes.",
|
||||||
|
),
|
||||||
|
"wheel": CommandInfo(
|
||||||
|
"pip._internal.commands.wheel",
|
||||||
|
"WheelCommand",
|
||||||
|
"Build wheels from your requirements.",
|
||||||
|
),
|
||||||
|
"hash": CommandInfo(
|
||||||
|
"pip._internal.commands.hash",
|
||||||
|
"HashCommand",
|
||||||
|
"Compute hashes of package archives.",
|
||||||
|
),
|
||||||
|
"completion": CommandInfo(
|
||||||
|
"pip._internal.commands.completion",
|
||||||
|
"CompletionCommand",
|
||||||
|
"A helper command used for command completion.",
|
||||||
|
),
|
||||||
|
"debug": CommandInfo(
|
||||||
|
"pip._internal.commands.debug",
|
||||||
|
"DebugCommand",
|
||||||
|
"Show information useful for debugging.",
|
||||||
|
),
|
||||||
|
"help": CommandInfo(
|
||||||
|
"pip._internal.commands.help",
|
||||||
|
"HelpCommand",
|
||||||
|
"Show help for commands.",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def create_command(name: str, **kwargs: Any) -> Command:
|
||||||
|
"""
|
||||||
|
Create an instance of the Command class with the given name.
|
||||||
|
"""
|
||||||
|
module_path, class_name, summary = commands_dict[name]
|
||||||
|
module = importlib.import_module(module_path)
|
||||||
|
command_class = getattr(module, class_name)
|
||||||
|
command = command_class(name=name, summary=summary, **kwargs)
|
||||||
|
|
||||||
|
return command
|
||||||
|
|
||||||
|
|
||||||
|
def get_similar_commands(name: str) -> str | None:
|
||||||
|
"""Command name auto-correct."""
|
||||||
|
from difflib import get_close_matches
|
||||||
|
|
||||||
|
name = name.lower()
|
||||||
|
|
||||||
|
close_commands = get_close_matches(name, commands_dict.keys())
|
||||||
|
|
||||||
|
if close_commands:
|
||||||
|
return close_commands[0]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
255
venv/Lib/site-packages/pip/_internal/commands/cache.py
Normal file
255
venv/Lib/site-packages/pip/_internal/commands/cache.py
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
import os
|
||||||
|
import textwrap
|
||||||
|
from optparse import Values
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
from pip._internal.cli.base_command import Command
|
||||||
|
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
||||||
|
from pip._internal.exceptions import CommandError, PipError
|
||||||
|
from pip._internal.utils import filesystem
|
||||||
|
from pip._internal.utils.logging import getLogger
|
||||||
|
from pip._internal.utils.misc import format_size
|
||||||
|
|
||||||
|
logger = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class CacheCommand(Command):
|
||||||
|
"""
|
||||||
|
Inspect and manage pip's wheel cache.
|
||||||
|
|
||||||
|
Subcommands:
|
||||||
|
|
||||||
|
- dir: Show the cache directory.
|
||||||
|
- info: Show information about the cache.
|
||||||
|
- list: List filenames of packages stored in the cache.
|
||||||
|
- remove: Remove one or more package from the cache.
|
||||||
|
- purge: Remove all items from the cache.
|
||||||
|
|
||||||
|
``<pattern>`` can be a glob expression or a package name.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ignore_require_venv = True
|
||||||
|
usage = """
|
||||||
|
%prog dir
|
||||||
|
%prog info
|
||||||
|
%prog list [<pattern>] [--format=[human, abspath]]
|
||||||
|
%prog remove <pattern>
|
||||||
|
%prog purge
|
||||||
|
"""
|
||||||
|
|
||||||
|
def add_options(self) -> None:
|
||||||
|
self.cmd_opts.add_option(
|
||||||
|
"--format",
|
||||||
|
action="store",
|
||||||
|
dest="list_format",
|
||||||
|
default="human",
|
||||||
|
choices=("human", "abspath"),
|
||||||
|
help="Select the output format among: human (default) or abspath",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.parser.insert_option_group(0, self.cmd_opts)
|
||||||
|
|
||||||
|
def handler_map(self) -> dict[str, Callable[[Values, list[str]], None]]:
|
||||||
|
return {
|
||||||
|
"dir": self.get_cache_dir,
|
||||||
|
"info": self.get_cache_info,
|
||||||
|
"list": self.list_cache_items,
|
||||||
|
"remove": self.remove_cache_items,
|
||||||
|
"purge": self.purge_cache,
|
||||||
|
}
|
||||||
|
|
||||||
|
def run(self, options: Values, args: list[str]) -> int:
|
||||||
|
handler_map = self.handler_map()
|
||||||
|
|
||||||
|
if not options.cache_dir:
|
||||||
|
logger.error("pip cache commands can not function since cache is disabled.")
|
||||||
|
return ERROR
|
||||||
|
|
||||||
|
# Determine action
|
||||||
|
if not args or args[0] not in handler_map:
|
||||||
|
logger.error(
|
||||||
|
"Need an action (%s) to perform.",
|
||||||
|
", ".join(sorted(handler_map)),
|
||||||
|
)
|
||||||
|
return ERROR
|
||||||
|
|
||||||
|
action = args[0]
|
||||||
|
|
||||||
|
# Error handling happens here, not in the action-handlers.
|
||||||
|
try:
|
||||||
|
handler_map[action](options, args[1:])
|
||||||
|
except PipError as e:
|
||||||
|
logger.error(e.args[0])
|
||||||
|
return ERROR
|
||||||
|
|
||||||
|
return SUCCESS
|
||||||
|
|
||||||
|
def get_cache_dir(self, options: Values, args: list[str]) -> None:
|
||||||
|
if args:
|
||||||
|
raise CommandError("Too many arguments")
|
||||||
|
|
||||||
|
logger.info(options.cache_dir)
|
||||||
|
|
||||||
|
def get_cache_info(self, options: Values, args: list[str]) -> None:
|
||||||
|
if args:
|
||||||
|
raise CommandError("Too many arguments")
|
||||||
|
|
||||||
|
num_http_files = len(self._find_http_files(options))
|
||||||
|
num_packages = len(self._find_wheels(options, "*"))
|
||||||
|
|
||||||
|
http_cache_location = self._cache_dir(options, "http-v2")
|
||||||
|
old_http_cache_location = self._cache_dir(options, "http")
|
||||||
|
wheels_cache_location = self._cache_dir(options, "wheels")
|
||||||
|
http_cache_size = filesystem.format_size(
|
||||||
|
filesystem.directory_size(http_cache_location)
|
||||||
|
+ filesystem.directory_size(old_http_cache_location)
|
||||||
|
)
|
||||||
|
wheels_cache_size = filesystem.format_directory_size(wheels_cache_location)
|
||||||
|
|
||||||
|
message = (
|
||||||
|
textwrap.dedent(
|
||||||
|
"""
|
||||||
|
Package index page cache location (pip v23.3+): {http_cache_location}
|
||||||
|
Package index page cache location (older pips): {old_http_cache_location}
|
||||||
|
Package index page cache size: {http_cache_size}
|
||||||
|
Number of HTTP files: {num_http_files}
|
||||||
|
Locally built wheels location: {wheels_cache_location}
|
||||||
|
Locally built wheels size: {wheels_cache_size}
|
||||||
|
Number of locally built wheels: {package_count}
|
||||||
|
""" # noqa: E501
|
||||||
|
)
|
||||||
|
.format(
|
||||||
|
http_cache_location=http_cache_location,
|
||||||
|
old_http_cache_location=old_http_cache_location,
|
||||||
|
http_cache_size=http_cache_size,
|
||||||
|
num_http_files=num_http_files,
|
||||||
|
wheels_cache_location=wheels_cache_location,
|
||||||
|
package_count=num_packages,
|
||||||
|
wheels_cache_size=wheels_cache_size,
|
||||||
|
)
|
||||||
|
.strip()
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(message)
|
||||||
|
|
||||||
|
def list_cache_items(self, options: Values, args: list[str]) -> None:
|
||||||
|
if len(args) > 1:
|
||||||
|
raise CommandError("Too many arguments")
|
||||||
|
|
||||||
|
if args:
|
||||||
|
pattern = args[0]
|
||||||
|
else:
|
||||||
|
pattern = "*"
|
||||||
|
|
||||||
|
files = self._find_wheels(options, pattern)
|
||||||
|
if options.list_format == "human":
|
||||||
|
self.format_for_human(files)
|
||||||
|
else:
|
||||||
|
self.format_for_abspath(files)
|
||||||
|
|
||||||
|
def format_for_human(self, files: list[str]) -> None:
|
||||||
|
if not files:
|
||||||
|
logger.info("No locally built wheels cached.")
|
||||||
|
return
|
||||||
|
|
||||||
|
results = []
|
||||||
|
for filename in files:
|
||||||
|
wheel = os.path.basename(filename)
|
||||||
|
size = filesystem.format_file_size(filename)
|
||||||
|
results.append(f" - {wheel} ({size})")
|
||||||
|
logger.info("Cache contents:\n")
|
||||||
|
logger.info("\n".join(sorted(results)))
|
||||||
|
|
||||||
|
def format_for_abspath(self, files: list[str]) -> None:
|
||||||
|
if files:
|
||||||
|
logger.info("\n".join(sorted(files)))
|
||||||
|
|
||||||
|
def remove_cache_items(self, options: Values, args: list[str]) -> None:
|
||||||
|
if len(args) > 1:
|
||||||
|
raise CommandError("Too many arguments")
|
||||||
|
|
||||||
|
if not args:
|
||||||
|
raise CommandError("Please provide a pattern")
|
||||||
|
|
||||||
|
files = self._find_wheels(options, args[0])
|
||||||
|
|
||||||
|
no_matching_msg = "No matching packages"
|
||||||
|
if args[0] == "*":
|
||||||
|
# Only fetch http files if no specific pattern given
|
||||||
|
files += self._find_http_files(options)
|
||||||
|
else:
|
||||||
|
# Add the pattern to the log message
|
||||||
|
no_matching_msg += f' for pattern "{args[0]}"'
|
||||||
|
|
||||||
|
if not files:
|
||||||
|
logger.warning(no_matching_msg)
|
||||||
|
|
||||||
|
bytes_removed = 0
|
||||||
|
for filename in files:
|
||||||
|
bytes_removed += os.stat(filename).st_size
|
||||||
|
os.unlink(filename)
|
||||||
|
logger.verbose("Removed %s", filename)
|
||||||
|
|
||||||
|
http_dirs = filesystem.subdirs_without_files(self._cache_dir(options, "http"))
|
||||||
|
wheel_dirs = filesystem.subdirs_without_wheels(
|
||||||
|
self._cache_dir(options, "wheels")
|
||||||
|
)
|
||||||
|
dirs = [*http_dirs, *wheel_dirs]
|
||||||
|
|
||||||
|
for subdir in dirs:
|
||||||
|
try:
|
||||||
|
for file in subdir.iterdir():
|
||||||
|
file.unlink(missing_ok=True)
|
||||||
|
subdir.rmdir()
|
||||||
|
except FileNotFoundError:
|
||||||
|
# If the directory is already gone, that's fine.
|
||||||
|
pass
|
||||||
|
logger.verbose("Removed %s", subdir)
|
||||||
|
|
||||||
|
# selfcheck.json is no longer used by pip.
|
||||||
|
selfcheck_json = self._cache_dir(options, "selfcheck.json")
|
||||||
|
if os.path.isfile(selfcheck_json):
|
||||||
|
os.remove(selfcheck_json)
|
||||||
|
logger.verbose("Removed legacy selfcheck.json file")
|
||||||
|
|
||||||
|
logger.info("Files removed: %s (%s)", len(files), format_size(bytes_removed))
|
||||||
|
logger.info("Directories removed: %s", len(dirs))
|
||||||
|
|
||||||
|
def purge_cache(self, options: Values, args: list[str]) -> None:
|
||||||
|
if args:
|
||||||
|
raise CommandError("Too many arguments")
|
||||||
|
|
||||||
|
return self.remove_cache_items(options, ["*"])
|
||||||
|
|
||||||
|
def _cache_dir(self, options: Values, subdir: str) -> str:
|
||||||
|
return os.path.join(options.cache_dir, subdir)
|
||||||
|
|
||||||
|
def _find_http_files(self, options: Values) -> list[str]:
|
||||||
|
old_http_dir = self._cache_dir(options, "http")
|
||||||
|
new_http_dir = self._cache_dir(options, "http-v2")
|
||||||
|
return filesystem.find_files(old_http_dir, "*") + filesystem.find_files(
|
||||||
|
new_http_dir, "*"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _find_wheels(self, options: Values, pattern: str) -> list[str]:
|
||||||
|
wheel_dir = self._cache_dir(options, "wheels")
|
||||||
|
|
||||||
|
# The wheel filename format, as specified in PEP 427, is:
|
||||||
|
# {distribution}-{version}(-{build})?-{python}-{abi}-{platform}.whl
|
||||||
|
#
|
||||||
|
# Additionally, non-alphanumeric values in the distribution are
|
||||||
|
# normalized to underscores (_), meaning hyphens can never occur
|
||||||
|
# before `-{version}`.
|
||||||
|
#
|
||||||
|
# Given that information:
|
||||||
|
# - If the pattern we're given contains a hyphen (-), the user is
|
||||||
|
# providing at least the version. Thus, we can just append `*.whl`
|
||||||
|
# to match the rest of it.
|
||||||
|
# - If the pattern we're given doesn't contain a hyphen (-), the
|
||||||
|
# user is only providing the name. Thus, we append `-*.whl` to
|
||||||
|
# match the hyphen before the version, followed by anything else.
|
||||||
|
#
|
||||||
|
# PEP 427: https://www.python.org/dev/peps/pep-0427/
|
||||||
|
pattern = pattern + ("*.whl" if "-" in pattern else "-*.whl")
|
||||||
|
|
||||||
|
return filesystem.find_files(wheel_dir, pattern)
|
||||||
66
venv/Lib/site-packages/pip/_internal/commands/check.py
Normal file
66
venv/Lib/site-packages/pip/_internal/commands/check.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import logging
|
||||||
|
from optparse import Values
|
||||||
|
|
||||||
|
from pip._internal.cli.base_command import Command
|
||||||
|
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
||||||
|
from pip._internal.metadata import get_default_environment
|
||||||
|
from pip._internal.operations.check import (
|
||||||
|
check_package_set,
|
||||||
|
check_unsupported,
|
||||||
|
create_package_set_from_installed,
|
||||||
|
)
|
||||||
|
from pip._internal.utils.compatibility_tags import get_supported
|
||||||
|
from pip._internal.utils.misc import write_output
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class CheckCommand(Command):
|
||||||
|
"""Verify installed packages have compatible dependencies."""
|
||||||
|
|
||||||
|
ignore_require_venv = True
|
||||||
|
usage = """
|
||||||
|
%prog [options]"""
|
||||||
|
|
||||||
|
def run(self, options: Values, args: list[str]) -> int:
|
||||||
|
package_set, parsing_probs = create_package_set_from_installed()
|
||||||
|
missing, conflicting = check_package_set(package_set)
|
||||||
|
unsupported = list(
|
||||||
|
check_unsupported(
|
||||||
|
get_default_environment().iter_installed_distributions(),
|
||||||
|
get_supported(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for project_name in missing:
|
||||||
|
version = package_set[project_name].version
|
||||||
|
for dependency in missing[project_name]:
|
||||||
|
write_output(
|
||||||
|
"%s %s requires %s, which is not installed.",
|
||||||
|
project_name,
|
||||||
|
version,
|
||||||
|
dependency[0],
|
||||||
|
)
|
||||||
|
|
||||||
|
for project_name in conflicting:
|
||||||
|
version = package_set[project_name].version
|
||||||
|
for dep_name, dep_version, req in conflicting[project_name]:
|
||||||
|
write_output(
|
||||||
|
"%s %s has requirement %s, but you have %s %s.",
|
||||||
|
project_name,
|
||||||
|
version,
|
||||||
|
req,
|
||||||
|
dep_name,
|
||||||
|
dep_version,
|
||||||
|
)
|
||||||
|
for package in unsupported:
|
||||||
|
write_output(
|
||||||
|
"%s %s is not supported on this platform",
|
||||||
|
package.raw_name,
|
||||||
|
package.version,
|
||||||
|
)
|
||||||
|
if missing or conflicting or parsing_probs or unsupported:
|
||||||
|
return ERROR
|
||||||
|
else:
|
||||||
|
write_output("No broken requirements found.")
|
||||||
|
return SUCCESS
|
||||||
136
venv/Lib/site-packages/pip/_internal/commands/completion.py
Normal file
136
venv/Lib/site-packages/pip/_internal/commands/completion.py
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
import sys
|
||||||
|
import textwrap
|
||||||
|
from optparse import Values
|
||||||
|
|
||||||
|
from pip._internal.cli.base_command import Command
|
||||||
|
from pip._internal.cli.status_codes import SUCCESS
|
||||||
|
from pip._internal.utils.misc import get_prog
|
||||||
|
|
||||||
|
BASE_COMPLETION = """
|
||||||
|
# pip {shell} completion start{script}# pip {shell} completion end
|
||||||
|
"""
|
||||||
|
|
||||||
|
COMPLETION_SCRIPTS = {
|
||||||
|
"bash": """
|
||||||
|
_pip_completion()
|
||||||
|
{{
|
||||||
|
local IFS=$' \\t\\n'
|
||||||
|
COMPREPLY=( $( COMP_WORDS="${{COMP_WORDS[*]}}" \\
|
||||||
|
COMP_CWORD=$COMP_CWORD \\
|
||||||
|
PIP_AUTO_COMPLETE=1 "$1" 2>/dev/null ) )
|
||||||
|
}}
|
||||||
|
complete -o default -F _pip_completion {prog}
|
||||||
|
""",
|
||||||
|
"zsh": """
|
||||||
|
#compdef -P pip[0-9.]#
|
||||||
|
__pip() {{
|
||||||
|
compadd $( COMP_WORDS="$words[*]" \\
|
||||||
|
COMP_CWORD=$((CURRENT-1)) \\
|
||||||
|
PIP_AUTO_COMPLETE=1 $words[1] 2>/dev/null )
|
||||||
|
}}
|
||||||
|
if [[ $zsh_eval_context[-1] == loadautofunc ]]; then
|
||||||
|
# autoload from fpath, call function directly
|
||||||
|
__pip "$@"
|
||||||
|
else
|
||||||
|
# eval/source/. command, register function for later
|
||||||
|
compdef __pip -P 'pip[0-9.]#'
|
||||||
|
fi
|
||||||
|
""",
|
||||||
|
"fish": """
|
||||||
|
function __fish_complete_pip
|
||||||
|
set -lx COMP_WORDS \\
|
||||||
|
(commandline --current-process --tokenize --cut-at-cursor) \\
|
||||||
|
(commandline --current-token --cut-at-cursor)
|
||||||
|
set -lx COMP_CWORD (math (count $COMP_WORDS) - 1)
|
||||||
|
set -lx PIP_AUTO_COMPLETE 1
|
||||||
|
set -l completions
|
||||||
|
if string match -q '2.*' $version
|
||||||
|
set completions (eval $COMP_WORDS[1])
|
||||||
|
else
|
||||||
|
set completions ($COMP_WORDS[1])
|
||||||
|
end
|
||||||
|
string split \\ -- $completions
|
||||||
|
end
|
||||||
|
complete -fa "(__fish_complete_pip)" -c {prog}
|
||||||
|
""",
|
||||||
|
"powershell": """
|
||||||
|
if ((Test-Path Function:\\TabExpansion) -and -not `
|
||||||
|
(Test-Path Function:\\_pip_completeBackup)) {{
|
||||||
|
Rename-Item Function:\\TabExpansion _pip_completeBackup
|
||||||
|
}}
|
||||||
|
function TabExpansion($line, $lastWord) {{
|
||||||
|
$lastBlock = [regex]::Split($line, '[|;]')[-1].TrimStart()
|
||||||
|
if ($lastBlock.StartsWith("{prog} ")) {{
|
||||||
|
$Env:COMP_WORDS=$lastBlock
|
||||||
|
$Env:COMP_CWORD=$lastBlock.Split().Length - 1
|
||||||
|
$Env:PIP_AUTO_COMPLETE=1
|
||||||
|
(& {prog}).Split()
|
||||||
|
Remove-Item Env:COMP_WORDS
|
||||||
|
Remove-Item Env:COMP_CWORD
|
||||||
|
Remove-Item Env:PIP_AUTO_COMPLETE
|
||||||
|
}}
|
||||||
|
elseif (Test-Path Function:\\_pip_completeBackup) {{
|
||||||
|
# Fall back on existing tab expansion
|
||||||
|
_pip_completeBackup $line $lastWord
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
""",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CompletionCommand(Command):
|
||||||
|
"""A helper command to be used for command completion."""
|
||||||
|
|
||||||
|
ignore_require_venv = True
|
||||||
|
|
||||||
|
def add_options(self) -> None:
|
||||||
|
self.cmd_opts.add_option(
|
||||||
|
"--bash",
|
||||||
|
"-b",
|
||||||
|
action="store_const",
|
||||||
|
const="bash",
|
||||||
|
dest="shell",
|
||||||
|
help="Emit completion code for bash",
|
||||||
|
)
|
||||||
|
self.cmd_opts.add_option(
|
||||||
|
"--zsh",
|
||||||
|
"-z",
|
||||||
|
action="store_const",
|
||||||
|
const="zsh",
|
||||||
|
dest="shell",
|
||||||
|
help="Emit completion code for zsh",
|
||||||
|
)
|
||||||
|
self.cmd_opts.add_option(
|
||||||
|
"--fish",
|
||||||
|
"-f",
|
||||||
|
action="store_const",
|
||||||
|
const="fish",
|
||||||
|
dest="shell",
|
||||||
|
help="Emit completion code for fish",
|
||||||
|
)
|
||||||
|
self.cmd_opts.add_option(
|
||||||
|
"--powershell",
|
||||||
|
"-p",
|
||||||
|
action="store_const",
|
||||||
|
const="powershell",
|
||||||
|
dest="shell",
|
||||||
|
help="Emit completion code for powershell",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.parser.insert_option_group(0, self.cmd_opts)
|
||||||
|
|
||||||
|
def run(self, options: Values, args: list[str]) -> int:
|
||||||
|
"""Prints the completion code of the given shell"""
|
||||||
|
shells = COMPLETION_SCRIPTS.keys()
|
||||||
|
shell_options = ["--" + shell for shell in sorted(shells)]
|
||||||
|
if options.shell in shells:
|
||||||
|
script = textwrap.dedent(
|
||||||
|
COMPLETION_SCRIPTS.get(options.shell, "").format(prog=get_prog())
|
||||||
|
)
|
||||||
|
print(BASE_COMPLETION.format(script=script, shell=options.shell))
|
||||||
|
return SUCCESS
|
||||||
|
else:
|
||||||
|
sys.stderr.write(
|
||||||
|
"ERROR: You must pass {}\n".format(" or ".join(shell_options))
|
||||||
|
)
|
||||||
|
return SUCCESS
|
||||||
288
venv/Lib/site-packages/pip/_internal/commands/configuration.py
Normal file
288
venv/Lib/site-packages/pip/_internal/commands/configuration.py
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from optparse import Values
|
||||||
|
from typing import Any, Callable
|
||||||
|
|
||||||
|
from pip._internal.cli.base_command import Command
|
||||||
|
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
||||||
|
from pip._internal.configuration import (
|
||||||
|
Configuration,
|
||||||
|
Kind,
|
||||||
|
get_configuration_files,
|
||||||
|
kinds,
|
||||||
|
)
|
||||||
|
from pip._internal.exceptions import PipError
|
||||||
|
from pip._internal.utils.logging import indent_log
|
||||||
|
from pip._internal.utils.misc import get_prog, write_output
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigurationCommand(Command):
|
||||||
|
"""
|
||||||
|
Manage local and global configuration.
|
||||||
|
|
||||||
|
Subcommands:
|
||||||
|
|
||||||
|
- list: List the active configuration (or from the file specified)
|
||||||
|
- edit: Edit the configuration file in an editor
|
||||||
|
- get: Get the value associated with command.option
|
||||||
|
- set: Set the command.option=value
|
||||||
|
- unset: Unset the value associated with command.option
|
||||||
|
- debug: List the configuration files and values defined under them
|
||||||
|
|
||||||
|
Configuration keys should be dot separated command and option name,
|
||||||
|
with the special prefix "global" affecting any command. For example,
|
||||||
|
"pip config set global.index-url https://example.org/" would configure
|
||||||
|
the index url for all commands, but "pip config set download.timeout 10"
|
||||||
|
would configure a 10 second timeout only for "pip download" commands.
|
||||||
|
|
||||||
|
If none of --user, --global and --site are passed, a virtual
|
||||||
|
environment configuration file is used if one is active and the file
|
||||||
|
exists. Otherwise, all modifications happen to the user file by
|
||||||
|
default.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ignore_require_venv = True
|
||||||
|
usage = """
|
||||||
|
%prog [<file-option>] list
|
||||||
|
%prog [<file-option>] [--editor <editor-path>] edit
|
||||||
|
|
||||||
|
%prog [<file-option>] get command.option
|
||||||
|
%prog [<file-option>] set command.option value
|
||||||
|
%prog [<file-option>] unset command.option
|
||||||
|
%prog [<file-option>] debug
|
||||||
|
"""
|
||||||
|
|
||||||
|
def add_options(self) -> None:
|
||||||
|
self.cmd_opts.add_option(
|
||||||
|
"--editor",
|
||||||
|
dest="editor",
|
||||||
|
action="store",
|
||||||
|
default=None,
|
||||||
|
help=(
|
||||||
|
"Editor to use to edit the file. Uses VISUAL or EDITOR "
|
||||||
|
"environment variables if not provided."
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.cmd_opts.add_option(
|
||||||
|
"--global",
|
||||||
|
dest="global_file",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="Use the system-wide configuration file only",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.cmd_opts.add_option(
|
||||||
|
"--user",
|
||||||
|
dest="user_file",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="Use the user configuration file only",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.cmd_opts.add_option(
|
||||||
|
"--site",
|
||||||
|
dest="site_file",
|
||||||
|
action="store_true",
|
||||||
|
default=False,
|
||||||
|
help="Use the current environment configuration file only",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.parser.insert_option_group(0, self.cmd_opts)
|
||||||
|
|
||||||
|
def handler_map(self) -> dict[str, Callable[[Values, list[str]], None]]:
|
||||||
|
return {
|
||||||
|
"list": self.list_values,
|
||||||
|
"edit": self.open_in_editor,
|
||||||
|
"get": self.get_name,
|
||||||
|
"set": self.set_name_value,
|
||||||
|
"unset": self.unset_name,
|
||||||
|
"debug": self.list_config_values,
|
||||||
|
}
|
||||||
|
|
||||||
|
def run(self, options: Values, args: list[str]) -> int:
|
||||||
|
handler_map = self.handler_map()
|
||||||
|
|
||||||
|
# Determine action
|
||||||
|
if not args or args[0] not in handler_map:
|
||||||
|
logger.error(
|
||||||
|
"Need an action (%s) to perform.",
|
||||||
|
", ".join(sorted(handler_map)),
|
||||||
|
)
|
||||||
|
return ERROR
|
||||||
|
|
||||||
|
action = args[0]
|
||||||
|
|
||||||
|
# Determine which configuration files are to be loaded
|
||||||
|
# Depends on whether the command is modifying.
|
||||||
|
try:
|
||||||
|
load_only = self._determine_file(
|
||||||
|
options, need_value=(action in ["get", "set", "unset", "edit"])
|
||||||
|
)
|
||||||
|
except PipError as e:
|
||||||
|
logger.error(e.args[0])
|
||||||
|
return ERROR
|
||||||
|
|
||||||
|
# Load a new configuration
|
||||||
|
self.configuration = Configuration(
|
||||||
|
isolated=options.isolated_mode, load_only=load_only
|
||||||
|
)
|
||||||
|
self.configuration.load()
|
||||||
|
|
||||||
|
# Error handling happens here, not in the action-handlers.
|
||||||
|
try:
|
||||||
|
handler_map[action](options, args[1:])
|
||||||
|
except PipError as e:
|
||||||
|
logger.error(e.args[0])
|
||||||
|
return ERROR
|
||||||
|
|
||||||
|
return SUCCESS
|
||||||
|
|
||||||
|
def _determine_file(self, options: Values, need_value: bool) -> Kind | None:
|
||||||
|
file_options = [
|
||||||
|
key
|
||||||
|
for key, value in (
|
||||||
|
(kinds.USER, options.user_file),
|
||||||
|
(kinds.GLOBAL, options.global_file),
|
||||||
|
(kinds.SITE, options.site_file),
|
||||||
|
)
|
||||||
|
if value
|
||||||
|
]
|
||||||
|
|
||||||
|
if not file_options:
|
||||||
|
if not need_value:
|
||||||
|
return None
|
||||||
|
# Default to user, unless there's a site file.
|
||||||
|
elif any(
|
||||||
|
os.path.exists(site_config_file)
|
||||||
|
for site_config_file in get_configuration_files()[kinds.SITE]
|
||||||
|
):
|
||||||
|
return kinds.SITE
|
||||||
|
else:
|
||||||
|
return kinds.USER
|
||||||
|
elif len(file_options) == 1:
|
||||||
|
return file_options[0]
|
||||||
|
|
||||||
|
raise PipError(
|
||||||
|
"Need exactly one file to operate upon "
|
||||||
|
"(--user, --site, --global) to perform."
|
||||||
|
)
|
||||||
|
|
||||||
|
def list_values(self, options: Values, args: list[str]) -> None:
|
||||||
|
self._get_n_args(args, "list", n=0)
|
||||||
|
|
||||||
|
for key, value in sorted(self.configuration.items()):
|
||||||
|
for key, value in sorted(value.items()):
|
||||||
|
write_output("%s=%r", key, value)
|
||||||
|
|
||||||
|
def get_name(self, options: Values, args: list[str]) -> None:
|
||||||
|
key = self._get_n_args(args, "get [name]", n=1)
|
||||||
|
value = self.configuration.get_value(key)
|
||||||
|
|
||||||
|
write_output("%s", value)
|
||||||
|
|
||||||
|
def set_name_value(self, options: Values, args: list[str]) -> None:
|
||||||
|
key, value = self._get_n_args(args, "set [name] [value]", n=2)
|
||||||
|
self.configuration.set_value(key, value)
|
||||||
|
|
||||||
|
self._save_configuration()
|
||||||
|
|
||||||
|
def unset_name(self, options: Values, args: list[str]) -> None:
|
||||||
|
key = self._get_n_args(args, "unset [name]", n=1)
|
||||||
|
self.configuration.unset_value(key)
|
||||||
|
|
||||||
|
self._save_configuration()
|
||||||
|
|
||||||
|
def list_config_values(self, options: Values, args: list[str]) -> None:
|
||||||
|
"""List config key-value pairs across different config files"""
|
||||||
|
self._get_n_args(args, "debug", n=0)
|
||||||
|
|
||||||
|
self.print_env_var_values()
|
||||||
|
# Iterate over config files and print if they exist, and the
|
||||||
|
# key-value pairs present in them if they do
|
||||||
|
for variant, files in sorted(self.configuration.iter_config_files()):
|
||||||
|
write_output("%s:", variant)
|
||||||
|
for fname in files:
|
||||||
|
with indent_log():
|
||||||
|
file_exists = os.path.exists(fname)
|
||||||
|
write_output("%s, exists: %r", fname, file_exists)
|
||||||
|
if file_exists:
|
||||||
|
self.print_config_file_values(variant, fname)
|
||||||
|
|
||||||
|
def print_config_file_values(self, variant: Kind, fname: str) -> None:
|
||||||
|
"""Get key-value pairs from the file of a variant"""
|
||||||
|
for name, value in self.configuration.get_values_in_config(variant).items():
|
||||||
|
with indent_log():
|
||||||
|
if name == fname:
|
||||||
|
for confname, confvalue in value.items():
|
||||||
|
write_output("%s: %s", confname, confvalue)
|
||||||
|
|
||||||
|
def print_env_var_values(self) -> None:
|
||||||
|
"""Get key-values pairs present as environment variables"""
|
||||||
|
write_output("%s:", "env_var")
|
||||||
|
with indent_log():
|
||||||
|
for key, value in sorted(self.configuration.get_environ_vars()):
|
||||||
|
env_var = f"PIP_{key.upper()}"
|
||||||
|
write_output("%s=%r", env_var, value)
|
||||||
|
|
||||||
|
def open_in_editor(self, options: Values, args: list[str]) -> None:
|
||||||
|
editor = self._determine_editor(options)
|
||||||
|
|
||||||
|
fname = self.configuration.get_file_to_edit()
|
||||||
|
if fname is None:
|
||||||
|
raise PipError("Could not determine appropriate file.")
|
||||||
|
elif '"' in fname:
|
||||||
|
# This shouldn't happen, unless we see a username like that.
|
||||||
|
# If that happens, we'd appreciate a pull request fixing this.
|
||||||
|
raise PipError(
|
||||||
|
f'Can not open an editor for a file name containing "\n{fname}'
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.check_call(f'{editor} "{fname}"', shell=True)
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
if not e.filename:
|
||||||
|
e.filename = editor
|
||||||
|
raise
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
raise PipError(f"Editor Subprocess exited with exit code {e.returncode}")
|
||||||
|
|
||||||
|
def _get_n_args(self, args: list[str], example: str, n: int) -> Any:
|
||||||
|
"""Helper to make sure the command got the right number of arguments"""
|
||||||
|
if len(args) != n:
|
||||||
|
msg = (
|
||||||
|
f"Got unexpected number of arguments, expected {n}. "
|
||||||
|
f'(example: "{get_prog()} config {example}")'
|
||||||
|
)
|
||||||
|
raise PipError(msg)
|
||||||
|
|
||||||
|
if n == 1:
|
||||||
|
return args[0]
|
||||||
|
else:
|
||||||
|
return args
|
||||||
|
|
||||||
|
def _save_configuration(self) -> None:
|
||||||
|
# We successfully ran a modifying command. Need to save the
|
||||||
|
# configuration.
|
||||||
|
try:
|
||||||
|
self.configuration.save()
|
||||||
|
except Exception:
|
||||||
|
logger.exception(
|
||||||
|
"Unable to save configuration. Please report this as a bug."
|
||||||
|
)
|
||||||
|
raise PipError("Internal Error.")
|
||||||
|
|
||||||
|
def _determine_editor(self, options: Values) -> str:
|
||||||
|
if options.editor is not None:
|
||||||
|
return options.editor
|
||||||
|
elif "VISUAL" in os.environ:
|
||||||
|
return os.environ["VISUAL"]
|
||||||
|
elif "EDITOR" in os.environ:
|
||||||
|
return os.environ["EDITOR"]
|
||||||
|
else:
|
||||||
|
raise PipError("Could not determine editor to use.")
|
||||||
Reference in New Issue
Block a user