mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-04 15:28:27 +01:00
222 lines
5.0 KiB
Python
222 lines
5.0 KiB
Python
"""DVC command line interface"""
|
|
import argparse
|
|
import logging
|
|
import sys
|
|
|
|
from .command import (
|
|
add,
|
|
cache,
|
|
check_ignore,
|
|
checkout,
|
|
commit,
|
|
completion,
|
|
config,
|
|
daemon,
|
|
dag,
|
|
data_sync,
|
|
destroy,
|
|
diff,
|
|
experiments,
|
|
freeze,
|
|
gc,
|
|
get,
|
|
get_url,
|
|
git_hook,
|
|
imp,
|
|
imp_url,
|
|
init,
|
|
install,
|
|
ls,
|
|
metrics,
|
|
move,
|
|
params,
|
|
plots,
|
|
remote,
|
|
remove,
|
|
repro,
|
|
root,
|
|
run,
|
|
unprotect,
|
|
update,
|
|
version,
|
|
)
|
|
from .command.base import fix_subparsers
|
|
from .exceptions import DvcParserError
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
COMMANDS = [
|
|
init,
|
|
get,
|
|
get_url,
|
|
destroy,
|
|
add,
|
|
remove,
|
|
move,
|
|
unprotect,
|
|
run,
|
|
repro,
|
|
data_sync,
|
|
gc,
|
|
imp,
|
|
imp_url,
|
|
config,
|
|
checkout,
|
|
remote,
|
|
cache,
|
|
metrics,
|
|
params,
|
|
install,
|
|
root,
|
|
ls,
|
|
freeze,
|
|
dag,
|
|
daemon,
|
|
commit,
|
|
completion,
|
|
diff,
|
|
version,
|
|
update,
|
|
git_hook,
|
|
plots,
|
|
experiments,
|
|
check_ignore,
|
|
]
|
|
|
|
|
|
def _find_parser(parser, cmd_cls):
|
|
defaults = parser._defaults # pylint: disable=protected-access
|
|
if not cmd_cls or cmd_cls == defaults.get("func"):
|
|
parser.print_help()
|
|
raise DvcParserError()
|
|
|
|
actions = parser._actions # pylint: disable=protected-access
|
|
for action in actions:
|
|
if not isinstance(action.choices, dict):
|
|
# NOTE: we are only interested in subparsers
|
|
continue
|
|
for subparser in action.choices.values():
|
|
_find_parser(subparser, cmd_cls)
|
|
|
|
|
|
class DvcParser(argparse.ArgumentParser):
|
|
"""Custom parser class for dvc CLI."""
|
|
|
|
def error(self, message, cmd_cls=None): # pylint: disable=arguments-differ
|
|
logger.error(message)
|
|
_find_parser(self, cmd_cls)
|
|
|
|
def parse_args(self, args=None, namespace=None):
|
|
# NOTE: overriding to provide a more granular help message.
|
|
# E.g. `dvc plots diff --bad-flag` would result in a `dvc plots diff`
|
|
# help message instead of generic `dvc` usage.
|
|
args, argv = self.parse_known_args(args, namespace)
|
|
if argv:
|
|
msg = "unrecognized arguments: %s"
|
|
self.error(msg % " ".join(argv), getattr(args, "func", None))
|
|
return args
|
|
|
|
|
|
class VersionAction(argparse.Action): # pragma: no cover
|
|
# pylint: disable=too-few-public-methods
|
|
"""Shows DVC version and exits."""
|
|
|
|
def __call__(self, parser, namespace, values, option_string=None):
|
|
from dvc import __version__
|
|
|
|
print(__version__)
|
|
sys.exit(0)
|
|
|
|
|
|
def get_parent_parser():
|
|
"""Create instances of a parser containing common arguments shared among
|
|
all the commands.
|
|
|
|
When overwriting `-q` or `-v`, you need to instantiate a new object
|
|
in order to prevent some weird behavior.
|
|
"""
|
|
parent_parser = argparse.ArgumentParser(add_help=False)
|
|
|
|
parent_parser.add_argument(
|
|
"--cprofile",
|
|
action="store_true",
|
|
default=False,
|
|
help=argparse.SUPPRESS,
|
|
)
|
|
parent_parser.add_argument("--cprofile-dump", help=argparse.SUPPRESS)
|
|
|
|
log_level_group = parent_parser.add_mutually_exclusive_group()
|
|
log_level_group.add_argument(
|
|
"-q", "--quiet", action="count", default=0, help="Be quiet."
|
|
)
|
|
log_level_group.add_argument(
|
|
"-v", "--verbose", action="count", default=0, help="Be verbose."
|
|
)
|
|
|
|
return parent_parser
|
|
|
|
|
|
def get_main_parser():
|
|
parent_parser = get_parent_parser()
|
|
|
|
# Main parser
|
|
desc = "Data Version Control"
|
|
parser = DvcParser(
|
|
prog="dvc",
|
|
description=desc,
|
|
parents=[parent_parser],
|
|
formatter_class=argparse.RawTextHelpFormatter,
|
|
add_help=False,
|
|
)
|
|
|
|
# NOTE: We are doing this to capitalize help message.
|
|
# Unfortunately, there is no easier and clearer way to do it,
|
|
# as adding this argument in get_parent_parser() either in
|
|
# log_level_group or on parent_parser itself will cause unexpected error.
|
|
parser.add_argument(
|
|
"-h",
|
|
"--help",
|
|
action="help",
|
|
default=argparse.SUPPRESS,
|
|
help="Show this help message and exit.",
|
|
)
|
|
|
|
# NOTE: On some python versions action='version' prints to stderr
|
|
# instead of stdout https://bugs.python.org/issue18920
|
|
parser.add_argument(
|
|
"-V",
|
|
"--version",
|
|
action=VersionAction,
|
|
nargs=0,
|
|
help="Show program's version.",
|
|
)
|
|
|
|
# Sub commands
|
|
subparsers = parser.add_subparsers(
|
|
title="Available Commands",
|
|
metavar="COMMAND",
|
|
dest="cmd",
|
|
help="Use `dvc COMMAND --help` for command-specific help.",
|
|
)
|
|
|
|
fix_subparsers(subparsers)
|
|
|
|
for cmd in COMMANDS:
|
|
cmd.add_parser(subparsers, parent_parser)
|
|
|
|
return parser
|
|
|
|
|
|
def parse_args(argv=None):
|
|
"""Parses CLI arguments.
|
|
|
|
Args:
|
|
argv: optional list of arguments to parse. sys.argv is used by default.
|
|
|
|
Raises:
|
|
dvc.exceptions.DvcParserError: raised for argument parsing errors.
|
|
"""
|
|
parser = get_main_parser()
|
|
args = parser.parse_args(argv)
|
|
return args
|