Files
dvc/dvc/cli/parser.py
T
Ronan Lamy fa7619dfee ls-url: create basic version of dvc ls-url command
For now, this only takes a URL (or local path) and lists its contents
if the protocol supports it. The command fails if the target doesn't
exist and returns the (absolute) path to the target if it's not a
directory.
2022-10-04 14:37:29 +03:00

223 lines
4.9 KiB
Python

"""Main parser for the dvc cli."""
import argparse
import logging
import os
import sys
from dvc.commands import (
add,
cache,
check_ignore,
checkout,
commit,
completion,
config,
daemon,
dag,
data,
data_sync,
destroy,
diff,
experiments,
freeze,
gc,
get,
get_url,
git_hook,
imp,
imp_url,
init,
install,
ls,
ls_url,
machine,
metrics,
move,
params,
plots,
queue,
remote,
remove,
repro,
root,
run,
stage,
unprotect,
update,
version,
)
from . import DvcParserError
logger = logging.getLogger(__name__)
COMMANDS = [
init,
queue,
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,
ls_url,
freeze,
dag,
daemon,
commit,
completion,
diff,
version,
update,
git_hook,
plots,
stage,
experiments,
check_ignore,
machine,
data,
]
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.
"""
from dvc._debug import add_debugging_flags
parent_parser = argparse.ArgumentParser(add_help=False)
add_debugging_flags(parent_parser)
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.",
)
parser.add_argument(
"--cd",
default=os.path.curdir,
metavar="<path>",
help="Change to directory before executing.",
type=str,
)
# Sub commands
subparsers = parser.add_subparsers(
title="Available Commands",
metavar="COMMAND",
dest="cmd",
help="Use `dvc COMMAND --help` for command-specific help.",
)
from .utils import fix_subparsers
fix_subparsers(subparsers)
for cmd in COMMANDS:
cmd.add_parser(subparsers, parent_parser)
return parser