diff --git a/dvc/cli.py b/dvc/cli.py index 5ffdc1347..2de78ff60 100644 --- a/dvc/cli.py +++ b/dvc/cli.py @@ -81,18 +81,33 @@ COMMANDS = [ class DvcParser(argparse.ArgumentParser): """Custom parser class for dvc CLI.""" - def error(self, message): + def error(self, message, command=None): """Custom error method. Args: message (str): error message. - + command (str): subcommand name for help message Raises: dvc.exceptions.DvcParser: dvc parser exception. + """ logger.error(message) + if command is not None: + for action in self._actions: + if action.dest == "cmd" and command in action.choices: + subparser = action.choices[command] + subparser.print_help() + raise DvcParserError() self.print_help() raise DvcParserError() + # override this to send subcommand name to error method + def parse_args(self, args=None, namespace=None): + args, argv = self.parse_known_args(args, namespace) + if argv: + msg = "unrecognized arguments: %s" + self.error(msg % " ".join(argv), args.cmd) + return args + class VersionAction(argparse.Action): # pragma: no cover # pylint: disable=too-few-public-methods diff --git a/tests/func/test_cli.py b/tests/func/test_cli.py index bd19836c5..970be5337 100644 --- a/tests/func/test_cli.py +++ b/tests/func/test_cli.py @@ -12,7 +12,7 @@ from dvc.command.remove import CmdRemove from dvc.command.repro import CmdRepro from dvc.command.run import CmdRun from dvc.command.status import CmdDataStatus -from dvc.exceptions import DvcException +from dvc.exceptions import DvcException, DvcParserError from tests.basic_env import TestDvc @@ -171,3 +171,36 @@ class TestFindRoot(TestDvc): args = A() with self.assertRaises(DvcException): CmdBase(args) + + +def test_unknown_command_help(capsys): + try: + _ = parse_args(["unknown"]) + except DvcParserError: + pass + captured = capsys.readouterr() + output = captured.out + try: + _ = parse_args(["--help"]) + except SystemExit: + pass + captured = capsys.readouterr() + help_output = captured.out + assert output == help_output + + +def test_unknown_subcommand_help(capsys): + sample_subcommand = "push" + try: + _ = parse_args([sample_subcommand, "--unknown"]) + except DvcParserError: + pass + captured = capsys.readouterr() + output = captured.out + try: + _ = parse_args([sample_subcommand, "--help"]) + except SystemExit: + pass + captured = capsys.readouterr() + help_output = captured.out + assert output == help_output