Voice et bot modif
This commit is contained in:
parent
189d56026b
commit
7333a22bcd
10774 changed files with 634644 additions and 933308 deletions
|
|
@ -2,11 +2,9 @@
|
|||
Package containing all pip commands
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
from collections import namedtuple
|
||||
from typing import Any
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from pip._internal.cli.base_command import Command
|
||||
|
||||
|
|
@ -19,17 +17,12 @@ CommandInfo = namedtuple("CommandInfo", "module_path, class_name, summary")
|
|||
# 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] = {
|
||||
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",
|
||||
|
|
@ -125,7 +118,7 @@ def create_command(name: str, **kwargs: Any) -> Command:
|
|||
return command
|
||||
|
||||
|
||||
def get_similar_commands(name: str) -> str | None:
|
||||
def get_similar_commands(name: str) -> Optional[str]:
|
||||
"""Command name auto-correct."""
|
||||
from difflib import get_close_matches
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,14 +1,13 @@
|
|||
import os
|
||||
import textwrap
|
||||
from optparse import Values
|
||||
from typing import Callable
|
||||
from typing import Any, List
|
||||
|
||||
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__)
|
||||
|
||||
|
|
@ -49,8 +48,8 @@ class CacheCommand(Command):
|
|||
|
||||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
def handler_map(self) -> dict[str, Callable[[Values, list[str]], None]]:
|
||||
return {
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
handlers = {
|
||||
"dir": self.get_cache_dir,
|
||||
"info": self.get_cache_info,
|
||||
"list": self.list_cache_items,
|
||||
|
|
@ -58,18 +57,15 @@ class CacheCommand(Command):
|
|||
"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:
|
||||
if not args or args[0] not in handlers:
|
||||
logger.error(
|
||||
"Need an action (%s) to perform.",
|
||||
", ".join(sorted(handler_map)),
|
||||
", ".join(sorted(handlers)),
|
||||
)
|
||||
return ERROR
|
||||
|
||||
|
|
@ -77,20 +73,20 @@ class CacheCommand(Command):
|
|||
|
||||
# Error handling happens here, not in the action-handlers.
|
||||
try:
|
||||
handler_map[action](options, args[1:])
|
||||
handlers[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:
|
||||
def get_cache_dir(self, options: Values, args: List[Any]) -> None:
|
||||
if args:
|
||||
raise CommandError("Too many arguments")
|
||||
|
||||
logger.info(options.cache_dir)
|
||||
|
||||
def get_cache_info(self, options: Values, args: list[str]) -> None:
|
||||
def get_cache_info(self, options: Values, args: List[Any]) -> None:
|
||||
if args:
|
||||
raise CommandError("Too many arguments")
|
||||
|
||||
|
|
@ -132,7 +128,7 @@ class CacheCommand(Command):
|
|||
|
||||
logger.info(message)
|
||||
|
||||
def list_cache_items(self, options: Values, args: list[str]) -> None:
|
||||
def list_cache_items(self, options: Values, args: List[Any]) -> None:
|
||||
if len(args) > 1:
|
||||
raise CommandError("Too many arguments")
|
||||
|
||||
|
|
@ -147,7 +143,7 @@ class CacheCommand(Command):
|
|||
else:
|
||||
self.format_for_abspath(files)
|
||||
|
||||
def format_for_human(self, files: list[str]) -> None:
|
||||
def format_for_human(self, files: List[str]) -> None:
|
||||
if not files:
|
||||
logger.info("No locally built wheels cached.")
|
||||
return
|
||||
|
|
@ -160,11 +156,11 @@ class CacheCommand(Command):
|
|||
logger.info("Cache contents:\n")
|
||||
logger.info("\n".join(sorted(results)))
|
||||
|
||||
def format_for_abspath(self, files: list[str]) -> None:
|
||||
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:
|
||||
def remove_cache_items(self, options: Values, args: List[Any]) -> None:
|
||||
if len(args) > 1:
|
||||
raise CommandError("Too many arguments")
|
||||
|
||||
|
|
@ -184,14 +180,12 @@ class CacheCommand(Command):
|
|||
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)
|
||||
logger.info("Files removed: %s (%s)", len(files), format_size(bytes_removed))
|
||||
logger.info("Files removed: %s", len(files))
|
||||
|
||||
def purge_cache(self, options: Values, args: list[str]) -> None:
|
||||
def purge_cache(self, options: Values, args: List[Any]) -> None:
|
||||
if args:
|
||||
raise CommandError("Too many arguments")
|
||||
|
||||
|
|
@ -200,14 +194,14 @@ class CacheCommand(Command):
|
|||
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]:
|
||||
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]:
|
||||
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:
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
import logging
|
||||
from optparse import Values
|
||||
from typing import List
|
||||
|
||||
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,
|
||||
warn_legacy_versions_and_specifiers,
|
||||
)
|
||||
from pip._internal.utils.compatibility_tags import get_supported
|
||||
from pip._internal.utils.misc import write_output
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -18,19 +17,13 @@ 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:
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
package_set, parsing_probs = create_package_set_from_installed()
|
||||
warn_legacy_versions_and_specifiers(package_set)
|
||||
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
|
||||
|
|
@ -53,13 +46,8 @@ class CheckCommand(Command):
|
|||
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:
|
||||
|
||||
if missing or conflicting or parsing_probs:
|
||||
return ERROR
|
||||
else:
|
||||
write_output("No broken requirements found.")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import sys
|
||||
import textwrap
|
||||
from optparse import Values
|
||||
from typing import List
|
||||
|
||||
from pip._internal.cli.base_command import Command
|
||||
from pip._internal.cli.status_codes import SUCCESS
|
||||
|
|
@ -37,18 +38,12 @@ COMPLETION_SCRIPTS = {
|
|||
""",
|
||||
"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 COMP_WORDS (commandline -o) ""
|
||||
set -lx COMP_CWORD ( \\
|
||||
math (contains -i -- (commandline -t) $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
|
||||
string split \\ -- (eval $COMP_WORDS[1])
|
||||
end
|
||||
complete -fa "(__fish_complete_pip)" -c {prog}
|
||||
""",
|
||||
|
|
@ -118,7 +113,7 @@ class CompletionCommand(Command):
|
|||
|
||||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
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)]
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
from optparse import Values
|
||||
from typing import Any, Callable
|
||||
from typing import Any, List, Optional
|
||||
|
||||
from pip._internal.cli.base_command import Command
|
||||
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
||||
|
|
@ -95,8 +93,8 @@ class ConfigurationCommand(Command):
|
|||
|
||||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
def handler_map(self) -> dict[str, Callable[[Values, list[str]], None]]:
|
||||
return {
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
handlers = {
|
||||
"list": self.list_values,
|
||||
"edit": self.open_in_editor,
|
||||
"get": self.get_name,
|
||||
|
|
@ -105,14 +103,11 @@ class ConfigurationCommand(Command):
|
|||
"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:
|
||||
if not args or args[0] not in handlers:
|
||||
logger.error(
|
||||
"Need an action (%s) to perform.",
|
||||
", ".join(sorted(handler_map)),
|
||||
", ".join(sorted(handlers)),
|
||||
)
|
||||
return ERROR
|
||||
|
||||
|
|
@ -136,14 +131,14 @@ class ConfigurationCommand(Command):
|
|||
|
||||
# Error handling happens here, not in the action-handlers.
|
||||
try:
|
||||
handler_map[action](options, args[1:])
|
||||
handlers[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:
|
||||
def _determine_file(self, options: Values, need_value: bool) -> Optional[Kind]:
|
||||
file_options = [
|
||||
key
|
||||
for key, value in (
|
||||
|
|
@ -173,32 +168,31 @@ class ConfigurationCommand(Command):
|
|||
"(--user, --site, --global) to perform."
|
||||
)
|
||||
|
||||
def list_values(self, options: Values, args: list[str]) -> None:
|
||||
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)
|
||||
write_output("%s=%r", key, value)
|
||||
|
||||
def get_name(self, options: Values, args: list[str]) -> None:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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)
|
||||
|
||||
|
|
@ -212,15 +206,13 @@ class ConfigurationCommand(Command):
|
|||
file_exists = os.path.exists(fname)
|
||||
write_output("%s, exists: %r", fname, file_exists)
|
||||
if file_exists:
|
||||
self.print_config_file_values(variant, fname)
|
||||
self.print_config_file_values(variant)
|
||||
|
||||
def print_config_file_values(self, variant: Kind, fname: str) -> None:
|
||||
def print_config_file_values(self, variant: Kind) -> 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)
|
||||
write_output("%s: %s", name, value)
|
||||
|
||||
def print_env_var_values(self) -> None:
|
||||
"""Get key-values pairs present as environment variables"""
|
||||
|
|
@ -230,7 +222,7 @@ class ConfigurationCommand(Command):
|
|||
env_var = f"PIP_{key.upper()}"
|
||||
write_output("%s=%r", env_var, value)
|
||||
|
||||
def open_in_editor(self, options: Values, args: list[str]) -> None:
|
||||
def open_in_editor(self, options: Values, args: List[str]) -> None:
|
||||
editor = self._determine_editor(options)
|
||||
|
||||
fname = self.configuration.get_file_to_edit()
|
||||
|
|
@ -252,7 +244,7 @@ class ConfigurationCommand(Command):
|
|||
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:
|
||||
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 = (
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import importlib.resources
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from optparse import Values
|
||||
from types import ModuleType
|
||||
from typing import Any
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import pip._vendor
|
||||
from pip._vendor.certifi import where
|
||||
|
|
@ -18,7 +17,6 @@ from pip._internal.cli.cmdoptions import make_target_python
|
|||
from pip._internal.cli.status_codes import SUCCESS
|
||||
from pip._internal.configuration import Configuration
|
||||
from pip._internal.metadata import get_environment
|
||||
from pip._internal.utils.compat import open_text_resource
|
||||
from pip._internal.utils.logging import indent_log
|
||||
from pip._internal.utils.misc import get_pip_version
|
||||
|
||||
|
|
@ -36,8 +34,8 @@ def show_sys_implementation() -> None:
|
|||
show_value("name", implementation_name)
|
||||
|
||||
|
||||
def create_vendor_txt_map() -> dict[str, str]:
|
||||
with open_text_resource("pip._vendor", "vendor.txt") as f:
|
||||
def create_vendor_txt_map() -> Dict[str, str]:
|
||||
with importlib.resources.open_text("pip._vendor", "vendor.txt") as f:
|
||||
# Purge non version specifying lines.
|
||||
# Also, remove any space prefix or suffixes (including comments).
|
||||
lines = [
|
||||
|
|
@ -48,7 +46,7 @@ def create_vendor_txt_map() -> dict[str, str]:
|
|||
return dict(line.split("==", 1) for line in lines)
|
||||
|
||||
|
||||
def get_module_from_module_name(module_name: str) -> ModuleType | None:
|
||||
def get_module_from_module_name(module_name: str) -> Optional[ModuleType]:
|
||||
# Module name can be uppercase in vendor.txt for some reason...
|
||||
module_name = module_name.lower().replace("-", "_")
|
||||
# PATCH: setuptools is actually only pkg_resources.
|
||||
|
|
@ -66,7 +64,7 @@ def get_module_from_module_name(module_name: str) -> ModuleType | None:
|
|||
raise
|
||||
|
||||
|
||||
def get_vendor_version_from_module(module_name: str) -> str | None:
|
||||
def get_vendor_version_from_module(module_name: str) -> Optional[str]:
|
||||
module = get_module_from_module_name(module_name)
|
||||
version = getattr(module, "__version__", None)
|
||||
|
||||
|
|
@ -81,7 +79,7 @@ def get_vendor_version_from_module(module_name: str) -> str | None:
|
|||
return version
|
||||
|
||||
|
||||
def show_actual_vendor_versions(vendor_txt_versions: dict[str, str]) -> None:
|
||||
def show_actual_vendor_versions(vendor_txt_versions: Dict[str, str]) -> None:
|
||||
"""Log the actual version and print extra info if there is
|
||||
a conflict or if the actual version could not be imported.
|
||||
"""
|
||||
|
|
@ -171,7 +169,7 @@ class DebugCommand(Command):
|
|||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
self.parser.config.load()
|
||||
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
logger.warning(
|
||||
"This command is only meant for debugging. "
|
||||
"Do not use this with automation for parsing and getting these "
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
import logging
|
||||
import os
|
||||
from optparse import Values
|
||||
from typing import List
|
||||
|
||||
from pip._internal.cli import cmdoptions
|
||||
from pip._internal.cli.cmdoptions import make_target_python
|
||||
from pip._internal.cli.req_command import RequirementCommand, with_cleanup
|
||||
from pip._internal.cli.status_codes import SUCCESS
|
||||
from pip._internal.operations.build.build_tracker import get_build_tracker
|
||||
from pip._internal.req.req_install import check_legacy_setup_py_options
|
||||
from pip._internal.utils.misc import ensure_dir, normalize_path, write_output
|
||||
from pip._internal.utils.temp_dir import TempDirectory
|
||||
|
||||
|
|
@ -35,9 +37,9 @@ class DownloadCommand(RequirementCommand):
|
|||
|
||||
def add_options(self) -> None:
|
||||
self.cmd_opts.add_option(cmdoptions.constraints())
|
||||
self.cmd_opts.add_option(cmdoptions.build_constraints())
|
||||
self.cmd_opts.add_option(cmdoptions.requirements())
|
||||
self.cmd_opts.add_option(cmdoptions.no_deps())
|
||||
self.cmd_opts.add_option(cmdoptions.global_options())
|
||||
self.cmd_opts.add_option(cmdoptions.no_binary())
|
||||
self.cmd_opts.add_option(cmdoptions.only_binary())
|
||||
self.cmd_opts.add_option(cmdoptions.prefer_binary())
|
||||
|
|
@ -47,6 +49,7 @@ class DownloadCommand(RequirementCommand):
|
|||
self.cmd_opts.add_option(cmdoptions.progress_bar())
|
||||
self.cmd_opts.add_option(cmdoptions.no_build_isolation())
|
||||
self.cmd_opts.add_option(cmdoptions.use_pep517())
|
||||
self.cmd_opts.add_option(cmdoptions.no_use_pep517())
|
||||
self.cmd_opts.add_option(cmdoptions.check_build_deps())
|
||||
self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
|
||||
|
||||
|
|
@ -72,14 +75,13 @@ class DownloadCommand(RequirementCommand):
|
|||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
@with_cleanup
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
options.ignore_installed = True
|
||||
# editable doesn't really make sense for `pip download`, but the bowels
|
||||
# of the RequirementSet code require that property.
|
||||
options.editables = []
|
||||
|
||||
cmdoptions.check_dist_restriction(options)
|
||||
cmdoptions.check_build_constraints(options)
|
||||
|
||||
options.download_dir = normalize_path(options.download_dir)
|
||||
ensure_dir(options.download_dir)
|
||||
|
|
@ -103,6 +105,7 @@ class DownloadCommand(RequirementCommand):
|
|||
)
|
||||
|
||||
reqs = self.get_requirements(args, options, finder, session)
|
||||
check_legacy_setup_py_options(options, reqs)
|
||||
|
||||
preparer = self.make_requirement_preparer(
|
||||
temp_build_dir=directory,
|
||||
|
|
@ -120,6 +123,7 @@ class DownloadCommand(RequirementCommand):
|
|||
finder=finder,
|
||||
options=options,
|
||||
ignore_requires_python=options.ignore_requires_python,
|
||||
use_pep517=options.use_pep517,
|
||||
py_version_info=options.python_version,
|
||||
)
|
||||
|
||||
|
|
@ -127,15 +131,16 @@ class DownloadCommand(RequirementCommand):
|
|||
|
||||
requirement_set = resolver.resolve(reqs, check_supported_wheels=True)
|
||||
|
||||
preparer.prepare_linked_requirements_more(requirement_set.requirements.values())
|
||||
|
||||
downloaded: list[str] = []
|
||||
downloaded: List[str] = []
|
||||
for req in requirement_set.requirements.values():
|
||||
if req.satisfied_by is None:
|
||||
assert req.name is not None
|
||||
preparer.save_linked_requirement(req)
|
||||
downloaded.append(req.name)
|
||||
|
||||
preparer.prepare_linked_requirements_more(requirement_set.requirements.values())
|
||||
requirement_set.warn_legacy_versions_and_specifiers()
|
||||
|
||||
if downloaded:
|
||||
write_output("Successfully downloaded %s", " ".join(downloaded))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import sys
|
||||
from optparse import Values
|
||||
from typing import AbstractSet, List
|
||||
|
||||
from pip._internal.cli import cmdoptions
|
||||
from pip._internal.cli.base_command import Command
|
||||
|
|
@ -12,11 +13,12 @@ def _should_suppress_build_backends() -> bool:
|
|||
return sys.version_info < (3, 12)
|
||||
|
||||
|
||||
def _dev_pkgs() -> set[str]:
|
||||
def _dev_pkgs() -> AbstractSet[str]:
|
||||
pkgs = {"pip"}
|
||||
|
||||
if _should_suppress_build_backends():
|
||||
pkgs |= {"setuptools", "distribute", "wheel"}
|
||||
pkgs |= {"setuptools", "distribute", "wheel", "pkg-resources"}
|
||||
|
||||
return pkgs
|
||||
|
||||
|
|
@ -28,9 +30,9 @@ class FreezeCommand(Command):
|
|||
packages are listed in a case-insensitive sorted order.
|
||||
"""
|
||||
|
||||
ignore_require_venv = True
|
||||
usage = """
|
||||
%prog [options]"""
|
||||
log_streams = ("ext://sys.stderr", "ext://sys.stderr")
|
||||
|
||||
def add_options(self) -> None:
|
||||
self.cmd_opts.add_option(
|
||||
|
|
@ -84,7 +86,7 @@ class FreezeCommand(Command):
|
|||
|
||||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
skip = set(stdlib_pkgs)
|
||||
if not options.freeze_all:
|
||||
skip.update(_dev_pkgs())
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import hashlib
|
|||
import logging
|
||||
import sys
|
||||
from optparse import Values
|
||||
from typing import List
|
||||
|
||||
from pip._internal.cli.base_command import Command
|
||||
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
||||
|
|
@ -36,7 +37,7 @@ class HashCommand(Command):
|
|||
)
|
||||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
if not args:
|
||||
self.parser.print_usage(sys.stderr)
|
||||
return ERROR
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
from optparse import Values
|
||||
from typing import List
|
||||
|
||||
from pip._internal.cli.base_command import Command
|
||||
from pip._internal.cli.status_codes import SUCCESS
|
||||
|
|
@ -12,7 +13,7 @@ class HelpCommand(Command):
|
|||
%prog <command>"""
|
||||
ignore_require_venv = True
|
||||
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
from pip._internal.commands import (
|
||||
commands_dict,
|
||||
create_command,
|
||||
|
|
|
|||
|
|
@ -1,20 +1,13 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from collections.abc import Iterable
|
||||
from optparse import Values
|
||||
from typing import Any, Callable
|
||||
from typing import Any, Iterable, List, Optional, Union
|
||||
|
||||
from pip._vendor.packaging.version import Version
|
||||
from pip._vendor.packaging.version import LegacyVersion, Version
|
||||
|
||||
from pip._internal.cli import cmdoptions
|
||||
from pip._internal.cli.req_command import IndexGroupCommand
|
||||
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
||||
from pip._internal.commands.search import (
|
||||
get_installed_distribution,
|
||||
print_dist_installation_info,
|
||||
)
|
||||
from pip._internal.commands.search import print_dist_installation_info
|
||||
from pip._internal.exceptions import CommandError, DistributionNotFound, PipError
|
||||
from pip._internal.index.collector import LinkCollector
|
||||
from pip._internal.index.package_finder import PackageFinder
|
||||
|
|
@ -41,7 +34,6 @@ class IndexCommand(IndexGroupCommand):
|
|||
|
||||
self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
|
||||
self.cmd_opts.add_option(cmdoptions.pre())
|
||||
self.cmd_opts.add_option(cmdoptions.json())
|
||||
self.cmd_opts.add_option(cmdoptions.no_binary())
|
||||
self.cmd_opts.add_option(cmdoptions.only_binary())
|
||||
|
||||
|
|
@ -53,19 +45,22 @@ class IndexCommand(IndexGroupCommand):
|
|||
self.parser.insert_option_group(0, index_opts)
|
||||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
def handler_map(self) -> dict[str, Callable[[Values, list[str]], None]]:
|
||||
return {
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
handlers = {
|
||||
"versions": self.get_available_package_versions,
|
||||
}
|
||||
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
handler_map = self.handler_map()
|
||||
logger.warning(
|
||||
"pip index is currently an experimental command. "
|
||||
"It may be removed/changed in a future release "
|
||||
"without prior warning."
|
||||
)
|
||||
|
||||
# Determine action
|
||||
if not args or args[0] not in handler_map:
|
||||
if not args or args[0] not in handlers:
|
||||
logger.error(
|
||||
"Need an action (%s) to perform.",
|
||||
", ".join(sorted(handler_map)),
|
||||
", ".join(sorted(handlers)),
|
||||
)
|
||||
return ERROR
|
||||
|
||||
|
|
@ -73,7 +68,7 @@ class IndexCommand(IndexGroupCommand):
|
|||
|
||||
# Error handling happens here, not in the action-handlers.
|
||||
try:
|
||||
handler_map[action](options, args[1:])
|
||||
handlers[action](options, args[1:])
|
||||
except PipError as e:
|
||||
logger.error(e.args[0])
|
||||
return ERROR
|
||||
|
|
@ -84,8 +79,8 @@ class IndexCommand(IndexGroupCommand):
|
|||
self,
|
||||
options: Values,
|
||||
session: PipSession,
|
||||
target_python: TargetPython | None = None,
|
||||
ignore_requires_python: bool | None = None,
|
||||
target_python: Optional[TargetPython] = None,
|
||||
ignore_requires_python: Optional[bool] = None,
|
||||
) -> PackageFinder:
|
||||
"""
|
||||
Create a package finder appropriate to the index command.
|
||||
|
|
@ -105,7 +100,7 @@ class IndexCommand(IndexGroupCommand):
|
|||
target_python=target_python,
|
||||
)
|
||||
|
||||
def get_available_package_versions(self, options: Values, args: list[Any]) -> None:
|
||||
def get_available_package_versions(self, options: Values, args: List[Any]) -> None:
|
||||
if len(args) != 1:
|
||||
raise CommandError("You need to specify exactly one argument")
|
||||
|
||||
|
|
@ -120,7 +115,7 @@ class IndexCommand(IndexGroupCommand):
|
|||
ignore_requires_python=options.ignore_requires_python,
|
||||
)
|
||||
|
||||
versions: Iterable[Version] = (
|
||||
versions: Iterable[Union[LegacyVersion, Version]] = (
|
||||
candidate.version for candidate in finder.find_all_candidates(query)
|
||||
)
|
||||
|
||||
|
|
@ -139,21 +134,6 @@ class IndexCommand(IndexGroupCommand):
|
|||
formatted_versions = [str(ver) for ver in sorted(versions, reverse=True)]
|
||||
latest = formatted_versions[0]
|
||||
|
||||
dist = get_installed_distribution(query)
|
||||
|
||||
if options.json:
|
||||
structured_output = {
|
||||
"name": query,
|
||||
"versions": formatted_versions,
|
||||
"latest": latest,
|
||||
}
|
||||
|
||||
if dist is not None:
|
||||
structured_output["installed_version"] = str(dist.version)
|
||||
|
||||
write_output(json.dumps(structured_output))
|
||||
|
||||
else:
|
||||
write_output(f"{query} ({latest})")
|
||||
write_output("Available versions: {}".format(", ".join(formatted_versions)))
|
||||
print_dist_installation_info(latest, dist)
|
||||
write_output(f"{query} ({latest})")
|
||||
write_output("Available versions: {}".format(", ".join(formatted_versions)))
|
||||
print_dist_installation_info(query, latest)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import logging
|
||||
from optparse import Values
|
||||
from typing import Any
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from pip._vendor.packaging.markers import default_environment
|
||||
from pip._vendor.rich import print_json
|
||||
|
||||
from pip import __version__
|
||||
from pip._internal.cli import cmdoptions
|
||||
from pip._internal.cli.base_command import Command
|
||||
from pip._internal.cli.req_command import Command
|
||||
from pip._internal.cli.status_codes import SUCCESS
|
||||
from pip._internal.metadata import BaseDistribution, get_environment
|
||||
from pip._internal.utils.compat import stdlib_pkgs
|
||||
|
|
@ -45,7 +45,7 @@ class InspectCommand(Command):
|
|||
self.cmd_opts.add_option(cmdoptions.list_path())
|
||||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
cmdoptions.check_list_path_option(options)
|
||||
dists = get_environment(options.path).iter_installed_distributions(
|
||||
local_only=options.local,
|
||||
|
|
@ -62,8 +62,8 @@ class InspectCommand(Command):
|
|||
print_json(data=output)
|
||||
return SUCCESS
|
||||
|
||||
def _dist_to_dict(self, dist: BaseDistribution) -> dict[str, Any]:
|
||||
res: dict[str, Any] = {
|
||||
def _dist_to_dict(self, dist: BaseDistribution) -> Dict[str, Any]:
|
||||
res: Dict[str, Any] = {
|
||||
"metadata": dist.metadata_dict,
|
||||
"metadata_location": dist.info_location,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import errno
|
||||
import json
|
||||
import operator
|
||||
|
|
@ -7,32 +5,20 @@ import os
|
|||
import shutil
|
||||
import site
|
||||
from optparse import SUPPRESS_HELP, Values
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
from pip._vendor.packaging.utils import canonicalize_name
|
||||
from pip._vendor.requests.exceptions import InvalidProxyURL
|
||||
from pip._vendor.rich import print_json
|
||||
|
||||
# Eagerly import self_outdated_check to avoid crashes. Otherwise,
|
||||
# this module would be imported *after* pip was replaced, resulting
|
||||
# in crashes if the new self_outdated_check module was incompatible
|
||||
# with the rest of pip that's already imported, or allowing a
|
||||
# wheel to execute arbitrary code on install by replacing
|
||||
# self_outdated_check.
|
||||
import pip._internal.self_outdated_check # noqa: F401
|
||||
from pip._internal.cache import WheelCache
|
||||
from pip._internal.cli import cmdoptions
|
||||
from pip._internal.cli.cmdoptions import make_target_python
|
||||
from pip._internal.cli.req_command import (
|
||||
RequirementCommand,
|
||||
warn_if_run_as_root,
|
||||
with_cleanup,
|
||||
)
|
||||
from pip._internal.cli.status_codes import ERROR, SUCCESS
|
||||
from pip._internal.exceptions import (
|
||||
CommandError,
|
||||
InstallationError,
|
||||
InstallWheelBuildError,
|
||||
)
|
||||
from pip._internal.exceptions import CommandError, InstallationError
|
||||
from pip._internal.locations import get_scheme
|
||||
from pip._internal.metadata import get_environment
|
||||
from pip._internal.models.installation_report import InstallationReport
|
||||
|
|
@ -41,6 +27,7 @@ from pip._internal.operations.check import ConflictDetails, check_install_confli
|
|||
from pip._internal.req import install_given_reqs
|
||||
from pip._internal.req.req_install import (
|
||||
InstallRequirement,
|
||||
check_legacy_setup_py_options,
|
||||
)
|
||||
from pip._internal.utils.compat import WINDOWS
|
||||
from pip._internal.utils.filesystem import test_writable_dir
|
||||
|
|
@ -50,7 +37,6 @@ from pip._internal.utils.misc import (
|
|||
ensure_dir,
|
||||
get_pip_version,
|
||||
protect_pip_from_modification_on_windows,
|
||||
warn_if_run_as_root,
|
||||
write_output,
|
||||
)
|
||||
from pip._internal.utils.temp_dir import TempDirectory
|
||||
|
|
@ -58,7 +44,7 @@ from pip._internal.utils.virtualenv import (
|
|||
running_under_virtualenv,
|
||||
virtualenv_no_global,
|
||||
)
|
||||
from pip._internal.wheel_builder import build
|
||||
from pip._internal.wheel_builder import build, should_build_for_install_command
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
|
@ -86,7 +72,6 @@ class InstallCommand(RequirementCommand):
|
|||
def add_options(self) -> None:
|
||||
self.cmd_opts.add_option(cmdoptions.requirements())
|
||||
self.cmd_opts.add_option(cmdoptions.constraints())
|
||||
self.cmd_opts.add_option(cmdoptions.build_constraints())
|
||||
self.cmd_opts.add_option(cmdoptions.no_deps())
|
||||
self.cmd_opts.add_option(cmdoptions.pre())
|
||||
|
||||
|
|
@ -210,10 +195,12 @@ class InstallCommand(RequirementCommand):
|
|||
self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
|
||||
self.cmd_opts.add_option(cmdoptions.no_build_isolation())
|
||||
self.cmd_opts.add_option(cmdoptions.use_pep517())
|
||||
self.cmd_opts.add_option(cmdoptions.no_use_pep517())
|
||||
self.cmd_opts.add_option(cmdoptions.check_build_deps())
|
||||
self.cmd_opts.add_option(cmdoptions.override_externally_managed())
|
||||
|
||||
self.cmd_opts.add_option(cmdoptions.config_settings())
|
||||
self.cmd_opts.add_option(cmdoptions.global_options())
|
||||
|
||||
self.cmd_opts.add_option(
|
||||
"--compile",
|
||||
|
|
@ -276,7 +263,7 @@ class InstallCommand(RequirementCommand):
|
|||
)
|
||||
|
||||
@with_cleanup
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
if options.use_user_site and options.target_dir is not None:
|
||||
raise CommandError("Can not combine '--user' and '--target'")
|
||||
|
||||
|
|
@ -301,7 +288,6 @@ class InstallCommand(RequirementCommand):
|
|||
if options.upgrade:
|
||||
upgrade_strategy = options.upgrade_strategy
|
||||
|
||||
cmdoptions.check_build_constraints(options)
|
||||
cmdoptions.check_dist_restriction(options, check_target=True)
|
||||
|
||||
logger.verbose("Using %s", get_pip_version())
|
||||
|
|
@ -313,8 +299,8 @@ class InstallCommand(RequirementCommand):
|
|||
isolated_mode=options.isolated_mode,
|
||||
)
|
||||
|
||||
target_temp_dir: TempDirectory | None = None
|
||||
target_temp_dir_path: str | None = None
|
||||
target_temp_dir: Optional[TempDirectory] = None
|
||||
target_temp_dir_path: Optional[str] = None
|
||||
if options.target_dir:
|
||||
options.ignore_installed = True
|
||||
options.target_dir = os.path.abspath(options.target_dir)
|
||||
|
|
@ -333,6 +319,8 @@ class InstallCommand(RequirementCommand):
|
|||
target_temp_dir_path = target_temp_dir.path
|
||||
self.enter_context(target_temp_dir)
|
||||
|
||||
global_options = options.global_options or []
|
||||
|
||||
session = self.get_default_session(options)
|
||||
|
||||
target_python = make_target_python(options)
|
||||
|
|
@ -352,6 +340,7 @@ class InstallCommand(RequirementCommand):
|
|||
|
||||
try:
|
||||
reqs = self.get_requirements(args, options, finder, session)
|
||||
check_legacy_setup_py_options(options, reqs)
|
||||
|
||||
wheel_cache = WheelCache(options.cache_dir)
|
||||
|
||||
|
|
@ -380,7 +369,7 @@ class InstallCommand(RequirementCommand):
|
|||
ignore_requires_python=options.ignore_requires_python,
|
||||
force_reinstall=options.force_reinstall,
|
||||
upgrade_strategy=upgrade_strategy,
|
||||
py_version_info=options.python_version,
|
||||
use_pep517=options.use_pep517,
|
||||
)
|
||||
|
||||
self.trace_basic_info(finder)
|
||||
|
|
@ -398,6 +387,9 @@ class InstallCommand(RequirementCommand):
|
|||
json.dump(report.to_dict(), f, indent=2, ensure_ascii=False)
|
||||
|
||||
if options.dry_run:
|
||||
# In non dry-run mode, the legacy versions and specifiers check
|
||||
# will be done as part of conflict detection.
|
||||
requirement_set.warn_legacy_versions_and_specifiers()
|
||||
would_install_items = sorted(
|
||||
(r.metadata["name"], r.metadata["version"])
|
||||
for r in requirement_set.requirements_to_install
|
||||
|
|
@ -409,13 +401,6 @@ class InstallCommand(RequirementCommand):
|
|||
)
|
||||
return SUCCESS
|
||||
|
||||
# If there is any more preparation to do for the actual installation, do
|
||||
# so now. This includes actually downloading the files in the case that
|
||||
# we have been using PEP-658 metadata so far.
|
||||
preparer.prepare_linked_requirements_more(
|
||||
requirement_set.requirements.values()
|
||||
)
|
||||
|
||||
try:
|
||||
pip_req = requirement_set.get_requirement("pip")
|
||||
except KeyError:
|
||||
|
|
@ -427,22 +412,31 @@ class InstallCommand(RequirementCommand):
|
|||
protect_pip_from_modification_on_windows(modifying_pip=modifying_pip)
|
||||
|
||||
reqs_to_build = [
|
||||
r for r in requirement_set.requirements_to_install if not r.is_wheel
|
||||
r
|
||||
for r in requirement_set.requirements.values()
|
||||
if should_build_for_install_command(r)
|
||||
]
|
||||
|
||||
_, build_failures = build(
|
||||
reqs_to_build,
|
||||
wheel_cache=wheel_cache,
|
||||
verify=True,
|
||||
build_options=[],
|
||||
global_options=global_options,
|
||||
)
|
||||
|
||||
if build_failures:
|
||||
raise InstallWheelBuildError(build_failures)
|
||||
raise InstallationError(
|
||||
"Could not build wheels for {}, which is required to "
|
||||
"install pyproject.toml-based projects".format(
|
||||
", ".join(r.name for r in build_failures) # type: ignore
|
||||
)
|
||||
)
|
||||
|
||||
to_install = resolver.get_installation_order(requirement_set)
|
||||
|
||||
# Check for conflicts in the package set we're installing.
|
||||
conflicts: ConflictDetails | None = None
|
||||
conflicts: Optional[ConflictDetails] = None
|
||||
should_warn_about_conflicts = (
|
||||
not options.ignore_dependencies and options.warn_about_conflicts
|
||||
)
|
||||
|
|
@ -457,13 +451,13 @@ class InstallCommand(RequirementCommand):
|
|||
|
||||
installed = install_given_reqs(
|
||||
to_install,
|
||||
global_options,
|
||||
root=options.root_path,
|
||||
home=target_temp_dir_path,
|
||||
prefix=options.prefix_path,
|
||||
warn_script_location=warn_script_location,
|
||||
use_user_site=options.use_user_site,
|
||||
pycompile=options.compile,
|
||||
progress_bar=options.progress_bar,
|
||||
)
|
||||
|
||||
lib_locations = get_lib_location_guesses(
|
||||
|
|
@ -475,21 +469,17 @@ class InstallCommand(RequirementCommand):
|
|||
)
|
||||
env = get_environment(lib_locations)
|
||||
|
||||
# Display a summary of installed packages, with extra care to
|
||||
# display a package name as it was requested by the user.
|
||||
installed.sort(key=operator.attrgetter("name"))
|
||||
summary = []
|
||||
installed_versions = {}
|
||||
for distribution in env.iter_all_distributions():
|
||||
installed_versions[distribution.canonical_name] = distribution.version
|
||||
for package in installed:
|
||||
display_name = package.name
|
||||
version = installed_versions.get(canonicalize_name(display_name), None)
|
||||
if version:
|
||||
text = f"{display_name}-{version}"
|
||||
else:
|
||||
text = display_name
|
||||
summary.append(text)
|
||||
items = []
|
||||
for result in installed:
|
||||
item = result.name
|
||||
try:
|
||||
installed_dist = env.get_distribution(item)
|
||||
if installed_dist is not None:
|
||||
item = f"{item}-{installed_dist.version}"
|
||||
except Exception:
|
||||
pass
|
||||
items.append(item)
|
||||
|
||||
if conflicts is not None:
|
||||
self._warn_about_conflicts(
|
||||
|
|
@ -497,7 +487,7 @@ class InstallCommand(RequirementCommand):
|
|||
resolver_variant=self.determine_resolver_variant(options),
|
||||
)
|
||||
|
||||
installed_desc = " ".join(summary)
|
||||
installed_desc = " ".join(items)
|
||||
if installed_desc:
|
||||
write_output(
|
||||
"Successfully installed %s",
|
||||
|
|
@ -579,8 +569,8 @@ class InstallCommand(RequirementCommand):
|
|||
shutil.move(os.path.join(lib_dir, item), target_item_dir)
|
||||
|
||||
def _determine_conflicts(
|
||||
self, to_install: list[InstallRequirement]
|
||||
) -> ConflictDetails | None:
|
||||
self, to_install: List[InstallRequirement]
|
||||
) -> Optional[ConflictDetails]:
|
||||
try:
|
||||
return check_install_conflicts(to_install)
|
||||
except Exception:
|
||||
|
|
@ -597,7 +587,7 @@ class InstallCommand(RequirementCommand):
|
|||
if not missing and not conflicting:
|
||||
return
|
||||
|
||||
parts: list[str] = []
|
||||
parts: List[str] = []
|
||||
if resolver_variant == "legacy":
|
||||
parts.append(
|
||||
"pip's legacy dependency resolver does not consider dependency "
|
||||
|
|
@ -643,11 +633,11 @@ class InstallCommand(RequirementCommand):
|
|||
|
||||
def get_lib_location_guesses(
|
||||
user: bool = False,
|
||||
home: str | None = None,
|
||||
root: str | None = None,
|
||||
home: Optional[str] = None,
|
||||
root: Optional[str] = None,
|
||||
isolated: bool = False,
|
||||
prefix: str | None = None,
|
||||
) -> list[str]:
|
||||
prefix: Optional[str] = None,
|
||||
) -> List[str]:
|
||||
scheme = get_scheme(
|
||||
"",
|
||||
user=user,
|
||||
|
|
@ -659,7 +649,7 @@ def get_lib_location_guesses(
|
|||
return [scheme.purelib, scheme.platlib]
|
||||
|
||||
|
||||
def site_packages_writable(root: str | None, isolated: bool) -> bool:
|
||||
def site_packages_writable(root: Optional[str], isolated: bool) -> bool:
|
||||
return all(
|
||||
test_writable_dir(d)
|
||||
for d in set(get_lib_location_guesses(root=root, isolated=isolated))
|
||||
|
|
@ -667,10 +657,10 @@ def site_packages_writable(root: str | None, isolated: bool) -> bool:
|
|||
|
||||
|
||||
def decide_user_install(
|
||||
use_user_site: bool | None,
|
||||
prefix_path: str | None = None,
|
||||
target_dir: str | None = None,
|
||||
root_path: str | None = None,
|
||||
use_user_site: Optional[bool],
|
||||
prefix_path: Optional[str] = None,
|
||||
target_dir: Optional[str] = None,
|
||||
root_path: Optional[str] = None,
|
||||
isolated_mode: bool = False,
|
||||
) -> bool:
|
||||
"""Determine whether to do a user install based on the input options.
|
||||
|
|
@ -687,7 +677,6 @@ def decide_user_install(
|
|||
logger.debug("Non-user install by explicit request")
|
||||
return False
|
||||
|
||||
# If we have been asked for a user install explicitly, check compatibility.
|
||||
if use_user_site:
|
||||
if prefix_path:
|
||||
raise CommandError(
|
||||
|
|
@ -699,13 +688,6 @@ def decide_user_install(
|
|||
"Can not perform a '--user' install. User site-packages "
|
||||
"are not visible in this virtualenv."
|
||||
)
|
||||
# Catch all remaining cases which honour the site.ENABLE_USER_SITE
|
||||
# value, such as a plain Python installation (e.g. no virtualenv).
|
||||
if not site.ENABLE_USER_SITE:
|
||||
raise InstallationError(
|
||||
"Can not perform a '--user' install. User site-packages "
|
||||
"are disabled for this Python."
|
||||
)
|
||||
logger.debug("User install by explicit request")
|
||||
return True
|
||||
|
||||
|
|
@ -773,31 +755,20 @@ def create_os_error_message(
|
|||
parts.append(permissions_part)
|
||||
parts.append(".\n")
|
||||
|
||||
# Suggest to check "pip config debug" in case of invalid proxy
|
||||
if type(error) is InvalidProxyURL:
|
||||
# Suggest the user to enable Long Paths if path length is
|
||||
# more than 260
|
||||
if (
|
||||
WINDOWS
|
||||
and error.errno == errno.ENOENT
|
||||
and error.filename
|
||||
and len(error.filename) > 260
|
||||
):
|
||||
parts.append(
|
||||
'Consider checking your local proxy configuration with "pip config debug"'
|
||||
"HINT: This error might have occurred since "
|
||||
"this system does not have Windows Long Path "
|
||||
"support enabled. You can find information on "
|
||||
"how to enable this at "
|
||||
"https://pip.pypa.io/warnings/enable-long-paths\n"
|
||||
)
|
||||
parts.append(".\n")
|
||||
|
||||
# On Windows, errors like EINVAL or ENOENT may occur
|
||||
# if a file or folder name exceeds 255 characters,
|
||||
# or if the full path exceeds 260 characters and long path support isn't enabled.
|
||||
# This condition checks for such cases and adds a hint to the error output.
|
||||
|
||||
if WINDOWS and error.errno in (errno.EINVAL, errno.ENOENT) and error.filename:
|
||||
if any(len(part) > 255 for part in Path(error.filename).parts):
|
||||
parts.append(
|
||||
"HINT: This error might be caused by a file or folder name exceeding "
|
||||
"255 characters, which is a Windows limitation even if long paths "
|
||||
"are enabled.\n "
|
||||
)
|
||||
if len(error.filename) > 260:
|
||||
parts.append(
|
||||
"HINT: This error might have occurred since "
|
||||
"this system does not have Windows Long Path "
|
||||
"support enabled. You can find information on "
|
||||
"how to enable this at "
|
||||
"https://pip.pypa.io/warnings/enable-long-paths\n"
|
||||
)
|
||||
return "".join(parts).strip() + "\n"
|
||||
|
|
|
|||
|
|
@ -1,27 +1,24 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from collections.abc import Generator, Sequence
|
||||
from email.parser import Parser
|
||||
from optparse import Values
|
||||
from typing import TYPE_CHECKING, cast
|
||||
from typing import TYPE_CHECKING, Generator, List, Optional, Sequence, Tuple, cast
|
||||
|
||||
from pip._vendor.packaging.utils import canonicalize_name
|
||||
from pip._vendor.packaging.version import InvalidVersion, Version
|
||||
|
||||
from pip._internal.cli import cmdoptions
|
||||
from pip._internal.cli.index_command import IndexGroupCommand
|
||||
from pip._internal.cli.req_command import IndexGroupCommand
|
||||
from pip._internal.cli.status_codes import SUCCESS
|
||||
from pip._internal.exceptions import CommandError
|
||||
from pip._internal.index.collector import LinkCollector
|
||||
from pip._internal.index.package_finder import PackageFinder
|
||||
from pip._internal.metadata import BaseDistribution, get_environment
|
||||
from pip._internal.models.selection_prefs import SelectionPreferences
|
||||
from pip._internal.network.session import PipSession
|
||||
from pip._internal.utils.compat import stdlib_pkgs
|
||||
from pip._internal.utils.misc import tabulate, write_output
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pip._internal.index.package_finder import PackageFinder
|
||||
from pip._internal.network.session import PipSession
|
||||
from pip._internal.metadata.base import DistributionVersion
|
||||
|
||||
class _DistWithLatestInfo(BaseDistribution):
|
||||
"""Give the distribution object a couple of extra fields.
|
||||
|
|
@ -30,12 +27,14 @@ if TYPE_CHECKING:
|
|||
makes the rest of the code much cleaner.
|
||||
"""
|
||||
|
||||
latest_version: Version
|
||||
latest_version: DistributionVersion
|
||||
latest_filetype: str
|
||||
|
||||
_ProcessedDists = Sequence[_DistWithLatestInfo]
|
||||
|
||||
|
||||
from pip._vendor.packaging.version import parse
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
|
@ -129,7 +128,7 @@ class ListCommand(IndexGroupCommand):
|
|||
"--include-editable",
|
||||
action="store_true",
|
||||
dest="include_editable",
|
||||
help="Include editable package in output.",
|
||||
help="Include editable package from output.",
|
||||
default=True,
|
||||
)
|
||||
self.cmd_opts.add_option(cmdoptions.list_exclude())
|
||||
|
|
@ -138,20 +137,12 @@ class ListCommand(IndexGroupCommand):
|
|||
self.parser.insert_option_group(0, index_opts)
|
||||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
def handle_pip_version_check(self, options: Values) -> None:
|
||||
if options.outdated or options.uptodate:
|
||||
super().handle_pip_version_check(options)
|
||||
|
||||
def _build_package_finder(
|
||||
self, options: Values, session: PipSession
|
||||
) -> PackageFinder:
|
||||
"""
|
||||
Create a package finder appropriate to this list command.
|
||||
"""
|
||||
# Lazy import the heavy index modules as most list invocations won't need 'em.
|
||||
from pip._internal.index.collector import LinkCollector
|
||||
from pip._internal.index.package_finder import PackageFinder
|
||||
|
||||
link_collector = LinkCollector.create(session, options=options)
|
||||
|
||||
# Pass allow_yanked=False to ignore yanked versions.
|
||||
|
|
@ -165,7 +156,7 @@ class ListCommand(IndexGroupCommand):
|
|||
selection_prefs=selection_prefs,
|
||||
)
|
||||
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
if options.outdated and options.uptodate:
|
||||
raise CommandError("Options --outdated and --uptodate cannot be combined.")
|
||||
|
||||
|
|
@ -180,7 +171,7 @@ class ListCommand(IndexGroupCommand):
|
|||
if options.excludes:
|
||||
skip.update(canonicalize_name(n) for n in options.excludes)
|
||||
|
||||
packages: _ProcessedDists = [
|
||||
packages: "_ProcessedDists" = [
|
||||
cast("_DistWithLatestInfo", d)
|
||||
for d in get_environment(options.path).iter_installed_distributions(
|
||||
local_only=options.local,
|
||||
|
|
@ -207,26 +198,26 @@ class ListCommand(IndexGroupCommand):
|
|||
return SUCCESS
|
||||
|
||||
def get_outdated(
|
||||
self, packages: _ProcessedDists, options: Values
|
||||
) -> _ProcessedDists:
|
||||
self, packages: "_ProcessedDists", options: Values
|
||||
) -> "_ProcessedDists":
|
||||
return [
|
||||
dist
|
||||
for dist in self.iter_packages_latest_infos(packages, options)
|
||||
if dist.latest_version > dist.version
|
||||
if parse(str(dist.latest_version)) > parse(str(dist.version))
|
||||
]
|
||||
|
||||
def get_uptodate(
|
||||
self, packages: _ProcessedDists, options: Values
|
||||
) -> _ProcessedDists:
|
||||
self, packages: "_ProcessedDists", options: Values
|
||||
) -> "_ProcessedDists":
|
||||
return [
|
||||
dist
|
||||
for dist in self.iter_packages_latest_infos(packages, options)
|
||||
if dist.latest_version == dist.version
|
||||
if parse(str(dist.latest_version)) == parse(str(dist.version))
|
||||
]
|
||||
|
||||
def get_not_required(
|
||||
self, packages: _ProcessedDists, options: Values
|
||||
) -> _ProcessedDists:
|
||||
self, packages: "_ProcessedDists", options: Values
|
||||
) -> "_ProcessedDists":
|
||||
dep_keys = {
|
||||
canonicalize_name(dep.name)
|
||||
for dist in packages
|
||||
|
|
@ -239,14 +230,14 @@ class ListCommand(IndexGroupCommand):
|
|||
return list({pkg for pkg in packages if pkg.canonical_name not in dep_keys})
|
||||
|
||||
def iter_packages_latest_infos(
|
||||
self, packages: _ProcessedDists, options: Values
|
||||
) -> Generator[_DistWithLatestInfo, None, None]:
|
||||
self, packages: "_ProcessedDists", options: Values
|
||||
) -> Generator["_DistWithLatestInfo", None, None]:
|
||||
with self._build_session(options) as session:
|
||||
finder = self._build_package_finder(options, session)
|
||||
|
||||
def latest_info(
|
||||
dist: _DistWithLatestInfo,
|
||||
) -> _DistWithLatestInfo | None:
|
||||
dist: "_DistWithLatestInfo",
|
||||
) -> Optional["_DistWithLatestInfo"]:
|
||||
all_candidates = finder.find_all_candidates(dist.canonical_name)
|
||||
if not options.pre:
|
||||
# Remove prereleases
|
||||
|
|
@ -277,7 +268,7 @@ class ListCommand(IndexGroupCommand):
|
|||
yield dist
|
||||
|
||||
def output_package_listing(
|
||||
self, packages: _ProcessedDists, options: Values
|
||||
self, packages: "_ProcessedDists", options: Values
|
||||
) -> None:
|
||||
packages = sorted(
|
||||
packages,
|
||||
|
|
@ -288,19 +279,17 @@ class ListCommand(IndexGroupCommand):
|
|||
self.output_package_listing_columns(data, header)
|
||||
elif options.list_format == "freeze":
|
||||
for dist in packages:
|
||||
try:
|
||||
req_string = f"{dist.raw_name}=={dist.version}"
|
||||
except InvalidVersion:
|
||||
req_string = f"{dist.raw_name}==={dist.raw_version}"
|
||||
if options.verbose >= 1:
|
||||
write_output("%s (%s)", req_string, dist.location)
|
||||
write_output(
|
||||
"%s==%s (%s)", dist.raw_name, dist.version, dist.location
|
||||
)
|
||||
else:
|
||||
write_output(req_string)
|
||||
write_output("%s==%s", dist.raw_name, dist.version)
|
||||
elif options.list_format == "json":
|
||||
write_output(format_for_json(packages, options))
|
||||
|
||||
def output_package_listing_columns(
|
||||
self, data: list[list[str]], header: list[str]
|
||||
self, data: List[List[str]], header: List[str]
|
||||
) -> None:
|
||||
# insert the header first: we need to know the size of column names
|
||||
if len(data) > 0:
|
||||
|
|
@ -317,8 +306,8 @@ class ListCommand(IndexGroupCommand):
|
|||
|
||||
|
||||
def format_for_columns(
|
||||
pkgs: _ProcessedDists, options: Values
|
||||
) -> tuple[list[list[str]], list[str]]:
|
||||
pkgs: "_ProcessedDists", options: Values
|
||||
) -> Tuple[List[List[str]], List[str]]:
|
||||
"""
|
||||
Convert the package data into something usable
|
||||
by output_package_listing_columns.
|
||||
|
|
@ -329,40 +318,25 @@ def format_for_columns(
|
|||
if running_outdated:
|
||||
header.extend(["Latest", "Type"])
|
||||
|
||||
def wheel_build_tag(dist: BaseDistribution) -> str | None:
|
||||
try:
|
||||
wheel_file = dist.read_text("WHEEL")
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
return Parser().parsestr(wheel_file).get("Build")
|
||||
|
||||
build_tags = [wheel_build_tag(p) for p in pkgs]
|
||||
has_build_tags = any(build_tags)
|
||||
if has_build_tags:
|
||||
header.append("Build")
|
||||
has_editables = any(x.editable for x in pkgs)
|
||||
if has_editables:
|
||||
header.append("Editable project location")
|
||||
|
||||
if options.verbose >= 1:
|
||||
header.append("Location")
|
||||
if options.verbose >= 1:
|
||||
header.append("Installer")
|
||||
|
||||
has_editables = any(x.editable for x in pkgs)
|
||||
if has_editables:
|
||||
header.append("Editable project location")
|
||||
|
||||
data = []
|
||||
for i, proj in enumerate(pkgs):
|
||||
for proj in pkgs:
|
||||
# if we're working on the 'outdated' list, separate out the
|
||||
# latest_version and type
|
||||
row = [proj.raw_name, proj.raw_version]
|
||||
row = [proj.raw_name, str(proj.version)]
|
||||
|
||||
if running_outdated:
|
||||
row.append(str(proj.latest_version))
|
||||
row.append(proj.latest_filetype)
|
||||
|
||||
if has_build_tags:
|
||||
row.append(build_tags[i] or "")
|
||||
|
||||
if has_editables:
|
||||
row.append(proj.editable_project_location or "")
|
||||
|
||||
|
|
@ -376,16 +350,12 @@ def format_for_columns(
|
|||
return data, header
|
||||
|
||||
|
||||
def format_for_json(packages: _ProcessedDists, options: Values) -> str:
|
||||
def format_for_json(packages: "_ProcessedDists", options: Values) -> str:
|
||||
data = []
|
||||
for dist in packages:
|
||||
try:
|
||||
version = str(dist.version)
|
||||
except InvalidVersion:
|
||||
version = dist.raw_version
|
||||
info = {
|
||||
"name": dist.raw_name,
|
||||
"version": version,
|
||||
"version": str(dist.version),
|
||||
}
|
||||
if options.verbose >= 1:
|
||||
info["location"] = dist.location or ""
|
||||
|
|
|
|||
|
|
@ -1,167 +0,0 @@
|
|||
import sys
|
||||
from optparse import Values
|
||||
from pathlib import Path
|
||||
|
||||
from pip._internal.cache import WheelCache
|
||||
from pip._internal.cli import cmdoptions
|
||||
from pip._internal.cli.req_command import (
|
||||
RequirementCommand,
|
||||
with_cleanup,
|
||||
)
|
||||
from pip._internal.cli.status_codes import SUCCESS
|
||||
from pip._internal.models.pylock import Pylock, is_valid_pylock_file_name
|
||||
from pip._internal.operations.build.build_tracker import get_build_tracker
|
||||
from pip._internal.utils.logging import getLogger
|
||||
from pip._internal.utils.misc import (
|
||||
get_pip_version,
|
||||
)
|
||||
from pip._internal.utils.temp_dir import TempDirectory
|
||||
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
class LockCommand(RequirementCommand):
|
||||
"""
|
||||
EXPERIMENTAL - Lock packages and their dependencies from:
|
||||
|
||||
- PyPI (and other indexes) using requirement specifiers.
|
||||
- VCS project urls.
|
||||
- Local project directories.
|
||||
- Local or remote source archives.
|
||||
|
||||
pip also supports locking from "requirements files", which provide an easy
|
||||
way to specify a whole environment to be installed.
|
||||
|
||||
The generated lock file is only guaranteed to be valid for the current
|
||||
python version and platform.
|
||||
"""
|
||||
|
||||
usage = """
|
||||
%prog [options] [-e] <local project path> ...
|
||||
%prog [options] <requirement specifier> [package-index-options] ...
|
||||
%prog [options] -r <requirements file> [package-index-options] ...
|
||||
%prog [options] <archive url/path> ..."""
|
||||
|
||||
def add_options(self) -> None:
|
||||
self.cmd_opts.add_option(
|
||||
cmdoptions.PipOption(
|
||||
"--output",
|
||||
"-o",
|
||||
dest="output_file",
|
||||
metavar="path",
|
||||
type="path",
|
||||
default="pylock.toml",
|
||||
help="Lock file name (default=pylock.toml). Use - for stdout.",
|
||||
)
|
||||
)
|
||||
self.cmd_opts.add_option(cmdoptions.requirements())
|
||||
self.cmd_opts.add_option(cmdoptions.constraints())
|
||||
self.cmd_opts.add_option(cmdoptions.build_constraints())
|
||||
self.cmd_opts.add_option(cmdoptions.no_deps())
|
||||
self.cmd_opts.add_option(cmdoptions.pre())
|
||||
|
||||
self.cmd_opts.add_option(cmdoptions.editable())
|
||||
|
||||
self.cmd_opts.add_option(cmdoptions.src())
|
||||
|
||||
self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
|
||||
self.cmd_opts.add_option(cmdoptions.no_build_isolation())
|
||||
self.cmd_opts.add_option(cmdoptions.use_pep517())
|
||||
self.cmd_opts.add_option(cmdoptions.check_build_deps())
|
||||
|
||||
self.cmd_opts.add_option(cmdoptions.config_settings())
|
||||
|
||||
self.cmd_opts.add_option(cmdoptions.no_binary())
|
||||
self.cmd_opts.add_option(cmdoptions.only_binary())
|
||||
self.cmd_opts.add_option(cmdoptions.prefer_binary())
|
||||
self.cmd_opts.add_option(cmdoptions.require_hashes())
|
||||
self.cmd_opts.add_option(cmdoptions.progress_bar())
|
||||
|
||||
index_opts = cmdoptions.make_option_group(
|
||||
cmdoptions.index_group,
|
||||
self.parser,
|
||||
)
|
||||
|
||||
self.parser.insert_option_group(0, index_opts)
|
||||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
@with_cleanup
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
logger.verbose("Using %s", get_pip_version())
|
||||
|
||||
logger.warning(
|
||||
"pip lock is currently an experimental command. "
|
||||
"It may be removed/changed in a future release "
|
||||
"without prior warning."
|
||||
)
|
||||
|
||||
cmdoptions.check_build_constraints(options)
|
||||
|
||||
session = self.get_default_session(options)
|
||||
|
||||
finder = self._build_package_finder(
|
||||
options=options,
|
||||
session=session,
|
||||
ignore_requires_python=options.ignore_requires_python,
|
||||
)
|
||||
build_tracker = self.enter_context(get_build_tracker())
|
||||
|
||||
directory = TempDirectory(
|
||||
delete=not options.no_clean,
|
||||
kind="install",
|
||||
globally_managed=True,
|
||||
)
|
||||
|
||||
reqs = self.get_requirements(args, options, finder, session)
|
||||
|
||||
wheel_cache = WheelCache(options.cache_dir)
|
||||
|
||||
# Only when installing is it permitted to use PEP 660.
|
||||
# In other circumstances (pip wheel, pip download) we generate
|
||||
# regular (i.e. non editable) metadata and wheels.
|
||||
for req in reqs:
|
||||
req.permit_editable_wheels = True
|
||||
|
||||
preparer = self.make_requirement_preparer(
|
||||
temp_build_dir=directory,
|
||||
options=options,
|
||||
build_tracker=build_tracker,
|
||||
session=session,
|
||||
finder=finder,
|
||||
use_user_site=False,
|
||||
verbosity=self.verbosity,
|
||||
)
|
||||
resolver = self.make_resolver(
|
||||
preparer=preparer,
|
||||
finder=finder,
|
||||
options=options,
|
||||
wheel_cache=wheel_cache,
|
||||
use_user_site=False,
|
||||
ignore_installed=True,
|
||||
ignore_requires_python=options.ignore_requires_python,
|
||||
upgrade_strategy="to-satisfy-only",
|
||||
)
|
||||
|
||||
self.trace_basic_info(finder)
|
||||
|
||||
requirement_set = resolver.resolve(reqs, check_supported_wheels=True)
|
||||
|
||||
if options.output_file == "-":
|
||||
base_dir = Path.cwd()
|
||||
else:
|
||||
output_file_path = Path(options.output_file)
|
||||
if not is_valid_pylock_file_name(output_file_path):
|
||||
logger.warning(
|
||||
"%s is not a valid lock file name.",
|
||||
output_file_path,
|
||||
)
|
||||
base_dir = output_file_path.parent
|
||||
pylock_toml = Pylock.from_install_requirements(
|
||||
requirement_set.requirements.values(), base_dir=base_dir
|
||||
).as_toml()
|
||||
if options.output_file == "-":
|
||||
sys.stdout.write(pylock_toml)
|
||||
else:
|
||||
output_file_path.write_text(pylock_toml, encoding="utf-8")
|
||||
|
||||
return SUCCESS
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import shutil
|
||||
import sys
|
||||
|
|
@ -7,7 +5,7 @@ import textwrap
|
|||
import xmlrpc.client
|
||||
from collections import OrderedDict
|
||||
from optparse import Values
|
||||
from typing import TypedDict
|
||||
from typing import TYPE_CHECKING, Dict, List, Optional
|
||||
|
||||
from pip._vendor.packaging.version import parse as parse_version
|
||||
|
||||
|
|
@ -16,17 +14,18 @@ from pip._internal.cli.req_command import SessionCommandMixin
|
|||
from pip._internal.cli.status_codes import NO_MATCHES_FOUND, SUCCESS
|
||||
from pip._internal.exceptions import CommandError
|
||||
from pip._internal.metadata import get_default_environment
|
||||
from pip._internal.metadata.base import BaseDistribution
|
||||
from pip._internal.models.index import PyPI
|
||||
from pip._internal.network.xmlrpc import PipXmlrpcTransport
|
||||
from pip._internal.utils.logging import indent_log
|
||||
from pip._internal.utils.misc import write_output
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import TypedDict
|
||||
|
||||
class TransformedHit(TypedDict):
|
||||
name: str
|
||||
summary: str
|
||||
versions: list[str]
|
||||
class TransformedHit(TypedDict):
|
||||
name: str
|
||||
summary: str
|
||||
versions: List[str]
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -51,7 +50,7 @@ class SearchCommand(Command, SessionCommandMixin):
|
|||
|
||||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
if not args:
|
||||
raise CommandError("Missing required argument (search query).")
|
||||
query = args
|
||||
|
|
@ -67,7 +66,7 @@ class SearchCommand(Command, SessionCommandMixin):
|
|||
return SUCCESS
|
||||
return NO_MATCHES_FOUND
|
||||
|
||||
def search(self, query: list[str], options: Values) -> list[dict[str, str]]:
|
||||
def search(self, query: List[str], options: Values) -> List[Dict[str, str]]:
|
||||
index_url = options.index
|
||||
|
||||
session = self.get_default_session(options)
|
||||
|
|
@ -77,21 +76,22 @@ class SearchCommand(Command, SessionCommandMixin):
|
|||
try:
|
||||
hits = pypi.search({"name": query, "summary": query}, "or")
|
||||
except xmlrpc.client.Fault as fault:
|
||||
message = (
|
||||
f"XMLRPC request failed [code: {fault.faultCode}]\n{fault.faultString}"
|
||||
message = "XMLRPC request failed [code: {code}]\n{string}".format(
|
||||
code=fault.faultCode,
|
||||
string=fault.faultString,
|
||||
)
|
||||
raise CommandError(message)
|
||||
assert isinstance(hits, list)
|
||||
return hits
|
||||
|
||||
|
||||
def transform_hits(hits: list[dict[str, str]]) -> list[TransformedHit]:
|
||||
def transform_hits(hits: List[Dict[str, str]]) -> List["TransformedHit"]:
|
||||
"""
|
||||
The list from pypi is really a list of versions. We want a list of
|
||||
packages with the list of versions stored inline. This converts the
|
||||
list from pypi into one we can use.
|
||||
"""
|
||||
packages: dict[str, TransformedHit] = OrderedDict()
|
||||
packages: Dict[str, "TransformedHit"] = OrderedDict()
|
||||
for hit in hits:
|
||||
name = hit["name"]
|
||||
summary = hit["summary"]
|
||||
|
|
@ -113,7 +113,9 @@ def transform_hits(hits: list[dict[str, str]]) -> list[TransformedHit]:
|
|||
return list(packages.values())
|
||||
|
||||
|
||||
def print_dist_installation_info(latest: str, dist: BaseDistribution | None) -> None:
|
||||
def print_dist_installation_info(name: str, latest: str) -> None:
|
||||
env = get_default_environment()
|
||||
dist = env.get_distribution(name)
|
||||
if dist is not None:
|
||||
with indent_log():
|
||||
if dist.version == latest:
|
||||
|
|
@ -130,15 +132,10 @@ def print_dist_installation_info(latest: str, dist: BaseDistribution | None) ->
|
|||
write_output("LATEST: %s", latest)
|
||||
|
||||
|
||||
def get_installed_distribution(name: str) -> BaseDistribution | None:
|
||||
env = get_default_environment()
|
||||
return env.get_distribution(name)
|
||||
|
||||
|
||||
def print_results(
|
||||
hits: list[TransformedHit],
|
||||
name_column_width: int | None = None,
|
||||
terminal_width: int | None = None,
|
||||
hits: List["TransformedHit"],
|
||||
name_column_width: Optional[int] = None,
|
||||
terminal_width: Optional[int] = None,
|
||||
) -> None:
|
||||
if not hits:
|
||||
return
|
||||
|
|
@ -168,11 +165,10 @@ def print_results(
|
|||
line = f"{name_latest:{name_column_width}} - {summary}"
|
||||
try:
|
||||
write_output(line)
|
||||
dist = get_installed_distribution(name)
|
||||
print_dist_installation_info(latest, dist)
|
||||
print_dist_installation_info(name, latest)
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
|
||||
|
||||
def highest_version(versions: list[str]) -> str:
|
||||
def highest_version(versions: List[str]) -> str:
|
||||
return max(versions, key=parse_version)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import string
|
||||
from collections.abc import Generator, Iterable, Iterator
|
||||
from optparse import Values
|
||||
from typing import NamedTuple
|
||||
from typing import Generator, Iterable, Iterator, List, NamedTuple, Optional
|
||||
|
||||
from pip._vendor.packaging.requirements import InvalidRequirement
|
||||
from pip._vendor.packaging.utils import canonicalize_name
|
||||
|
||||
from pip._internal.cli.base_command import Command
|
||||
|
|
@ -17,13 +12,6 @@ from pip._internal.utils.misc import write_output
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def normalize_project_url_label(label: str) -> str:
|
||||
# This logic is from PEP 753 (Well-known Project URLs in Metadata).
|
||||
chars_to_remove = string.punctuation + string.whitespace
|
||||
removal_map = str.maketrans("", "", chars_to_remove)
|
||||
return label.translate(removal_map).lower()
|
||||
|
||||
|
||||
class ShowCommand(Command):
|
||||
"""
|
||||
Show information about one or more installed packages.
|
||||
|
|
@ -47,7 +35,7 @@ class ShowCommand(Command):
|
|||
|
||||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
if not args:
|
||||
logger.warning("ERROR: Please provide a package name or names.")
|
||||
return ERROR
|
||||
|
|
@ -65,24 +53,23 @@ class _PackageInfo(NamedTuple):
|
|||
name: str
|
||||
version: str
|
||||
location: str
|
||||
editable_project_location: str | None
|
||||
requires: list[str]
|
||||
required_by: list[str]
|
||||
editable_project_location: Optional[str]
|
||||
requires: List[str]
|
||||
required_by: List[str]
|
||||
installer: str
|
||||
metadata_version: str
|
||||
classifiers: list[str]
|
||||
classifiers: List[str]
|
||||
summary: str
|
||||
homepage: str
|
||||
project_urls: list[str]
|
||||
project_urls: List[str]
|
||||
author: str
|
||||
author_email: str
|
||||
license: str
|
||||
license_expression: str
|
||||
entry_points: list[str]
|
||||
files: list[str] | None
|
||||
entry_points: List[str]
|
||||
files: Optional[List[str]]
|
||||
|
||||
|
||||
def search_packages_info(query: list[str]) -> Generator[_PackageInfo, None, None]:
|
||||
def search_packages_info(query: List[str]) -> Generator[_PackageInfo, None, None]:
|
||||
"""
|
||||
Gather details from installed distributions. Print distribution name,
|
||||
version, location, and installed files. Installed files requires a
|
||||
|
|
@ -113,19 +100,8 @@ def search_packages_info(query: list[str]) -> Generator[_PackageInfo, None, None
|
|||
except KeyError:
|
||||
continue
|
||||
|
||||
try:
|
||||
requires = sorted(
|
||||
# Avoid duplicates in requirements (e.g. due to environment markers).
|
||||
{req.name for req in dist.iter_dependencies()},
|
||||
key=str.lower,
|
||||
)
|
||||
except InvalidRequirement:
|
||||
requires = sorted(dist.iter_raw_dependencies(), key=str.lower)
|
||||
|
||||
try:
|
||||
required_by = sorted(_get_requiring_packages(dist), key=str.lower)
|
||||
except InvalidRequirement:
|
||||
required_by = ["#N/A"]
|
||||
requires = sorted((req.name for req in dist.iter_dependencies()), key=str.lower)
|
||||
required_by = sorted(_get_requiring_packages(dist), key=str.lower)
|
||||
|
||||
try:
|
||||
entry_points_text = dist.read_text("entry_points.txt")
|
||||
|
|
@ -135,27 +111,15 @@ def search_packages_info(query: list[str]) -> Generator[_PackageInfo, None, None
|
|||
|
||||
files_iter = dist.iter_declared_entries()
|
||||
if files_iter is None:
|
||||
files: list[str] | None = None
|
||||
files: Optional[List[str]] = None
|
||||
else:
|
||||
files = sorted(files_iter)
|
||||
|
||||
metadata = dist.metadata
|
||||
|
||||
project_urls = metadata.get_all("Project-URL", [])
|
||||
homepage = metadata.get("Home-page", "")
|
||||
if not homepage:
|
||||
# It's common that there is a "homepage" Project-URL, but Home-page
|
||||
# remains unset (especially as PEP 621 doesn't surface the field).
|
||||
for url in project_urls:
|
||||
url_label, url = url.split(",", maxsplit=1)
|
||||
normalized_label = normalize_project_url_label(url_label)
|
||||
if normalized_label == "homepage":
|
||||
homepage = url.strip()
|
||||
break
|
||||
|
||||
yield _PackageInfo(
|
||||
name=dist.raw_name,
|
||||
version=dist.raw_version,
|
||||
version=str(dist.version),
|
||||
location=dist.location or "",
|
||||
editable_project_location=dist.editable_project_location,
|
||||
requires=requires,
|
||||
|
|
@ -164,12 +128,11 @@ def search_packages_info(query: list[str]) -> Generator[_PackageInfo, None, None
|
|||
metadata_version=dist.metadata_version or "",
|
||||
classifiers=metadata.get_all("Classifier", []),
|
||||
summary=metadata.get("Summary", ""),
|
||||
homepage=homepage,
|
||||
project_urls=project_urls,
|
||||
homepage=metadata.get("Home-page", ""),
|
||||
project_urls=metadata.get_all("Project-URL", []),
|
||||
author=metadata.get("Author", ""),
|
||||
author_email=metadata.get("Author-email", ""),
|
||||
license=metadata.get("License", ""),
|
||||
license_expression=metadata.get("License-Expression", ""),
|
||||
entry_points=entry_points,
|
||||
files=files,
|
||||
)
|
||||
|
|
@ -189,18 +152,13 @@ def print_results(
|
|||
if i > 0:
|
||||
write_output("---")
|
||||
|
||||
metadata_version_tuple = tuple(map(int, dist.metadata_version.split(".")))
|
||||
|
||||
write_output("Name: %s", dist.name)
|
||||
write_output("Version: %s", dist.version)
|
||||
write_output("Summary: %s", dist.summary)
|
||||
write_output("Home-page: %s", dist.homepage)
|
||||
write_output("Author: %s", dist.author)
|
||||
write_output("Author-email: %s", dist.author_email)
|
||||
if metadata_version_tuple >= (2, 4) and dist.license_expression:
|
||||
write_output("License-Expression: %s", dist.license_expression)
|
||||
else:
|
||||
write_output("License: %s", dist.license)
|
||||
write_output("License: %s", dist.license)
|
||||
write_output("Location: %s", dist.location)
|
||||
if dist.editable_project_location is not None:
|
||||
write_output(
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import logging
|
||||
from optparse import Values
|
||||
from typing import List
|
||||
|
||||
from pip._vendor.packaging.utils import canonicalize_name
|
||||
|
||||
from pip._internal.cli import cmdoptions
|
||||
from pip._internal.cli.base_command import Command
|
||||
from pip._internal.cli.index_command import SessionCommandMixin
|
||||
from pip._internal.cli.req_command import SessionCommandMixin, warn_if_run_as_root
|
||||
from pip._internal.cli.status_codes import SUCCESS
|
||||
from pip._internal.exceptions import InstallationError
|
||||
from pip._internal.req import parse_requirements
|
||||
|
|
@ -16,7 +17,6 @@ from pip._internal.req.constructors import (
|
|||
from pip._internal.utils.misc import (
|
||||
check_externally_managed,
|
||||
protect_pip_from_modification_on_windows,
|
||||
warn_if_run_as_root,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -61,7 +61,7 @@ class UninstallCommand(Command, SessionCommandMixin):
|
|||
self.cmd_opts.add_option(cmdoptions.override_externally_managed())
|
||||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
session = self.get_default_session(options)
|
||||
|
||||
reqs_to_uninstall = {}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import logging
|
|||
import os
|
||||
import shutil
|
||||
from optparse import Values
|
||||
from typing import List
|
||||
|
||||
from pip._internal.cache import WheelCache
|
||||
from pip._internal.cli import cmdoptions
|
||||
|
|
@ -11,10 +12,11 @@ from pip._internal.exceptions import CommandError
|
|||
from pip._internal.operations.build.build_tracker import get_build_tracker
|
||||
from pip._internal.req.req_install import (
|
||||
InstallRequirement,
|
||||
check_legacy_setup_py_options,
|
||||
)
|
||||
from pip._internal.utils.misc import ensure_dir, normalize_path
|
||||
from pip._internal.utils.temp_dir import TempDirectory
|
||||
from pip._internal.wheel_builder import build
|
||||
from pip._internal.wheel_builder import build, should_build_for_wheel_command
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -56,9 +58,9 @@ class WheelCommand(RequirementCommand):
|
|||
self.cmd_opts.add_option(cmdoptions.prefer_binary())
|
||||
self.cmd_opts.add_option(cmdoptions.no_build_isolation())
|
||||
self.cmd_opts.add_option(cmdoptions.use_pep517())
|
||||
self.cmd_opts.add_option(cmdoptions.no_use_pep517())
|
||||
self.cmd_opts.add_option(cmdoptions.check_build_deps())
|
||||
self.cmd_opts.add_option(cmdoptions.constraints())
|
||||
self.cmd_opts.add_option(cmdoptions.build_constraints())
|
||||
self.cmd_opts.add_option(cmdoptions.editable())
|
||||
self.cmd_opts.add_option(cmdoptions.requirements())
|
||||
self.cmd_opts.add_option(cmdoptions.src())
|
||||
|
|
@ -75,6 +77,8 @@ class WheelCommand(RequirementCommand):
|
|||
)
|
||||
|
||||
self.cmd_opts.add_option(cmdoptions.config_settings())
|
||||
self.cmd_opts.add_option(cmdoptions.build_options())
|
||||
self.cmd_opts.add_option(cmdoptions.global_options())
|
||||
|
||||
self.cmd_opts.add_option(
|
||||
"--pre",
|
||||
|
|
@ -97,9 +101,7 @@ class WheelCommand(RequirementCommand):
|
|||
self.parser.insert_option_group(0, self.cmd_opts)
|
||||
|
||||
@with_cleanup
|
||||
def run(self, options: Values, args: list[str]) -> int:
|
||||
cmdoptions.check_build_constraints(options)
|
||||
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
session = self.get_default_session(options)
|
||||
|
||||
finder = self._build_package_finder(options, session)
|
||||
|
|
@ -116,6 +118,7 @@ class WheelCommand(RequirementCommand):
|
|||
)
|
||||
|
||||
reqs = self.get_requirements(args, options, finder, session)
|
||||
check_legacy_setup_py_options(options, reqs)
|
||||
|
||||
wheel_cache = WheelCache(options.cache_dir)
|
||||
|
||||
|
|
@ -136,26 +139,30 @@ class WheelCommand(RequirementCommand):
|
|||
options=options,
|
||||
wheel_cache=wheel_cache,
|
||||
ignore_requires_python=options.ignore_requires_python,
|
||||
use_pep517=options.use_pep517,
|
||||
)
|
||||
|
||||
self.trace_basic_info(finder)
|
||||
|
||||
requirement_set = resolver.resolve(reqs, check_supported_wheels=True)
|
||||
|
||||
preparer.prepare_linked_requirements_more(requirement_set.requirements.values())
|
||||
|
||||
reqs_to_build: list[InstallRequirement] = []
|
||||
reqs_to_build: List[InstallRequirement] = []
|
||||
for req in requirement_set.requirements.values():
|
||||
if req.is_wheel:
|
||||
preparer.save_linked_requirement(req)
|
||||
else:
|
||||
elif should_build_for_wheel_command(req):
|
||||
reqs_to_build.append(req)
|
||||
|
||||
preparer.prepare_linked_requirements_more(requirement_set.requirements.values())
|
||||
requirement_set.warn_legacy_versions_and_specifiers()
|
||||
|
||||
# build wheels
|
||||
build_successes, build_failures = build(
|
||||
reqs_to_build,
|
||||
wheel_cache=wheel_cache,
|
||||
verify=(not options.no_verify),
|
||||
build_options=options.build_options or [],
|
||||
global_options=options.global_options or [],
|
||||
)
|
||||
for req in build_successes:
|
||||
assert req.link and req.link.is_wheel
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue