Skip to content
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
30 changes: 11 additions & 19 deletions awscli/argparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
)
USAGE = (
"aws [options] <command> <subcommand> [<subcommand> ...] [parameters]\n"
"%s" % HELP_BLURB
f"{HELP_BLURB}"
)


Expand All @@ -42,9 +42,7 @@ class CommandAction(argparse.Action):

def __init__(self, option_strings, dest, command_table, **kwargs):
self.command_table = command_table
super(CommandAction, self).__init__(
option_strings, dest, choices=self.choices, **kwargs
)
super().__init__(option_strings, dest, choices=self.choices, **kwargs)

def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, values)
Expand Down Expand Up @@ -78,14 +76,12 @@ def _check_value(self, action, value):
if possible:
extra = ['Maybe you meant:\n']
for word in possible:
extra.append(' * %s' % word)
extra.append(f' * {word}')
msg.extend(extra)
raise argparse.ArgumentError(action, '\n'.join(msg))

def parse_known_args(self, args, namespace=None):
parsed, remaining = super(CLIArgParser, self).parse_known_args(
args, namespace
)
parsed, remaining = super().parse_known_args(args, namespace)
terminal_encoding = getattr(sys.stdin, 'encoding', 'utf-8')
if terminal_encoding is None:
# In some cases, sys.stdin won't have an encoding set,
Expand Down Expand Up @@ -117,7 +113,7 @@ def error(self, message):
should raise an exception.
"""
usage_message = self.format_usage()
error_message = f'{self.prog}: error: {message}'
error_message = f'{self.prog}: [ERROR]: {message}'
raise ArgParseException(f'{error_message}\n\n{usage_message}')


Expand All @@ -132,7 +128,7 @@ def __init__(
argument_table,
prog=None,
):
super(MainArgParser, self).__init__(
super().__init__(
formatter_class=self.Formatter,
add_help=False,
conflict_handler='resolve',
Expand All @@ -145,7 +141,7 @@ def __init__(
def _create_choice_help(self, choices):
help_str = ''
for choice in sorted(choices):
help_str += '* %s\n' % choice
help_str += f'* {choice}\n'
return help_str

def _build(self, command_table, version_string, argument_table):
Expand All @@ -165,7 +161,7 @@ def _build(self, command_table, version_string, argument_table):

class ServiceArgParser(CLIArgParser):
def __init__(self, operations_table, service_name):
super(ServiceArgParser, self).__init__(
super().__init__(
formatter_class=argparse.RawTextHelpFormatter,
add_help=False,
conflict_handler='resolve',
Expand All @@ -187,7 +183,7 @@ def __init__(self, argument_table, command_table=None):
# command_table is an optional subcommand_table. If it's passed
# in, then we'll update the argparse to parse a 'subcommand' argument
# and populate the choices field with the command table keys.
super(ArgTableArgParser, self).__init__(
super().__init__(
formatter_class=self.Formatter,
add_help=False,
usage=USAGE,
Expand Down Expand Up @@ -215,9 +211,7 @@ def parse_known_args(self, args, namespace=None):
namespace.help = 'help'
return namespace, []
else:
return super(ArgTableArgParser, self).parse_known_args(
args, namespace
)
return super().parse_known_args(args, namespace)


class SubCommandArgParser(ArgTableArgParser):
Expand All @@ -230,9 +224,7 @@ class SubCommandArgParser(ArgTableArgParser):
"""

def parse_known_args(self, args, namespace=None):
parsed_args, remaining = super(
SubCommandArgParser, self
).parse_known_args(args, namespace)
parsed_args, remaining = super().parse_known_args(args, namespace)
if getattr(parsed_args, 'subcommand', None) is not None:
new_args = self._remove_subcommand(args, parsed_args)
return new_args, parsed_args.subcommand
Expand Down
44 changes: 18 additions & 26 deletions awscli/customizations/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,7 @@ def __call__(self, args, parsed_globals):
# an arg parser and parse them.
self._subcommand_table = self._build_subcommand_table()
self._arg_table = self._build_arg_table()
event = 'before-building-argument-table-parser.%s' % ".".join(
self.lineage_names
)
event = f'before-building-argument-table-parser.{".".join(self.lineage_names)}'
self._session.emit(
event,
argument_table=self._arg_table,
Expand Down Expand Up @@ -177,7 +175,7 @@ def __call__(self, args, parsed_globals):
# a chance to process and override its value.
if self._should_allow_plugins_override(cli_argument, value):
override = self._session.emit_first_non_none_response(
'process-cli-arg.%s.%s' % ('custom', self.name),
f'process-cli-arg.custom.{self.name}',
cli_argument=cli_argument,
value=value,
operation=None,
Expand All @@ -204,15 +202,15 @@ def __call__(self, args, parsed_globals):
# function for this top level command.
if remaining:
raise ParamValidationError(
"Unknown options: %s" % ','.join(remaining)
f"Unknown options: {','.join(remaining)}"
)
rc = self._run_main(parsed_args, parsed_globals)
if rc is None:
return 0
else:
return rc

def _validate_value_against_schema(self, model, value):
def _validate_value_against_schema(self, model, value): ## noqa: F811
validate_parameters(value, model)

def _should_allow_plugins_override(self, param, value):
Expand All @@ -239,7 +237,7 @@ def _build_subcommand_table(self):
subcommand_table[subcommand_name] = subcommand_class(self._session)
name = '_'.join([c.name for c in self.lineage])
self._session.emit(
'building-command-table.%s' % name,
f'building-command-table.{name}',
command_table=subcommand_table,
session=self._session,
command_object=self,
Expand Down Expand Up @@ -277,7 +275,7 @@ def _build_arg_table(self):
arg_table = OrderedDict()
name = '_'.join([c.name for c in self.lineage])
self._session.emit(
'building-arg-table.%s' % name, arg_table=self.ARG_TABLE
f'building-arg-table.{name}', arg_table=self.ARG_TABLE
)
for arg_data in self.ARG_TABLE:
# If a custom schema was passed in, create the argument_model
Expand Down Expand Up @@ -328,9 +326,9 @@ def lineage(self, value):
def _raise_usage_error(self):
lineage = ' '.join([c.name for c in self.lineage])
error_msg = (
"usage: aws [options] %s <subcommand> "
"[parameters]\naws: error: too few arguments"
) % lineage
f"usage: aws [options] {lineage} <subcommand> "
"[parameters]\naws: [ERROR]: too few arguments"
)
raise ParamValidationError(error_msg)

def _add_customization_to_user_agent(self):
Expand All @@ -348,9 +346,7 @@ def __init__(
arg_table,
event_handler_class=None,
):
super(BasicHelp, self).__init__(
session, command_object, command_table, arg_table
)
super().__init__(session, command_object, command_table, arg_table)
# This is defined in HelpCommand so we're matching the
# casing here.
if event_handler_class is None:
Expand Down Expand Up @@ -414,7 +410,7 @@ def __call__(self, args, parsed_globals):

class BasicDocHandler(OperationDocumentEventHandler):
def __init__(self, help_command):
super(BasicDocHandler, self).__init__(help_command)
super().__init__(help_command)
self.doc = help_command.doc

def doc_description(self, help_command, **kwargs):
Expand All @@ -424,9 +420,7 @@ def doc_description(self, help_command, **kwargs):

def doc_synopsis_start(self, help_command, **kwargs):
if not help_command.synopsis:
super(BasicDocHandler, self).doc_synopsis_start(
help_command=help_command, **kwargs
)
super().doc_synopsis_start(help_command=help_command, **kwargs)
else:
self.doc.style.h2('Synopsis')
self.doc.style.start_codeblock()
Expand All @@ -447,14 +441,14 @@ def doc_synopsis_option(self, arg_name, help_command, **kwargs):
)
self._documented_arg_groups.append(argument.group_name)
elif argument.cli_type_name == 'boolean':
option_str = '%s' % argument.cli_name
option_str = f'{argument.cli_name}'
elif argument.nargs == '+':
option_str = "%s <value> [<value>...]" % argument.cli_name
option_str = f"{argument.cli_name} <value> [<value>...]"
else:
option_str = '%s <value>' % argument.cli_name
option_str = f'{argument.cli_name} <value>'
if not (argument.required or argument.positional_arg):
option_str = '[%s]' % option_str
doc.writeln('%s' % option_str)
option_str = f'[{option_str}]'
doc.writeln(f'{option_str}')

else:
# A synopsis has been provided so we don't need to write
Expand All @@ -463,9 +457,7 @@ def doc_synopsis_option(self, arg_name, help_command, **kwargs):

def doc_synopsis_end(self, help_command, **kwargs):
if not help_command.synopsis and not help_command.command_table:
super(BasicDocHandler, self).doc_synopsis_end(
help_command=help_command, **kwargs
)
super().doc_synopsis_end(help_command=help_command, **kwargs)
else:
self.doc.style.end_codeblock()

Expand Down
2 changes: 1 addition & 1 deletion tests/functional/ddb/test_ddb.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ def test_no_command_specified(self):
_, stderr, _ = self.run_cmd('ddb', expected_rc=252)
expected = (
"usage: aws [options] ddb <subcommand> "
"[parameters]\naws: error: too few arguments"
"[parameters]\naws: [ERROR]: too few arguments"
)
self.assertIn(expected, stderr)
48 changes: 22 additions & 26 deletions tests/integration/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def test_param_with_bad_json(self):
self.assertIn(
"The filter 'bad-filter' is invalid",
p.stderr,
"stdout: %s, stderr: %s" % (p.stdout, p.stderr),
f"stdout: {p.stdout}, stderr: {p.stderr}",
)

def test_param_with_file(self):
Expand All @@ -166,7 +166,7 @@ def test_param_with_file(self):
with open(param_file, 'w') as f:
f.write('[{"Name": "instance-id", "Values": ["i-123"]}]')
self.addCleanup(os.remove, param_file)
p = aws('ec2 describe-instances --filters file://%s' % param_file)
p = aws(f'ec2 describe-instances --filters file://{param_file}')
self.assertEqual(p.rc, 0)
self.assertIn('Reservations', p.json)

Expand All @@ -181,8 +181,7 @@ def test_streaming_output_operation(self):
bucket=bucket_name, key='foobar', content='foobar contents'
)
p = aws(
's3api get-object --bucket %s --key foobar %s'
% (bucket_name, os.path.join(d, 'foobar'))
f's3api get-object --bucket {bucket_name} --key foobar {os.path.join(d, "foobar")}'
)
self.assertEqual(p.rc, 0)
with open(os.path.join(d, 'foobar')) as f:
Expand All @@ -208,16 +207,15 @@ def test_no_sign_request(self):
)

p = aws(
's3api get-object --bucket %s --key foo %s'
% (bucket_name, os.path.join(d, 'foo')),
f's3api get-object --bucket {bucket_name} --key foo {os.path.join(d, "foo")}',
env_vars=env_vars,
)
# Should have credential issues.
self.assertEqual(p.rc, 254)

p = aws(
's3api get-object --bucket %s --key foo '
'%s --no-sign-request' % (bucket_name, os.path.join(d, 'foo')),
f's3api get-object --bucket {bucket_name} --key foo '
f'{os.path.join(d, "foo")} --no-sign-request',
env_vars=env_vars,
)

Expand All @@ -238,10 +236,10 @@ def test_no_paginate_arg(self):
self.put_object(
bucket=bucket_name, key='foobar', content='foobar contents'
)
p = aws('s3api list-objects --bucket %s --no-paginate' % bucket_name)
p = aws(f's3api list-objects --bucket {bucket_name} --no-paginate')
self.assertEqual(p.rc, 0, p.stdout + p.stderr)

p = aws('s3api list-objects --bucket %s' % bucket_name)
p = aws(f's3api list-objects --bucket {bucket_name}')
self.assertEqual(p.rc, 0, p.stdout + p.stderr)

def test_top_level_options_debug(self):
Expand All @@ -261,7 +259,7 @@ def test_help_usage_top_level(self):
'<subcommand> [<subcommand> ...] [parameters]',
p.stderr,
)
self.assertIn('aws: error', p.stderr)
self.assertIn('aws: [ERROR]', p.stderr)

def test_help_usage_service_level(self):
p = aws('ec2')
Expand All @@ -270,11 +268,11 @@ def test_help_usage_service_level(self):
'<subcommand> [<subcommand> ...] [parameters]',
p.stderr,
)
# python3: aws: error: the following arguments are required: operation
# python2: aws: error: too few arguments
# python3: aws: [ERROR]: the following arguments are required: operation
# python2: aws: [ERROR]: too few arguments
# We don't care too much about the specific error message, as long
# as it says we have a parse error.
self.assertIn('aws: error', p.stderr)
self.assertIn('aws: [ERROR]', p.stderr)

def test_help_usage_operation_level(self):
p = aws('ec2 start-instances')
Expand Down Expand Up @@ -458,8 +456,8 @@ def test_no_pagination(self):
self.put_object(bucket_name, 'foo2.txt', contents=b'bar')
self.put_object(bucket_name, 'foo3.txt', contents=b'bar')
p = aws(
's3api list-objects --bucket %s '
'--no-paginate --output json' % bucket_name
f's3api list-objects --bucket {bucket_name} '
'--no-paginate --output json'
)
# A really simple way to check that --no-paginate was
# honored is to see if we have all the mirrored input
Expand All @@ -476,8 +474,8 @@ def test_no_paginate_and_original_args(self):
self.put_object(bucket_name, 'foo2.txt', contents=b'bar')
self.put_object(bucket_name, 'foo3.txt', contents=b'bar')
p = aws(
's3api list-objects --bucket %s '
'--max-keys 1 --no-paginate --output json' % bucket_name
f's3api list-objects --bucket {bucket_name} '
'--max-keys 1 --no-paginate --output json'
)
self.assert_no_errors(p)
response_json = p.json
Expand All @@ -489,8 +487,8 @@ def test_max_items(self):
self.put_object(bucket_name, 'foo2.txt', contents=b'bar')
self.put_object(bucket_name, 'foo3.txt', contents=b'bar')
p = aws(
's3api list-objects --bucket %s '
'--max-items 1 --output json' % bucket_name
f's3api list-objects --bucket {bucket_name} '
'--max-items 1 --output json'
)
self.assert_no_errors(p)
response_json = p.json
Expand All @@ -500,8 +498,8 @@ def test_query(self):
bucket_name = self.create_bucket()
self.put_object(bucket_name, 'foo.txt', contents=b'bar')
p = aws(
's3api list-objects --bucket %s '
'--query Contents[].Key --output json' % bucket_name
f's3api list-objects --bucket {bucket_name} '
'--query Contents[].Key --output json'
)
self.assert_no_errors(p)
response_json = p.json
Expand All @@ -522,8 +520,7 @@ def test_no_sign_requests(self):
env['AWS_ACCESS_KEY_ID'] = 'foo'
env['AWS_SECRET_ACCESS_KEY'] = 'bar'
p = aws(
's3api head-object --bucket %s --key public --no-sign-request'
% bucket_name,
f's3api head-object --bucket {bucket_name} --key public --no-sign-request',
env_vars=env,
)
self.assert_no_errors(p)
Expand All @@ -532,8 +529,7 @@ def test_no_sign_requests(self):
# Should fail because we're not signing the request but the object is
# private.
p = aws(
's3api head-object --bucket %s --key private --no-sign-request'
% bucket_name,
f's3api head-object --bucket {bucket_name} --key private --no-sign-request',
env_vars=env,
)
self.assertEqual(p.rc, 254)
Expand Down
Loading