diff options
Diffstat (limited to 'venv/lib/python3.11/site-packages/pip/_internal/commands')
36 files changed, 3409 insertions, 0 deletions
| diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__init__.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/__init__.py new file mode 100644 index 0000000..858a410 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__init__.py @@ -0,0 +1,132 @@ +""" +Package containing all pip commands +""" + +import importlib +from collections import namedtuple +from typing import Any, Dict, Optional + +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.", +    ), +    "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) -> Optional[str]: +    """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 diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-311.pycBinary files differ new file mode 100644 index 0000000..a6dc288 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/cache.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/cache.cpython-311.pycBinary files differ new file mode 100644 index 0000000..f0a8329 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/cache.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/check.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/check.cpython-311.pycBinary files differ new file mode 100644 index 0000000..25a1351 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/check.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/completion.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/completion.cpython-311.pycBinary files differ new file mode 100644 index 0000000..bde80a0 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/completion.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-311.pycBinary files differ new file mode 100644 index 0000000..ddef073 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/debug.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/debug.cpython-311.pycBinary files differ new file mode 100644 index 0000000..cd6954d --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/debug.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/download.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/download.cpython-311.pycBinary files differ new file mode 100644 index 0000000..d0a2f02 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/download.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-311.pycBinary files differ new file mode 100644 index 0000000..399e976 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/hash.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/hash.cpython-311.pycBinary files differ new file mode 100644 index 0000000..6abf8bc --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/hash.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/help.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/help.cpython-311.pycBinary files differ new file mode 100644 index 0000000..4d3eb4e --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/help.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/index.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/index.cpython-311.pycBinary files differ new file mode 100644 index 0000000..6493e2d --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/index.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-311.pycBinary files differ new file mode 100644 index 0000000..5b8c2f9 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/install.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/install.cpython-311.pycBinary files differ new file mode 100644 index 0000000..121e229 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/install.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/list.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/list.cpython-311.pycBinary files differ new file mode 100644 index 0000000..22c139e --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/list.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/search.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/search.cpython-311.pycBinary files differ new file mode 100644 index 0000000..481a62f --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/search.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/show.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/show.cpython-311.pycBinary files differ new file mode 100644 index 0000000..a733863 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/show.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-311.pycBinary files differ new file mode 100644 index 0000000..a940a04 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-311.pyc b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-311.pycBinary files differ new file mode 100644 index 0000000..cbe067f --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-311.pyc diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/cache.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/cache.py new file mode 100644 index 0000000..3283361 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/cache.py @@ -0,0 +1,225 @@ +import os +import textwrap +from optparse import Values +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 + +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 run(self, options: Values, args: List[str]) -> int: +        handlers = { +            "dir": self.get_cache_dir, +            "info": self.get_cache_info, +            "list": self.list_cache_items, +            "remove": self.remove_cache_items, +            "purge": self.purge_cache, +        } + +        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 handlers: +            logger.error( +                "Need an action (%s) to perform.", +                ", ".join(sorted(handlers)), +            ) +            return ERROR + +        action = args[0] + +        # Error handling happens here, not in the action-handlers. +        try: +            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[Any]) -> None: +        if args: +            raise CommandError("Too many arguments") + +        logger.info(options.cache_dir) + +    def get_cache_info(self, options: Values, args: List[Any]) -> 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[Any]) -> 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[Any]) -> 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) + +        for filename in files: +            os.unlink(filename) +            logger.verbose("Removed %s", filename) +        logger.info("Files removed: %s", len(files)) + +    def purge_cache(self, options: Values, args: List[Any]) -> 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) diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/check.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/check.py new file mode 100644 index 0000000..5efd0a3 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/check.py @@ -0,0 +1,54 @@ +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.operations.check import ( +    check_package_set, +    create_package_set_from_installed, +    warn_legacy_versions_and_specifiers, +) +from pip._internal.utils.misc import write_output + +logger = logging.getLogger(__name__) + + +class CheckCommand(Command): +    """Verify installed packages have compatible dependencies.""" + +    usage = """ +      %prog [options]""" + +    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) + +        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, +                ) + +        if missing or conflicting or parsing_probs: +            return ERROR +        else: +            write_output("No broken requirements found.") +            return SUCCESS diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/completion.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/completion.py new file mode 100644 index 0000000..9e89e27 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/completion.py @@ -0,0 +1,130 @@ +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 +from pip._internal.utils.misc import get_prog + +BASE_COMPLETION = """ +# pip {shell} completion start{script}# pip {shell} completion end +""" + +COMPLETION_SCRIPTS = { +    "bash": """ +        _pip_completion() +        {{ +            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 -o) "" +            set -lx COMP_CWORD ( \\ +                math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\ +            ) +            set -lx PIP_AUTO_COMPLETE 1 +            string split \\  -- (eval $COMP_WORDS[1]) +        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 diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/configuration.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/configuration.py new file mode 100644 index 0000000..1a1dc6b --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/configuration.py @@ -0,0 +1,280 @@ +import logging +import os +import subprocess +from optparse import Values +from typing import Any, List, Optional + +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 run(self, options: Values, args: List[str]) -> int: +        handlers = { +            "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, +        } + +        # Determine action +        if not args or args[0] not in handlers: +            logger.error( +                "Need an action (%s) to perform.", +                ", ".join(sorted(handlers)), +            ) +            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: +            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) -> Optional[Kind]: +        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()): +            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) + +    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(): +                write_output("%s: %s", name, value) + +    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.") diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/debug.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/debug.py new file mode 100644 index 0000000..7e5271c --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/debug.py @@ -0,0 +1,201 @@ +import importlib.resources +import locale +import logging +import os +import sys +from optparse import Values +from types import ModuleType +from typing import Any, Dict, List, Optional + +import pip._vendor +from pip._vendor.certifi import where +from pip._vendor.packaging.version import parse as parse_version + +from pip._internal.cli import cmdoptions +from pip._internal.cli.base_command import Command +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.logging import indent_log +from pip._internal.utils.misc import get_pip_version + +logger = logging.getLogger(__name__) + + +def show_value(name: str, value: Any) -> None: +    logger.info("%s: %s", name, value) + + +def show_sys_implementation() -> None: +    logger.info("sys.implementation:") +    implementation_name = sys.implementation.name +    with indent_log(): +        show_value("name", implementation_name) + + +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 = [ +            line.strip().split(" ", 1)[0] for line in f.readlines() if "==" in line +        ] + +    # Transform into "module" -> version dict. +    return dict(line.split("==", 1) for line in lines) + + +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. +    if module_name == "setuptools": +        module_name = "pkg_resources" + +    try: +        __import__(f"pip._vendor.{module_name}", globals(), locals(), level=0) +        return getattr(pip._vendor, module_name) +    except ImportError: +        # We allow 'truststore' to fail to import due +        # to being unavailable on Python 3.9 and earlier. +        if module_name == "truststore" and sys.version_info < (3, 10): +            return None +        raise + + +def get_vendor_version_from_module(module_name: str) -> Optional[str]: +    module = get_module_from_module_name(module_name) +    version = getattr(module, "__version__", None) + +    if module and not version: +        # Try to find version in debundled module info. +        assert module.__file__ is not None +        env = get_environment([os.path.dirname(module.__file__)]) +        dist = env.get_distribution(module_name) +        if dist: +            version = str(dist.version) + +    return version + + +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. +    """ +    for module_name, expected_version in vendor_txt_versions.items(): +        extra_message = "" +        actual_version = get_vendor_version_from_module(module_name) +        if not actual_version: +            extra_message = ( +                " (Unable to locate actual module version, using" +                " vendor.txt specified version)" +            ) +            actual_version = expected_version +        elif parse_version(actual_version) != parse_version(expected_version): +            extra_message = ( +                " (CONFLICT: vendor.txt suggests version should" +                f" be {expected_version})" +            ) +        logger.info("%s==%s%s", module_name, actual_version, extra_message) + + +def show_vendor_versions() -> None: +    logger.info("vendored library versions:") + +    vendor_txt_versions = create_vendor_txt_map() +    with indent_log(): +        show_actual_vendor_versions(vendor_txt_versions) + + +def show_tags(options: Values) -> None: +    tag_limit = 10 + +    target_python = make_target_python(options) +    tags = target_python.get_sorted_tags() + +    # Display the target options that were explicitly provided. +    formatted_target = target_python.format_given() +    suffix = "" +    if formatted_target: +        suffix = f" (target: {formatted_target})" + +    msg = f"Compatible tags: {len(tags)}{suffix}" +    logger.info(msg) + +    if options.verbose < 1 and len(tags) > tag_limit: +        tags_limited = True +        tags = tags[:tag_limit] +    else: +        tags_limited = False + +    with indent_log(): +        for tag in tags: +            logger.info(str(tag)) + +        if tags_limited: +            msg = f"...\n[First {tag_limit} tags shown. Pass --verbose to show all.]" +            logger.info(msg) + + +def ca_bundle_info(config: Configuration) -> str: +    levels = {key.split(".", 1)[0] for key, _ in config.items()} +    if not levels: +        return "Not specified" + +    levels_that_override_global = ["install", "wheel", "download"] +    global_overriding_level = [ +        level for level in levels if level in levels_that_override_global +    ] +    if not global_overriding_level: +        return "global" + +    if "global" in levels: +        levels.remove("global") +    return ", ".join(levels) + + +class DebugCommand(Command): +    """ +    Display debug information. +    """ + +    usage = """ +      %prog <options>""" +    ignore_require_venv = True + +    def add_options(self) -> None: +        cmdoptions.add_target_python_options(self.cmd_opts) +        self.parser.insert_option_group(0, self.cmd_opts) +        self.parser.config.load() + +    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 " +            "details, since the output and options of this command may " +            "change without notice." +        ) +        show_value("pip version", get_pip_version()) +        show_value("sys.version", sys.version) +        show_value("sys.executable", sys.executable) +        show_value("sys.getdefaultencoding", sys.getdefaultencoding()) +        show_value("sys.getfilesystemencoding", sys.getfilesystemencoding()) +        show_value( +            "locale.getpreferredencoding", +            locale.getpreferredencoding(), +        ) +        show_value("sys.platform", sys.platform) +        show_sys_implementation() + +        show_value("'cert' config value", ca_bundle_info(self.parser.config)) +        show_value("REQUESTS_CA_BUNDLE", os.environ.get("REQUESTS_CA_BUNDLE")) +        show_value("CURL_CA_BUNDLE", os.environ.get("CURL_CA_BUNDLE")) +        show_value("pip._vendor.certifi.where()", where()) +        show_value("pip._vendor.DEBUNDLED", pip._vendor.DEBUNDLED) + +        show_vendor_versions() + +        show_tags(options) + +        return SUCCESS diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/download.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/download.py new file mode 100644 index 0000000..54247a7 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/download.py @@ -0,0 +1,147 @@ +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 + +logger = logging.getLogger(__name__) + + +class DownloadCommand(RequirementCommand): +    """ +    Download packages from: + +    - PyPI (and other indexes) using requirement specifiers. +    - VCS project urls. +    - Local project directories. +    - Local or remote source archives. + +    pip also supports downloading from "requirements files", which provide +    an easy way to specify a whole environment to be downloaded. +    """ + +    usage = """ +      %prog [options] <requirement specifier> [package-index-options] ... +      %prog [options] -r <requirements file> [package-index-options] ... +      %prog [options] <vcs project url> ... +      %prog [options] <local project path> ... +      %prog [options] <archive url/path> ...""" + +    def add_options(self) -> None: +        self.cmd_opts.add_option(cmdoptions.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()) +        self.cmd_opts.add_option(cmdoptions.src()) +        self.cmd_opts.add_option(cmdoptions.pre()) +        self.cmd_opts.add_option(cmdoptions.require_hashes()) +        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()) + +        self.cmd_opts.add_option( +            "-d", +            "--dest", +            "--destination-dir", +            "--destination-directory", +            dest="download_dir", +            metavar="dir", +            default=os.curdir, +            help="Download packages into <dir>.", +        ) + +        cmdoptions.add_target_python_options(self.cmd_opts) + +        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: +        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) + +        options.download_dir = normalize_path(options.download_dir) +        ensure_dir(options.download_dir) + +        session = self.get_default_session(options) + +        target_python = make_target_python(options) +        finder = self._build_package_finder( +            options=options, +            session=session, +            target_python=target_python, +            ignore_requires_python=options.ignore_requires_python, +        ) + +        build_tracker = self.enter_context(get_build_tracker()) + +        directory = TempDirectory( +            delete=not options.no_clean, +            kind="download", +            globally_managed=True, +        ) + +        reqs = self.get_requirements(args, options, finder, session) +        check_legacy_setup_py_options(options, reqs) + +        preparer = self.make_requirement_preparer( +            temp_build_dir=directory, +            options=options, +            build_tracker=build_tracker, +            session=session, +            finder=finder, +            download_dir=options.download_dir, +            use_user_site=False, +            verbosity=self.verbosity, +        ) + +        resolver = self.make_resolver( +            preparer=preparer, +            finder=finder, +            options=options, +            ignore_requires_python=options.ignore_requires_python, +            use_pep517=options.use_pep517, +            py_version_info=options.python_version, +        ) + +        self.trace_basic_info(finder) + +        requirement_set = resolver.resolve(reqs, check_supported_wheels=True) + +        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)) + +        return SUCCESS diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/freeze.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/freeze.py new file mode 100644 index 0000000..fd9d88a --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/freeze.py @@ -0,0 +1,108 @@ +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 +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.operations.freeze import freeze +from pip._internal.utils.compat import stdlib_pkgs + + +def _should_suppress_build_backends() -> bool: +    return sys.version_info < (3, 12) + + +def _dev_pkgs() -> AbstractSet[str]: +    pkgs = {"pip"} + +    if _should_suppress_build_backends(): +        pkgs |= {"setuptools", "distribute", "wheel"} + +    return pkgs + + +class FreezeCommand(Command): +    """ +    Output installed packages in requirements format. + +    packages are listed in a case-insensitive sorted order. +    """ + +    usage = """ +      %prog [options]""" +    log_streams = ("ext://sys.stderr", "ext://sys.stderr") + +    def add_options(self) -> None: +        self.cmd_opts.add_option( +            "-r", +            "--requirement", +            dest="requirements", +            action="append", +            default=[], +            metavar="file", +            help=( +                "Use the order in the given requirements file and its " +                "comments when generating output. This option can be " +                "used multiple times." +            ), +        ) +        self.cmd_opts.add_option( +            "-l", +            "--local", +            dest="local", +            action="store_true", +            default=False, +            help=( +                "If in a virtualenv that has global access, do not output " +                "globally-installed packages." +            ), +        ) +        self.cmd_opts.add_option( +            "--user", +            dest="user", +            action="store_true", +            default=False, +            help="Only output packages installed in user-site.", +        ) +        self.cmd_opts.add_option(cmdoptions.list_path()) +        self.cmd_opts.add_option( +            "--all", +            dest="freeze_all", +            action="store_true", +            help=( +                "Do not skip these packages in the output:" +                " {}".format(", ".join(_dev_pkgs())) +            ), +        ) +        self.cmd_opts.add_option( +            "--exclude-editable", +            dest="exclude_editable", +            action="store_true", +            help="Exclude editable package from output.", +        ) +        self.cmd_opts.add_option(cmdoptions.list_exclude()) + +        self.parser.insert_option_group(0, self.cmd_opts) + +    def run(self, options: Values, args: List[str]) -> int: +        skip = set(stdlib_pkgs) +        if not options.freeze_all: +            skip.update(_dev_pkgs()) + +        if options.excludes: +            skip.update(options.excludes) + +        cmdoptions.check_list_path_option(options) + +        for line in freeze( +            requirement=options.requirements, +            local_only=options.local, +            user_only=options.user, +            paths=options.path, +            isolated=options.isolated_mode, +            skip=skip, +            exclude_editable=options.exclude_editable, +        ): +            sys.stdout.write(line + "\n") +        return SUCCESS diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/hash.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/hash.py new file mode 100644 index 0000000..042dac8 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/hash.py @@ -0,0 +1,59 @@ +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 +from pip._internal.utils.hashes import FAVORITE_HASH, STRONG_HASHES +from pip._internal.utils.misc import read_chunks, write_output + +logger = logging.getLogger(__name__) + + +class HashCommand(Command): +    """ +    Compute a hash of a local package archive. + +    These can be used with --hash in a requirements file to do repeatable +    installs. +    """ + +    usage = "%prog [options] <file> ..." +    ignore_require_venv = True + +    def add_options(self) -> None: +        self.cmd_opts.add_option( +            "-a", +            "--algorithm", +            dest="algorithm", +            choices=STRONG_HASHES, +            action="store", +            default=FAVORITE_HASH, +            help="The hash algorithm to use: one of {}".format( +                ", ".join(STRONG_HASHES) +            ), +        ) +        self.parser.insert_option_group(0, self.cmd_opts) + +    def run(self, options: Values, args: List[str]) -> int: +        if not args: +            self.parser.print_usage(sys.stderr) +            return ERROR + +        algorithm = options.algorithm +        for path in args: +            write_output( +                "%s:\n--hash=%s:%s", path, algorithm, _hash_of_file(path, algorithm) +            ) +        return SUCCESS + + +def _hash_of_file(path: str, algorithm: str) -> str: +    """Return the hash digest of a file.""" +    with open(path, "rb") as archive: +        hash = hashlib.new(algorithm) +        for chunk in read_chunks(archive): +            hash.update(chunk) +    return hash.hexdigest() diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/help.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/help.py new file mode 100644 index 0000000..6206631 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/help.py @@ -0,0 +1,41 @@ +from optparse import Values +from typing import List + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.exceptions import CommandError + + +class HelpCommand(Command): +    """Show help for commands""" + +    usage = """ +      %prog <command>""" +    ignore_require_venv = True + +    def run(self, options: Values, args: List[str]) -> int: +        from pip._internal.commands import ( +            commands_dict, +            create_command, +            get_similar_commands, +        ) + +        try: +            # 'pip help' with no args is handled by pip.__init__.parseopt() +            cmd_name = args[0]  # the command we need help for +        except IndexError: +            return SUCCESS + +        if cmd_name not in commands_dict: +            guess = get_similar_commands(cmd_name) + +            msg = [f'unknown command "{cmd_name}"'] +            if guess: +                msg.append(f'maybe you meant "{guess}"') + +            raise CommandError(" - ".join(msg)) + +        command = create_command(cmd_name) +        command.parser.print_help() + +        return SUCCESS diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/index.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/index.py new file mode 100644 index 0000000..f55e9e4 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/index.py @@ -0,0 +1,139 @@ +import logging +from optparse import Values +from typing import Any, Iterable, List, Optional, Union + +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 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 +from pip._internal.models.selection_prefs import SelectionPreferences +from pip._internal.models.target_python import TargetPython +from pip._internal.network.session import PipSession +from pip._internal.utils.misc import write_output + +logger = logging.getLogger(__name__) + + +class IndexCommand(IndexGroupCommand): +    """ +    Inspect information available from package indexes. +    """ + +    ignore_require_venv = True +    usage = """ +        %prog versions <package> +    """ + +    def add_options(self) -> None: +        cmdoptions.add_target_python_options(self.cmd_opts) + +        self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) +        self.cmd_opts.add_option(cmdoptions.pre()) +        self.cmd_opts.add_option(cmdoptions.no_binary()) +        self.cmd_opts.add_option(cmdoptions.only_binary()) + +        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) + +    def run(self, options: Values, args: List[str]) -> int: +        handlers = { +            "versions": self.get_available_package_versions, +        } + +        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 handlers: +            logger.error( +                "Need an action (%s) to perform.", +                ", ".join(sorted(handlers)), +            ) +            return ERROR + +        action = args[0] + +        # Error handling happens here, not in the action-handlers. +        try: +            handlers[action](options, args[1:]) +        except PipError as e: +            logger.error(e.args[0]) +            return ERROR + +        return SUCCESS + +    def _build_package_finder( +        self, +        options: Values, +        session: PipSession, +        target_python: Optional[TargetPython] = None, +        ignore_requires_python: Optional[bool] = None, +    ) -> PackageFinder: +        """ +        Create a package finder appropriate to the index command. +        """ +        link_collector = LinkCollector.create(session, options=options) + +        # Pass allow_yanked=False to ignore yanked versions. +        selection_prefs = SelectionPreferences( +            allow_yanked=False, +            allow_all_prereleases=options.pre, +            ignore_requires_python=ignore_requires_python, +        ) + +        return PackageFinder.create( +            link_collector=link_collector, +            selection_prefs=selection_prefs, +            target_python=target_python, +        ) + +    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") + +        target_python = cmdoptions.make_target_python(options) +        query = args[0] + +        with self._build_session(options) as session: +            finder = self._build_package_finder( +                options=options, +                session=session, +                target_python=target_python, +                ignore_requires_python=options.ignore_requires_python, +            ) + +            versions: Iterable[Union[LegacyVersion, Version]] = ( +                candidate.version for candidate in finder.find_all_candidates(query) +            ) + +            if not options.pre: +                # Remove prereleases +                versions = ( +                    version for version in versions if not version.is_prerelease +                ) +            versions = set(versions) + +            if not versions: +                raise DistributionNotFound( +                    f"No matching distribution found for {query}" +                ) + +            formatted_versions = [str(ver) for ver in sorted(versions, reverse=True)] +            latest = formatted_versions[0] + +        write_output(f"{query} ({latest})") +        write_output("Available versions: {}".format(", ".join(formatted_versions))) +        print_dist_installation_info(query, latest) diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/inspect.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/inspect.py new file mode 100644 index 0000000..27c8fa3 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/inspect.py @@ -0,0 +1,92 @@ +import logging +from optparse import Values +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.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 +from pip._internal.utils.urls import path_to_url + +logger = logging.getLogger(__name__) + + +class InspectCommand(Command): +    """ +    Inspect the content of a Python environment and produce a report in JSON format. +    """ + +    ignore_require_venv = True +    usage = """ +      %prog [options]""" + +    def add_options(self) -> None: +        self.cmd_opts.add_option( +            "--local", +            action="store_true", +            default=False, +            help=( +                "If in a virtualenv that has global access, do not list " +                "globally-installed packages." +            ), +        ) +        self.cmd_opts.add_option( +            "--user", +            dest="user", +            action="store_true", +            default=False, +            help="Only output packages installed in user-site.", +        ) +        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: +        cmdoptions.check_list_path_option(options) +        dists = get_environment(options.path).iter_installed_distributions( +            local_only=options.local, +            user_only=options.user, +            skip=set(stdlib_pkgs), +        ) +        output = { +            "version": "1", +            "pip_version": __version__, +            "installed": [self._dist_to_dict(dist) for dist in dists], +            "environment": default_environment(), +            # TODO tags? scheme? +        } +        print_json(data=output) +        return SUCCESS + +    def _dist_to_dict(self, dist: BaseDistribution) -> Dict[str, Any]: +        res: Dict[str, Any] = { +            "metadata": dist.metadata_dict, +            "metadata_location": dist.info_location, +        } +        # direct_url. Note that we don't have download_info (as in the installation +        # report) since it is not recorded in installed metadata. +        direct_url = dist.direct_url +        if direct_url is not None: +            res["direct_url"] = direct_url.to_dict() +        else: +            # Emulate direct_url for legacy editable installs. +            editable_project_location = dist.editable_project_location +            if editable_project_location is not None: +                res["direct_url"] = { +                    "url": path_to_url(editable_project_location), +                    "dir_info": { +                        "editable": True, +                    }, +                } +        # installer +        installer = dist.installer +        if dist.installer: +            res["installer"] = installer +        # requested +        if dist.installed_with_dist_info: +            res["requested"] = dist.requested +        return res diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/install.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/install.py new file mode 100644 index 0000000..e944bb9 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/install.py @@ -0,0 +1,774 @@ +import errno +import json +import operator +import os +import shutil +import site +from optparse import SUPPRESS_HELP, Values +from typing import List, Optional + +from pip._vendor.rich import print_json + +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 +from pip._internal.locations import get_scheme +from pip._internal.metadata import get_environment +from pip._internal.models.installation_report import InstallationReport +from pip._internal.operations.build.build_tracker import get_build_tracker +from pip._internal.operations.check import ConflictDetails, check_install_conflicts +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 +from pip._internal.utils.logging import getLogger +from pip._internal.utils.misc import ( +    check_externally_managed, +    ensure_dir, +    get_pip_version, +    protect_pip_from_modification_on_windows, +    write_output, +) +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.virtualenv import ( +    running_under_virtualenv, +    virtualenv_no_global, +) +from pip._internal.wheel_builder import build, should_build_for_install_command + +logger = getLogger(__name__) + + +class InstallCommand(RequirementCommand): +    """ +    Install packages from: + +    - PyPI (and other indexes) using requirement specifiers. +    - VCS project urls. +    - Local project directories. +    - Local or remote source archives. + +    pip also supports installing from "requirements files", which provide +    an easy way to specify a whole environment to be installed. +    """ + +    usage = """ +      %prog [options] <requirement specifier> [package-index-options] ... +      %prog [options] -r <requirements file> [package-index-options] ... +      %prog [options] [-e] <vcs project url> ... +      %prog [options] [-e] <local project path> ... +      %prog [options] <archive url/path> ...""" + +    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.no_deps()) +        self.cmd_opts.add_option(cmdoptions.pre()) + +        self.cmd_opts.add_option(cmdoptions.editable()) +        self.cmd_opts.add_option( +            "--dry-run", +            action="store_true", +            dest="dry_run", +            default=False, +            help=( +                "Don't actually install anything, just print what would be. " +                "Can be used in combination with --ignore-installed " +                "to 'resolve' the requirements." +            ), +        ) +        self.cmd_opts.add_option( +            "-t", +            "--target", +            dest="target_dir", +            metavar="dir", +            default=None, +            help=( +                "Install packages into <dir>. " +                "By default this will not replace existing files/folders in " +                "<dir>. Use --upgrade to replace existing packages in <dir> " +                "with new versions." +            ), +        ) +        cmdoptions.add_target_python_options(self.cmd_opts) + +        self.cmd_opts.add_option( +            "--user", +            dest="use_user_site", +            action="store_true", +            help=( +                "Install to the Python user install directory for your " +                "platform. Typically ~/.local/, or %APPDATA%\\Python on " +                "Windows. (See the Python documentation for site.USER_BASE " +                "for full details.)" +            ), +        ) +        self.cmd_opts.add_option( +            "--no-user", +            dest="use_user_site", +            action="store_false", +            help=SUPPRESS_HELP, +        ) +        self.cmd_opts.add_option( +            "--root", +            dest="root_path", +            metavar="dir", +            default=None, +            help="Install everything relative to this alternate root directory.", +        ) +        self.cmd_opts.add_option( +            "--prefix", +            dest="prefix_path", +            metavar="dir", +            default=None, +            help=( +                "Installation prefix where lib, bin and other top-level " +                "folders are placed. Note that the resulting installation may " +                "contain scripts and other resources which reference the " +                "Python interpreter of pip, and not that of ``--prefix``. " +                "See also the ``--python`` option if the intention is to " +                "install packages into another (possibly pip-free) " +                "environment." +            ), +        ) + +        self.cmd_opts.add_option(cmdoptions.src()) + +        self.cmd_opts.add_option( +            "-U", +            "--upgrade", +            dest="upgrade", +            action="store_true", +            help=( +                "Upgrade all specified packages to the newest available " +                "version. The handling of dependencies depends on the " +                "upgrade-strategy used." +            ), +        ) + +        self.cmd_opts.add_option( +            "--upgrade-strategy", +            dest="upgrade_strategy", +            default="only-if-needed", +            choices=["only-if-needed", "eager"], +            help=( +                "Determines how dependency upgrading should be handled " +                "[default: %default]. " +                '"eager" - dependencies are upgraded regardless of ' +                "whether the currently installed version satisfies the " +                "requirements of the upgraded package(s). " +                '"only-if-needed" -  are upgraded only when they do not ' +                "satisfy the requirements of the upgraded package(s)." +            ), +        ) + +        self.cmd_opts.add_option( +            "--force-reinstall", +            dest="force_reinstall", +            action="store_true", +            help="Reinstall all packages even if they are already up-to-date.", +        ) + +        self.cmd_opts.add_option( +            "-I", +            "--ignore-installed", +            dest="ignore_installed", +            action="store_true", +            help=( +                "Ignore the installed packages, overwriting them. " +                "This can break your system if the existing package " +                "is of a different version or was installed " +                "with a different package manager!" +            ), +        ) + +        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", +            action="store_true", +            dest="compile", +            default=True, +            help="Compile Python source files to bytecode", +        ) + +        self.cmd_opts.add_option( +            "--no-compile", +            action="store_false", +            dest="compile", +            help="Do not compile Python source files to bytecode", +        ) + +        self.cmd_opts.add_option( +            "--no-warn-script-location", +            action="store_false", +            dest="warn_script_location", +            default=True, +            help="Do not warn when installing scripts outside PATH", +        ) +        self.cmd_opts.add_option( +            "--no-warn-conflicts", +            action="store_false", +            dest="warn_about_conflicts", +            default=True, +            help="Do not warn about broken dependencies", +        ) +        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()) +        self.cmd_opts.add_option(cmdoptions.root_user_action()) + +        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) + +        self.cmd_opts.add_option( +            "--report", +            dest="json_report_file", +            metavar="file", +            default=None, +            help=( +                "Generate a JSON file describing what pip did to install " +                "the provided requirements. " +                "Can be used in combination with --dry-run and --ignore-installed " +                "to 'resolve' the requirements. " +                "When - is used as file name it writes to stdout. " +                "When writing to stdout, please combine with the --quiet option " +                "to avoid mixing pip logging output with JSON output." +            ), +        ) + +    @with_cleanup +    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'") + +        # Check whether the environment we're installing into is externally +        # managed, as specified in PEP 668. Specifying --root, --target, or +        # --prefix disables the check, since there's no reliable way to locate +        # the EXTERNALLY-MANAGED file for those cases. An exception is also +        # made specifically for "--dry-run --report" for convenience. +        installing_into_current_environment = ( +            not (options.dry_run and options.json_report_file) +            and options.root_path is None +            and options.target_dir is None +            and options.prefix_path is None +        ) +        if ( +            installing_into_current_environment +            and not options.override_externally_managed +        ): +            check_externally_managed() + +        upgrade_strategy = "to-satisfy-only" +        if options.upgrade: +            upgrade_strategy = options.upgrade_strategy + +        cmdoptions.check_dist_restriction(options, check_target=True) + +        logger.verbose("Using %s", get_pip_version()) +        options.use_user_site = decide_user_install( +            options.use_user_site, +            prefix_path=options.prefix_path, +            target_dir=options.target_dir, +            root_path=options.root_path, +            isolated_mode=options.isolated_mode, +        ) + +        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) +            if ( +                # fmt: off +                os.path.exists(options.target_dir) and +                not os.path.isdir(options.target_dir) +                # fmt: on +            ): +                raise CommandError( +                    "Target path exists but is not a directory, will not continue." +                ) + +            # Create a target directory for using with the target option +            target_temp_dir = TempDirectory(kind="target") +            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) +        finder = self._build_package_finder( +            options=options, +            session=session, +            target_python=target_python, +            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, +        ) + +        try: +            reqs = self.get_requirements(args, options, finder, session) +            check_legacy_setup_py_options(options, reqs) + +            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=options.use_user_site, +                verbosity=self.verbosity, +            ) +            resolver = self.make_resolver( +                preparer=preparer, +                finder=finder, +                options=options, +                wheel_cache=wheel_cache, +                use_user_site=options.use_user_site, +                ignore_installed=options.ignore_installed, +                ignore_requires_python=options.ignore_requires_python, +                force_reinstall=options.force_reinstall, +                upgrade_strategy=upgrade_strategy, +                use_pep517=options.use_pep517, +            ) + +            self.trace_basic_info(finder) + +            requirement_set = resolver.resolve( +                reqs, check_supported_wheels=not options.target_dir +            ) + +            if options.json_report_file: +                report = InstallationReport(requirement_set.requirements_to_install) +                if options.json_report_file == "-": +                    print_json(data=report.to_dict()) +                else: +                    with open(options.json_report_file, "w", encoding="utf-8") as f: +                        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 +                ) +                if would_install_items: +                    write_output( +                        "Would install %s", +                        " ".join("-".join(item) for item in would_install_items), +                    ) +                return SUCCESS + +            try: +                pip_req = requirement_set.get_requirement("pip") +            except KeyError: +                modifying_pip = False +            else: +                # If we're not replacing an already installed pip, +                # we're not modifying it. +                modifying_pip = pip_req.satisfied_by is None +            protect_pip_from_modification_on_windows(modifying_pip=modifying_pip) + +            reqs_to_build = [ +                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 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: Optional[ConflictDetails] = None +            should_warn_about_conflicts = ( +                not options.ignore_dependencies and options.warn_about_conflicts +            ) +            if should_warn_about_conflicts: +                conflicts = self._determine_conflicts(to_install) + +            # Don't warn about script install locations if +            # --target or --prefix has been specified +            warn_script_location = options.warn_script_location +            if options.target_dir or options.prefix_path: +                warn_script_location = False + +            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, +            ) + +            lib_locations = get_lib_location_guesses( +                user=options.use_user_site, +                home=target_temp_dir_path, +                root=options.root_path, +                prefix=options.prefix_path, +                isolated=options.isolated_mode, +            ) +            env = get_environment(lib_locations) + +            installed.sort(key=operator.attrgetter("name")) +            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( +                    conflicts, +                    resolver_variant=self.determine_resolver_variant(options), +                ) + +            installed_desc = " ".join(items) +            if installed_desc: +                write_output( +                    "Successfully installed %s", +                    installed_desc, +                ) +        except OSError as error: +            show_traceback = self.verbosity >= 1 + +            message = create_os_error_message( +                error, +                show_traceback, +                options.use_user_site, +            ) +            logger.error(message, exc_info=show_traceback) + +            return ERROR + +        if options.target_dir: +            assert target_temp_dir +            self._handle_target_dir( +                options.target_dir, target_temp_dir, options.upgrade +            ) +        if options.root_user_action == "warn": +            warn_if_run_as_root() +        return SUCCESS + +    def _handle_target_dir( +        self, target_dir: str, target_temp_dir: TempDirectory, upgrade: bool +    ) -> None: +        ensure_dir(target_dir) + +        # Checking both purelib and platlib directories for installed +        # packages to be moved to target directory +        lib_dir_list = [] + +        # Checking both purelib and platlib directories for installed +        # packages to be moved to target directory +        scheme = get_scheme("", home=target_temp_dir.path) +        purelib_dir = scheme.purelib +        platlib_dir = scheme.platlib +        data_dir = scheme.data + +        if os.path.exists(purelib_dir): +            lib_dir_list.append(purelib_dir) +        if os.path.exists(platlib_dir) and platlib_dir != purelib_dir: +            lib_dir_list.append(platlib_dir) +        if os.path.exists(data_dir): +            lib_dir_list.append(data_dir) + +        for lib_dir in lib_dir_list: +            for item in os.listdir(lib_dir): +                if lib_dir == data_dir: +                    ddir = os.path.join(data_dir, item) +                    if any(s.startswith(ddir) for s in lib_dir_list[:-1]): +                        continue +                target_item_dir = os.path.join(target_dir, item) +                if os.path.exists(target_item_dir): +                    if not upgrade: +                        logger.warning( +                            "Target directory %s already exists. Specify " +                            "--upgrade to force replacement.", +                            target_item_dir, +                        ) +                        continue +                    if os.path.islink(target_item_dir): +                        logger.warning( +                            "Target directory %s already exists and is " +                            "a link. pip will not automatically replace " +                            "links, please remove if replacement is " +                            "desired.", +                            target_item_dir, +                        ) +                        continue +                    if os.path.isdir(target_item_dir): +                        shutil.rmtree(target_item_dir) +                    else: +                        os.remove(target_item_dir) + +                shutil.move(os.path.join(lib_dir, item), target_item_dir) + +    def _determine_conflicts( +        self, to_install: List[InstallRequirement] +    ) -> Optional[ConflictDetails]: +        try: +            return check_install_conflicts(to_install) +        except Exception: +            logger.exception( +                "Error while checking for conflicts. Please file an issue on " +                "pip's issue tracker: https://github.com/pypa/pip/issues/new" +            ) +            return None + +    def _warn_about_conflicts( +        self, conflict_details: ConflictDetails, resolver_variant: str +    ) -> None: +        package_set, (missing, conflicting) = conflict_details +        if not missing and not conflicting: +            return + +        parts: List[str] = [] +        if resolver_variant == "legacy": +            parts.append( +                "pip's legacy dependency resolver does not consider dependency " +                "conflicts when selecting packages. This behaviour is the " +                "source of the following dependency conflicts." +            ) +        else: +            assert resolver_variant == "resolvelib" +            parts.append( +                "pip's dependency resolver does not currently take into account " +                "all the packages that are installed. This behaviour is the " +                "source of the following dependency conflicts." +            ) + +        # NOTE: There is some duplication here, with commands/check.py +        for project_name in missing: +            version = package_set[project_name][0] +            for dependency in missing[project_name]: +                message = ( +                    f"{project_name} {version} requires {dependency[1]}, " +                    "which is not installed." +                ) +                parts.append(message) + +        for project_name in conflicting: +            version = package_set[project_name][0] +            for dep_name, dep_version, req in conflicting[project_name]: +                message = ( +                    "{name} {version} requires {requirement}, but {you} have " +                    "{dep_name} {dep_version} which is incompatible." +                ).format( +                    name=project_name, +                    version=version, +                    requirement=req, +                    dep_name=dep_name, +                    dep_version=dep_version, +                    you=("you" if resolver_variant == "resolvelib" else "you'll"), +                ) +                parts.append(message) + +        logger.critical("\n".join(parts)) + + +def get_lib_location_guesses( +    user: bool = False, +    home: Optional[str] = None, +    root: Optional[str] = None, +    isolated: bool = False, +    prefix: Optional[str] = None, +) -> List[str]: +    scheme = get_scheme( +        "", +        user=user, +        home=home, +        root=root, +        isolated=isolated, +        prefix=prefix, +    ) +    return [scheme.purelib, scheme.platlib] + + +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)) +    ) + + +def decide_user_install( +    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. + +    If use_user_site is False, no additional checks are done. +    If use_user_site is True, it is checked for compatibility with other +    options. +    If use_user_site is None, the default behaviour depends on the environment, +    which is provided by the other arguments. +    """ +    # In some cases (config from tox), use_user_site can be set to an integer +    # rather than a bool, which 'use_user_site is False' wouldn't catch. +    if (use_user_site is not None) and (not use_user_site): +        logger.debug("Non-user install by explicit request") +        return False + +    if use_user_site: +        if prefix_path: +            raise CommandError( +                "Can not combine '--user' and '--prefix' as they imply " +                "different installation locations" +            ) +        if virtualenv_no_global(): +            raise InstallationError( +                "Can not perform a '--user' install. User site-packages " +                "are not visible in this virtualenv." +            ) +        logger.debug("User install by explicit request") +        return True + +    # If we are here, user installs have not been explicitly requested/avoided +    assert use_user_site is None + +    # user install incompatible with --prefix/--target +    if prefix_path or target_dir: +        logger.debug("Non-user install due to --prefix or --target option") +        return False + +    # If user installs are not enabled, choose a non-user install +    if not site.ENABLE_USER_SITE: +        logger.debug("Non-user install because user site-packages disabled") +        return False + +    # If we have permission for a non-user install, do that, +    # otherwise do a user install. +    if site_packages_writable(root=root_path, isolated=isolated_mode): +        logger.debug("Non-user install because site-packages writeable") +        return False + +    logger.info( +        "Defaulting to user installation because normal site-packages " +        "is not writeable" +    ) +    return True + + +def create_os_error_message( +    error: OSError, show_traceback: bool, using_user_site: bool +) -> str: +    """Format an error message for an OSError + +    It may occur anytime during the execution of the install command. +    """ +    parts = [] + +    # Mention the error if we are not going to show a traceback +    parts.append("Could not install packages due to an OSError") +    if not show_traceback: +        parts.append(": ") +        parts.append(str(error)) +    else: +        parts.append(".") + +    # Spilt the error indication from a helper message (if any) +    parts[-1] += "\n" + +    # Suggest useful actions to the user: +    #  (1) using user site-packages or (2) verifying the permissions +    if error.errno == errno.EACCES: +        user_option_part = "Consider using the `--user` option" +        permissions_part = "Check the permissions" + +        if not running_under_virtualenv() and not using_user_site: +            parts.extend( +                [ +                    user_option_part, +                    " or ", +                    permissions_part.lower(), +                ] +            ) +        else: +            parts.append(permissions_part) +        parts.append(".\n") + +    # 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( +            "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" diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/list.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/list.py new file mode 100644 index 0000000..e551dda --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/list.py @@ -0,0 +1,368 @@ +import json +import logging +from optparse import Values +from typing import TYPE_CHECKING, Generator, List, Optional, Sequence, Tuple, cast + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.cli import cmdoptions +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.metadata.base import DistributionVersion + +    class _DistWithLatestInfo(BaseDistribution): +        """Give the distribution object a couple of extra fields. + +        These will be populated during ``get_outdated()``. This is dirty but +        makes the rest of the code much cleaner. +        """ + +        latest_version: DistributionVersion +        latest_filetype: str + +    _ProcessedDists = Sequence[_DistWithLatestInfo] + + +logger = logging.getLogger(__name__) + + +class ListCommand(IndexGroupCommand): +    """ +    List installed packages, including editables. + +    Packages are listed in a case-insensitive sorted order. +    """ + +    ignore_require_venv = True +    usage = """ +      %prog [options]""" + +    def add_options(self) -> None: +        self.cmd_opts.add_option( +            "-o", +            "--outdated", +            action="store_true", +            default=False, +            help="List outdated packages", +        ) +        self.cmd_opts.add_option( +            "-u", +            "--uptodate", +            action="store_true", +            default=False, +            help="List uptodate packages", +        ) +        self.cmd_opts.add_option( +            "-e", +            "--editable", +            action="store_true", +            default=False, +            help="List editable projects.", +        ) +        self.cmd_opts.add_option( +            "-l", +            "--local", +            action="store_true", +            default=False, +            help=( +                "If in a virtualenv that has global access, do not list " +                "globally-installed packages." +            ), +        ) +        self.cmd_opts.add_option( +            "--user", +            dest="user", +            action="store_true", +            default=False, +            help="Only output packages installed in user-site.", +        ) +        self.cmd_opts.add_option(cmdoptions.list_path()) +        self.cmd_opts.add_option( +            "--pre", +            action="store_true", +            default=False, +            help=( +                "Include pre-release and development versions. By default, " +                "pip only finds stable versions." +            ), +        ) + +        self.cmd_opts.add_option( +            "--format", +            action="store", +            dest="list_format", +            default="columns", +            choices=("columns", "freeze", "json"), +            help=( +                "Select the output format among: columns (default), freeze, or json. " +                "The 'freeze' format cannot be used with the --outdated option." +            ), +        ) + +        self.cmd_opts.add_option( +            "--not-required", +            action="store_true", +            dest="not_required", +            help="List packages that are not dependencies of installed packages.", +        ) + +        self.cmd_opts.add_option( +            "--exclude-editable", +            action="store_false", +            dest="include_editable", +            help="Exclude editable package from output.", +        ) +        self.cmd_opts.add_option( +            "--include-editable", +            action="store_true", +            dest="include_editable", +            help="Include editable package from output.", +            default=True, +        ) +        self.cmd_opts.add_option(cmdoptions.list_exclude()) +        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) + +    def _build_package_finder( +        self, options: Values, session: PipSession +    ) -> PackageFinder: +        """ +        Create a package finder appropriate to this list command. +        """ +        link_collector = LinkCollector.create(session, options=options) + +        # Pass allow_yanked=False to ignore yanked versions. +        selection_prefs = SelectionPreferences( +            allow_yanked=False, +            allow_all_prereleases=options.pre, +        ) + +        return PackageFinder.create( +            link_collector=link_collector, +            selection_prefs=selection_prefs, +        ) + +    def run(self, options: Values, args: List[str]) -> int: +        if options.outdated and options.uptodate: +            raise CommandError("Options --outdated and --uptodate cannot be combined.") + +        if options.outdated and options.list_format == "freeze": +            raise CommandError( +                "List format 'freeze' cannot be used with the --outdated option." +            ) + +        cmdoptions.check_list_path_option(options) + +        skip = set(stdlib_pkgs) +        if options.excludes: +            skip.update(canonicalize_name(n) for n in options.excludes) + +        packages: "_ProcessedDists" = [ +            cast("_DistWithLatestInfo", d) +            for d in get_environment(options.path).iter_installed_distributions( +                local_only=options.local, +                user_only=options.user, +                editables_only=options.editable, +                include_editables=options.include_editable, +                skip=skip, +            ) +        ] + +        # get_not_required must be called firstly in order to find and +        # filter out all dependencies correctly. Otherwise a package +        # can't be identified as requirement because some parent packages +        # could be filtered out before. +        if options.not_required: +            packages = self.get_not_required(packages, options) + +        if options.outdated: +            packages = self.get_outdated(packages, options) +        elif options.uptodate: +            packages = self.get_uptodate(packages, options) + +        self.output_package_listing(packages, options) +        return SUCCESS + +    def get_outdated( +        self, packages: "_ProcessedDists", options: Values +    ) -> "_ProcessedDists": +        return [ +            dist +            for dist in self.iter_packages_latest_infos(packages, options) +            if dist.latest_version > dist.version +        ] + +    def get_uptodate( +        self, packages: "_ProcessedDists", options: Values +    ) -> "_ProcessedDists": +        return [ +            dist +            for dist in self.iter_packages_latest_infos(packages, options) +            if dist.latest_version == dist.version +        ] + +    def get_not_required( +        self, packages: "_ProcessedDists", options: Values +    ) -> "_ProcessedDists": +        dep_keys = { +            canonicalize_name(dep.name) +            for dist in packages +            for dep in (dist.iter_dependencies() or ()) +        } + +        # Create a set to remove duplicate packages, and cast it to a list +        # to keep the return type consistent with get_outdated and +        # get_uptodate +        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]: +        with self._build_session(options) as session: +            finder = self._build_package_finder(options, session) + +            def latest_info( +                dist: "_DistWithLatestInfo", +            ) -> Optional["_DistWithLatestInfo"]: +                all_candidates = finder.find_all_candidates(dist.canonical_name) +                if not options.pre: +                    # Remove prereleases +                    all_candidates = [ +                        candidate +                        for candidate in all_candidates +                        if not candidate.version.is_prerelease +                    ] + +                evaluator = finder.make_candidate_evaluator( +                    project_name=dist.canonical_name, +                ) +                best_candidate = evaluator.sort_best_candidate(all_candidates) +                if best_candidate is None: +                    return None + +                remote_version = best_candidate.version +                if best_candidate.link.is_wheel: +                    typ = "wheel" +                else: +                    typ = "sdist" +                dist.latest_version = remote_version +                dist.latest_filetype = typ +                return dist + +            for dist in map(latest_info, packages): +                if dist is not None: +                    yield dist + +    def output_package_listing( +        self, packages: "_ProcessedDists", options: Values +    ) -> None: +        packages = sorted( +            packages, +            key=lambda dist: dist.canonical_name, +        ) +        if options.list_format == "columns" and packages: +            data, header = format_for_columns(packages, options) +            self.output_package_listing_columns(data, header) +        elif options.list_format == "freeze": +            for dist in packages: +                if options.verbose >= 1: +                    write_output( +                        "%s==%s (%s)", dist.raw_name, dist.version, dist.location +                    ) +                else: +                    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] +    ) -> None: +        # insert the header first: we need to know the size of column names +        if len(data) > 0: +            data.insert(0, header) + +        pkg_strings, sizes = tabulate(data) + +        # Create and add a separator. +        if len(data) > 0: +            pkg_strings.insert(1, " ".join("-" * x for x in sizes)) + +        for val in pkg_strings: +            write_output(val) + + +def format_for_columns( +    pkgs: "_ProcessedDists", options: Values +) -> Tuple[List[List[str]], List[str]]: +    """ +    Convert the package data into something usable +    by output_package_listing_columns. +    """ +    header = ["Package", "Version"] + +    running_outdated = options.outdated +    if running_outdated: +        header.extend(["Latest", "Type"]) + +    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") + +    data = [] +    for proj in pkgs: +        # if we're working on the 'outdated' list, separate out the +        # latest_version and type +        row = [proj.raw_name, str(proj.version)] + +        if running_outdated: +            row.append(str(proj.latest_version)) +            row.append(proj.latest_filetype) + +        if has_editables: +            row.append(proj.editable_project_location or "") + +        if options.verbose >= 1: +            row.append(proj.location or "") +        if options.verbose >= 1: +            row.append(proj.installer) + +        data.append(row) + +    return data, header + + +def format_for_json(packages: "_ProcessedDists", options: Values) -> str: +    data = [] +    for dist in packages: +        info = { +            "name": dist.raw_name, +            "version": str(dist.version), +        } +        if options.verbose >= 1: +            info["location"] = dist.location or "" +            info["installer"] = dist.installer +        if options.outdated: +            info["latest_version"] = str(dist.latest_version) +            info["latest_filetype"] = dist.latest_filetype +        editable_project_location = dist.editable_project_location +        if editable_project_location: +            info["editable_project_location"] = editable_project_location +        data.append(info) +    return json.dumps(data) diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/search.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/search.py new file mode 100644 index 0000000..03ed925 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/search.py @@ -0,0 +1,174 @@ +import logging +import shutil +import sys +import textwrap +import xmlrpc.client +from collections import OrderedDict +from optparse import Values +from typing import TYPE_CHECKING, Dict, List, Optional + +from pip._vendor.packaging.version import parse as parse_version + +from pip._internal.cli.base_command import Command +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.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] + + +logger = logging.getLogger(__name__) + + +class SearchCommand(Command, SessionCommandMixin): +    """Search for PyPI packages whose name or summary contains <query>.""" + +    usage = """ +      %prog [options] <query>""" +    ignore_require_venv = True + +    def add_options(self) -> None: +        self.cmd_opts.add_option( +            "-i", +            "--index", +            dest="index", +            metavar="URL", +            default=PyPI.pypi_url, +            help="Base URL of Python Package Index (default %default)", +        ) + +        self.parser.insert_option_group(0, self.cmd_opts) + +    def run(self, options: Values, args: List[str]) -> int: +        if not args: +            raise CommandError("Missing required argument (search query).") +        query = args +        pypi_hits = self.search(query, options) +        hits = transform_hits(pypi_hits) + +        terminal_width = None +        if sys.stdout.isatty(): +            terminal_width = shutil.get_terminal_size()[0] + +        print_results(hits, terminal_width=terminal_width) +        if pypi_hits: +            return SUCCESS +        return NO_MATCHES_FOUND + +    def search(self, query: List[str], options: Values) -> List[Dict[str, str]]: +        index_url = options.index + +        session = self.get_default_session(options) + +        transport = PipXmlrpcTransport(index_url, session) +        pypi = xmlrpc.client.ServerProxy(index_url, transport) +        try: +            hits = pypi.search({"name": query, "summary": query}, "or") +        except xmlrpc.client.Fault as fault: +            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"]: +    """ +    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() +    for hit in hits: +        name = hit["name"] +        summary = hit["summary"] +        version = hit["version"] + +        if name not in packages.keys(): +            packages[name] = { +                "name": name, +                "summary": summary, +                "versions": [version], +            } +        else: +            packages[name]["versions"].append(version) + +            # if this is the highest version, replace summary and score +            if version == highest_version(packages[name]["versions"]): +                packages[name]["summary"] = summary + +    return list(packages.values()) + + +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: +                write_output("INSTALLED: %s (latest)", dist.version) +            else: +                write_output("INSTALLED: %s", dist.version) +                if parse_version(latest).pre: +                    write_output( +                        "LATEST:    %s (pre-release; install" +                        " with `pip install --pre`)", +                        latest, +                    ) +                else: +                    write_output("LATEST:    %s", latest) + + +def print_results( +    hits: List["TransformedHit"], +    name_column_width: Optional[int] = None, +    terminal_width: Optional[int] = None, +) -> None: +    if not hits: +        return +    if name_column_width is None: +        name_column_width = ( +            max( +                [ +                    len(hit["name"]) + len(highest_version(hit.get("versions", ["-"]))) +                    for hit in hits +                ] +            ) +            + 4 +        ) + +    for hit in hits: +        name = hit["name"] +        summary = hit["summary"] or "" +        latest = highest_version(hit.get("versions", ["-"])) +        if terminal_width is not None: +            target_width = terminal_width - name_column_width - 5 +            if target_width > 10: +                # wrap and indent summary to fit terminal +                summary_lines = textwrap.wrap(summary, target_width) +                summary = ("\n" + " " * (name_column_width + 3)).join(summary_lines) + +        name_latest = f"{name} ({latest})" +        line = f"{name_latest:{name_column_width}} - {summary}" +        try: +            write_output(line) +            print_dist_installation_info(name, latest) +        except UnicodeEncodeError: +            pass + + +def highest_version(versions: List[str]) -> str: +    return max(versions, key=parse_version) diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/show.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/show.py new file mode 100644 index 0000000..3f10701 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/show.py @@ -0,0 +1,189 @@ +import logging +from optparse import Values +from typing import Generator, Iterable, Iterator, List, NamedTuple, Optional + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.metadata import BaseDistribution, get_default_environment +from pip._internal.utils.misc import write_output + +logger = logging.getLogger(__name__) + + +class ShowCommand(Command): +    """ +    Show information about one or more installed packages. + +    The output is in RFC-compliant mail header format. +    """ + +    usage = """ +      %prog [options] <package> ...""" +    ignore_require_venv = True + +    def add_options(self) -> None: +        self.cmd_opts.add_option( +            "-f", +            "--files", +            dest="files", +            action="store_true", +            default=False, +            help="Show the full list of installed files for each package.", +        ) + +        self.parser.insert_option_group(0, self.cmd_opts) + +    def run(self, options: Values, args: List[str]) -> int: +        if not args: +            logger.warning("ERROR: Please provide a package name or names.") +            return ERROR +        query = args + +        results = search_packages_info(query) +        if not print_results( +            results, list_files=options.files, verbose=options.verbose +        ): +            return ERROR +        return SUCCESS + + +class _PackageInfo(NamedTuple): +    name: str +    version: str +    location: str +    editable_project_location: Optional[str] +    requires: List[str] +    required_by: List[str] +    installer: str +    metadata_version: str +    classifiers: List[str] +    summary: str +    homepage: str +    project_urls: List[str] +    author: str +    author_email: str +    license: str +    entry_points: List[str] +    files: Optional[List[str]] + + +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 +    pip generated 'installed-files.txt' in the distributions '.egg-info' +    directory. +    """ +    env = get_default_environment() + +    installed = {dist.canonical_name: dist for dist in env.iter_all_distributions()} +    query_names = [canonicalize_name(name) for name in query] +    missing = sorted( +        [name for name, pkg in zip(query, query_names) if pkg not in installed] +    ) +    if missing: +        logger.warning("Package(s) not found: %s", ", ".join(missing)) + +    def _get_requiring_packages(current_dist: BaseDistribution) -> Iterator[str]: +        return ( +            dist.metadata["Name"] or "UNKNOWN" +            for dist in installed.values() +            if current_dist.canonical_name +            in {canonicalize_name(d.name) for d in dist.iter_dependencies()} +        ) + +    for query_name in query_names: +        try: +            dist = installed[query_name] +        except KeyError: +            continue + +        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") +            entry_points = entry_points_text.splitlines(keepends=False) +        except FileNotFoundError: +            entry_points = [] + +        files_iter = dist.iter_declared_entries() +        if files_iter is None: +            files: Optional[List[str]] = None +        else: +            files = sorted(files_iter) + +        metadata = dist.metadata + +        yield _PackageInfo( +            name=dist.raw_name, +            version=str(dist.version), +            location=dist.location or "", +            editable_project_location=dist.editable_project_location, +            requires=requires, +            required_by=required_by, +            installer=dist.installer, +            metadata_version=dist.metadata_version or "", +            classifiers=metadata.get_all("Classifier", []), +            summary=metadata.get("Summary", ""), +            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", ""), +            entry_points=entry_points, +            files=files, +        ) + + +def print_results( +    distributions: Iterable[_PackageInfo], +    list_files: bool, +    verbose: bool, +) -> bool: +    """ +    Print the information from installed distributions found. +    """ +    results_printed = False +    for i, dist in enumerate(distributions): +        results_printed = True +        if i > 0: +            write_output("---") + +        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) +        write_output("License: %s", dist.license) +        write_output("Location: %s", dist.location) +        if dist.editable_project_location is not None: +            write_output( +                "Editable project location: %s", dist.editable_project_location +            ) +        write_output("Requires: %s", ", ".join(dist.requires)) +        write_output("Required-by: %s", ", ".join(dist.required_by)) + +        if verbose: +            write_output("Metadata-Version: %s", dist.metadata_version) +            write_output("Installer: %s", dist.installer) +            write_output("Classifiers:") +            for classifier in dist.classifiers: +                write_output("  %s", classifier) +            write_output("Entry-points:") +            for entry in dist.entry_points: +                write_output("  %s", entry.strip()) +            write_output("Project-URLs:") +            for project_url in dist.project_urls: +                write_output("  %s", project_url) +        if list_files: +            write_output("Files:") +            if dist.files is None: +                write_output("Cannot locate RECORD or installed-files.txt") +            else: +                for line in dist.files: +                    write_output("  %s", line.strip()) +    return results_printed diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/uninstall.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/uninstall.py new file mode 100644 index 0000000..f198fc3 --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/uninstall.py @@ -0,0 +1,113 @@ +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.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 +from pip._internal.req.constructors import ( +    install_req_from_line, +    install_req_from_parsed_requirement, +) +from pip._internal.utils.misc import ( +    check_externally_managed, +    protect_pip_from_modification_on_windows, +) + +logger = logging.getLogger(__name__) + + +class UninstallCommand(Command, SessionCommandMixin): +    """ +    Uninstall packages. + +    pip is able to uninstall most installed packages. Known exceptions are: + +    - Pure distutils packages installed with ``python setup.py install``, which +      leave behind no metadata to determine what files were installed. +    - Script wrappers installed by ``python setup.py develop``. +    """ + +    usage = """ +      %prog [options] <package> ... +      %prog [options] -r <requirements file> ...""" + +    def add_options(self) -> None: +        self.cmd_opts.add_option( +            "-r", +            "--requirement", +            dest="requirements", +            action="append", +            default=[], +            metavar="file", +            help=( +                "Uninstall all the packages listed in the given requirements " +                "file.  This option can be used multiple times." +            ), +        ) +        self.cmd_opts.add_option( +            "-y", +            "--yes", +            dest="yes", +            action="store_true", +            help="Don't ask for confirmation of uninstall deletions.", +        ) +        self.cmd_opts.add_option(cmdoptions.root_user_action()) +        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: +        session = self.get_default_session(options) + +        reqs_to_uninstall = {} +        for name in args: +            req = install_req_from_line( +                name, +                isolated=options.isolated_mode, +            ) +            if req.name: +                reqs_to_uninstall[canonicalize_name(req.name)] = req +            else: +                logger.warning( +                    "Invalid requirement: %r ignored -" +                    " the uninstall command expects named" +                    " requirements.", +                    name, +                ) +        for filename in options.requirements: +            for parsed_req in parse_requirements( +                filename, options=options, session=session +            ): +                req = install_req_from_parsed_requirement( +                    parsed_req, isolated=options.isolated_mode +                ) +                if req.name: +                    reqs_to_uninstall[canonicalize_name(req.name)] = req +        if not reqs_to_uninstall: +            raise InstallationError( +                f"You must give at least one requirement to {self.name} (see " +                f'"pip help {self.name}")' +            ) + +        if not options.override_externally_managed: +            check_externally_managed() + +        protect_pip_from_modification_on_windows( +            modifying_pip="pip" in reqs_to_uninstall +        ) + +        for req in reqs_to_uninstall.values(): +            uninstall_pathset = req.uninstall( +                auto_confirm=options.yes, +                verbose=self.verbosity > 0, +            ) +            if uninstall_pathset: +                uninstall_pathset.commit() +        if options.root_user_action == "warn": +            warn_if_run_as_root() +        return SUCCESS diff --git a/venv/lib/python3.11/site-packages/pip/_internal/commands/wheel.py b/venv/lib/python3.11/site-packages/pip/_internal/commands/wheel.py new file mode 100644 index 0000000..ed578aa --- /dev/null +++ b/venv/lib/python3.11/site-packages/pip/_internal/commands/wheel.py @@ -0,0 +1,183 @@ +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 +from pip._internal.cli.req_command import RequirementCommand, with_cleanup +from pip._internal.cli.status_codes import SUCCESS +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, should_build_for_wheel_command + +logger = logging.getLogger(__name__) + + +class WheelCommand(RequirementCommand): +    """ +    Build Wheel archives for your requirements and dependencies. + +    Wheel is a built-package format, and offers the advantage of not +    recompiling your software during every install. For more details, see the +    wheel docs: https://wheel.readthedocs.io/en/latest/ + +    'pip wheel' uses the build system interface as described here: +    https://pip.pypa.io/en/stable/reference/build-system/ + +    """ + +    usage = """ +      %prog [options] <requirement specifier> ... +      %prog [options] -r <requirements file> ... +      %prog [options] [-e] <vcs project url> ... +      %prog [options] [-e] <local project path> ... +      %prog [options] <archive url/path> ...""" + +    def add_options(self) -> None: +        self.cmd_opts.add_option( +            "-w", +            "--wheel-dir", +            dest="wheel_dir", +            metavar="dir", +            default=os.curdir, +            help=( +                "Build wheels into <dir>, where the default is the " +                "current working directory." +            ), +        ) +        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.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.editable()) +        self.cmd_opts.add_option(cmdoptions.requirements()) +        self.cmd_opts.add_option(cmdoptions.src()) +        self.cmd_opts.add_option(cmdoptions.ignore_requires_python()) +        self.cmd_opts.add_option(cmdoptions.no_deps()) +        self.cmd_opts.add_option(cmdoptions.progress_bar()) + +        self.cmd_opts.add_option( +            "--no-verify", +            dest="no_verify", +            action="store_true", +            default=False, +            help="Don't verify if built wheel is valid.", +        ) + +        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", +            action="store_true", +            default=False, +            help=( +                "Include pre-release and development versions. By default, " +                "pip only finds stable versions." +            ), +        ) + +        self.cmd_opts.add_option(cmdoptions.require_hashes()) + +        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: +        session = self.get_default_session(options) + +        finder = self._build_package_finder(options, session) + +        options.wheel_dir = normalize_path(options.wheel_dir) +        ensure_dir(options.wheel_dir) + +        build_tracker = self.enter_context(get_build_tracker()) + +        directory = TempDirectory( +            delete=not options.no_clean, +            kind="wheel", +            globally_managed=True, +        ) + +        reqs = self.get_requirements(args, options, finder, session) +        check_legacy_setup_py_options(options, reqs) + +        wheel_cache = WheelCache(options.cache_dir) + +        preparer = self.make_requirement_preparer( +            temp_build_dir=directory, +            options=options, +            build_tracker=build_tracker, +            session=session, +            finder=finder, +            download_dir=options.wheel_dir, +            use_user_site=False, +            verbosity=self.verbosity, +        ) + +        resolver = self.make_resolver( +            preparer=preparer, +            finder=finder, +            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) + +        reqs_to_build: List[InstallRequirement] = [] +        for req in requirement_set.requirements.values(): +            if req.is_wheel: +                preparer.save_linked_requirement(req) +            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 +            assert req.local_file_path +            # copy from cache to target directory +            try: +                shutil.copy(req.local_file_path, options.wheel_dir) +            except OSError as e: +                logger.warning( +                    "Building wheel for %s failed: %s", +                    req.name, +                    e, +                ) +                build_failures.append(req) +        if len(build_failures) != 0: +            raise CommandError("Failed to build one or more wheels") + +        return SUCCESS | 
