1from __future__ import absolute_import
2
3import locale
4import logging
5import sys
6
7from pip._internal.cli import cmdoptions
8from pip._internal.cli.base_command import Command
9from pip._internal.cli.cmdoptions import make_target_python
10from pip._internal.cli.status_codes import SUCCESS
11from pip._internal.utils.logging import indent_log
12from pip._internal.utils.misc import get_pip_version
13from pip._internal.utils.typing import MYPY_CHECK_RUNNING
14from pip._internal.wheel import format_tag
15
16if MYPY_CHECK_RUNNING:
17    from typing import Any, List
18    from optparse import Values
19
20logger = logging.getLogger(__name__)
21
22
23def show_value(name, value):
24    # type: (str, str) -> None
25    logger.info('{}: {}'.format(name, value))
26
27
28def show_sys_implementation():
29    # type: () -> None
30    logger.info('sys.implementation:')
31    if hasattr(sys, 'implementation'):
32        implementation = sys.implementation  # type: ignore
33        implementation_name = implementation.name
34    else:
35        implementation_name = ''
36
37    with indent_log():
38        show_value('name', implementation_name)
39
40
41def show_tags(options):
42    # type: (Values) -> None
43    tag_limit = 10
44
45    target_python = make_target_python(options)
46    tags = target_python.get_tags()
47
48    # Display the target options that were explicitly provided.
49    formatted_target = target_python.format_given()
50    suffix = ''
51    if formatted_target:
52        suffix = ' (target: {})'.format(formatted_target)
53
54    msg = 'Compatible tags: {}{}'.format(len(tags), suffix)
55    logger.info(msg)
56
57    if options.verbose < 1 and len(tags) > tag_limit:
58        tags_limited = True
59        tags = tags[:tag_limit]
60    else:
61        tags_limited = False
62
63    with indent_log():
64        for tag in tags:
65            logger.info(format_tag(tag))
66
67        if tags_limited:
68            msg = (
69                '...\n'
70                '[First {tag_limit} tags shown. Pass --verbose to show all.]'
71            ).format(tag_limit=tag_limit)
72            logger.info(msg)
73
74
75class DebugCommand(Command):
76    """
77    Display debug information.
78    """
79
80    name = 'debug'
81    usage = """
82      %prog <options>"""
83    summary = 'Show information useful for debugging.'
84    ignore_require_venv = True
85
86    def __init__(self, *args, **kw):
87        super(DebugCommand, self).__init__(*args, **kw)
88
89        cmd_opts = self.cmd_opts
90        cmdoptions.add_target_python_options(cmd_opts)
91        self.parser.insert_option_group(0, cmd_opts)
92
93    def run(self, options, args):
94        # type: (Values, List[Any]) -> int
95        logger.warning(
96            "This command is only meant for debugging. "
97            "Do not use this with automation for parsing and getting these "
98            "details, since the output and options of this command may "
99            "change without notice."
100        )
101        show_value('pip version', get_pip_version())
102        show_value('sys.version', sys.version)
103        show_value('sys.executable', sys.executable)
104        show_value('sys.getdefaultencoding', sys.getdefaultencoding())
105        show_value('sys.getfilesystemencoding', sys.getfilesystemencoding())
106        show_value(
107            'locale.getpreferredencoding', locale.getpreferredencoding(),
108        )
109        show_value('sys.platform', sys.platform)
110        show_sys_implementation()
111
112        show_tags(options)
113
114        return SUCCESS
115