1"""
2Package containing all pip commands
3"""
4
5import importlib
6from collections import OrderedDict, namedtuple
7
8from pip._internal.utils.typing import MYPY_CHECK_RUNNING
9
10if MYPY_CHECK_RUNNING:
11    from typing import Any, Optional
12
13    from pip._internal.cli.base_command import Command
14
15
16CommandInfo = namedtuple('CommandInfo', 'module_path, class_name, summary')
17
18# The ordering matters for help display.
19#    Also, even though the module path starts with the same
20# "pip._internal.commands" prefix in each case, we include the full path
21# because it makes testing easier (specifically when modifying commands_dict
22# in test setup / teardown by adding info for a FakeCommand class defined
23# in a test-related module).
24#    Finally, we need to pass an iterable of pairs here rather than a dict
25# so that the ordering won't be lost when using Python 2.7.
26commands_dict = OrderedDict([
27    ('install', CommandInfo(
28        'pip._internal.commands.install', 'InstallCommand',
29        'Install packages.',
30    )),
31    ('download', CommandInfo(
32        'pip._internal.commands.download', 'DownloadCommand',
33        'Download packages.',
34    )),
35    ('uninstall', CommandInfo(
36        'pip._internal.commands.uninstall', 'UninstallCommand',
37        'Uninstall packages.',
38    )),
39    ('freeze', CommandInfo(
40        'pip._internal.commands.freeze', 'FreezeCommand',
41        'Output installed packages in requirements format.',
42    )),
43    ('list', CommandInfo(
44        'pip._internal.commands.list', 'ListCommand',
45        'List installed packages.',
46    )),
47    ('show', CommandInfo(
48        'pip._internal.commands.show', 'ShowCommand',
49        'Show information about installed packages.',
50    )),
51    ('check', CommandInfo(
52        'pip._internal.commands.check', 'CheckCommand',
53        'Verify installed packages have compatible dependencies.',
54    )),
55    ('config', CommandInfo(
56        'pip._internal.commands.configuration', 'ConfigurationCommand',
57        'Manage local and global configuration.',
58    )),
59    ('search', CommandInfo(
60        'pip._internal.commands.search', 'SearchCommand',
61        'Search PyPI for packages.',
62    )),
63    ('cache', CommandInfo(
64        'pip._internal.commands.cache', 'CacheCommand',
65        "Inspect and manage pip's wheel cache.",
66    )),
67    ('wheel', CommandInfo(
68        'pip._internal.commands.wheel', 'WheelCommand',
69        'Build wheels from your requirements.',
70    )),
71    ('hash', CommandInfo(
72        'pip._internal.commands.hash', 'HashCommand',
73        'Compute hashes of package archives.',
74    )),
75    ('completion', CommandInfo(
76        'pip._internal.commands.completion', 'CompletionCommand',
77        'A helper command used for command completion.',
78    )),
79    ('debug', CommandInfo(
80        'pip._internal.commands.debug', 'DebugCommand',
81        'Show information useful for debugging.',
82    )),
83    ('help', CommandInfo(
84        'pip._internal.commands.help', 'HelpCommand',
85        'Show help for commands.',
86    )),
87])  # type: OrderedDict[str, CommandInfo]
88
89
90def create_command(name, **kwargs):
91    # type: (str, **Any) -> Command
92    """
93    Create an instance of the Command class with the given name.
94    """
95    module_path, class_name, summary = commands_dict[name]
96    module = importlib.import_module(module_path)
97    command_class = getattr(module, class_name)
98    command = command_class(name=name, summary=summary, **kwargs)
99
100    return command
101
102
103def get_similar_commands(name):
104    # type: (str) -> Optional[str]
105    """Command name auto-correct."""
106    from difflib import get_close_matches
107
108    name = name.lower()
109
110    close_commands = get_close_matches(name, commands_dict.keys())
111
112    if close_commands:
113        return close_commands[0]
114    else:
115        return None
116