Skip to content

Commit

Permalink
Add "pip debug" command.
Browse files Browse the repository at this point in the history
  • Loading branch information
cjerdonek committed Jun 27, 2019
1 parent a360649 commit d67acca
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 0 deletions.
2 changes: 2 additions & 0 deletions news/6638.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add a new command ``pip debug`` that can display e.g. the list of compatible
tags for the current Python.
2 changes: 2 additions & 0 deletions src/pip/_internal/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from pip._internal.commands.completion import CompletionCommand
from pip._internal.commands.configuration import ConfigurationCommand
from pip._internal.commands.debug import DebugCommand
from pip._internal.commands.download import DownloadCommand
from pip._internal.commands.freeze import FreezeCommand
from pip._internal.commands.hash import HashCommand
Expand Down Expand Up @@ -36,6 +37,7 @@
WheelCommand,
HashCommand,
CompletionCommand,
DebugCommand,
HelpCommand,
] # type: List[Type[Command]]

Expand Down
102 changes: 102 additions & 0 deletions src/pip/_internal/commands/debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
from __future__ import absolute_import

import logging
import sys

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.utils.logging import indent_log
from pip._internal.utils.misc import get_pip_version
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
from pip._internal.wheel import format_tag

if MYPY_CHECK_RUNNING:
from typing import Any, List
from optparse import Values

logger = logging.getLogger(__name__)


def show_value(name, value):
# type: (str, str) -> None
logger.info('{}: {}'.format(name, value))


def show_sys_implementation():
# type: () -> None
logger.info('sys.implementation:')
if hasattr(sys, 'implementation'):
implementation = sys.implementation # type: ignore
implementation_name = implementation.name
else:
implementation_name = ''

with indent_log():
show_value('name', implementation_name)


def show_tags(options):
# type: (Values) -> None
tag_limit = 10

target_python = make_target_python(options)
tags = target_python.get_tags()

# Display the target options that were explicitly provided.
formatted_target = target_python.format_given()
suffix = ''
if formatted_target:
suffix = ' (target: {})'.format(formatted_target)

msg = 'Compatible tags: {}{}'.format(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(format_tag(tag))

if tags_limited:
msg = (
'...\n'
'[First {tag_limit} tags shown. Pass --verbose to show all.]'
).format(tag_limit=tag_limit)
logger.info(msg)


class DebugCommand(Command):
"""
Display debug information.
"""

name = 'debug'
usage = """
%prog <options>"""
summary = 'Show information useful for debugging.'
ignore_require_venv = True

def __init__(self, *args, **kw):
super(DebugCommand, self).__init__(*args, **kw)

cmd_opts = self.cmd_opts
cmdoptions.add_target_python_options(cmd_opts)
self.parser.insert_option_group(0, cmd_opts)

def run(self, options, args):
# type: (Values, List[Any]) -> int
show_value('pip version', get_pip_version())
show_value('sys.version', sys.version)
show_value('sys.executable', sys.executable)
show_value('sys.platform', sys.platform)
show_sys_implementation()

show_tags(options)

return SUCCESS
50 changes: 50 additions & 0 deletions tests/functional/test_debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import pytest

from pip._internal import pep425tags


@pytest.mark.parametrize(
'args',
[
[],
['--verbose'],
]
)
def test_debug(script, args):
"""
Check simple option cases.
"""
args = ['debug'] + args
result = script.pip(*args)
stdout = result.stdout

assert 'sys.executable: ' in stdout
assert 'sys.platform: ' in stdout
assert 'sys.implementation:' in stdout

tags = pep425tags.get_supported()
expected_tag_header = 'Compatible tags: {}'.format(len(tags))
assert expected_tag_header in stdout

show_verbose_note = '--verbose' not in args
assert (
'...\n [First 10 tags shown. Pass --verbose to show all.]' in stdout
) == show_verbose_note


@pytest.mark.parametrize(
'args, expected',
[
(['--python-version', '3.7'], "(target: version_info='3.7')"),
]
)
def test_debug__target_options(script, args, expected):
"""
Check passing target-related options.
"""
args = ['debug'] + args
result = script.pip(*args)
stdout = result.stdout

assert 'Compatible tags: ' in stdout
assert expected in stdout

0 comments on commit d67acca

Please sign in to comment.