Skip to content

Commit

Permalink
Refactor argument parser construction (#239)
Browse files Browse the repository at this point in the history
Each subparser is added in its own function
  • Loading branch information
clbarnes authored and Chad Smith committed Oct 18, 2019
1 parent 047a0be commit 997b0eb
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 22 deletions.
92 changes: 70 additions & 22 deletions pipx/main.py
Expand Up @@ -6,22 +6,37 @@
import argparse
import functools
import logging
from pkg_resources import parse_version
import shlex
import sys
import textwrap
import urllib.parse
from typing import Dict, List
from typing import Dict, List, Tuple, Union

import argcomplete # type: ignore

from . import commands, constants
from .colors import bold, green
from . import commands
from . import constants
from .util import PipxError, mkdir
from .Venv import VenvContainer

__version__ = "0.14.0.0"


def simple_parse_version(s, segments=4) -> Tuple[Union[int, str], ...]:
_, out, subver, *_ = parse_version(s)._key # type: ignore

if isinstance(subver, tuple):
while len(out) < segments:
out += (0,)
out += subver

return out


__version_info__ = simple_parse_version(__version__)


def print_version() -> None:
print(__version__)

Expand All @@ -47,7 +62,6 @@ def print_version() -> None:
"""
)


INSTALL_DESCRIPTION = f"""
The install command is the preferred way to globally install apps
from python packages on your system. It creates an isolated virtual
Expand Down Expand Up @@ -257,21 +271,7 @@ def _autocomplete_list_of_installed_packages(
return list(str(p.name) for p in sorted(venv_container.iter_venv_dirs()))


def get_command_parser():
venv_container = VenvContainer(constants.PIPX_LOCAL_VENVS)

autocomplete_list_of_installed_packages = functools.partial(
_autocomplete_list_of_installed_packages, venv_container
)

parser = argparse.ArgumentParser(
formatter_class=LineWrapRawTextHelpFormatter, description=PIPX_DESCRIPTION
)

subparsers = parser.add_subparsers(
dest="command", description="Get help for commands with pipx COMMAND --help"
)

def _add_install(subparsers):
p = subparsers.add_parser(
"install",
help="Install a package",
Expand All @@ -298,6 +298,8 @@ def get_command_parser():
)
add_pip_venv_args(p)


def _add_inject(subparsers, autocomplete_list_of_installed_packages):
p = subparsers.add_parser(
"inject",
help="Install packages into an existing Virtual Environment",
Expand Down Expand Up @@ -327,6 +329,8 @@ def get_command_parser():
)
p.add_argument("--verbose", action="store_true")


def _add_upgrade(subparsers, autocomplete_list_of_installed_packages):
p = subparsers.add_parser(
"upgrade",
help="Upgrade a package",
Expand All @@ -344,6 +348,8 @@ def get_command_parser():
add_pip_venv_args(p)
p.add_argument("--verbose", action="store_true")


def _add_upgrade_all(subparsers):
p = subparsers.add_parser(
"upgrade-all",
help="Upgrade all packages. "
Expand All @@ -362,6 +368,8 @@ def get_command_parser():
)
p.add_argument("--verbose", action="store_true")


def _add_uninstall(subparsers, autocomplete_list_of_installed_packages):
p = subparsers.add_parser(
"uninstall",
help="Uninstall a package",
Expand All @@ -370,13 +378,17 @@ def get_command_parser():
p.add_argument("package").completer = autocomplete_list_of_installed_packages
p.add_argument("--verbose", action="store_true")


def _add_uninstall_all(subparsers):
p = subparsers.add_parser(
"uninstall-all",
help="Uninstall all packages",
description="Uninstall all pipx-managed packages",
)
p.add_argument("--verbose", action="store_true")


def _add_reinstall_all(subparsers):
p = subparsers.add_parser(
"reinstall-all",
formatter_class=LineWrapRawTextHelpFormatter,
Expand All @@ -401,13 +413,17 @@ def get_command_parser():
p.add_argument("--skip", nargs="+", default=[], help="skip these packages")
p.add_argument("--verbose", action="store_true")


def _add_list(subparsers):
p = subparsers.add_parser(
"list",
help="List installed packages",
description="List packages and apps installed with pipx",
)
p.add_argument("--verbose", action="store_true")


def _add_run(subparsers):
p = subparsers.add_parser(
"run",
formatter_class=LineWrapRawTextHelpFormatter,
Expand Down Expand Up @@ -457,6 +473,8 @@ def get_command_parser():
)
add_pip_venv_args(p)


def _add_runpip(subparsers, autocomplete_list_of_installed_packages):
p = subparsers.add_parser(
"runpip",
help="Run pip in an existing pipx-managed Virtual Environment",
Expand All @@ -474,6 +492,8 @@ def get_command_parser():
)
p.add_argument("--verbose", action="store_true")


def _add_ensurepath(subparsers):
p = subparsers.add_parser(
"ensurepath",
help=(
Expand All @@ -491,10 +511,38 @@ def get_command_parser():
f"PATH already has {str(constants.LOCAL_BIN_DIR)}"
),
)


def get_command_parser():
venv_container = VenvContainer(constants.PIPX_LOCAL_VENVS)

autocomplete_list_of_installed_packages = functools.partial(
_autocomplete_list_of_installed_packages, venv_container
)

parser = argparse.ArgumentParser(
formatter_class=LineWrapRawTextHelpFormatter, description=PIPX_DESCRIPTION
)

subparsers = parser.add_subparsers(
dest="command", description="Get help for commands with pipx COMMAND --help"
)

_add_install(subparsers)
_add_inject(subparsers, autocomplete_list_of_installed_packages)
_add_upgrade(subparsers, autocomplete_list_of_installed_packages)
_add_upgrade_all(subparsers)
_add_uninstall(subparsers, autocomplete_list_of_installed_packages)
_add_uninstall_all(subparsers)
_add_reinstall_all(subparsers)
_add_list(subparsers)
_add_run(subparsers)
_add_runpip(subparsers, autocomplete_list_of_installed_packages)
_add_ensurepath(subparsers)

parser.add_argument("--version", action="store_true", help="Print version and exit")
p = subparsers.add_parser(
"completions",
help=("Print instructions on enabling shell completions for pipx"),
subparsers.add_parser(
"completions", help="Print instructions on enabling shell completions for pipx"
)
return parser

Expand Down
14 changes: 14 additions & 0 deletions tests/test_main.py
Expand Up @@ -11,6 +11,20 @@
assert_not_in_virtualenv()


@pytest.mark.parametrize(
"ver_str,expected",
[
["0.14.0.0", (0, 14)],
["0.14.0.0b0", (0, 14, 0, 0, "b", 0)],
["0.14", (0, 14)],
["0.14b0", (0, 14, 0, 0, "b", 0)],
["1.1.1.1", (1, 1, 1, 1)],
],
)
def test_simple_parse_version(ver_str, expected):
assert main.simple_parse_version(ver_str) == expected


def test_help_text(monkeypatch, capsys):
mock_exit = mock.Mock(side_effect=ValueError("raised in test to exit early"))
with mock.patch.object(sys, "exit", mock_exit), pytest.raises(
Expand Down

0 comments on commit 997b0eb

Please sign in to comment.