Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Derive "param_hint" in errors from param itself #709

Merged
merged 3 commits into from
May 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions click/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1431,6 +1431,13 @@ def get_help_record(self, ctx):
def get_usage_pieces(self, ctx):
return []

def get_error_hint(self, ctx):
"""Get a stringified version of the param for use in error messages to
indicate which param caused the error.
"""
hint_list = self.opts or [self.human_readable_name]
return ' / '.join('"%s"' % x for x in hint_list)


class Option(Parameter):
"""Options are usually optional values on the command line and
Expand Down Expand Up @@ -1755,6 +1762,9 @@ def _parse_decls(self, decls, expose_value):
def get_usage_pieces(self, ctx):
return [self.make_metavar()]

def get_error_hint(self, ctx):
return '"%s"' % self.make_metavar()

def add_to_parser(self, parser, ctx):
parser.add_argument(dest=self.name, nargs=self.nargs,
obj=self)
Expand Down
17 changes: 11 additions & 6 deletions click/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
from .utils import echo


def _join_param_hints(param_hint):
if isinstance(param_hint, (tuple, list)):
return ' / '.join('"%s"' % x for x in param_hint)
return param_hint


class ClickException(Exception):
"""An exception that Click can handle and show to the user."""

Expand Down Expand Up @@ -92,11 +98,11 @@ def format_message(self):
if self.param_hint is not None:
param_hint = self.param_hint
elif self.param is not None:
param_hint = self.param.opts or [self.param.human_readable_name]
param_hint = self.param.get_error_hint(self.ctx)
else:
return 'Invalid value: %s' % self.message
if isinstance(param_hint, (tuple, list)):
param_hint = ' / '.join('"%s"' % x for x in param_hint)
param_hint = _join_param_hints(param_hint)

return 'Invalid value for %s: %s' % (param_hint, self.message)


Expand All @@ -121,11 +127,10 @@ def format_message(self):
if self.param_hint is not None:
param_hint = self.param_hint
elif self.param is not None:
param_hint = self.param.opts or [self.param.human_readable_name]
param_hint = self.param.get_error_hint(self.ctx)
else:
param_hint = None
if isinstance(param_hint, (tuple, list)):
param_hint = ' / '.join('"%s"' % x for x in param_hint)
param_hint = _join_param_hints(param_hint)

param_type = self.param_type
if param_type is None and self.param is not None:
Expand Down
4 changes: 2 additions & 2 deletions tests/test_arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def cmd2(arg):

result = runner.invoke(cmd2, [])
assert result.exit_code == 2
assert 'Missing argument "arg"' in result.output
assert 'Missing argument "ARG..."' in result.output


def test_missing_arg(runner):
Expand All @@ -199,7 +199,7 @@ def cmd(arg):

result = runner.invoke(cmd, [])
assert result.exit_code == 2
assert 'Missing argument "arg".' in result.output
assert 'Missing argument "ARG".' in result.output


def test_implicit_non_required(runner):
Expand Down
44 changes: 40 additions & 4 deletions tests/test_formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,43 @@ def cmd(arg):
'Usage: cmd [OPTIONS] ARG',
'Try "cmd --help" for help.',
'',
'Error: Missing argument "arg".'
'Error: Missing argument "ARG".'
]


def test_formatting_usage_error_metavar_missing_arg(runner):
"""
:author: @r-m-n
Including attribution to #612
"""
@click.command()
@click.argument('arg', metavar='metavar')
def cmd(arg):
pass

result = runner.invoke(cmd, [])
assert result.exit_code == 2
assert result.output.splitlines() == [
'Usage: cmd [OPTIONS] metavar',
'Try "cmd --help" for help.',
'',
'Error: Missing argument "metavar".'
]


def test_formatting_usage_error_metavar_bad_arg(runner):
@click.command()
@click.argument('arg', type=click.INT, metavar='metavar')
def cmd(arg):
pass

result = runner.invoke(cmd, ['3.14'])
assert result.exit_code == 2
assert result.output.splitlines() == [
'Usage: cmd [OPTIONS] metavar',
'Try "cmd --help" for help.',
'',
'Error: Invalid value for "metavar": 3.14 is not a valid integer'
]


Expand All @@ -179,7 +215,7 @@ def foo(bar):
'Usage: cmd foo [OPTIONS] BAR',
'Try "cmd foo --help" for help.',
'',
'Error: Missing argument "bar".'
'Error: Missing argument "BAR".'
]


Expand All @@ -194,7 +230,7 @@ def cmd(arg):
assert result.output.splitlines() == [
'Usage: cmd [OPTIONS] ARG',
'',
'Error: Missing argument "arg".'
'Error: Missing argument "ARG".'
]


Expand All @@ -210,5 +246,5 @@ def cmd(arg):
'Usage: cmd [OPTIONS] ARG',
'Try "cmd --man" for help.',
'',
'Error: Missing argument "arg".'
'Error: Missing argument "ARG".'
]