diff --git a/awscli/autocomplete/__init__.py b/awscli/autocomplete/__init__.py
index 61e108c38e7f..50f76da3d69b 100644
--- a/awscli/autocomplete/__init__.py
+++ b/awscli/autocomplete/__init__.py
@@ -40,21 +40,24 @@ class LazyClientCreator(object):
a client. This class manages this process.
"""
- def __init__(self,
- import_name='awscli.clidriver.create_clidriver'):
+
+ def __init__(self, import_name='awscli.clidriver.create_clidriver'):
self._import_name = import_name
self._session_cache = {}
- def create_client(self, service_name, parsed_region=None,
- parsed_profile=None, **kwargs):
+ def create_client(
+ self, service_name, parsed_region=None, parsed_profile=None, **kwargs
+ ):
if self._session_cache.get(parsed_profile) is None:
session = self.create_session()
session.set_config_variable('profile', parsed_profile)
self._session_cache[parsed_profile] = session
self._session_cache[parsed_profile].set_config_variable(
- 'region', parsed_region)
+ 'region', parsed_region
+ )
return self._session_cache[parsed_profile].create_client(
- service_name, **kwargs)
+ service_name, **kwargs
+ )
def create_session(self):
return lazy_call(self._import_name).session
diff --git a/awscli/autocomplete/autogen.py b/awscli/autocomplete/autogen.py
index 5ac01d266ecb..6f5792399a22 100644
--- a/awscli/autocomplete/autogen.py
+++ b/awscli/autocomplete/autogen.py
@@ -5,14 +5,22 @@
It can also be used to regen completion data as new heuristics are added.
"""
+
import logging
+from collections import defaultdict, namedtuple
from difflib import SequenceMatcher
-from collections import namedtuple, defaultdict
-
LOG = logging.getLogger(__name__)
-Resource = namedtuple('Resource', ['resource_name', 'ident_name',
- 'input_parameters', 'operation', 'jp_expr'])
+Resource = namedtuple(
+ 'Resource',
+ [
+ 'resource_name',
+ 'ident_name',
+ 'input_parameters',
+ 'operation',
+ 'jp_expr',
+ ],
+)
class ServerCompletionHeuristic(object):
@@ -26,8 +34,9 @@ def __init__(self, singularize=None):
singularize = BasicSingularize()
self._singularize = singularize
- def generate_completion_descriptions(self, service_model,
- prune_completions=True):
+ def generate_completion_descriptions(
+ self, service_model, prune_completions=True
+ ):
"""
:param service_model: A botocore.model.ServiceModel.
@@ -48,10 +57,13 @@ def generate_completion_descriptions(self, service_model,
if op_name.lower().startswith(self._RESOURCE_VERB_PREFIX):
candidates.append(op_name)
all_resources = self._generate_resource_descriptions(
- candidates, service_model)
+ candidates, service_model
+ )
all_operations = self._generate_operations(
self._filter_operation_names(service_model.operation_names),
- all_resources, service_model)
+ all_resources,
+ service_model,
+ )
if prune_completions:
self._prune_resource_identifiers(all_resources, all_operations)
return {
@@ -61,14 +73,18 @@ def generate_completion_descriptions(self, service_model,
}
def _filter_operation_names(self, op_names):
- return [name for name in op_names
- if not name.lower().startswith(self._OPERATION_EXCLUDES)]
+ return [
+ name
+ for name in op_names
+ if not name.lower().startswith(self._OPERATION_EXCLUDES)
+ ]
def _generate_resource_descriptions(self, candidates, service_model):
all_resources = {}
for op_name in candidates:
resources = self._resource_for_single_operation(
- op_name, service_model)
+ op_name, service_model
+ )
if resources is not None:
for resource in resources:
self._inject_resource(all_resources, resource)
@@ -97,15 +113,17 @@ def _generate_operations(self, op_names, resources, service_model):
)
return op_map
- def _add_completion_data_for_operation(self, op_map, op_name,
- service_model, reverse_mapping):
+ def _add_completion_data_for_operation(
+ self, op_map, op_name, service_model, reverse_mapping
+ ):
op_model = service_model.operation_model(op_name)
input_shape = op_model.input_shape
if not input_shape:
return
for member in input_shape.members:
member_name = self._find_matching_member_name(
- member, reverse_mapping)
+ member, reverse_mapping
+ )
if member_name is None:
continue
resource_name = self._find_matching_op_name(
@@ -114,9 +132,11 @@ def _add_completion_data_for_operation(self, op_map, op_name,
op = op_map.setdefault(op_name, {})
param = op.setdefault(member, {})
param['completions'] = [
- {'parameters': {},
- 'resourceName': resource_name,
- 'resourceIdentifier': member_name}
+ {
+ 'parameters': {},
+ 'resourceName': resource_name,
+ 'resourceIdentifier': member_name,
+ }
]
def _find_matching_op_name(self, op_name, candidates):
@@ -139,9 +159,7 @@ def _find_matching_op_name(self, op_name, candidates):
matcher.set_seq1(candidate)
match_ratio = matcher.ratio()
matching_score.append((match_ratio, candidate))
- return sorted(
- matching_score, key=lambda x: x[0], reverse=True
- )[0][1]
+ return sorted(matching_score, key=lambda x: x[0], reverse=True)[0][1]
def _find_matching_member_name(self, member, reverse_mapping):
# Try to find something in the reverse mapping that's close
@@ -174,11 +192,18 @@ def _resource_for_single_operation(self, op_name, service_model):
# conventions.
op_model = service_model.operation_model(op_name)
output = op_model.output_shape
- list_members = [member for member, shape in output.members.items()
- if shape.type_name == 'list']
+ list_members = [
+ member
+ for member, shape in output.members.items()
+ if shape.type_name == 'list'
+ ]
if len(list_members) != 1:
- LOG.debug("Operation does not have exactly one list member, "
- "skipping: %s (%s)", op_name, list_members)
+ LOG.debug(
+ "Operation does not have exactly one list member, "
+ "skipping: %s (%s)",
+ op_name,
+ list_members,
+ )
return
resource_member_name = list_members[0]
list_member = output.members[resource_member_name].member
@@ -187,52 +212,64 @@ def _resource_for_single_operation(self, op_name, service_model):
required_members = op_model.input_shape.required_members
if list_member.type_name == 'structure':
return self._resource_from_structure(
- op_name, resource_member_name, list_member, required_members)
+ op_name, resource_member_name, list_member, required_members
+ )
elif list_member.type_name == 'string':
- return [self._resource_from_string(
- op_name, resource_member_name, required_members,
- )]
+ return [
+ self._resource_from_string(
+ op_name,
+ resource_member_name,
+ required_members,
+ )
+ ]
- def _resource_from_structure(self, op_name,
- resource_member_name, list_member,
- required_members):
+ def _resource_from_structure(
+ self, op_name, resource_member_name, list_member, required_members
+ ):
op_with_prefix_removed = self._remove_verb_prefix(op_name)
- singular_name = self._singularize.make_singular(
- op_with_prefix_removed)
+ singular_name = self._singularize.make_singular(op_with_prefix_removed)
resources = []
for member_name in list_member.members:
- jp_expr = (
- '{resource_member_name}[].{member_name}').format(
- resource_member_name=resource_member_name,
- member_name=member_name)
- r = Resource(singular_name, member_name, required_members,
- op_name, jp_expr)
+ jp_expr = ('{resource_member_name}[].{member_name}').format(
+ resource_member_name=resource_member_name,
+ member_name=member_name,
+ )
+ r = Resource(
+ singular_name, member_name, required_members, op_name, jp_expr
+ )
resources.append(r)
return resources
- def _resource_from_string(self, op_name, resource_member_name,
- required_members):
+ def _resource_from_string(
+ self, op_name, resource_member_name, required_members
+ ):
op_with_prefix_removed = self._remove_verb_prefix(op_name)
- singular_name = self._singularize.make_singular(
- op_with_prefix_removed)
+ singular_name = self._singularize.make_singular(op_with_prefix_removed)
singular_member_name = self._singularize.make_singular(
- resource_member_name)
- r = Resource(singular_name, singular_member_name, required_members,
- op_name,
- '{resource_member_name}[]'.format(
- resource_member_name=resource_member_name))
+ resource_member_name
+ )
+ r = Resource(
+ singular_name,
+ singular_member_name,
+ required_members,
+ op_name,
+ '{resource_member_name}[]'.format(
+ resource_member_name=resource_member_name
+ ),
+ )
return r
def _remove_verb_prefix(self, op_name):
for prefix in self._RESOURCE_VERB_PREFIX:
# 'ListResources' -> 'Resources'
if op_name.lower().startswith(prefix):
- op_with_prefix_removed = op_name[len(prefix):]
+ op_with_prefix_removed = op_name[len(prefix) :]
return op_with_prefix_removed
def _prune_resource_identifiers(self, all_resources, all_operations):
used_identifiers = self._get_identifiers_referenced_by_operations(
- all_operations)
+ all_operations
+ )
for resource, resource_data in list(all_resources.items()):
identifiers = resource_data['resourceIdentifier']
known_ids_for_resource = used_identifiers.get(resource, set())
@@ -249,7 +286,8 @@ def _get_identifiers_referenced_by_operations(self, operations):
used_identifiers = {}
for completion in self._all_completions(operations):
used_identifiers.setdefault(completion['resourceName'], set()).add(
- completion['resourceIdentifier'])
+ completion['resourceIdentifier']
+ )
return used_identifiers
def _all_completions(self, operations):
diff --git a/awscli/autocomplete/completer.py b/awscli/autocomplete/completer.py
index ed1baf853046..76dc97d8ec8c 100644
--- a/awscli/autocomplete/completer.py
+++ b/awscli/autocomplete/completer.py
@@ -19,6 +19,7 @@ class AutoCompleter(object):
completions for specific cases (e.g model-based completions,
server-side completions, etc).
"""
+
def __init__(self, parser, completers):
"""
@@ -54,8 +55,16 @@ class CompletionResult(object):
stores metadata about the completion.
"""
- def __init__(self, name, starting_index=0, required=False,
- cli_type_name='', help_text='', display_text=None):
+
+ def __init__(
+ self,
+ name,
+ starting_index=0,
+ required=False,
+ cli_type_name='',
+ help_text='',
+ display_text=None,
+ ):
self.name = name
self.starting_index = starting_index
self.required = required
@@ -65,17 +74,22 @@ def __init__(self, name, starting_index=0, required=False,
def __eq__(self, other):
return (
- isinstance(other, self.__class__) and
- self.name == other.name and
- self.starting_index == other.starting_index and
- self.display_text == other.display_text
+ isinstance(other, self.__class__)
+ and self.name == other.name
+ and self.starting_index == other.starting_index
+ and self.display_text == other.display_text
)
def __repr__(self):
- return '%s(%s, %s, %s, %s, %s, %s)' % (self.__class__.__name__, self.name,
- self.starting_index, self.required,
- self.cli_type_name, self.help_text,
- self.display_text)
+ return '%s(%s, %s, %s, %s, %s, %s)' % (
+ self.__class__.__name__,
+ self.name,
+ self.starting_index,
+ self.required,
+ self.cli_type_name,
+ self.help_text,
+ self.display_text,
+ )
class BaseCompleter(object):
diff --git a/awscli/autocomplete/custom.py b/awscli/autocomplete/custom.py
index d9ea75c25e3f..6deee16eedff 100644
--- a/awscli/autocomplete/custom.py
+++ b/awscli/autocomplete/custom.py
@@ -10,8 +10,12 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
-from awscli.autocomplete.serverside.custom_completers.ddb.autocomplete import add_ddb_completers
-from awscli.autocomplete.serverside.custom_completers.logs.autocomplete import add_log_completers
+from awscli.autocomplete.serverside.custom_completers.ddb.autocomplete import (
+ add_ddb_completers,
+)
+from awscli.autocomplete.serverside.custom_completers.logs.autocomplete import (
+ add_log_completers,
+)
def get_custom_completers():
diff --git a/awscli/autocomplete/db.py b/awscli/autocomplete/db.py
index 860bba04cb4f..3b41f4082468 100644
--- a/awscli/autocomplete/db.py
+++ b/awscli/autocomplete/db.py
@@ -1,10 +1,9 @@
-import os
import logging
+import os
import sqlite3
from awscli import __version__ as cli_version
-
LOG = logging.getLogger(__name__)
# We may eventually include a pre-generated version of this index as part
@@ -14,7 +13,8 @@
INDEX_FILE = os.path.join(INDEX_DIR, '%s.index' % cli_version)
BUILTIN_INDEX_FILE = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
- 'data', 'ac.index'
+ 'data',
+ 'ac.index',
)
@@ -34,10 +34,7 @@ def __init__(self, db_filename=None):
@property
def _connection(self):
if self._db_conn is None:
- kwargs = {
- 'check_same_thread': False,
- 'isolation_level': None
- }
+ kwargs = {'check_same_thread': False, 'isolation_level': None}
if self._db_filename.startswith('file::memory:'):
# This statement was added because old versions of sqlite
# don't support 'uri' but we use it for tests and because
diff --git a/awscli/autocomplete/filters.py b/awscli/autocomplete/filters.py
index 9a614a09dd21..fb2abd77854d 100644
--- a/awscli/autocomplete/filters.py
+++ b/awscli/autocomplete/filters.py
@@ -37,26 +37,29 @@ def fuzzy_filter(prefix, completions):
matches = list(regex.finditer(name))
if matches:
# Prefer the match, closest to the left, then shortest.
- best = min(matches, key=lambda m: (m.start(),
- len(m.group(1))))
- fuzzy_matches.append(_FuzzyMatch(
- len(best.group(1)),
- best.start(),
- completion)
+ best = min(matches, key=lambda m: (m.start(), len(m.group(1))))
+ fuzzy_matches.append(
+ _FuzzyMatch(len(best.group(1)), best.start(), completion)
)
- return [x for _, _, x in sorted(
- fuzzy_matches,
- key=lambda match: (
- match.match_length, match.start_pos,
- match.completion.display_text,
- match.completion.name)
- )]
+ return [
+ x
+ for _, _, x in sorted(
+ fuzzy_matches,
+ key=lambda match: (
+ match.match_length,
+ match.start_pos,
+ match.completion.display_text,
+ match.completion.name,
+ ),
+ )
+ ]
return completions
def startswith_filter(prefix, completions):
return [
- completion for completion in completions
+ completion
+ for completion in completions
if (completion.display_text or completion.name).startswith(prefix)
]
diff --git a/awscli/autocomplete/generator.py b/awscli/autocomplete/generator.py
index 733fd505e546..4b228b49a466 100644
--- a/awscli/autocomplete/generator.py
+++ b/awscli/autocomplete/generator.py
@@ -11,12 +11,13 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""Generates auto completion index."""
+
import os
+from awscli import clidriver
+from awscli.autocomplete import db
from awscli.autocomplete.local import indexer
from awscli.autocomplete.serverside.indexer import APICallIndexer
-from awscli.autocomplete import db
-from awscli import clidriver
def generate_index(filename):
@@ -64,6 +65,7 @@ class IndexGenerator(object):
indices.
"""
+
def __init__(self, indexers):
self._indexers = indexers
diff --git a/awscli/autocomplete/main.py b/awscli/autocomplete/main.py
index 8055768a1bd8..6a1ae444767a 100644
--- a/awscli/autocomplete/main.py
+++ b/awscli/autocomplete/main.py
@@ -16,14 +16,16 @@
# everytime a user hits . Try to avoid any expensive module level
# work or really heavyweight imports. Prefer to lazy load as much as possible.
-from awscli.autocomplete import parser, completer, filters
-from awscli.autocomplete.local import model, basic, fetcher
-from awscli.autocomplete import serverside
-from awscli.autocomplete import custom
+from awscli.autocomplete import completer, custom, filters, parser, serverside
+from awscli.autocomplete.local import basic, fetcher, model
-def create_autocompleter(index_filename=None, custom_completers=None,
- driver=None, response_filter=None):
+def create_autocompleter(
+ index_filename=None,
+ custom_completers=None,
+ driver=None,
+ response_filter=None,
+):
if response_filter is None:
response_filter = filters.startswith_filter
if custom_completers is None:
@@ -36,15 +38,19 @@ def create_autocompleter(index_filename=None, custom_completers=None,
completers = [
basic.RegionCompleter(response_filter=response_filter),
basic.ProfileCompleter(response_filter=response_filter),
- basic.ModelIndexCompleter(index, cli_driver_fetcher,
- response_filter=response_filter),
+ basic.ModelIndexCompleter(
+ index, cli_driver_fetcher, response_filter=response_filter
+ ),
basic.FilePathCompleter(response_filter=response_filter),
serverside.create_server_side_completer(
- index_filename, response_filter=response_filter),
- basic.ShorthandCompleter(cli_driver_fetcher,
- response_filter=response_filter),
- basic.QueryCompleter(cli_driver_fetcher,
- response_filter=response_filter),
+ index_filename, response_filter=response_filter
+ ),
+ basic.ShorthandCompleter(
+ cli_driver_fetcher, response_filter=response_filter
+ ),
+ basic.QueryCompleter(
+ cli_driver_fetcher, response_filter=response_filter
+ ),
] + custom_completers
cli_completer = completer.AutoCompleter(cli_parser, completers)
return cli_completer
diff --git a/awscli/autocomplete/parser.py b/awscli/autocomplete/parser.py
index 15b3ed240712..e13cc6ecc0db 100644
--- a/awscli/autocomplete/parser.py
+++ b/awscli/autocomplete/parser.py
@@ -14,9 +14,16 @@
class ParsedResult(object):
- def __init__(self, current_command=None, current_param=None,
- global_params=None, parsed_params=None,
- lineage=None, current_fragment=None, unparsed_items=None):
+ def __init__(
+ self,
+ current_command=None,
+ current_param=None,
+ global_params=None,
+ parsed_params=None,
+ lineage=None,
+ current_fragment=None,
+ unparsed_items=None,
+ ):
"""
:param current_command: The name of the leaf command; the most
@@ -126,6 +133,7 @@ class CLIParser(object):
not a general purpose AWS CLI parser.
"""
+
def __init__(self, index, return_first_command_match=False):
self._index = index
self._return_first_command_match = return_first_command_match
@@ -149,18 +157,26 @@ def parse(self, command_line, location=None):
while remaining_parts:
current = remaining_parts.pop(0)
if current.startswith('--'):
- self._handle_option(current, remaining_parts,
- current_args, global_args, parsed, state)
+ self._handle_option(
+ current,
+ remaining_parts,
+ current_args,
+ global_args,
+ parsed,
+ state,
+ )
else:
current_args = self._handle_positional(
- current, state, remaining_parts, parsed)
+ current, state, remaining_parts, parsed
+ )
parsed.current_command = state.current_command
parsed.current_param = state.current_param
parsed.lineage = state.lineage
return parsed
- def _consume_value(self, remaining_parts, option_name,
- lineage, current_command, state):
+ def _consume_value(
+ self, remaining_parts, option_name, lineage, current_command, state
+ ):
# We have a special case where a user is trying to complete
# a value for an option, which is the last fragment of the command,
# e.g. 'aws ec2 describe-instances --instance-ids '
@@ -205,8 +221,9 @@ def _consume_value(self, remaining_parts, option_name,
# an empty list being returned. This is acceptable
# for auto-completion purposes.
value = []
- while len(remaining_parts) > 0 and \
- not remaining_parts == [WORD_BOUNDARY]:
+ while len(remaining_parts) > 0 and not remaining_parts == [
+ WORD_BOUNDARY
+ ]:
if remaining_parts[0].startswith('--'):
state.current_param = None
break
@@ -243,8 +260,15 @@ def _split_to_parts(self, command_line, location):
state.current_command = 'aws'
return state, parts
- def _handle_option(self, current, remaining_parts, current_args,
- global_args, parsed, state):
+ def _handle_option(
+ self,
+ current,
+ remaining_parts,
+ current_args,
+ global_args,
+ parsed,
+ state,
+ ):
if current_args is None:
# If there are no arguments found for this current scope,
# it usually indicates we've encounted a command we don't know.
@@ -257,15 +281,21 @@ def _handle_option(self, current, remaining_parts, current_args,
if option_name in global_args:
state.current_param = option_name
value = self._consume_value(
- remaining_parts, option_name, lineage=[],
+ remaining_parts,
+ option_name,
+ lineage=[],
state=state,
- current_command='aws')
+ current_command='aws',
+ )
parsed.global_params[option_name] = value
elif option_name in current_args:
state.current_param = option_name
value = self._consume_value(
- remaining_parts, option_name, state.lineage,
- state.current_command, state=state,
+ remaining_parts,
+ option_name,
+ state.lineage,
+ state.current_command,
+ state=state,
)
parsed.parsed_params[option_name] = value
elif self._is_last_word(remaining_parts, current):
@@ -284,8 +314,10 @@ def _is_last_word(self, remaining_parts, current):
return not remaining_parts and current
def _is_part_of_command(self, current, command_names):
- return any(command.startswith(current) and command != current
- for command in command_names)
+ return any(
+ command.startswith(current) and command != current
+ for command in command_names
+ )
def _is_command_name(self, current, remaining_parts, command_names):
# If _return_first_command_match is True
@@ -323,16 +355,18 @@ def _handle_positional(self, current, state, remaining_parts, parsed):
state.current_command = current
# We also need to get the next set of command line options.
current_args = self._index.arg_names(
- lineage=state.lineage,
- command_name=state.current_command)
+ lineage=state.lineage, command_name=state.current_command
+ )
return current_args
if not command_names:
# If there are no more command names check. See if the command
# has a positional argument. This will require an additional
# select on the argument index.
positional_argname = self._get_positional_argname(state)
- if (positional_argname and
- positional_argname not in parsed.parsed_params):
+ if (
+ positional_argname
+ and positional_argname not in parsed.parsed_params
+ ):
# Parse the current string to be a positional argument
# if the command has the a positional arg and the positional arg
# has not already been parsed.
@@ -347,8 +381,8 @@ def _handle_positional(self, current, state, remaining_parts, parsed):
parsed.parsed_params[positional_argname] = current
state.current_param = None
return self._index.arg_names(
- lineage=state.lineage,
- command_name=state.current_command)
+ lineage=state.lineage, command_name=state.current_command
+ )
else:
if not remaining_parts:
# If this is the last chunk of the command line but
@@ -371,7 +405,8 @@ def _handle_positional(self, current, state, remaining_parts, parsed):
state.current_param = None
return self._index.arg_names(
lineage=state.lineage,
- command_name=state.current_command)
+ command_name=state.current_command,
+ )
else:
# Otherwise this is some command we don't know about
# so we add it to the list of unparsed_items.
@@ -382,7 +417,7 @@ def _get_positional_argname(self, state):
positional_args = self._index.arg_names(
lineage=state.lineage,
command_name=state.current_command,
- positional_arg=True
+ positional_arg=True,
)
if positional_args:
# We are assuming there is only ever one positional
diff --git a/awscli/autoprompt/core.py b/awscli/autoprompt/core.py
index 3b0bb900e47f..47d9b5d54a78 100644
--- a/awscli/autoprompt/core.py
+++ b/awscli/autoprompt/core.py
@@ -12,15 +12,14 @@
# language governing permissions and limitations under the License.
from botocore.exceptions import ProfileNotFound
-from awscli.customizations.exceptions import ParamValidationError
-from awscli.autoprompt.prompttoolkit import PromptToolkitPrompter
-from awscli.autocomplete.main import create_autocompleter
from awscli.autocomplete.filters import fuzzy_filter
+from awscli.autocomplete.main import create_autocompleter
+from awscli.autoprompt.prompttoolkit import PromptToolkitPrompter
+from awscli.customizations.exceptions import ParamValidationError
from awscli.errorhandler import SilenceParamValidationMsgErrorHandler
class AutoPromptDriver:
-
_NO_PROMPT_ARGS = ['help', '--version']
_CLI_AUTO_PROMPT_OPTION = '--cli-auto-prompt'
_NO_CLI_AUTO_PROMPT_OPTION = '--no-cli-auto-prompt'
@@ -32,13 +31,15 @@ def __init__(self, driver, completion_source=None, prompter=None):
self._driver = driver
if self._completion_source is None:
self._completion_source = create_autocompleter(
- driver=self._driver, response_filter=fuzzy_filter)
+ driver=self._driver, response_filter=fuzzy_filter
+ )
@property
def prompter(self):
if self._prompter is None:
- self._prompter = AutoPrompter(self._completion_source,
- self._driver)
+ self._prompter = AutoPrompter(
+ self._completion_source, self._driver
+ )
return self._prompter
def validate_auto_prompt_args_are_mutually_exclusive(self, args):
@@ -84,12 +85,14 @@ class AutoPrompter:
the UI prompt backend easily if needed.
"""
+
def __init__(self, completion_source, driver, prompter=None):
self._completion_source = completion_source
self._driver = driver
if prompter is None:
- prompter = PromptToolkitPrompter(self._completion_source,
- self._driver)
+ prompter = PromptToolkitPrompter(
+ self._completion_source, self._driver
+ )
self._prompter = prompter
def prompt_for_values(self, original_args):
diff --git a/awscli/autoprompt/doc.py b/awscli/autoprompt/doc.py
index 12933cca0eec..38d866df50f3 100644
--- a/awscli/autoprompt/doc.py
+++ b/awscli/autoprompt/doc.py
@@ -11,6 +11,7 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import io
+
from docutils.core import publish_string
from awscli.bcdoc import docevents, textwriter
@@ -23,6 +24,7 @@ class DocsGetter:
service commands and service operations.
"""
+
def __init__(self, driver):
self._driver = driver
self._cache = {}
@@ -37,7 +39,7 @@ def _render_docs(self, help_command):
text_content = self._convert_rst_to_basic_text(original_cli_help)
index = text_content.find('DESCRIPTION')
if index > 0:
- text_content = text_content[index + len('DESCRIPTION'):]
+ text_content = text_content[index + len('DESCRIPTION') :]
return text_content
def _convert_rst_to_basic_text(self, contents):
@@ -57,8 +59,9 @@ def _convert_rst_to_basic_text(self, contents):
# The report_level override is so that we don't print anything
# to stdout/stderr on rendering issues.
converted = publish_string(
- contents, writer=BasicTextWriter(),
- settings_overrides={'report_level': 5, 'halt_level': 5}
+ contents,
+ writer=BasicTextWriter(),
+ settings_overrides={'report_level': 5, 'halt_level': 5},
)
return converted.decode('utf-8').replace('\r', '')
@@ -92,7 +95,6 @@ def get_docs(self, parsed):
class FileRenderer:
-
def __init__(self):
self._io = io.BytesIO()
diff --git a/awscli/autoprompt/factory.py b/awscli/autoprompt/factory.py
index 1b35f4b88d66..59cffbc6daea 100644
--- a/awscli/autoprompt/factory.py
+++ b/awscli/autoprompt/factory.py
@@ -15,23 +15,34 @@
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.document import Document
from prompt_toolkit.key_binding import KeyBindings
+from prompt_toolkit.key_binding.bindings.focus import focus_next
from prompt_toolkit.keys import Keys
-from prompt_toolkit.layout import Float, FloatContainer, HSplit, Window, VSplit
+from prompt_toolkit.layout import Float, FloatContainer, HSplit, VSplit, Window
from prompt_toolkit.layout.controls import BufferControl
from prompt_toolkit.layout.dimension import Dimension
-from prompt_toolkit.layout.layout import Layout, ConditionalContainer
-from prompt_toolkit.layout.menus import CompletionsMenu, MultiColumnCompletionsMenu
+from prompt_toolkit.layout.layout import ConditionalContainer, Layout
+from prompt_toolkit.layout.menus import (
+ CompletionsMenu,
+ MultiColumnCompletionsMenu,
+)
from prompt_toolkit.layout.processors import BeforeInput
from prompt_toolkit.widgets import SearchToolbar, VerticalLine
-from prompt_toolkit.key_binding.bindings.focus import focus_next
-from awscli.autoprompt.history import HistoryDriver, HistoryCompleter
-from awscli.autoprompt.widgets import (
- HelpPanelWidget, ToolbarWidget, DebugPanelWidget, TitleLine
-)
from awscli.autoprompt.filters import (
- is_one_column, is_multi_column, doc_section_visible, output_section_visible,
- input_buffer_has_focus, doc_window_has_focus, is_history_mode
+ doc_section_visible,
+ doc_window_has_focus,
+ input_buffer_has_focus,
+ is_history_mode,
+ is_multi_column,
+ is_one_column,
+ output_section_visible,
+)
+from awscli.autoprompt.history import HistoryCompleter, HistoryDriver
+from awscli.autoprompt.widgets import (
+ DebugPanelWidget,
+ HelpPanelWidget,
+ TitleLine,
+ ToolbarWidget,
)
@@ -40,7 +51,6 @@ class PrompterKeyboardInterrupt(KeyboardInterrupt):
class CLIPromptBuffer(Buffer):
-
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._completer = self.completer
@@ -73,16 +83,20 @@ def __init__(self, completer, history_driver=None):
def history_driver(self):
if self._history_driver is None:
cache_dir = os.path.expanduser(
- os.path.join('~', '.aws', 'cli', 'cache'))
+ os.path.join('~', '.aws', 'cli', 'cache')
+ )
history_filename = os.path.join(cache_dir, 'prompt_history.json')
self._history_driver = HistoryDriver(history_filename)
return self._history_driver
def create_input_buffer(self, on_text_changed_callback=None):
return CLIPromptBuffer(
- name='input_buffer', completer=self._completer,
- history=self.history_driver, complete_while_typing=True,
- on_text_changed=on_text_changed_callback)
+ name='input_buffer',
+ completer=self._completer,
+ history=self.history_driver,
+ complete_while_typing=True,
+ on_text_changed=on_text_changed_callback,
+ )
def create_doc_buffer(self):
return Buffer(name='doc_buffer', read_only=True)
@@ -95,12 +109,12 @@ def create_input_buffer_container(self, input_buffer):
Window(
BufferControl(
buffer=input_buffer,
- input_processors=[BeforeInput('> aws ')]
+ input_processors=[BeforeInput('> aws ')],
),
height=Dimension(
min=self.DIMENSIONS['input_buffer_height_min']
),
- wrap_lines=True
+ wrap_lines=True,
),
[
Float(
@@ -108,7 +122,7 @@ def create_input_buffer_container(self, input_buffer):
ycursor=True,
content=MultiColumnCompletionsMenu(
extra_filter=is_multi_column
- )
+ ),
),
Float(
xcursor=True,
@@ -116,41 +130,51 @@ def create_input_buffer_container(self, input_buffer):
content=CompletionsMenu(
extra_filter=is_one_column,
max_height=self.DIMENSIONS['menu_height_max'],
- scroll_offset=self.DIMENSIONS['menu_scroll_offset']
- )
- )
- ]
+ scroll_offset=self.DIMENSIONS['menu_scroll_offset'],
+ ),
+ ),
+ ],
)
def create_bottom_panel(self, doc_window, output_window):
- return VSplit([
- ConditionalContainer(doc_window, doc_section_visible),
- ConditionalContainer(VerticalLine(),
- output_section_visible & doc_section_visible),
- ConditionalContainer(output_window, output_section_visible),
- ])
+ return VSplit(
+ [
+ ConditionalContainer(doc_window, doc_section_visible),
+ ConditionalContainer(
+ VerticalLine(),
+ output_section_visible & doc_section_visible,
+ ),
+ ConditionalContainer(output_window, output_section_visible),
+ ]
+ )
def create_searchable_window(self, title, output_buffer):
search_field = SearchToolbar()
- return HSplit([
- TitleLine(title),
- Window(
- content=BufferControl(
- buffer=output_buffer,
- search_buffer_control=search_field.control
- ),
- height=Dimension(
- max=self.DIMENSIONS['doc_window_height_max'],
- preferred=self.DIMENSIONS['doc_window_height_pref']
+ return HSplit(
+ [
+ TitleLine(title),
+ Window(
+ content=BufferControl(
+ buffer=output_buffer,
+ search_buffer_control=search_field.control,
+ ),
+ height=Dimension(
+ max=self.DIMENSIONS['doc_window_height_max'],
+ preferred=self.DIMENSIONS['doc_window_height_pref'],
+ ),
+ wrap_lines=True,
),
- wrap_lines=True
- ),
- search_field
- ])
+ search_field,
+ ]
+ )
- def create_layout(self, on_input_buffer_text_changed=None,
- input_buffer_container=None, doc_window=None,
- output_window=None):
+ def create_layout(
+ self,
+ on_input_buffer_text_changed=None,
+ input_buffer_container=None,
+ doc_window=None,
+ output_window=None,
+ ):
# This is the main layout, which consists of:
# - The main input buffer with completion menus floating on top of it.
# - A separating line between the input buffer and the doc window.
@@ -160,27 +184,34 @@ def create_layout(self, on_input_buffer_text_changed=None,
# - A help panel
# - A debug panel in case debug mode enabled
if input_buffer_container is None:
- input_buffer = \
- self.create_input_buffer(on_input_buffer_text_changed)
- input_buffer_container = \
- self.create_input_buffer_container(input_buffer)
+ input_buffer = self.create_input_buffer(
+ on_input_buffer_text_changed
+ )
+ input_buffer_container = self.create_input_buffer_container(
+ input_buffer
+ )
if doc_window is None:
doc_buffer = self.create_doc_buffer()
doc_window = self.create_searchable_window('Doc panel', doc_buffer)
if output_window is None:
output_buffer = self.create_output_buffer()
output_window = self.create_searchable_window(
- 'Output panel', output_buffer)
+ 'Output panel', output_buffer
+ )
bottom_panel = self.create_bottom_panel(doc_window, output_window)
return Layout(
- HSplit([
- VSplit([
- HSplit([input_buffer_container, bottom_panel]),
- HelpPanelWidget(),
- DebugPanelWidget(),
- ]),
- ToolbarWidget()
- ])
+ HSplit(
+ [
+ VSplit(
+ [
+ HSplit([input_buffer_container, bottom_panel]),
+ HelpPanelWidget(),
+ DebugPanelWidget(),
+ ]
+ ),
+ ToolbarWidget(),
+ ]
+ )
)
def create_key_bindings(self):
@@ -210,14 +241,16 @@ def _(event):
event.app.current_buffer.reset()
updated_document = Document(
text=current_document.text,
- cursor_position=current_document.cursor_position)
+ cursor_position=current_document.cursor_position,
+ )
buffer.set_document(updated_document)
# If prompter suggested us something ended with slash and
# started with 'file://' or 'fileb://' it should be path ended
# with directory then we run completion again
cur_word = current_document.get_word_under_cursor(WORD=True)
- if cur_word.endswith(os.sep) \
- and cur_word.startswith(('file://', 'fileb://')):
+ if cur_word.endswith(os.sep) and cur_word.startswith(
+ ('file://', 'fileb://')
+ ):
buffer.start_completion()
@self._kb.add(Keys.Escape, filter=is_history_mode)
@@ -231,8 +264,10 @@ def _(event):
"""Exit from history mode if something was selected or
just add space to the end of the text and keep suggesting"""
buffer = event.app.current_buffer
- if (buffer.complete_state
- and buffer.complete_state.current_completion):
+ if (
+ buffer.complete_state
+ and buffer.complete_state.current_completion
+ ):
buffer.switch_history_mode()
buffer.insert_text(' ')
diff --git a/awscli/autoprompt/filters.py b/awscli/autoprompt/filters.py
index 7600828753ac..0f71c43ddcab 100644
--- a/awscli/autoprompt/filters.py
+++ b/awscli/autoprompt/filters.py
@@ -68,7 +68,7 @@ def input_buffer_has_focus():
@Condition
def is_history_mode():
"""Only activate these key bindings if input buffer has focus
- and history_mode is on """
+ and history_mode is on"""
buffer = get_app().current_buffer
return buffer.name == 'input_buffer' and buffer.history_mode
@@ -76,6 +76,6 @@ def is_history_mode():
@Condition
def is_debug_mode():
"""Only activate these key bindings if input buffer has focus
- and history_mode is on """
+ and history_mode is on"""
app = get_app()
return app.debug
diff --git a/awscli/autoprompt/history.py b/awscli/autoprompt/history.py
index 1a2c6dc6cf3f..2a8ba8932c51 100644
--- a/awscli/autoprompt/history.py
+++ b/awscli/autoprompt/history.py
@@ -10,17 +10,16 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
-import logging
import json
+import logging
import os
-from prompt_toolkit.completion import Completion, Completer
+from prompt_toolkit.completion import Completer, Completion
from prompt_toolkit.history import FileHistory
from awscli.autocomplete.completer import CompletionResult
from awscli.autocomplete.filters import fuzzy_filter
-
LOG = logging.getLogger(__name__)
@@ -37,8 +36,9 @@ def load_history_strings(self):
commands = json.load(f).get('commands', [])
return reversed(commands)
except Exception as e:
- LOG.debug('Exception on loading prompt history: %s' % e,
- exc_info=True)
+ LOG.debug(
+ 'Exception on loading prompt history: %s' % e, exc_info=True
+ )
return []
def store_string(self, string):
@@ -50,7 +50,7 @@ def store_string(self, string):
elif not os.path.exists(os.path.dirname(self.filename)):
os.makedirs(os.path.dirname(self.filename))
history['commands'].append(string)
- history['commands'] = history['commands'][-self._max_commands:]
+ history['commands'] = history['commands'][-self._max_commands :]
with open(self.filename, 'w') as f:
json.dump(history, f)
except Exception:
@@ -58,7 +58,6 @@ def store_string(self, string):
class HistoryCompleter(Completer):
-
def __init__(self, buffer):
self.buffer = buffer
@@ -73,12 +72,16 @@ def get_completions(self, document, *args):
s_line = line.strip()
if s_line and s_line not in found_completions:
found_completions.add(s_line)
- completions.append(CompletionResult(
- s_line,
- starting_index=-len(current_line)))
+ completions.append(
+ CompletionResult(
+ s_line, starting_index=-len(current_line)
+ )
+ )
if current_line:
completions = fuzzy_filter(current_line, completions)
- yield from (Completion(c.name, start_position=c.starting_index)
- for c in completions)
+ yield from (
+ Completion(c.name, start_position=c.starting_index)
+ for c in completions
+ )
except Exception:
LOG.debug('Exception on loading prompt history:', exc_info=True)
diff --git a/awscli/autoprompt/logger.py b/awscli/autoprompt/logger.py
index 1a5653a09f75..a7eda934e5c5 100644
--- a/awscli/autoprompt/logger.py
+++ b/awscli/autoprompt/logger.py
@@ -12,12 +12,11 @@
# language governing permissions and limitations under the License.
import logging
-from prompt_toolkit.document import Document
from prompt_toolkit.application import get_app
+from prompt_toolkit.document import Document
class PromptToolkitHandler(logging.StreamHandler):
-
def emit(self, record):
try:
app = get_app()
diff --git a/awscli/autoprompt/output.py b/awscli/autoprompt/output.py
index 01528ca181d9..ba7806ad282e 100644
--- a/awscli/autoprompt/output.py
+++ b/awscli/autoprompt/output.py
@@ -11,16 +11,15 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import argparse
-import logging
import io
+import logging
import re
import jmespath
from botocore.utils import ArgumentGenerator
-from awscli.formatter import get_formatter
from awscli.autocomplete.local.fetcher import CliDriverFetcher
-
+from awscli.formatter import get_formatter
LOG = logging.getLogger(__name__)
@@ -34,13 +33,16 @@ def __init__(self, driver):
def get_output(self, parsed):
operation_model = self._cli_driver_fetcher.get_operation_model(
- parsed.lineage, parsed.current_command)
+ parsed.lineage, parsed.current_command
+ )
if operation_model:
output_shape = getattr(operation_model, 'output_shape', None)
if self._shape_has_members(output_shape):
operation = ''.join(
- [part.capitalize()
- for part in parsed.current_command.split('-')]
+ [
+ part.capitalize()
+ for part in parsed.current_command.split('-')
+ ]
)
output, error_message = self._get_output(parsed)
if error_message is not None:
@@ -48,13 +50,15 @@ def get_output(self, parsed):
query, error_message = self._get_query(parsed)
if error_message is not None:
return error_message
- return self._get_display(operation, output_shape,
- output, query)
+ return self._get_display(
+ operation, output_shape, output, query
+ )
return 'No output'
def _shape_has_members(self, shape):
- return shape and (getattr(shape, 'members', False) or
- getattr(shape, 'member', False))
+ return shape and (
+ getattr(shape, 'members', False) or getattr(shape, 'member', False)
+ )
def _get_output(self, parsed):
error_message = None
@@ -65,8 +69,8 @@ def _get_output(self, parsed):
output = parsed.global_params.get('output') or session_output
if output not in self._output_formats:
error_message = (
- "Bad value for --output: %s\n\nValid values are: %s" %
- (output, ', '.join(self._output_formats))
+ "Bad value for --output: %s\n\nValid values are: %s"
+ % (output, ', '.join(self._output_formats))
)
return output, error_message
diff --git a/awscli/autoprompt/prompttoolkit.py b/awscli/autoprompt/prompttoolkit.py
index b7e81f364df7..8f5f91512e37 100644
--- a/awscli/autoprompt/prompttoolkit.py
+++ b/awscli/autoprompt/prompttoolkit.py
@@ -13,21 +13,19 @@
import logging
import shlex
import sys
-from contextlib import nullcontext, contextmanager
+from contextlib import contextmanager, nullcontext
from prompt_toolkit.application import Application
-from prompt_toolkit.completion import Completer, ThreadedCompleter
-from prompt_toolkit.completion import Completion
+from prompt_toolkit.completion import Completer, Completion, ThreadedCompleter
from prompt_toolkit.document import Document
-from awscli.logger import LOG_FORMAT, disable_crt_logging
from awscli.autocomplete import parser
from awscli.autocomplete.local import model
from awscli.autoprompt.doc import DocsGetter
-from awscli.autoprompt.output import OutputGetter
from awscli.autoprompt.factory import PromptToolkitFactory
from awscli.autoprompt.logger import PromptToolkitHandler
-
+from awscli.autoprompt.output import OutputGetter
+from awscli.logger import LOG_FORMAT, disable_crt_logging
LOG = logging.getLogger(__name__)
@@ -54,12 +52,19 @@ def loggers_handler_switcher():
class PromptToolkitPrompter:
- """Handles the actual prompting in the autoprompt workflow.
-
- """
- def __init__(self, completion_source, driver, completer=None,
- factory=None, app=None, cli_parser=None, output=None,
- app_input=None):
+ """Handles the actual prompting in the autoprompt workflow."""
+
+ def __init__(
+ self,
+ completion_source,
+ driver,
+ completer=None,
+ factory=None,
+ app=None,
+ cli_parser=None,
+ output=None,
+ app_input=None,
+ ):
self._completion_source = completion_source
self._output = output
self._input = app_input
@@ -73,7 +78,8 @@ def __init__(self, completion_source, driver, completer=None,
self._parser = cli_parser
if self._parser is None:
self._parser = parser.CLIParser(
- model.ModelIndex(), return_first_command_match=True)
+ model.ModelIndex(), return_first_command_match=True
+ )
self._factory = factory
self.input_buffer = None
self.doc_buffer = None
@@ -93,33 +99,44 @@ def args(self, value):
def _create_buffers(self):
self.input_buffer = self._factory.create_input_buffer(
- self.update_bottom_buffers_text)
+ self.update_bottom_buffers_text
+ )
self.doc_buffer = self._factory.create_doc_buffer()
self.output_buffer = self._factory.create_output_buffer()
def _create_containers(self):
input_buffer_container = self._factory.create_input_buffer_container(
- self.input_buffer)
+ self.input_buffer
+ )
doc_window = self._factory.create_searchable_window(
- 'Doc panel', self.doc_buffer)
+ 'Doc panel', self.doc_buffer
+ )
output_window = self._factory.create_searchable_window(
- 'Output panel', self.output_buffer)
+ 'Output panel', self.output_buffer
+ )
return input_buffer_container, doc_window, output_window
def create_application(self):
self._create_buffers()
- input_buffer_container, \
- doc_window, output_window = self._create_containers()
+ input_buffer_container, doc_window, output_window = (
+ self._create_containers()
+ )
layout = self._factory.create_layout(
on_input_buffer_text_changed=self.update_bottom_buffers_text,
input_buffer_container=input_buffer_container,
- doc_window=doc_window, output_window=output_window
+ doc_window=doc_window,
+ output_window=output_window,
)
kb_manager = self._factory.create_key_bindings()
kb = kb_manager.keybindings
- app = Application(layout=layout, key_bindings=kb, full_screen=False,
- output=self._output, erase_when_done=True,
- input=self._input)
+ app = Application(
+ layout=layout,
+ key_bindings=kb,
+ full_screen=False,
+ output=self._output,
+ erase_when_done=True,
+ input=self._input,
+ )
self._set_app_defaults(app)
return app
@@ -132,8 +149,7 @@ def _set_app_defaults(self, app):
return app
def update_bottom_buffers_text(self, *args):
- parsed = self._parser.parse(
- 'aws ' + self.input_buffer.document.text)
+ parsed = self._parser.parse('aws ' + self.input_buffer.document.text)
self._update_doc_window_contents(parsed)
self._update_output_window_contents(parsed)
@@ -182,8 +198,8 @@ def pre_run(self):
def _set_input_buffer_text(self, cmd_line_text):
"""If entered command line does not have trailing space and can not
- be autocompleted we assume that it is a completed part of command
- and add trailing space to it"""
+ be autocompleted we assume that it is a completed part of command
+ and add trailing space to it"""
if cmd_line_text[-1] == ' ':
return
if self._can_autocomplete(cmd_line_text):
@@ -240,11 +256,13 @@ class PromptToolkitCompleter(Completer):
`prompt_toolkit.Completion` objects.
"""
+
def __init__(self, completion_source):
self._completion_source = completion_source
- def _convert_to_prompt_completions(self, low_level_completions,
- text_before_cursor):
+ def _convert_to_prompt_completions(
+ self, low_level_completions, text_before_cursor
+ ):
# Converts the low-level completions from the model autocompleter
# and converts them to Completion() objects that are used by
# prompt_toolkit.
@@ -255,21 +273,30 @@ def _convert_to_prompt_completions(self, low_level_completions,
display_text = self._get_display_text(completion)
display_meta = self._get_display_meta(completion)
location = self._get_starting_location_of_last_word(
- text_before_cursor, word_before_cursor)
- yield Completion(completion.name, location, display=display_text,
- display_meta=display_meta)
+ text_before_cursor, word_before_cursor
+ )
+ yield Completion(
+ completion.name,
+ location,
+ display=display_text,
+ display_meta=display_meta,
+ )
def get_completions(self, document, complete_event):
try:
text_before_cursor = document.text_before_cursor
text_to_autocomplete = 'aws ' + text_before_cursor
completions = self._completion_source.autocomplete(
- text_to_autocomplete, len(text_to_autocomplete))
+ text_to_autocomplete, len(text_to_autocomplete)
+ )
yield from self._convert_to_prompt_completions(
- completions, text_before_cursor)
+ completions, text_before_cursor
+ )
except Exception as e:
- LOG.debug('Exception caught in PromptToolkitCompleter: %s' % e,
- exc_info=True)
+ LOG.debug(
+ 'Exception caught in PromptToolkitCompleter: %s' % e,
+ exc_info=True,
+ )
def _strip_whitespace(self, text):
word_before_cursor = ''
@@ -283,17 +310,11 @@ def _prioritize_required_args(self, completions):
return required_args + optional_args
def _get_required_args(self, completions):
- results = [
- arg for arg in completions
- if arg.required
- ]
+ results = [arg for arg in completions if arg.required]
return results
def _get_optional_args(self, completions):
- results = [
- arg for arg in completions
- if not arg.required
- ]
+ results = [arg for arg in completions if not arg.required]
return results
def _get_display_text(self, completion):
@@ -321,9 +342,10 @@ def _filter_completions(self, completions):
def _filter_out_autoprompt_overrides(self, completions):
filtered_completions = [
- completion for completion in completions
- if completion.name not in ['--cli-auto-prompt',
- '--no-cli-auto-prompt']
+ completion
+ for completion in completions
+ if completion.name
+ not in ['--cli-auto-prompt', '--no-cli-auto-prompt']
]
return filtered_completions
@@ -336,8 +358,9 @@ def _remove_duplicate_completions(self, completions):
unique_completions.append(completion)
return unique_completions
- def _get_starting_location_of_last_word(self, text_before_cursor,
- word_before_cursor):
+ def _get_starting_location_of_last_word(
+ self, text_before_cursor, word_before_cursor
+ ):
if text_before_cursor and text_before_cursor[-1] == ' ':
location = 0
else:
diff --git a/awscli/autoprompt/widgets.py b/awscli/autoprompt/widgets.py
index cfd4adefc556..7f446ff7e031 100644
--- a/awscli/autoprompt/widgets.py
+++ b/awscli/autoprompt/widgets.py
@@ -14,27 +14,41 @@
from functools import partial
from prompt_toolkit.application import get_app
+from prompt_toolkit.buffer import Buffer
+from prompt_toolkit.document import Document
from prompt_toolkit.filters import has_focus
from prompt_toolkit.formatted_text import HTML, to_formatted_text
from prompt_toolkit.formatted_text.utils import fragment_list_to_text
-from prompt_toolkit.buffer import Buffer
-from prompt_toolkit.document import Document
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.keys import Keys
+from prompt_toolkit.layout import (
+ ConditionalContainer,
+ Float,
+ FloatContainer,
+ HSplit,
+ VSplit,
+ Window,
+)
from prompt_toolkit.layout.controls import BufferControl
from prompt_toolkit.layout.dimension import Dimension
from prompt_toolkit.layout.processors import Processor, Transformation
-from prompt_toolkit.layout import (
- HSplit, Window, VSplit, FloatContainer, Float, ConditionalContainer
-)
from prompt_toolkit.widgets import (
- Frame, HorizontalLine, Dialog, Button, TextArea, Label
+ Button,
+ Dialog,
+ Frame,
+ HorizontalLine,
+ Label,
+ TextArea,
)
from prompt_toolkit.widgets.base import Border
from awscli.autoprompt.filters import (
- help_section_visible, doc_window_has_focus, search_input_has_focus,
- input_buffer_has_focus, is_history_mode, is_debug_mode,
+ doc_window_has_focus,
+ help_section_visible,
+ input_buffer_has_focus,
+ is_debug_mode,
+ is_history_mode,
+ search_input_has_focus,
)
@@ -43,24 +57,30 @@ class FormatTextProcessor(Processor):
format inside a ``prompt_toolkit.buffer.Buffer``.
"""
+
def apply_transformation(self, text_input):
# https://python-prompt-toolkit.readthedocs.io/en/master/pages/reference.html#module-prompt_toolkit.formatted_text
fragments = to_formatted_text(
- HTML(fragment_list_to_text(text_input.fragments)))
+ HTML(fragment_list_to_text(text_input.fragments))
+ )
return Transformation(fragments)
class TitleLine:
-
def __init__(self, title):
fill = partial(Window, style='class:frame.border')
- self.container = VSplit([
- fill(char=Border.HORIZONTAL),
- fill(width=1, height=1, char='|'),
- Label(title, style='class:frame.label', dont_extend_width=True),
- fill(width=1, height=1, char='|'),
- fill(char=Border.HORIZONTAL),
- ], height=1)
+ self.container = VSplit(
+ [
+ fill(char=Border.HORIZONTAL),
+ fill(width=1, height=1, char='|'),
+ Label(
+ title, style='class:frame.label', dont_extend_width=True
+ ),
+ fill(width=1, height=1, char='|'),
+ fill(char=Border.HORIZONTAL),
+ ],
+ height=1,
+ )
def __pt_container__(self):
return self.container
@@ -92,10 +112,10 @@ def create_window(self, help_buffer):
content=BufferControl(
buffer=help_buffer,
input_processors=[FormatTextProcessor()],
- focusable=self.FOCUSABLE
+ focusable=self.FOCUSABLE,
),
wrap_lines=True,
- **self.DIMENSIONS
+ **self.DIMENSIONS,
)
@@ -106,7 +126,7 @@ class BaseHelpView(BaseHelpContainer):
def create_window(self, help_buffer):
return Frame(
super(BaseHelpView, self).create_window(help_buffer),
- title=self.TITLE
+ title=self.TITLE,
)
@@ -203,7 +223,7 @@ def help_text(self):
f'{self.STYLE}[F2] Focus on next panel{self.SPACING}'
f'{self.STYLE}[F3] Hide/Show Docs{self.SPACING}'
f'{self.STYLE}[F5] Hide/Show Output'
- )
+ )
class OutputToolbarView(BaseToolbarView):
@@ -217,7 +237,7 @@ def help_text(self):
f'{self.STYLE}[F2] Focus on next panel{self.SPACING}'
f'{self.STYLE}[F3] Hide/Show Docs{self.SPACING}'
f'{self.STYLE}[F5] Hide/Show Output'
- )
+ )
class DebugToolbarView(BaseToolbarView):
@@ -226,9 +246,7 @@ class DebugToolbarView(BaseToolbarView):
@property
def help_text(self):
- return (
- f'{self.STYLE}[CONTROL+S] Save log to file'
- )
+ return f'{self.STYLE}[CONTROL+S] Save log to file'
class HistorySignToolbarView(BaseToolbarView):
@@ -246,31 +264,37 @@ def help_text(self):
class ToolbarWidget:
-
def __init__(self):
- self.container = HSplit([
- ConditionalContainer(HorizontalLine(), ~help_section_visible),
- VSplit([
- HistorySignToolbarView(),
- ConditionalContainer(
- VSplit([InputToolbarView(),
- DocToolbarView(),
- OutputToolbarView()]),
- ~help_section_visible
- )
- ])
- ])
+ self.container = HSplit(
+ [
+ ConditionalContainer(HorizontalLine(), ~help_section_visible),
+ VSplit(
+ [
+ HistorySignToolbarView(),
+ ConditionalContainer(
+ VSplit(
+ [
+ InputToolbarView(),
+ DocToolbarView(),
+ OutputToolbarView(),
+ ]
+ ),
+ ~help_section_visible,
+ ),
+ ]
+ ),
+ ]
+ )
def __pt_container__(self):
return self.container
class HelpPanelWidget:
-
def __init__(self):
self.container = ConditionalContainer(
HSplit([DocHelpView(), InputHelpView(), OutputHelpView()]),
- help_section_visible
+ help_section_visible,
)
def __pt_container__(self):
@@ -289,7 +313,8 @@ def __init__(self):
_kb = KeyBindings()
_kb.add(Keys.ControlS, filter=is_debug_mode, is_global=True)(
- self._activate_dialog)
+ self._activate_dialog
+ )
self.float_container = FloatContainer(
Window(
@@ -299,19 +324,21 @@ def __init__(self):
wrap_lines=True,
),
key_bindings=_kb,
- floats=[]
+ floats=[],
)
self.container = ConditionalContainer(
Frame(
- HSplit([
- self.float_container,
- HorizontalLine(),
- DebugToolbarView()
- ]),
+ HSplit(
+ [
+ self.float_container,
+ HorizontalLine(),
+ DebugToolbarView(),
+ ]
+ ),
**self.DIMENSIONS,
- title='Debug panel'
+ title='Debug panel',
),
- filter=is_debug_mode
+ filter=is_debug_mode,
)
def _activate_dialog(self, event):
@@ -347,15 +374,20 @@ def ok_handler(*args, **kwargs):
dialog = Dialog(
title='Save logs to file',
- body=HSplit([
- Label(text='Log file name', dont_extend_height=True),
- textfield,
- ], padding=Dimension(preferred=1, max=1)),
+ body=HSplit(
+ [
+ Label(text='Log file name', dont_extend_height=True),
+ textfield,
+ ],
+ padding=Dimension(preferred=1, max=1),
+ ),
buttons=[ok_button, cancel_button],
- with_background=True)
+ with_background=True,
+ )
# add keybinding to save file on press Enter in textfield
dialog.container.body.container.content.key_bindings.add(
- Keys.Enter, filter=has_focus(textfield))(ok_handler)
+ Keys.Enter, filter=has_focus(textfield)
+ )(ok_handler)
return dialog
diff --git a/awscli/bcdoc/docevents.py b/awscli/bcdoc/docevents.py
index 54bce6ebd9d9..e861d91ba3b5 100644
--- a/awscli/bcdoc/docevents.py
+++ b/awscli/bcdoc/docevents.py
@@ -31,76 +31,114 @@
'doc-subitems-end': '.%s',
'doc-relateditems-start': '.%s',
'doc-relateditem': '.%s.%s',
- 'doc-relateditems-end': '.%s'
- }
+ 'doc-relateditems-end': '.%s',
+}
def generate_events(session, help_command):
# Now generate the documentation events
- session.emit('doc-breadcrumbs.%s' % help_command.event_class,
- help_command=help_command)
- session.emit('doc-title.%s' % help_command.event_class,
- help_command=help_command)
- session.emit('doc-description.%s' % help_command.event_class,
- help_command=help_command)
- session.emit('doc-synopsis-start.%s' % help_command.event_class,
- help_command=help_command)
+ session.emit(
+ 'doc-breadcrumbs.%s' % help_command.event_class,
+ help_command=help_command,
+ )
+ session.emit(
+ 'doc-title.%s' % help_command.event_class, help_command=help_command
+ )
+ session.emit(
+ 'doc-description.%s' % help_command.event_class,
+ help_command=help_command,
+ )
+ session.emit(
+ 'doc-synopsis-start.%s' % help_command.event_class,
+ help_command=help_command,
+ )
if help_command.arg_table:
for arg_name in help_command.arg_table:
# An argument can set an '_UNDOCUMENTED' attribute
# to True to indicate a parameter that exists
# but shouldn't be documented. This can be used
# for backwards compatibility of deprecated arguments.
- if getattr(help_command.arg_table[arg_name],
- '_UNDOCUMENTED', False):
+ if getattr(
+ help_command.arg_table[arg_name], '_UNDOCUMENTED', False
+ ):
continue
session.emit(
- 'doc-synopsis-option.%s.%s' % (help_command.event_class,
- arg_name),
- arg_name=arg_name, help_command=help_command)
- session.emit('doc-synopsis-end.%s' % help_command.event_class,
- help_command=help_command)
- session.emit('doc-options-start.%s' % help_command.event_class,
- help_command=help_command)
+ 'doc-synopsis-option.%s.%s'
+ % (help_command.event_class, arg_name),
+ arg_name=arg_name,
+ help_command=help_command,
+ )
+ session.emit(
+ 'doc-synopsis-end.%s' % help_command.event_class,
+ help_command=help_command,
+ )
+ session.emit(
+ 'doc-options-start.%s' % help_command.event_class,
+ help_command=help_command,
+ )
if help_command.arg_table:
for arg_name in help_command.arg_table:
- if getattr(help_command.arg_table[arg_name],
- '_UNDOCUMENTED', False):
+ if getattr(
+ help_command.arg_table[arg_name], '_UNDOCUMENTED', False
+ ):
continue
- session.emit('doc-option.%s.%s' % (help_command.event_class,
- arg_name),
- arg_name=arg_name, help_command=help_command)
- session.emit('doc-option-example.%s.%s' %
- (help_command.event_class, arg_name),
- arg_name=arg_name, help_command=help_command)
- session.emit('doc-options-end.%s' % help_command.event_class,
- help_command=help_command)
- session.emit('doc-global-option.%s' % help_command.event_class,
- help_command=help_command)
- session.emit('doc-subitems-start.%s' % help_command.event_class,
- help_command=help_command)
+ session.emit(
+ 'doc-option.%s.%s' % (help_command.event_class, arg_name),
+ arg_name=arg_name,
+ help_command=help_command,
+ )
+ session.emit(
+ 'doc-option-example.%s.%s'
+ % (help_command.event_class, arg_name),
+ arg_name=arg_name,
+ help_command=help_command,
+ )
+ session.emit(
+ 'doc-options-end.%s' % help_command.event_class,
+ help_command=help_command,
+ )
+ session.emit(
+ 'doc-global-option.%s' % help_command.event_class,
+ help_command=help_command,
+ )
+ session.emit(
+ 'doc-subitems-start.%s' % help_command.event_class,
+ help_command=help_command,
+ )
if help_command.command_table:
for command_name in sorted(help_command.command_table.keys()):
- if hasattr(help_command.command_table[command_name],
- '_UNDOCUMENTED'):
+ if hasattr(
+ help_command.command_table[command_name], '_UNDOCUMENTED'
+ ):
continue
- session.emit('doc-subitem.%s.%s'
- % (help_command.event_class, command_name),
- command_name=command_name,
- help_command=help_command)
- session.emit('doc-subitems-end.%s' % help_command.event_class,
- help_command=help_command)
- session.emit('doc-examples.%s' % help_command.event_class,
- help_command=help_command)
- session.emit('doc-output.%s' % help_command.event_class,
- help_command=help_command)
- session.emit('doc-relateditems-start.%s' % help_command.event_class,
- help_command=help_command)
+ session.emit(
+ 'doc-subitem.%s.%s' % (help_command.event_class, command_name),
+ command_name=command_name,
+ help_command=help_command,
+ )
+ session.emit(
+ 'doc-subitems-end.%s' % help_command.event_class,
+ help_command=help_command,
+ )
+ session.emit(
+ 'doc-examples.%s' % help_command.event_class, help_command=help_command
+ )
+ session.emit(
+ 'doc-output.%s' % help_command.event_class, help_command=help_command
+ )
+ session.emit(
+ 'doc-relateditems-start.%s' % help_command.event_class,
+ help_command=help_command,
+ )
if help_command.related_items:
for related_item in sorted(help_command.related_items):
- session.emit('doc-relateditem.%s.%s'
- % (help_command.event_class, related_item),
- help_command=help_command,
- related_item=related_item)
- session.emit('doc-relateditems-end.%s' % help_command.event_class,
- help_command=help_command)
+ session.emit(
+ 'doc-relateditem.%s.%s'
+ % (help_command.event_class, related_item),
+ help_command=help_command,
+ related_item=related_item,
+ )
+ session.emit(
+ 'doc-relateditems-end.%s' % help_command.event_class,
+ help_command=help_command,
+ )
diff --git a/awscli/bcdoc/docstringparser.py b/awscli/bcdoc/docstringparser.py
index cfff547db59d..791f7d5e5021 100644
--- a/awscli/bcdoc/docstringparser.py
+++ b/awscli/bcdoc/docstringparser.py
@@ -57,6 +57,7 @@ class HTMLTree(object):
meaning that the current_node will be the most recently opened tag. When
a tag is closed, the current_node moves up to the parent node.
"""
+
def __init__(self, doc):
self.doc = doc
self.head = StemNode()
@@ -122,6 +123,7 @@ class TagNode(StemNode):
"""
A generic Tag node. It will verify that handlers exist before writing.
"""
+
def __init__(self, tag, attrs=None, parent=None):
super(TagNode, self).__init__(parent)
self.attrs = attrs
@@ -174,6 +176,7 @@ class DataNode(Node):
"""
A Node that contains only string data.
"""
+
def __init__(self, data, parent=None):
super(DataNode, self).__init__(parent)
if not isinstance(data, str):
diff --git a/awscli/bcdoc/restdoc.py b/awscli/bcdoc/restdoc.py
index d194d0e9f0ac..b93792798426 100644
--- a/awscli/bcdoc/restdoc.py
+++ b/awscli/bcdoc/restdoc.py
@@ -13,6 +13,7 @@
import logging
from botocore.compat import OrderedDict
+
from awscli.bcdoc.docstringparser import DocStringParser
from awscli.bcdoc.style import ReSTStyle
@@ -20,7 +21,6 @@
class ReSTDocument(object):
-
def __init__(self, target='man'):
self.style = ReSTStyle(self)
self.target = target
@@ -194,8 +194,9 @@ def add_new_section(self, name, context=None):
to the document structure it was instantiated from.
"""
# Add a new section
- section = self.__class__(name=name, target=self.target,
- context=context)
+ section = self.__class__(
+ name=name, target=self.target, context=context
+ )
section.path = self.path + [name]
# Indent the section apporpriately as well
section.style.indentation = self.style.indentation
diff --git a/awscli/bcdoc/style.py b/awscli/bcdoc/style.py
index 4470d65d3cc6..6ffbae853503 100644
--- a/awscli/bcdoc/style.py
+++ b/awscli/bcdoc/style.py
@@ -17,7 +17,6 @@
class BaseStyle(object):
-
def __init__(self, doc, indent_width=2):
self.doc = doc
self.indent_width = indent_width
@@ -65,7 +64,6 @@ def italics(self, s):
class ReSTStyle(BaseStyle):
-
def __init__(self, doc, indent_width=2):
BaseStyle.__init__(self, doc, indent_width)
self.do_p = True
diff --git a/awscli/bcdoc/textwriter.py b/awscli/bcdoc/textwriter.py
index 6fc171b9b475..6ccc2dab90fd 100644
--- a/awscli/bcdoc/textwriter.py
+++ b/awscli/bcdoc/textwriter.py
@@ -1,13 +1,14 @@
# -*- coding: utf-8 -*-
"""
- Custom docutils writer for plain text.
- Based heavily on the Sphinx text writer. See copyright below.
+Custom docutils writer for plain text.
+Based heavily on the Sphinx text writer. See copyright below.
- :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
- :license: BSD, see LICENSE for details.
+:copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+:license: BSD, see LICENSE for details.
"""
+
import os
import re
import textwrap
@@ -19,10 +20,11 @@ class TextWrapper(textwrap.TextWrapper):
"""Custom subclass that uses a different word separator regex."""
wordsep_re = re.compile(
- r'(\s+|' # any whitespace
- r'(?<=\s)(?::[a-z-]+:)?`\S+|' # interpreted text start
- r'[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|' # hyphenated words
- r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash
+ r'(\s+|' # any whitespace
+ r'(?<=\s)(?::[a-z-]+:)?`\S+|' # interpreted text start
+ r'[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|' # hyphenated words
+ r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))'
+ ) # em-dash
MAXWIDTH = 70
@@ -81,12 +83,13 @@ def do_format():
if not toformat:
return
if wrap:
- res = my_wrap(''.join(toformat), width=MAXWIDTH-maxindent)
+ res = my_wrap(''.join(toformat), width=MAXWIDTH - maxindent)
else:
res = ''.join(toformat).splitlines()
if end:
res += end
result.append((indent, res))
+
for itemindent, item in content:
if itemindent == -1:
toformat.append(item)
@@ -107,9 +110,11 @@ def visit_document(self, node):
def depart_document(self, node):
self.end_state()
- self.body = self.nl.join(line and (' '*indent + line)
- for indent, lines in self.states[0]
- for line in lines)
+ self.body = self.nl.join(
+ line and (' ' * indent + line)
+ for indent, lines in self.states[0]
+ for line in lines
+ )
# XXX header/footer?
def visit_highlightlang(self, node):
@@ -153,7 +158,7 @@ def depart_glossary(self, node):
def visit_title(self, node):
if isinstance(node.parent, nodes.Admonition):
- self.add_text(node.astext()+': ')
+ self.add_text(node.astext() + ': ')
raise nodes.SkipNode
self.new_state(0)
@@ -280,7 +285,7 @@ def visit_productionlist(self, node):
self.add_text(production['tokenname'].ljust(maxlen) + ' ::=')
lastname = production['tokenname']
else:
- self.add_text('%s ' % (' '*len(lastname)))
+ self.add_text('%s ' % (' ' * len(lastname)))
self.add_text(production.astext() + self.nl)
self.end_state(wrap=False)
raise nodes.SkipNode
@@ -391,8 +396,9 @@ def depart_row(self, node):
def visit_entry(self, node):
if 'morerows' in node or 'morecols' in node:
- raise NotImplementedError('Column or row spanning cells are '
- 'not implemented.')
+ raise NotImplementedError(
+ 'Column or row spanning cells are ' 'not implemented.'
+ )
self.new_state(0)
def depart_entry(self, node):
@@ -431,7 +437,7 @@ def depart_table(self, node):
def writesep(char='-'):
out = ['+']
for width in realwidths:
- out.append(char * (width+2))
+ out.append(char * (width + 2))
out.append('+')
self.add_text(''.join(out) + self.nl)
@@ -441,7 +447,7 @@ def writerow(row):
out = ['|']
for i, cell in enumerate(line):
if cell:
- out.append(' ' + cell.ljust(realwidths[i]+1))
+ out.append(' ' + cell.ljust(realwidths[i] + 1))
else:
out.append(' ' * (realwidths[i] + 2))
out.append('|')
@@ -460,7 +466,8 @@ def writerow(row):
def visit_acks(self, node):
self.new_state(0)
self.add_text(
- ', '.join(n.astext() for n in node.children[0].children) + '.')
+ ', '.join(n.astext() for n in node.children[0].children) + '.'
+ )
self.end_state()
raise nodes.SkipNode
@@ -516,8 +523,9 @@ def depart_list_item(self, node):
self.end_state(first='%s. ' % self.list_counter[-1], end=None)
def visit_definition_list_item(self, node):
- self._li_has_classifier = len(node) >= 2 and \
- isinstance(node[1], nodes.classifier)
+ self._li_has_classifier = len(node) >= 2 and isinstance(
+ node[1], nodes.classifier
+ )
def depart_definition_list_item(self, node):
pass
@@ -774,6 +782,7 @@ def _visit_admonition(self, node):
def _make_depart_admonition(name):
def depart_admonition(self, node):
self.end_state(first=name.capitalize() + ': ')
+
return depart_admonition
visit_attention = _visit_admonition
diff --git a/awscli/clidriver.py b/awscli/clidriver.py
index 5e6460182ef0..fa9f60061841 100644
--- a/awscli/clidriver.py
+++ b/awscli/clidriver.py
@@ -151,7 +151,7 @@ def _add_linux_distribution_to_user_agent(session):
if linux_distribution := _get_distribution():
add_metadata_component_to_user_agent_extra(
session,
- 'distrib',
+ 'distrib',
linux_distribution,
)
@@ -453,7 +453,7 @@ def _cli_version(self):
if 'AWS_EXECUTION_ENV' in os.environ:
version_string += f' exec-env/{os.environ.get("AWS_EXECUTION_ENV")}'
-
+
version_string += f' {_get_distribution_source()}/{platform.machine()}'
if linux_distribution := _get_distribution():
diff --git a/awscli/customizations/addexamples.py b/awscli/customizations/addexamples.py
index db34371adfdd..49a9ed65b55c 100644
--- a/awscli/customizations/addexamples.py
+++ b/awscli/customizations/addexamples.py
@@ -26,36 +26,38 @@
For example, ``examples/ec2/ec2-create-key-pair.rst``.
"""
-import os
-import logging
+import logging
+import os
LOG = logging.getLogger(__name__)
def add_examples(help_command, **kwargs):
doc_path = os.path.join(
- os.path.dirname(
- os.path.dirname(
- os.path.abspath(__file__))), 'examples')
- doc_path = os.path.join(doc_path,
- help_command.event_class.replace('.', os.path.sep))
+ os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'examples'
+ )
+ doc_path = os.path.join(
+ doc_path, help_command.event_class.replace('.', os.path.sep)
+ )
doc_path = doc_path + '.rst'
LOG.debug("Looking for example file at: %s", doc_path)
if os.path.isfile(doc_path):
help_command.doc.style.h2('Examples')
help_command.doc.style.start_note()
- msg = ("To use the following examples, you must have the AWS "
- "CLI installed and configured. See the "
- ""
- "Getting started guide in the AWS CLI User Guide "
- "for more information.
"
- "Unless otherwise stated, all examples have unix-like "
- "quotation rules. These examples will need to be adapted "
- "to your terminal's quoting rules. See "
- ""
- "Using quotation marks with strings "
- "in the AWS CLI User Guide.
")
+ msg = (
+ "To use the following examples, you must have the AWS "
+ "CLI installed and configured. See the "
+ ""
+ "Getting started guide in the AWS CLI User Guide "
+ "for more information.
"
+ "Unless otherwise stated, all examples have unix-like "
+ "quotation rules. These examples will need to be adapted "
+ "to your terminal's quoting rules. See "
+ ""
+ "Using quotation marks with strings "
+ "in the AWS CLI User Guide.
"
+ )
help_command.doc.include_doc_string(msg)
help_command.doc.style.end_note()
fp = open(doc_path)
diff --git a/awscli/customizations/argrename.py b/awscli/customizations/argrename.py
index eb905df769a9..b188436eac1d 100644
--- a/awscli/customizations/argrename.py
+++ b/awscli/customizations/argrename.py
@@ -10,12 +10,10 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
-"""
-"""
+""" """
from awscli.customizations import utils
-
ARGUMENT_RENAMES = {
# Mapping of original arg to renamed arg.
# The key is ..argname
@@ -76,8 +74,7 @@
'stepfunctions.send-task-success.output': 'task-output',
'clouddirectory.publish-schema.version': 'schema-version',
'mturk.list-qualification-types.query': 'types-query',
- 'workdocs.create-notification-subscription.endpoint':
- 'notification-endpoint',
+ 'workdocs.create-notification-subscription.endpoint': 'notification-endpoint',
'workdocs.describe-users.query': 'user-query',
'lex-models.delete-bot.version': 'bot-version',
'lex-models.delete-intent.version': 'intent-version',
@@ -117,36 +114,41 @@
# This is useful when you need to change the name of an argument but you
# still need to support the old argument.
HIDDEN_ALIASES = {
- 'mgn.*.replication-servers-security-groups-ids':
- 'replication-servers-security-groups-i-ds',
+ 'mgn.*.replication-servers-security-groups-ids': 'replication-servers-security-groups-i-ds',
'mgn.*.source-server-ids': 'source-server-i-ds',
- 'mgn.*.replication-configuration-template-ids':
- 'replication-configuration-template-i-ds',
- 'elasticache.create-replication-group.preferred-cache-cluster-azs':
- 'preferred-cache-cluster-a-zs'
+ 'mgn.*.replication-configuration-template-ids': 'replication-configuration-template-i-ds',
+ 'elasticache.create-replication-group.preferred-cache-cluster-azs': 'preferred-cache-cluster-a-zs',
}
def register_arg_renames(cli):
for original, new_name in ARGUMENT_RENAMES.items():
event_portion, original_arg_name = original.rsplit('.', 1)
- cli.register('building-argument-table.%s' % event_portion,
- rename_arg(original_arg_name, new_name))
+ cli.register(
+ f'building-argument-table.{event_portion}',
+ rename_arg(original_arg_name, new_name),
+ )
for original, new_name in HIDDEN_ALIASES.items():
event_portion, original_arg_name = original.rsplit('.', 1)
- cli.register('building-argument-table.%s' % event_portion,
- hidden_alias(original_arg_name, new_name))
+ cli.register(
+ f'building-argument-table.{event_portion}',
+ hidden_alias(original_arg_name, new_name),
+ )
def rename_arg(original_arg_name, new_name):
def _rename_arg(argument_table, **kwargs):
if original_arg_name in argument_table:
utils.rename_argument(argument_table, original_arg_name, new_name)
+
return _rename_arg
def hidden_alias(original_arg_name, alias_name):
def _alias_arg(argument_table, **kwargs):
if original_arg_name in argument_table:
- utils.make_hidden_alias(argument_table, original_arg_name, alias_name)
+ utils.make_hidden_alias(
+ argument_table, original_arg_name, alias_name
+ )
+
return _alias_arg
diff --git a/awscli/customizations/arguments.py b/awscli/customizations/arguments.py
index 43ec260a7aa4..a6b30eca6cb9 100644
--- a/awscli/customizations/arguments.py
+++ b/awscli/customizations/arguments.py
@@ -13,10 +13,11 @@
import os
import re
+import jmespath
+
from awscli.arguments import CustomArgument
from awscli.compat import compat_open
from awscli.customizations.exceptions import ParamValidationError
-import jmespath
def resolve_given_outfile_path(path):
@@ -25,7 +26,7 @@ def resolve_given_outfile_path(path):
return
outfile = os.path.expanduser(os.path.expandvars(path))
if not os.access(os.path.dirname(os.path.abspath(outfile)), os.W_OK):
- raise ParamValidationError('Unable to write to file: %s' % outfile)
+ raise ParamValidationError(f'Unable to write to file: {outfile}')
return outfile
@@ -59,11 +60,13 @@ class OverrideRequiredArgsArgument(CustomArgument):
def __init__(self, session):
self._session = session
self._register_argument_action()
- super(OverrideRequiredArgsArgument, self).__init__(**self.ARG_DATA)
+ super().__init__(**self.ARG_DATA)
def _register_argument_action(self):
- self._session.register('before-building-argument-table-parser',
- self.override_required_args)
+ self._session.register(
+ 'before-building-argument-table-parser',
+ self.override_required_args,
+ )
def override_required_args(self, argument_table, args, **kwargs):
name_in_cmdline = '--' + self.name
@@ -78,11 +81,11 @@ class StatefulArgument(CustomArgument):
"""An argument that maintains a stateful value"""
def __init__(self, *args, **kwargs):
- super(StatefulArgument, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
self._value = None
def add_to_params(self, parameters, value):
- super(StatefulArgument, self).add_to_params(parameters, value)
+ super().add_to_params(parameters, value)
self._value = value
@property
@@ -93,17 +96,20 @@ def value(self):
class QueryOutFileArgument(StatefulArgument):
"""An argument that write a JMESPath query result to a file"""
- def __init__(self, session, name, query, after_call_event, perm,
- *args, **kwargs):
+ def __init__(
+ self, session, name, query, after_call_event, perm, *args, **kwargs
+ ):
self._session = session
self._query = query
self._after_call_event = after_call_event
self._perm = perm
# Generate default help_text if text was not provided.
if 'help_text' not in kwargs:
- kwargs['help_text'] = ('Saves the command output contents of %s '
- 'to the given filename' % self.query)
- super(QueryOutFileArgument, self).__init__(name, *args, **kwargs)
+ kwargs['help_text'] = (
+ f'Saves the command output contents of {self.query} '
+ 'to the given filename'
+ )
+ super().__init__(name, *args, **kwargs)
@property
def query(self):
@@ -115,7 +121,7 @@ def perm(self):
def add_to_params(self, parameters, value):
value = resolve_given_outfile_path(value)
- super(QueryOutFileArgument, self).add_to_params(parameters, value)
+ super().add_to_params(parameters, value)
if self.value is not None:
# Only register the event to save the argument if it is set
self._session.register(self._after_call_event, self.save_query)
@@ -129,7 +135,8 @@ def save_query(self, parsed, **kwargs):
if is_parsed_result_successful(parsed):
contents = jmespath.search(self.query, parsed)
with compat_open(
- self.value, 'w', access_permissions=self.perm) as fp:
+ self.value, 'w', access_permissions=self.perm
+ ) as fp:
# Don't write 'None' to a file -- write ''.
if contents is None:
fp.write('')
@@ -145,15 +152,21 @@ def save_query(self, parsed, **kwargs):
os.chmod(self.value, self.perm)
-class NestedBlobArgumentHoister(object):
+class NestedBlobArgumentHoister:
"""Can be registered to update a single argument / model value combination
mapping that to a new top-level argument.
Currently limited to blob argument types as these are the only ones
requiring the hoist.
"""
- def __init__(self, source_arg, source_arg_blob_member,
- new_arg, new_arg_doc_string, doc_string_addendum):
+ def __init__(
+ self,
+ source_arg,
+ source_arg_blob_member,
+ new_arg,
+ new_arg_doc_string,
+ doc_string_addendum,
+ ):
self._source_arg = source_arg
self._source_arg_blob_member = source_arg_blob_member
self._new_arg = new_arg
@@ -163,8 +176,7 @@ def __init__(self, source_arg, source_arg_blob_member,
def __call__(self, session, argument_table, **kwargs):
if not self._valid_target(argument_table):
return
- self._update_arg(
- argument_table, self._source_arg, self._new_arg)
+ self._update_arg(argument_table, self._source_arg, self._new_arg)
def _valid_target(self, argument_table):
# Find the source argument and check that it has a member of
@@ -173,24 +185,27 @@ def _valid_target(self, argument_table):
arg = argument_table[self._source_arg]
input_model = arg.argument_model
member = input_model.members.get(self._source_arg_blob_member)
- if (member is not None and
- member.type_name == 'blob'):
+ if member is not None and member.type_name == 'blob':
return True
return False
def _update_arg(self, argument_table, source_arg, new_arg):
argument_table[new_arg] = _NestedBlobArgumentParamOverwrite(
- new_arg, source_arg, self._source_arg_blob_member,
+ new_arg,
+ source_arg,
+ self._source_arg_blob_member,
help_text=self._new_arg_doc_string,
- cli_type_name='blob')
+ cli_type_name='blob',
+ )
argument_table[source_arg].required = False
argument_table[source_arg].documentation += self._doc_string_addendum
class _NestedBlobArgumentParamOverwrite(CustomArgument):
def __init__(self, new_arg, source_arg, source_arg_blob_member, **kwargs):
- super(_NestedBlobArgumentParamOverwrite, self).__init__(
- new_arg, **kwargs)
+ super().__init__(
+ new_arg, **kwargs
+ )
self._param_to_overwrite = _reverse_xform_name(source_arg)
self._source_arg_blob_member = source_arg_blob_member
diff --git a/awscli/customizations/assumerole.py b/awscli/customizations/assumerole.py
index b25a80b2def6..760918a62a70 100644
--- a/awscli/customizations/assumerole.py
+++ b/awscli/customizations/assumerole.py
@@ -1,17 +1,19 @@
-import os
import logging
+import os
-from botocore.exceptions import ProfileNotFound
from botocore.credentials import JSONFileCache
+from botocore.exceptions import ProfileNotFound
LOG = logging.getLogger(__name__)
CACHE_DIR = os.path.expanduser(os.path.join('~', '.aws', 'cli', 'cache'))
def register_assume_role_provider(event_handlers):
- event_handlers.register('session-initialized',
- inject_assume_role_provider_cache,
- unique_id='inject_assume_role_cred_provider_cache')
+ event_handlers.register(
+ 'session-initialized',
+ inject_assume_role_provider_cache,
+ unique_id='inject_assume_role_cred_provider_cache',
+ )
def inject_assume_role_provider_cache(session, **kwargs):
@@ -33,9 +35,11 @@ def inject_assume_role_provider_cache(session, **kwargs):
# immediately return. If it's invalid something else
# up the stack will raise ProfileNotFound, otherwise
# the configure (and other) commands will work as expected.
- LOG.debug("ProfileNotFound caught when trying to inject "
- "assume-role cred provider cache. Not configuring "
- "JSONFileCache for assume-role.")
+ LOG.debug(
+ "ProfileNotFound caught when trying to inject "
+ "assume-role cred provider cache. Not configuring "
+ "JSONFileCache for assume-role."
+ )
return
assume_role_provider = cred_chain.get_provider('assume-role')
assume_role_provider.cache = JSONFileCache(CACHE_DIR)
diff --git a/awscli/customizations/awslambda.py b/awscli/customizations/awslambda.py
index 121488ef18ed..b19e6c781ad8 100644
--- a/awscli/customizations/awslambda.py
+++ b/awscli/customizations/awslambda.py
@@ -10,18 +10,18 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
-import zipfile
import copy
+import zipfile
from contextlib import closing
-from awscli.arguments import CustomArgument, CLIArgument
-from awscli.customizations.exceptions import ParamValidationError
+from awscli.arguments import CLIArgument, CustomArgument
from awscli.compat import BytesIO
-
+from awscli.customizations.exceptions import ParamValidationError
ERROR_MSG = (
"--zip-file must be a zip file with the fileb:// prefix.\n"
- "Example usage: --zip-file fileb://path/to/file.zip")
+ "Example usage: --zip-file fileb://path/to/file.zip"
+)
ZIP_DOCSTRING = (
'The path to the zip file of the {param_type} you are uploading. '
@@ -31,14 +31,21 @@
def register_lambda_create_function(cli):
- cli.register('building-argument-table.lambda.create-function',
- ZipFileArgumentHoister('Code').hoist)
- cli.register('building-argument-table.lambda.publish-layer-version',
- ZipFileArgumentHoister('Content').hoist)
- cli.register('building-argument-table.lambda.update-function-code',
- _modify_zipfile_docstring)
- cli.register('process-cli-arg.lambda.update-function-code',
- validate_is_zip_file)
+ cli.register(
+ 'building-argument-table.lambda.create-function',
+ ZipFileArgumentHoister('Code').hoist,
+ )
+ cli.register(
+ 'building-argument-table.lambda.publish-layer-version',
+ ZipFileArgumentHoister('Content').hoist,
+ )
+ cli.register(
+ 'building-argument-table.lambda.update-function-code',
+ _modify_zipfile_docstring,
+ )
+ cli.register(
+ 'process-cli-arg.lambda.update-function-code', validate_is_zip_file
+ )
def validate_is_zip_file(cli_argument, value, **kwargs):
@@ -46,7 +53,7 @@ def validate_is_zip_file(cli_argument, value, **kwargs):
_should_contain_zip_content(value)
-class ZipFileArgumentHoister(object):
+class ZipFileArgumentHoister:
"""Hoists a ZipFile argument up to the top level.
Injects a top-level ZipFileArgument into the argument table which maps
@@ -55,6 +62,7 @@ class ZipFileArgumentHoister(object):
ReplacedZipFileArgument to prevent its usage and recommend the new
top-level injected parameter.
"""
+
def __init__(self, serialized_name):
self._serialized_name = serialized_name
self._name = serialized_name.lower()
@@ -62,8 +70,10 @@ def __init__(self, serialized_name):
def hoist(self, session, argument_table, **kwargs):
help_text = ZIP_DOCSTRING.format(param_type=self._name)
argument_table['zip-file'] = ZipFileArgument(
- 'zip-file', help_text=help_text, cli_type_name='blob',
- serialized_name=self._serialized_name
+ 'zip-file',
+ help_text=help_text,
+ cli_type_name='blob',
+ serialized_name=self._serialized_name,
)
argument = argument_table[self._name]
model = copy.deepcopy(argument.argument_model)
@@ -107,9 +117,10 @@ class ZipFileArgument(CustomArgument):
--zip-file foo.zip winds up being serialized as
{ 'Code': { 'ZipFile': } }.
"""
+
def __init__(self, *args, **kwargs):
self._param_to_replace = kwargs.pop('serialized_name')
- super(ZipFileArgument, self).__init__(*args, **kwargs)
+ super().__init__(*args, **kwargs)
def add_to_params(self, parameters, value):
if value is None:
@@ -131,9 +142,10 @@ class ReplacedZipFileArgument(CLIArgument):
contents. And the argument class can inject those bytes into the correct
serialization name.
"""
+
def __init__(self, *args, **kwargs):
- super(ReplacedZipFileArgument, self).__init__(*args, **kwargs)
- self._cli_name = '--%s' % kwargs['name']
+ super().__init__(*args, **kwargs)
+ self._cli_name = '--{}'.format(kwargs['name'])
self._param_to_replace = kwargs['serialized_name']
def add_to_params(self, parameters, value):
@@ -143,9 +155,9 @@ def add_to_params(self, parameters, value):
if 'ZipFile' in unpacked:
raise ParamValidationError(
"ZipFile cannot be provided "
- "as part of the %s argument. "
+ f"as part of the {self._cli_name} argument. "
"Please use the '--zip-file' "
- "option instead to specify a zip file." % self._cli_name
+ "option instead to specify a zip file."
)
if parameters.get(self._param_to_replace):
parameters[self._param_to_replace].update(unpacked)
diff --git a/awscli/customizations/binaryformat.py b/awscli/customizations/binaryformat.py
index 501284df0a8d..3d031a29e905 100644
--- a/awscli/customizations/binaryformat.py
+++ b/awscli/customizations/binaryformat.py
@@ -57,10 +57,10 @@ def _visit_scalar(self, parent, shape, name, value):
try:
parent[name] = base64.b64decode(value)
except (binascii.Error, TypeError):
- raise InvalidBase64Error('Invalid base64: "%s"' % value)
+ raise InvalidBase64Error(f'Invalid base64: "{value}"')
-class BinaryFormatHandler(object):
+class BinaryFormatHandler:
_BINARY_FORMATS = {
'base64': (base64_decode_input_blobs, register_identity_blob_parser),
'raw-in-base64-out': (None, register_identity_blob_parser),
diff --git a/awscli/customizations/binaryhoist.py b/awscli/customizations/binaryhoist.py
index 94a7d5d6cdd7..247ae4e4a63b 100644
--- a/awscli/customizations/binaryhoist.py
+++ b/awscli/customizations/binaryhoist.py
@@ -11,10 +11,10 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import copy
-
from dataclasses import dataclass
from typing import Optional
-from awscli.arguments import CustomArgument, CLIArgument
+
+from awscli.arguments import CLIArgument, CustomArgument
from awscli.customizations.exceptions import ParamValidationError
diff --git a/awscli/customizations/cliinput.py b/awscli/customizations/cliinput.py
index 9b8aa2e254f7..e1196502ea68 100644
--- a/awscli/customizations/cliinput.py
+++ b/awscli/customizations/cliinput.py
@@ -15,9 +15,9 @@
from ruamel.yaml import YAML
from ruamel.yaml.error import YAMLError
-from awscli.paramfile import get_paramfile, LOCAL_PREFIX_MAP
from awscli.argprocess import ParamError, ParamSyntaxError
from awscli.customizations.arguments import OverrideRequiredArgsArgument
+from awscli.paramfile import LOCAL_PREFIX_MAP, get_paramfile
def register_cli_input_args(cli):
@@ -49,11 +49,12 @@ class CliInputArgument(OverrideRequiredArgsArgument):
The parameters in the file will be overwritten by any arguments specified
on the command line.
"""
+
def _register_argument_action(self):
self._session.register(
'calling-command.*', self.add_to_call_parameters
)
- super(CliInputArgument, self)._register_argument_action()
+ super()._register_argument_action()
def add_to_call_parameters(self, call_parameters, parsed_args, **kwargs):
arg_value = self._get_arg_value(parsed_args)
@@ -65,7 +66,7 @@ def add_to_call_parameters(self, call_parameters, parsed_args, **kwargs):
raise ParamError(
self.cli_name,
"Invalid type: expecting map, "
- "received %s" % type(loaded_params)
+ f"received {type(loaded_params)}",
)
self._update_call_parameters(call_parameters, loaded_params)
@@ -75,7 +76,8 @@ def _get_arg_value(self, parsed_args):
return
cli_input_args = [
- k for k, v in vars(parsed_args).items()
+ k
+ for k, v in vars(parsed_args).items()
if v is not None and k.startswith('cli_input')
]
if len(cli_input_args) != 1:
@@ -109,6 +111,7 @@ class CliInputJSONArgument(CliInputArgument):
generated by ``--generate-cli-skeleton``. The items in the JSON string
will not clobber other arguments entered into the command line.
"""
+
ARG_DATA = {
'name': 'cli-input-json',
'group_name': 'cli_input',
@@ -120,7 +123,7 @@ class CliInputJSONArgument(CliInputArgument):
'pass arbitrary binary values using a JSON-provided value as the '
'string will be taken literally. This may not be specified along '
'with ``--cli-input-yaml``.'
- )
+ ),
}
def _load_parameters(self, arg_value):
@@ -141,7 +144,7 @@ class CliInputYAMLArgument(CliInputArgument):
'If other arguments are provided on the command line, those '
'values will override the YAML-provided values. This may not be '
'specified along with ``--cli-input-json``.'
- )
+ ),
}
def _load_parameters(self, arg_value):
diff --git a/awscli/customizations/cloudfront.py b/awscli/customizations/cloudfront.py
index 6c02bf260dbe..0b0b78cd5fcb 100644
--- a/awscli/customizations/cloudfront.py
+++ b/awscli/customizations/cloudfront.py
@@ -11,18 +11,17 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import hashlib
+import random
import sys
import time
-import random
from awscrt.crypto import RSA, RSASignatureAlgorithm
-
-from botocore.utils import parse_to_aware_datetime
from botocore.signers import CloudFrontSigner
+from botocore.utils import parse_to_aware_datetime
from awscli.arguments import CustomArgument
-from awscli.customizations.utils import validate_mutually_exclusive_handler
from awscli.customizations.commands import BasicCommand
+from awscli.customizations.utils import validate_mutually_exclusive_handler
def register(event_handler):
@@ -30,41 +29,56 @@ def register(event_handler):
# Provides a simpler --paths for ``aws cloudfront create-invalidation``
event_handler.register(
- 'building-argument-table.cloudfront.create-invalidation', _add_paths)
+ 'building-argument-table.cloudfront.create-invalidation', _add_paths
+ )
event_handler.register(
'operation-args-parsed.cloudfront.create-invalidation',
- validate_mutually_exclusive_handler(['invalidation_batch'], ['paths']))
+ validate_mutually_exclusive_handler(['invalidation_batch'], ['paths']),
+ )
event_handler.register(
'operation-args-parsed.cloudfront.create-distribution',
validate_mutually_exclusive_handler(
['default_root_object', 'origin_domain_name'],
- ['distribution_config']))
+ ['distribution_config'],
+ ),
+ )
event_handler.register(
'building-argument-table.cloudfront.create-distribution',
lambda argument_table, **kwargs: argument_table.__setitem__(
- 'origin-domain-name', OriginDomainName(argument_table)))
+ 'origin-domain-name', OriginDomainName(argument_table)
+ ),
+ )
event_handler.register(
'building-argument-table.cloudfront.create-distribution',
lambda argument_table, **kwargs: argument_table.__setitem__(
- 'default-root-object', CreateDefaultRootObject(argument_table)))
+ 'default-root-object', CreateDefaultRootObject(argument_table)
+ ),
+ )
context = {}
event_handler.register(
- 'top-level-args-parsed', context.update, unique_id='cloudfront')
+ 'top-level-args-parsed', context.update, unique_id='cloudfront'
+ )
event_handler.register(
'operation-args-parsed.cloudfront.update-distribution',
validate_mutually_exclusive_handler(
- ['default_root_object'], ['distribution_config']))
+ ['default_root_object'], ['distribution_config']
+ ),
+ )
event_handler.register(
'building-argument-table.cloudfront.update-distribution',
lambda argument_table, **kwargs: argument_table.__setitem__(
- 'default-root-object', UpdateDefaultRootObject(
- context=context, argument_table=argument_table)))
+ 'default-root-object',
+ UpdateDefaultRootObject(
+ context=context, argument_table=argument_table
+ ),
+ ),
+ )
def unique_string(prefix='cli'):
- return '%s-%s-%s' % (prefix, int(time.time()), random.randint(1, 1000000))
+ return f'{prefix}-{int(time.time())}-{random.randint(1, 1000000)}'
def _add_paths(argument_table, **kwargs):
@@ -73,30 +87,35 @@ def _add_paths(argument_table, **kwargs):
class PathsArgument(CustomArgument):
-
def __init__(self):
doc = (
'The space-separated paths to be invalidated.'
' Note: --invalidation-batch and --paths are mutually exclusive.'
)
- super(PathsArgument, self).__init__('paths', nargs='+', help_text=doc)
+ super().__init__('paths', nargs='+', help_text=doc)
def add_to_params(self, parameters, value):
if value is not None:
parameters['InvalidationBatch'] = {
"CallerReference": unique_string(),
"Paths": {"Quantity": len(value), "Items": value},
- }
+ }
class ExclusiveArgument(CustomArgument):
DOC = '%s This argument and --%s are mutually exclusive.'
- def __init__(self, name, argument_table,
- exclusive_to='distribution-config', help_text=''):
+ def __init__(
+ self,
+ name,
+ argument_table,
+ exclusive_to='distribution-config',
+ help_text='',
+ ):
argument_table[exclusive_to].required = False
- super(ExclusiveArgument, self).__init__(
- name, help_text=self.DOC % (help_text, exclusive_to))
+ super().__init__(
+ name, help_text=self.DOC % (help_text, exclusive_to)
+ )
def distribution_config_template(self):
return {
@@ -108,12 +127,9 @@ def distribution_config_template(self):
"QueryString": False,
"Cookies": {"Forward": "none"},
},
- "TrustedSigners": {
- "Enabled": False,
- "Quantity": 0
- },
+ "TrustedSigners": {"Enabled": False, "Quantity": 0},
"ViewerProtocolPolicy": "allow-all",
- "MinTTL": 0
+ "MinTTL": 0,
},
"Enabled": True,
"Comment": "",
@@ -122,15 +138,18 @@ def distribution_config_template(self):
class OriginDomainName(ExclusiveArgument):
def __init__(self, argument_table):
- super(OriginDomainName, self).__init__(
- 'origin-domain-name', argument_table,
- help_text='The domain name for your origin.')
+ super().__init__(
+ 'origin-domain-name',
+ argument_table,
+ help_text='The domain name for your origin.',
+ )
def add_to_params(self, parameters, value):
if value is None:
return
parameters.setdefault(
- 'DistributionConfig', self.distribution_config_template())
+ 'DistributionConfig', self.distribution_config_template()
+ )
origin_id = unique_string(prefix=value)
item = {"Id": origin_id, "DomainName": value, "OriginPath": ''}
if item['DomainName'].endswith('.s3.amazonaws.com'):
@@ -140,36 +159,50 @@ def add_to_params(self, parameters, value):
item["S3OriginConfig"] = {"OriginAccessIdentity": ""}
else:
item["CustomOriginConfig"] = {
- 'HTTPPort': 80, 'HTTPSPort': 443,
- 'OriginProtocolPolicy': 'http-only'}
+ 'HTTPPort': 80,
+ 'HTTPSPort': 443,
+ 'OriginProtocolPolicy': 'http-only',
+ }
parameters['DistributionConfig']['Origins'] = {
- "Quantity": 1, "Items": [item]}
+ "Quantity": 1,
+ "Items": [item],
+ }
parameters['DistributionConfig']['DefaultCacheBehavior'][
- 'TargetOriginId'] = origin_id
+ 'TargetOriginId'
+ ] = origin_id
class CreateDefaultRootObject(ExclusiveArgument):
def __init__(self, argument_table, help_text=''):
- super(CreateDefaultRootObject, self).__init__(
- 'default-root-object', argument_table, help_text=help_text or (
+ super().__init__(
+ 'default-root-object',
+ argument_table,
+ help_text=help_text
+ or (
'The object that you want CloudFront to return (for example, '
- 'index.html) when a viewer request points to your root URL.'))
+ 'index.html) when a viewer request points to your root URL.'
+ ),
+ )
def add_to_params(self, parameters, value):
if value is not None:
parameters.setdefault(
- 'DistributionConfig', self.distribution_config_template())
+ 'DistributionConfig', self.distribution_config_template()
+ )
parameters['DistributionConfig']['DefaultRootObject'] = value
class UpdateDefaultRootObject(CreateDefaultRootObject):
def __init__(self, context, argument_table):
- super(UpdateDefaultRootObject, self).__init__(
- argument_table, help_text=(
+ super().__init__(
+ argument_table,
+ help_text=(
'The object that you want CloudFront to return (for example, '
'index.html) when a viewer request points to your root URL. '
'CLI will automatically make a get-distribution-config call '
- 'to load and preserve your other settings.'))
+ 'to load and preserve your other settings.'
+ ),
+ )
self.context = context
def add_to_params(self, parameters, value):
@@ -178,7 +211,8 @@ def add_to_params(self, parameters, value):
'cloudfront',
region_name=self.context['parsed_args'].region,
endpoint_url=self.context['parsed_args'].endpoint_url,
- verify=self.context['parsed_args'].verify_ssl)
+ verify=self.context['parsed_args'].verify_ssl,
+ )
response = client.get_distribution_config(Id=parameters['Id'])
parameters['IfMatch'] = response['ETag']
parameters['DistributionConfig'] = response['DistributionConfig']
@@ -210,7 +244,8 @@ class SignCommand(BasicCommand):
'required': True,
'help_text': (
"The active CloudFront key pair Id for the key pair "
- "that you're using to generate the signature."),
+ "that you're using to generate the signature."
+ ),
},
{
'name': 'private-key',
@@ -218,49 +253,58 @@ class SignCommand(BasicCommand):
'help_text': 'file://path/to/your/private-key.pem',
},
{
- 'name': 'date-less-than', 'required': True,
- 'help_text':
- 'The expiration date and time for the URL. ' + DATE_FORMAT,
+ 'name': 'date-less-than',
+ 'required': True,
+ 'help_text': 'The expiration date and time for the URL. '
+ + DATE_FORMAT,
},
{
'name': 'date-greater-than',
- 'help_text':
- 'An optional start date and time for the URL. ' + DATE_FORMAT,
+ 'help_text': 'An optional start date and time for the URL. '
+ + DATE_FORMAT,
},
{
'name': 'ip-address',
'help_text': (
'An optional IP address or IP address range to allow client '
- 'making the GET request from. Format: x.x.x.x/x or x.x.x.x'),
+ 'making the GET request from. Format: x.x.x.x/x or x.x.x.x'
+ ),
},
]
def _run_main(self, args, parsed_globals):
signer = CloudFrontSigner(
- args.key_pair_id, RSASigner(args.private_key).sign)
+ args.key_pair_id, RSASigner(args.private_key).sign
+ )
date_less_than = parse_to_aware_datetime(args.date_less_than)
date_greater_than = args.date_greater_than
if date_greater_than is not None:
date_greater_than = parse_to_aware_datetime(date_greater_than)
if date_greater_than is not None or args.ip_address is not None:
policy = signer.build_policy(
- args.url, date_less_than, date_greater_than=date_greater_than,
- ip_address=args.ip_address)
- sys.stdout.write(signer.generate_presigned_url(
- args.url, policy=policy))
+ args.url,
+ date_less_than,
+ date_greater_than=date_greater_than,
+ ip_address=args.ip_address,
+ )
+ sys.stdout.write(
+ signer.generate_presigned_url(args.url, policy=policy)
+ )
else:
- sys.stdout.write(signer.generate_presigned_url(
- args.url, date_less_than=date_less_than))
+ sys.stdout.write(
+ signer.generate_presigned_url(
+ args.url, date_less_than=date_less_than
+ )
+ )
return 0
-class RSASigner(object):
+class RSASigner:
def __init__(self, private_key):
key_bytes = private_key.encode('utf8')
self.priv_key = RSA.new_private_key_from_pem_data(key_bytes)
def sign(self, message):
return self.priv_key.sign(
- RSASignatureAlgorithm.PKCS1_5_SHA1,
- hashlib.sha1(message).digest()
+ RSASignatureAlgorithm.PKCS1_5_SHA1, hashlib.sha1(message).digest()
)
diff --git a/awscli/customizations/cloudsearch.py b/awscli/customizations/cloudsearch.py
index 8ea8f0a5f265..45a10a0149e8 100644
--- a/awscli/customizations/cloudsearch.py
+++ b/awscli/customizations/cloudsearch.py
@@ -13,17 +13,18 @@
import logging
-from awscli.customizations.flatten import FlattenArguments, SEP
-from awscli.customizations.exceptions import ParamValidationError
from botocore.compat import OrderedDict
+from awscli.customizations.exceptions import ParamValidationError
+from awscli.customizations.flatten import SEP, FlattenArguments
+
LOG = logging.getLogger(__name__)
DEFAULT_VALUE_TYPE_MAP = {
'Int': int,
'Double': float,
'IntArray': int,
- 'DoubleArray': float
+ 'DoubleArray': float,
}
@@ -71,13 +72,16 @@ def index_hydrate(params, container, cli_type, key, value):
"define-expression": {
"expression": {
"keep": False,
- "flatten": OrderedDict([
- # Order is crucial here! We're
- # flattening ExpressionValue to be "expression",
- # but this is the name ("expression") of the our parent
- # key, the top level nested param.
- ("ExpressionName", {"name": "name"}),
- ("ExpressionValue", {"name": "expression"}),]),
+ "flatten": OrderedDict(
+ [
+ # Order is crucial here! We're
+ # flattening ExpressionValue to be "expression",
+ # but this is the name ("expression") of the our parent
+ # key, the top level nested param.
+ ("ExpressionName", {"name": "name"}),
+ ("ExpressionValue", {"name": "expression"}),
+ ]
+ ),
}
},
"define-index-field": {
@@ -85,30 +89,57 @@ def index_hydrate(params, container, cli_type, key, value):
"keep": False,
# We use an ordered dict because `type` needs to be parsed before
# any of the Options values.
- "flatten": OrderedDict([
- ("IndexFieldName", {"name": "name"}),
- ("IndexFieldType", {"name": "type"}),
- ("IntOptions.DefaultValue", {"name": "default-value",
- "type": "string",
- "hydrate": index_hydrate}),
- ("IntOptions.FacetEnabled", {"name": "facet-enabled",
- "hydrate": index_hydrate }),
- ("IntOptions.SearchEnabled", {"name": "search-enabled",
- "hydrate": index_hydrate}),
- ("IntOptions.ReturnEnabled", {"name": "return-enabled",
- "hydrate": index_hydrate}),
- ("IntOptions.SortEnabled", {"name": "sort-enabled",
- "hydrate": index_hydrate}),
- ("IntOptions.SourceField", {"name": "source-field",
- "type": "string",
- "hydrate": index_hydrate }),
- ("TextOptions.HighlightEnabled", {"name": "highlight-enabled",
- "hydrate": index_hydrate}),
- ("TextOptions.AnalysisScheme", {"name": "analysis-scheme",
- "hydrate": index_hydrate})
- ])
+ "flatten": OrderedDict(
+ [
+ ("IndexFieldName", {"name": "name"}),
+ ("IndexFieldType", {"name": "type"}),
+ (
+ "IntOptions.DefaultValue",
+ {
+ "name": "default-value",
+ "type": "string",
+ "hydrate": index_hydrate,
+ },
+ ),
+ (
+ "IntOptions.FacetEnabled",
+ {"name": "facet-enabled", "hydrate": index_hydrate},
+ ),
+ (
+ "IntOptions.SearchEnabled",
+ {"name": "search-enabled", "hydrate": index_hydrate},
+ ),
+ (
+ "IntOptions.ReturnEnabled",
+ {"name": "return-enabled", "hydrate": index_hydrate},
+ ),
+ (
+ "IntOptions.SortEnabled",
+ {"name": "sort-enabled", "hydrate": index_hydrate},
+ ),
+ (
+ "IntOptions.SourceField",
+ {
+ "name": "source-field",
+ "type": "string",
+ "hydrate": index_hydrate,
+ },
+ ),
+ (
+ "TextOptions.HighlightEnabled",
+ {
+ "name": "highlight-enabled",
+ "hydrate": index_hydrate,
+ },
+ ),
+ (
+ "TextOptions.AnalysisScheme",
+ {"name": "analysis-scheme", "hydrate": index_hydrate},
+ ),
+ ]
+ ),
}
- }
+ },
}
diff --git a/awscli/customizations/cloudsearchdomain.py b/awscli/customizations/cloudsearchdomain.py
index 9a6b16610a6e..27ac41d1457c 100644
--- a/awscli/customizations/cloudsearchdomain.py
+++ b/awscli/customizations/cloudsearchdomain.py
@@ -17,11 +17,14 @@
* Add validation that --endpoint-url is required.
"""
+
from awscli.customizations.exceptions import ParamValidationError
+
def register_cloudsearchdomain(cli):
- cli.register_last('calling-command.cloudsearchdomain',
- validate_endpoint_url)
+ cli.register_last(
+ 'calling-command.cloudsearchdomain', validate_endpoint_url
+ )
def validate_endpoint_url(parsed_globals, **kwargs):
diff --git a/awscli/customizations/codecommit.py b/awscli/customizations/codecommit.py
index 6b30e834f67f..8ddd4d404c15 100644
--- a/awscli/customizations/codecommit.py
+++ b/awscli/customizations/codecommit.py
@@ -11,18 +11,19 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
+import datetime
+import fileinput
+import logging
import os
import re
import sys
-import logging
-import fileinput
-import datetime
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
from botocore.compat import urlsplit
-from awscli.customizations.commands import BasicCommand
+
from awscli.compat import NonTranslatedStdout
+from awscli.customizations.commands import BasicCommand
logger = logging.getLogger('botocore.credentials')
@@ -43,9 +44,10 @@ def inject_commands(command_table, session, **kwargs):
class CodeCommitNoOpStoreCommand(BasicCommand):
NAME = 'store'
- DESCRIPTION = ('This operation does nothing, credentials'
- ' are calculated each time')
- SYNOPSIS = ('aws codecommit credential-helper store')
+ DESCRIPTION = (
+ 'This operation does nothing, credentials' ' are calculated each time'
+ )
+ SYNOPSIS = 'aws codecommit credential-helper store'
EXAMPLES = ''
_UNDOCUMENTED = True
@@ -55,9 +57,10 @@ def _run_main(self, args, parsed_globals):
class CodeCommitNoOpEraseCommand(BasicCommand):
NAME = 'erase'
- DESCRIPTION = ('This operation does nothing, no credentials'
- ' are ever stored')
- SYNOPSIS = ('aws codecommit credential-helper erase')
+ DESCRIPTION = (
+ 'This operation does nothing, no credentials' ' are ever stored'
+ )
+ SYNOPSIS = 'aws codecommit credential-helper erase'
EXAMPLES = ''
_UNDOCUMENTED = True
@@ -67,16 +70,20 @@ def _run_main(self, args, parsed_globals):
class CodeCommitGetCommand(BasicCommand):
NAME = 'get'
- DESCRIPTION = ('get a username SigV4 credential pair'
- ' based on protocol, host and path provided'
- ' from standard in. This is primarily'
- ' called by git to generate credentials to'
- ' authenticate against AWS CodeCommit')
- SYNOPSIS = ('aws codecommit credential-helper get')
- EXAMPLES = (r'echo -e "protocol=https\\n'
- r'path=/v1/repos/myrepo\\n'
- 'host=git-codecommit.us-east-1.amazonaws.com"'
- ' | aws codecommit credential-helper get')
+ DESCRIPTION = (
+ 'get a username SigV4 credential pair'
+ ' based on protocol, host and path provided'
+ ' from standard in. This is primarily'
+ ' called by git to generate credentials to'
+ ' authenticate against AWS CodeCommit'
+ )
+ SYNOPSIS = 'aws codecommit credential-helper get'
+ EXAMPLES = (
+ r'echo -e "protocol=https\\n'
+ r'path=/v1/repos/myrepo\\n'
+ 'host=git-codecommit.us-east-1.amazonaws.com"'
+ ' | aws codecommit credential-helper get'
+ )
ARG_TABLE = [
{
'name': 'ignore-host-check',
@@ -86,18 +93,20 @@ class CodeCommitGetCommand(BasicCommand):
'help_text': (
'Optional. Generate credentials regardless of whether'
' the domain is an Amazon domain.'
- )
- }
- ]
+ ),
+ }
+ ]
def __init__(self, session):
- super(CodeCommitGetCommand, self).__init__(session)
+ super().__init__(session)
def _run_main(self, args, parsed_globals):
git_parameters = self.read_git_parameters()
- if ('amazon.com' in git_parameters['host'] or
- 'amazonaws.com' in git_parameters['host'] or
- args.ignore_host_check):
+ if (
+ 'amazon.com' in git_parameters['host']
+ or 'amazonaws.com' in git_parameters['host']
+ or args.ignore_host_check
+ ):
theUrl = self.extract_url(git_parameters)
region = self.extract_region(git_parameters, parsed_globals)
signature = self.sign_request(region, theUrl)
@@ -111,9 +120,9 @@ def write_git_parameters(self, signature):
# Python will add a \r to the line ending for a text stdout in Windows.
# Git does not like the \r, so switch to binary
with NonTranslatedStdout() as binary_stdout:
- binary_stdout.write('username={0}\n'.format(username))
+ binary_stdout.write(f'username={username}\n')
logger.debug('username\n%s', username)
- binary_stdout.write('password={0}\n'.format(signature))
+ binary_stdout.write(f'password={signature}\n')
# need to explicitly flush the buffer here,
# before we turn the stream back to text for windows
binary_stdout.flush()
@@ -129,14 +138,16 @@ def read_git_parameters(self):
return parsed
def extract_url(self, parameters):
- url = '{0}://{1}/{2}'.format(parameters['protocol'],
- parameters['host'],
- parameters['path'])
+ url = '{}://{}/{}'.format(
+ parameters['protocol'], parameters['host'], parameters['path']
+ )
return url
def extract_region(self, parameters, parsed_globals):
- match = re.match(r'(vpce-.+\.)?git-codecommit(-fips)?\.([^.]+)\.(vpce\.)?amazonaws\.com',
- parameters['host'])
+ match = re.match(
+ r'(vpce-.+\.)?git-codecommit(-fips)?\.([^.]+)\.(vpce\.)?amazonaws\.com',
+ parameters['host'],
+ )
if match is not None:
return match.group(3)
elif parsed_globals.region is not None:
@@ -155,22 +166,19 @@ def sign_request(self, region, url_to_sign):
split = urlsplit(request.url)
# we don't want to include the port number in the signature
hostname = split.netloc.split(':')[0]
- canonical_request = '{0}\n{1}\n\nhost:{2}\n\nhost\n'.format(
- request.method,
- split.path,
- hostname)
+ canonical_request = f'{request.method}\n{split.path}\n\nhost:{hostname}\n\nhost\n'
logger.debug("Calculating signature using v4 auth.")
logger.debug('CanonicalRequest:\n%s', canonical_request)
string_to_sign = signer.string_to_sign(request, canonical_request)
logger.debug('StringToSign:\n%s', string_to_sign)
signature = signer.signature(string_to_sign, request)
logger.debug('Signature:\n%s', signature)
- return '{0}Z{1}'.format(request.context['timestamp'], signature)
+ return '{}Z{}'.format(request.context['timestamp'], signature)
class CodeCommitCommand(BasicCommand):
NAME = 'credential-helper'
- SYNOPSIS = ('aws codecommit credential-helper')
+ SYNOPSIS = 'aws codecommit credential-helper'
EXAMPLES = ''
SUBCOMMANDS = [
@@ -178,14 +186,16 @@ class CodeCommitCommand(BasicCommand):
{'name': 'store', 'command_class': CodeCommitNoOpStoreCommand},
{'name': 'erase', 'command_class': CodeCommitNoOpEraseCommand},
]
- DESCRIPTION = ('Provide a SigV4 compatible user name and'
- ' password for git smart HTTP '
- ' These commands are consumed by git and'
- ' should not used directly. Erase and Store'
- ' are no-ops. Get is operation to generate'
- ' credentials to authenticate AWS CodeCommit.'
- ' Run \"aws codecommit credential-helper help\"'
- ' for details')
+ DESCRIPTION = (
+ 'Provide a SigV4 compatible user name and'
+ ' password for git smart HTTP '
+ ' These commands are consumed by git and'
+ ' should not used directly. Erase and Store'
+ ' are no-ops. Get is operation to generate'
+ ' credentials to authenticate AWS CodeCommit.'
+ ' Run "aws codecommit credential-helper help"'
+ ' for details'
+ )
def _run_main(self, args, parsed_globals):
self._raise_usage_error()
diff --git a/awscli/customizations/commands.py b/awscli/customizations/commands.py
index 55722888704e..58db27a05be5 100644
--- a/awscli/customizations/commands.py
+++ b/awscli/customizations/commands.py
@@ -1,8 +1,7 @@
-import logging
import copy
+import logging
import os
-from botocore import model
from botocore.compat import OrderedDict
from botocore.validate import validate_parameters
@@ -10,20 +9,19 @@
from awscli.argparser import ArgTableArgParser, SubCommandArgParser
from awscli.argprocess import unpack_argument, unpack_cli_arg
from awscli.arguments import CustomArgument, create_argument_model_from_schema
+from awscli.bcdoc import docevents
from awscli.clidocs import OperationDocumentEventHandler
from awscli.commands import CLICommand
-from awscli.bcdoc import docevents
+from awscli.customizations.exceptions import ParamValidationError
from awscli.help import HelpCommand
from awscli.schema import SchemaTransformer
from awscli.utils import add_command_lineage_to_user_agent_extra
-from awscli.customizations.exceptions import ParamValidationError
LOG = logging.getLogger(__name__)
_open = open
-class _FromFile(object):
-
+class _FromFile:
def __init__(self, *paths, **kwargs):
"""
``**kwargs`` can contain a ``root_module`` argument
@@ -43,7 +41,6 @@ def __init__(self, *paths, **kwargs):
class BasicCommand(CLICommand):
-
"""Basic top level command with no subcommands.
If you want to create a new command, subclass this and
@@ -140,17 +137,23 @@ 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)
- self._session.emit(event, argument_table=self._arg_table, args=args,
- session=self._session)
+ event = 'before-building-argument-table-parser.{}'.format(".".join(
+ self.lineage_names
+ ))
+ self._session.emit(
+ event,
+ argument_table=self._arg_table,
+ args=args,
+ session=self._session,
+ )
maybe_parsed_subcommand = self._parse_potential_subcommand(
args, self._subcommand_table
)
if maybe_parsed_subcommand is not None:
new_args, subcommand_name = maybe_parsed_subcommand
return self._subcommand_table[subcommand_name](
- new_args, parsed_globals)
+ new_args, parsed_globals
+ )
parser = ArgTableArgParser(self.arg_table, self.subcommand_table)
parsed_args, remaining = parser.parse_known_args(args)
@@ -166,20 +169,18 @@ def __call__(self, args, parsed_globals):
cli_argument = self.arg_table[xformed]
value = unpack_argument(
- self._session,
- 'custom',
- self.name,
- cli_argument,
- value
+ self._session, 'custom', self.name, cli_argument, value
)
# If this parameter has a schema defined, then allow plugins
# 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),
- cli_argument=cli_argument, value=value, operation=None)
+ override = self._session.emit_first_non_none_response(
+ 'process-cli-arg.{}.{}'.format('custom', self.name),
+ cli_argument=cli_argument,
+ value=value,
+ operation=None,
+ )
if override is not None:
# A plugin supplied a conversion
@@ -189,7 +190,8 @@ def __call__(self, args, parsed_globals):
# correct Python type (dict, list, etc)
value = unpack_cli_arg(cli_argument, value)
self._validate_value_against_schema(
- cli_argument.argument_model, value)
+ cli_argument.argument_model, value
+ )
setattr(parsed_args, key, value)
if hasattr(self._session, 'user_agent_extra'):
@@ -201,7 +203,7 @@ def __call__(self, args, parsed_globals):
# function for this top level command.
if remaining:
raise ParamValidationError(
- "Unknown options: %s" % ','.join(remaining)
+ "Unknown options: {}".format(','.join(remaining))
)
rc = self._run_main(parsed_args, parsed_globals)
if rc is None:
@@ -213,8 +215,7 @@ def _validate_value_against_schema(self, model, value):
validate_parameters(value, model)
def _should_allow_plugins_override(self, param, value):
- if (param and param.argument_model is not None and
- value is not None):
+ if param and param.argument_model is not None and value is not None:
return True
return False
@@ -236,10 +237,12 @@ def _build_subcommand_table(self):
subcommand_class = subcommand['command_class']
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,
- command_table=subcommand_table,
- session=self._session,
- command_object=self)
+ self._session.emit(
+ f'building-command-table.{name}',
+ command_table=subcommand_table,
+ session=self._session,
+ command_object=self,
+ )
self._add_lineage(subcommand_table)
return subcommand_table
@@ -251,8 +254,12 @@ def create_help_command(self):
command_help_table = {}
if self.SUBCOMMANDS:
command_help_table = self.create_help_command_table()
- return BasicHelp(self._session, self, command_table=command_help_table,
- arg_table=self.arg_table)
+ return BasicHelp(
+ self._session,
+ self,
+ command_table=command_help_table,
+ arg_table=self.arg_table,
+ )
def create_help_command_table(self):
"""
@@ -268,15 +275,16 @@ def create_help_command_table(self):
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)
+ self._session.emit(
+ 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
# so that it can be validated and docs can be generated.
if 'schema' in arg_data:
argument_model = create_argument_model_from_schema(
- arg_data.pop('schema'))
+ arg_data.pop('schema')
+ )
arg_data['argument_model'] = argument_model
custom_argument = CustomArgument(**arg_data)
@@ -319,21 +327,29 @@ def lineage(self, value):
def _raise_usage_error(self):
lineage = ' '.join([c.name for c in self.lineage])
error_msg = (
- "usage: aws [options] %s "
+ f"usage: aws [options] {lineage} "
"[parameters]\naws: error: too few arguments"
- ) % lineage
+ )
raise ParamValidationError(error_msg)
def _add_customization_to_user_agent(self):
- add_command_lineage_to_user_agent_extra(self._session, self.lineage_names)
+ add_command_lineage_to_user_agent_extra(
+ self._session, self.lineage_names
+ )
class BasicHelp(HelpCommand):
-
- def __init__(self, session, command_object, command_table, arg_table,
- event_handler_class=None):
- super(BasicHelp, self).__init__(session, command_object,
- command_table, arg_table)
+ def __init__(
+ self,
+ session,
+ command_object,
+ command_table,
+ arg_table,
+ event_handler_class=None,
+ ):
+ 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:
@@ -376,7 +392,9 @@ def _get_doc_contents(self, attr_name):
root_module = value.root_module
doc_path = os.path.join(
os.path.abspath(os.path.dirname(root_module.__file__)),
- 'examples', trailing_path)
+ 'examples',
+ trailing_path,
+ )
with _open(doc_path) as f:
return f.read()
else:
@@ -394,9 +412,8 @@ 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):
@@ -406,8 +423,9 @@ 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()
@@ -424,18 +442,18 @@ def doc_synopsis_option(self, arg_name, help_command, **kwargs):
# This arg is already documented so we can move on.
return
option_str = ' | '.join(
- [a.cli_name for a in
- self._arg_groups[argument.group_name]])
+ [a.cli_name for a in self._arg_groups[argument.group_name]]
+ )
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 [...]" % argument.cli_name
+ option_str = f"{argument.cli_name} [...]"
else:
- option_str = '%s ' % argument.cli_name
+ option_str = f'{argument.cli_name} '
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
@@ -444,8 +462,9 @@ 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()
diff --git a/awscli/customizations/devcommands.py b/awscli/customizations/devcommands.py
index 029c1d852745..c547355ae299 100644
--- a/awscli/customizations/devcommands.py
+++ b/awscli/customizations/devcommands.py
@@ -14,8 +14,9 @@
def register_dev_commands(event_handlers):
- event_handlers.register('building-command-table.main',
- CLIDevCommand.add_command)
+ event_handlers.register(
+ 'building-command-table.main', CLIDevCommand.add_command
+ )
# This is adding a top level placeholder command to add dev commands.
diff --git a/awscli/customizations/dsql.py b/awscli/customizations/dsql.py
index e1817f78f9eb..0271717bc714 100644
--- a/awscli/customizations/dsql.py
+++ b/awscli/customizations/dsql.py
@@ -15,8 +15,13 @@
def register_dsql_customizations(cli):
- cli.register('building-command-table.dsql', _add_generate_dsql_db_connect_auth_token)
- cli.register('building-command-table.dsql', _add_generate_dsql_db_connect_admin_auth_token)
+ cli.register(
+ 'building-command-table.dsql', _add_generate_dsql_db_connect_auth_token
+ )
+ cli.register(
+ 'building-command-table.dsql',
+ _add_generate_dsql_db_connect_admin_auth_token,
+ )
def _add_generate_dsql_db_connect_auth_token(command_table, session, **kwargs):
@@ -24,33 +29,41 @@ def _add_generate_dsql_db_connect_auth_token(command_table, session, **kwargs):
command_table['generate-db-connect-auth-token'] = command
-def _add_generate_dsql_db_connect_admin_auth_token(command_table, session, **kwargs):
+def _add_generate_dsql_db_connect_admin_auth_token(
+ command_table, session, **kwargs
+):
command = GenerateDBConnectAdminAuthTokenCommand(session)
command_table['generate-db-connect-admin-auth-token'] = command
class GenerateDBConnectAuthTokenCommand(BasicCommand):
NAME = 'generate-db-connect-auth-token'
- DESCRIPTION = (
- 'Generates an authorization token used to connect to a DSQL database with IAM credentials.'
- )
+ DESCRIPTION = 'Generates an authorization token used to connect to a DSQL database with IAM credentials.'
ARG_TABLE = [
- {'name': 'hostname', 'required': True,
- 'help_text': 'Cluster endpoint e.g. http://test.example.com'},
- {'name': 'expires-in', 'cli_type_name': 'integer', 'default': 900, 'required': False,
- 'help_text': 'Token expiry duration in seconds e.g. 3600. Default is 900 seconds.'},
+ {
+ 'name': 'hostname',
+ 'required': True,
+ 'help_text': 'Cluster endpoint e.g. http://test.example.com',
+ },
+ {
+ 'name': 'expires-in',
+ 'cli_type_name': 'integer',
+ 'default': 900,
+ 'required': False,
+ 'help_text': 'Token expiry duration in seconds e.g. 3600. Default is 900 seconds.',
+ },
]
def _run_main(self, parsed_args, parsed_globals):
dsql = self._session.create_client(
- 'dsql', parsed_globals.region, parsed_globals.endpoint_url,
- parsed_globals.verify_ssl
+ 'dsql',
+ parsed_globals.region,
+ parsed_globals.endpoint_url,
+ parsed_globals.verify_ssl,
)
token = dsql.generate_db_connect_auth_token(
- parsed_args.hostname,
- parsed_globals.region,
- parsed_args.expires_in
+ parsed_args.hostname, parsed_globals.region, parsed_args.expires_in
)
uni_print(token)
uni_print('\n')
@@ -59,26 +72,32 @@ def _run_main(self, parsed_args, parsed_globals):
class GenerateDBConnectAdminAuthTokenCommand(BasicCommand):
NAME = 'generate-db-connect-admin-auth-token'
- DESCRIPTION = (
- 'Generates an Admin authorization token used to connect to a DSQL database with IAM credentials.'
- )
+ DESCRIPTION = 'Generates an Admin authorization token used to connect to a DSQL database with IAM credentials.'
ARG_TABLE = [
- {'name': 'hostname', 'required': True,
- 'help_text': 'Cluster endpoint e.g. http://test.example.com'},
- {'name': 'expires-in', 'cli_type_name': 'integer', 'default': 900, 'required': False,
- 'help_text': 'Token expiry duration in seconds e.g. 3600. Default is 900 seconds.'},
+ {
+ 'name': 'hostname',
+ 'required': True,
+ 'help_text': 'Cluster endpoint e.g. http://test.example.com',
+ },
+ {
+ 'name': 'expires-in',
+ 'cli_type_name': 'integer',
+ 'default': 900,
+ 'required': False,
+ 'help_text': 'Token expiry duration in seconds e.g. 3600. Default is 900 seconds.',
+ },
]
def _run_main(self, parsed_args, parsed_globals):
dsql = self._session.create_client(
- 'dsql', parsed_globals.region, parsed_globals.endpoint_url,
- parsed_globals.verify_ssl
+ 'dsql',
+ parsed_globals.region,
+ parsed_globals.endpoint_url,
+ parsed_globals.verify_ssl,
)
token = dsql.generate_db_connect_admin_auth_token(
- parsed_args.hostname,
- parsed_globals.region,
- parsed_args.expires_in
+ parsed_args.hostname, parsed_globals.region, parsed_args.expires_in
)
uni_print(token)
uni_print('\n')
diff --git a/awscli/customizations/ecr.py b/awscli/customizations/ecr.py
index 71e7abe19b51..ae141b9ee7ac 100644
--- a/awscli/customizations/ecr.py
+++ b/awscli/customizations/ecr.py
@@ -10,12 +10,12 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
+import sys
+from base64 import b64decode
+
from awscli.customizations.commands import BasicCommand
from awscli.customizations.utils import create_client_from_parsed_globals
-from base64 import b64decode
-import sys
-
def register_ecr_commands(cli):
cli.register('building-command-table.ecr', _inject_commands)
@@ -27,16 +27,17 @@ def _inject_commands(command_table, session, **kwargs):
class ECRGetLoginPassword(BasicCommand):
"""Get a password to be used with container clients such as Docker"""
+
NAME = 'get-login-password'
DESCRIPTION = BasicCommand.FROM_FILE(
- 'ecr/get-login-password_description.rst')
+ 'ecr/get-login-password_description.rst'
+ )
def _run_main(self, parsed_args, parsed_globals):
ecr_client = create_client_from_parsed_globals(
- self._session,
- 'ecr',
- parsed_globals)
+ self._session, 'ecr', parsed_globals
+ )
result = ecr_client.get_authorization_token()
auth = result['authorizationData'][0]
auth_token = b64decode(auth['authorizationToken']).decode()
diff --git a/awscli/customizations/ecr_public.py b/awscli/customizations/ecr_public.py
index 01a5458907a2..c48f81a32b5f 100644
--- a/awscli/customizations/ecr_public.py
+++ b/awscli/customizations/ecr_public.py
@@ -10,12 +10,12 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
+import sys
+from base64 import b64decode
+
from awscli.customizations.commands import BasicCommand
from awscli.customizations.utils import create_client_from_parsed_globals
-from base64 import b64decode
-import sys
-
def register_ecr_public_commands(cli):
cli.register('building-command-table.ecr-public', _inject_commands)
@@ -27,16 +27,17 @@ def _inject_commands(command_table, session, **kwargs):
class ECRPublicGetLoginPassword(BasicCommand):
"""Get a password to be used with container clients such as Docker"""
+
NAME = 'get-login-password'
DESCRIPTION = BasicCommand.FROM_FILE(
- 'ecr-public/get-login-password_description.rst')
+ 'ecr-public/get-login-password_description.rst'
+ )
def _run_main(self, parsed_args, parsed_globals):
ecr_public_client = create_client_from_parsed_globals(
- self._session,
- 'ecr-public',
- parsed_globals)
+ self._session, 'ecr-public', parsed_globals
+ )
result = ecr_public_client.get_authorization_token()
auth = result['authorizationData']
auth_token = b64decode(auth['authorizationToken']).decode()
diff --git a/awscli/customizations/flatten.py b/awscli/customizations/flatten.py
index a7b893fa077c..c875a058b630 100644
--- a/awscli/customizations/flatten.py
+++ b/awscli/customizations/flatten.py
@@ -30,15 +30,26 @@ class FlattenedArgument(CustomArgument):
Supports both an object and a list of objects, in which case the flattened
parameters will hydrate a list with a single object in it.
"""
- def __init__(self, name, container, prop, help_text='', required=None,
- type=None, hydrate=None, hydrate_value=None):
+
+ def __init__(
+ self,
+ name,
+ container,
+ prop,
+ help_text='',
+ required=None,
+ type=None,
+ hydrate=None,
+ hydrate_value=None,
+ ):
self.type = type
self._container = container
self._property = prop
self._hydrate = hydrate
self._hydrate_value = hydrate_value
- super(FlattenedArgument, self).__init__(name=name, help_text=help_text,
- required=required)
+ super().__init__(
+ name=name, help_text=help_text, required=required
+ )
@property
def cli_type_name(self):
@@ -56,7 +67,7 @@ def add_to_params(self, parameters, value):
cli_type = self._container.cli_type_name
key = self._property
- LOG.debug('Hydrating {0}[{1}]'.format(container, key))
+ LOG.debug(f'Hydrating {container}[{key}]')
if value is not None:
# Convert type if possible
@@ -85,7 +96,7 @@ def add_to_params(self, parameters, value):
parameters[container][key] = value
-class FlattenArguments(object):
+class FlattenArguments:
"""
Flatten arguments for one or more commands for a particular service from
a given configuration which maps service call parameters to flattened
@@ -151,6 +162,7 @@ def my_hydrate(params, container, cli_type, key, value):
ensure that a list of one or more objects is hydrated rather than a
single object.
"""
+
def __init__(self, service_name, configs):
self.configs = configs
self.service_name = service_name
@@ -163,9 +175,10 @@ def register(self, cli):
# Flatten each configured operation when they are built
service = self.service_name
for operation in self.configs:
- cli.register('building-argument-table.{0}.{1}'.format(service,
- operation),
- self.flatten_args)
+ cli.register(
+ f'building-argument-table.{service}.{operation}',
+ self.flatten_args,
+ )
def flatten_args(self, command, argument_table, **kwargs):
# For each argument with a bag of parameters
@@ -173,10 +186,15 @@ def flatten_args(self, command, argument_table, **kwargs):
argument_from_table = argument_table[name]
overwritten = False
- LOG.debug('Flattening {0} argument {1} into {2}'.format(
- command.name, name,
- ', '.join([v['name'] for k, v in argument['flatten'].items()])
- ))
+ LOG.debug(
+ 'Flattening {} argument {} into {}'.format(
+ command.name,
+ name,
+ ', '.join(
+ [v['name'] for k, v in argument['flatten'].items()]
+ ),
+ )
+ )
# For each parameter to flatten out
for sub_argument, new_config in argument['flatten'].items():
@@ -200,8 +218,9 @@ def flatten_args(self, command, argument_table, **kwargs):
overwritten = True
# Delete the original argument?
- if not overwritten and ('keep' not in argument or
- not argument['keep']):
+ if not overwritten and (
+ 'keep' not in argument or not argument['keep']
+ ):
del argument_table[name]
def _find_nested_arg(self, argument, name):
@@ -212,7 +231,7 @@ def _find_nested_arg(self, argument, name):
"""
if SEP in name:
# Find the actual nested argument to pull out
- LOG.debug('Finding nested argument in {0}'.format(name))
+ LOG.debug(f'Finding nested argument in {name}')
for piece in name.split(SEP)[:-1]:
for member_name, member in argument.members.items():
if member_name == piece:
@@ -220,7 +239,7 @@ def _find_nested_arg(self, argument, name):
break
else:
raise ParamValidationError(
- 'Invalid piece {0}'.format(piece)
+ f'Invalid piece {piece}'
)
return argument
@@ -239,7 +258,9 @@ def _merge_member_config(self, argument, name, config):
config['help_text'] = member.documentation
if 'required' not in config:
- config['required'] = member_name in argument.required_members
+ config['required'] = (
+ member_name in argument.required_members
+ )
if 'type' not in config:
config['type'] = member.type_name
diff --git a/awscli/customizations/generatecliskeleton.py b/awscli/customizations/generatecliskeleton.py
index 3f0f12dd6588..941ed3bca3f9 100644
--- a/awscli/customizations/generatecliskeleton.py
+++ b/awscli/customizations/generatecliskeleton.py
@@ -33,7 +33,8 @@ def add_generate_skeleton(session, operation_model, argument_table, **kwargs):
# is designated by the argument name `outfile`.
if 'outfile' not in argument_table:
generate_cli_skeleton_argument = GenerateCliSkeletonArgument(
- session, operation_model)
+ session, operation_model
+ )
generate_cli_skeleton_argument.add_to_arg_table(argument_table)
@@ -44,6 +45,7 @@ class GenerateCliSkeletonArgument(OverrideRequiredArgsArgument):
command from taking place. Instead, it will generate a JSON skeleton and
print it to standard output.
"""
+
ARG_DATA = {
'name': 'generate-cli-skeleton',
'help_text': (
@@ -65,12 +67,12 @@ class GenerateCliSkeletonArgument(OverrideRequiredArgsArgument):
}
def __init__(self, session, operation_model):
- super(GenerateCliSkeletonArgument, self).__init__(session)
+ super().__init__(session)
self._operation_model = operation_model
def _register_argument_action(self):
self._session.register('calling-command.*', self.generate_skeleton)
- super(GenerateCliSkeletonArgument, self)._register_argument_action()
+ super()._register_argument_action()
def override_required_args(self, argument_table, args, **kwargs):
arg_name = '--' + self.name
@@ -85,18 +87,19 @@ def override_required_args(self, argument_table, args, **kwargs):
return
except IndexError:
pass
- super(GenerateCliSkeletonArgument, self).override_required_args(
- argument_table, args, **kwargs)
+ super().override_required_args(
+ argument_table, args, **kwargs
+ )
- def generate_skeleton(self, call_parameters, parsed_args,
- parsed_globals, **kwargs):
+ def generate_skeleton(
+ self, call_parameters, parsed_args, parsed_globals, **kwargs
+ ):
if not getattr(parsed_args, 'generate_cli_skeleton', None):
return
arg_value = parsed_args.generate_cli_skeleton
return getattr(
- self, '_generate_%s_skeleton' % arg_value.replace('-', '_'))(
- call_parameters=call_parameters, parsed_globals=parsed_globals
- )
+ self, '_generate_{}_skeleton'.format(arg_value.replace('-', '_'))
+ )(call_parameters=call_parameters, parsed_globals=parsed_globals)
def _generate_yaml_input_skeleton(self, **kwargs):
input_shape = self._operation_model.input_shape
@@ -120,13 +123,14 @@ def _generate_input_skeleton(self, **kwargs):
outfile.write('\n')
return 0
- def _generate_output_skeleton(self, call_parameters, parsed_globals,
- **kwargs):
+ def _generate_output_skeleton(
+ self, call_parameters, parsed_globals, **kwargs
+ ):
service_name = self._operation_model.service_model.service_name
operation_name = self._operation_model.name
return StubbedCLIOperationCaller(self._session).invoke(
- service_name, operation_name, call_parameters,
- parsed_globals)
+ service_name, operation_name, call_parameters, parsed_globals
+ )
class StubbedCLIOperationCaller(CLIOperationCaller):
@@ -135,31 +139,36 @@ class StubbedCLIOperationCaller(CLIOperationCaller):
It generates a fake response and uses the response and provided parameters
to make a stubbed client call for an operation command.
"""
- def _make_client_call(self, client, operation_name, parameters,
- parsed_globals):
+
+ def _make_client_call(
+ self, client, operation_name, parameters, parsed_globals
+ ):
method_name = xform_name(operation_name)
operation_model = client.meta.service_model.operation_model(
- operation_name)
+ operation_name
+ )
fake_response = {}
if operation_model.output_shape:
argument_generator = ArgumentGenerator(use_member_names=True)
fake_response = argument_generator.generate_skeleton(
- operation_model.output_shape)
+ operation_model.output_shape
+ )
with Stubber(client) as stubber:
stubber.add_response(method_name, fake_response)
return getattr(client, method_name)(**parameters)
-class _Bytes(object):
+class _Bytes:
@classmethod
def represent(cls, dumper, data):
- return dumper.represent_scalar(u'tag:yaml.org,2002:binary', '')
+ return dumper.represent_scalar('tag:yaml.org,2002:binary', '')
class YAMLArgumentGenerator(ArgumentGenerator):
def __init__(self, use_member_names=False, yaml=None):
- super(YAMLArgumentGenerator, self).__init__(
- use_member_names=use_member_names)
+ super().__init__(
+ use_member_names=use_member_names
+ )
self._yaml = yaml
if self._yaml is None:
self._yaml = YAML()
@@ -171,7 +180,7 @@ def _generate_skeleton(self, shape, stack, name=''):
# serialization output more usable on python 3.
if shape.type_name == 'blob':
return _Bytes()
- return super(YAMLArgumentGenerator, self)._generate_skeleton(
+ return super()._generate_skeleton(
shape, stack, name
)
@@ -181,14 +190,17 @@ def _generate_type_structure(self, shape, stack):
skeleton = self._yaml.map()
for member_name, member_shape in shape.members.items():
skeleton[member_name] = self._generate_skeleton(
- member_shape, stack, name=member_name)
+ member_shape, stack, name=member_name
+ )
is_required = member_name in shape.required_members
self._add_member_comments(
- skeleton, member_name, member_shape, is_required)
+ skeleton, member_name, member_shape, is_required
+ )
return skeleton
- def _add_member_comments(self, skeleton, member_name, member_shape,
- is_required):
+ def _add_member_comments(
+ self, skeleton, member_name, member_shape, is_required
+ ):
comment_components = []
if is_required:
comment_components.append('[REQUIRED]')
@@ -202,12 +214,12 @@ def _add_member_comments(self, skeleton, member_name, member_shape,
skeleton.yaml_add_eol_comment('# ' + comment, member_name)
def _get_enums_comment_content(self, enums):
- return 'Valid values are: %s.' % ', '.join(enums)
+ return 'Valid values are: {}.'.format(', '.join(enums))
def _generate_type_map(self, shape, stack):
# YAML has support for ordered maps, so don't use ordereddicts
# because that isn't necessary and it makes the output harder to
# understand and read.
- return dict(super(YAMLArgumentGenerator, self)._generate_type_map(
- shape, stack
- ))
+ return dict(
+ super()._generate_type_map(shape, stack)
+ )
diff --git a/awscli/customizations/globalargs.py b/awscli/customizations/globalargs.py
index 3a84223f93ce..fcb5ce2d6794 100644
--- a/awscli/customizations/globalargs.py
+++ b/awscli/customizations/globalargs.py
@@ -10,29 +10,38 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
-import sys
import os
+import sys
+import jmespath
from botocore.client import Config
from botocore.endpoint import DEFAULT_TIMEOUT
from botocore.handlers import disable_signing
-import jmespath
from awscli.compat import urlparse
from awscli.customizations.exceptions import ParamValidationError
def register_parse_global_args(cli):
- cli.register('top-level-args-parsed', resolve_types,
- unique_id='resolve-types')
- cli.register('top-level-args-parsed', no_sign_request,
- unique_id='no-sign')
- cli.register('top-level-args-parsed', resolve_verify_ssl,
- unique_id='resolve-verify-ssl')
- cli.register('top-level-args-parsed', resolve_cli_read_timeout,
- unique_id='resolve-cli-read-timeout')
- cli.register('top-level-args-parsed', resolve_cli_connect_timeout,
- unique_id='resolve-cli-connect-timeout')
+ cli.register(
+ 'top-level-args-parsed', resolve_types, unique_id='resolve-types'
+ )
+ cli.register('top-level-args-parsed', no_sign_request, unique_id='no-sign')
+ cli.register(
+ 'top-level-args-parsed',
+ resolve_verify_ssl,
+ unique_id='resolve-verify-ssl',
+ )
+ cli.register(
+ 'top-level-args-parsed',
+ resolve_cli_read_timeout,
+ unique_id='resolve-cli-read-timeout',
+ )
+ cli.register(
+ 'top-level-args-parsed',
+ resolve_cli_connect_timeout,
+ unique_id='resolve-cli-connect-timeout',
+ )
def resolve_types(parsed_args, **kwargs):
@@ -45,7 +54,7 @@ def resolve_types(parsed_args, **kwargs):
def _resolve_arg(parsed_args, name):
value = getattr(parsed_args, name, None)
if value is not None:
- new_value = getattr(sys.modules[__name__], '_resolve_%s' % name)(value)
+ new_value = getattr(sys.modules[__name__], f'_resolve_{name}')(value)
setattr(parsed_args, name, new_value)
@@ -54,7 +63,7 @@ def _resolve_query(value):
return jmespath.compile(value)
except Exception as e:
raise ParamValidationError(
- "Bad value for --query %s: %s" % (value, str(e))
+ f"Bad value for --query {value}: {str(e)}"
)
@@ -64,9 +73,9 @@ def _resolve_endpoint_url(value):
# that contains a scheme, so we'll verify that up front.
if not parsed.scheme:
raise ParamValidationError(
- 'Bad value for --endpoint-url "%s": scheme is '
+ f'Bad value for --endpoint-url "{value}": scheme is '
'missing. Must be of the form '
- 'http:/// or https:///' % value
+ 'http:/// or https:///'
)
return value
@@ -94,7 +103,9 @@ def no_sign_request(parsed_args, session, **kwargs):
# Register this first to override other handlers.
emitter = session.get_component('event_emitter')
emitter.register_first(
- 'choose-signer', disable_signing, unique_id='disable-signing',
+ 'choose-signer',
+ disable_signing,
+ unique_id='disable-signing',
)
diff --git a/awscli/customizations/iamvirtmfa.py b/awscli/customizations/iamvirtmfa.py
index c0ee3582d6b4..9a90b48c3e2d 100644
--- a/awscli/customizations/iamvirtmfa.py
+++ b/awscli/customizations/iamvirtmfa.py
@@ -22,43 +22,53 @@
to the specified file. It will also remove the two bootstrap data
fields from the response.
"""
-import base64
-from awscli.customizations.arguments import StatefulArgument
-from awscli.customizations.arguments import resolve_given_outfile_path
-from awscli.customizations.arguments import is_parsed_result_successful
+import base64
+from awscli.customizations.arguments import (
+ StatefulArgument,
+ is_parsed_result_successful,
+ resolve_given_outfile_path,
+)
CHOICES = ('QRCodePNG', 'Base32StringSeed')
-OUTPUT_HELP = ('The output path and file name where the bootstrap '
- 'information will be stored.')
-BOOTSTRAP_HELP = ('Method to use to seed the virtual MFA. '
- 'Valid values are: %s | %s' % CHOICES)
+OUTPUT_HELP = (
+ 'The output path and file name where the bootstrap '
+ 'information will be stored.'
+)
+BOOTSTRAP_HELP = (
+ 'Method to use to seed the virtual MFA. '
+ 'Valid values are: {} | {}'.format(*CHOICES)
+)
class FileArgument(StatefulArgument):
-
def add_to_params(self, parameters, value):
# Validate the file here so we can raise an error prior
# calling the service.
value = resolve_given_outfile_path(value)
- super(FileArgument, self).add_to_params(parameters, value)
-
+ super().add_to_params(parameters, value)
-class IAMVMFAWrapper(object):
+class IAMVMFAWrapper:
def __init__(self, event_handler):
self._event_handler = event_handler
self._outfile = FileArgument(
- 'outfile', help_text=OUTPUT_HELP, required=True)
+ 'outfile', help_text=OUTPUT_HELP, required=True
+ )
self._method = StatefulArgument(
- 'bootstrap-method', help_text=BOOTSTRAP_HELP,
- choices=CHOICES, required=True)
+ 'bootstrap-method',
+ help_text=BOOTSTRAP_HELP,
+ choices=CHOICES,
+ required=True,
+ )
self._event_handler.register(
'building-argument-table.iam.create-virtual-mfa-device',
- self._add_options)
+ self._add_options,
+ )
self._event_handler.register(
- 'after-call.iam.CreateVirtualMFADevice', self._save_file)
+ 'after-call.iam.CreateVirtualMFADevice', self._save_file
+ )
def _add_options(self, argument_table, **kwargs):
argument_table['outfile'] = self._outfile
diff --git a/awscli/customizations/iot.py b/awscli/customizations/iot.py
index 7703014335b1..f4e4b9770513 100644
--- a/awscli/customizations/iot.py
+++ b/awscli/customizations/iot.py
@@ -22,6 +22,7 @@
- ``--public-key-outfile``: keyPair.PublicKey
- ``--private-key-outfile``: keyPair.PrivateKey
"""
+
from awscli.customizations.arguments import QueryOutFileArgument
@@ -34,19 +35,34 @@ def register_create_keys_and_cert_arguments(session, argument_table, **kwargs):
"""
after_event = 'after-call.iot.CreateKeysAndCertificate'
argument_table['certificate-pem-outfile'] = QueryOutFileArgument(
- session=session, name='certificate-pem-outfile',
- query='certificatePem', after_call_event=after_event, perm=0o600)
+ session=session,
+ name='certificate-pem-outfile',
+ query='certificatePem',
+ after_call_event=after_event,
+ perm=0o600,
+ )
argument_table['public-key-outfile'] = QueryOutFileArgument(
- session=session, name='public-key-outfile', query='keyPair.PublicKey',
- after_call_event=after_event, perm=0o600)
+ session=session,
+ name='public-key-outfile',
+ query='keyPair.PublicKey',
+ after_call_event=after_event,
+ perm=0o600,
+ )
argument_table['private-key-outfile'] = QueryOutFileArgument(
- session=session, name='private-key-outfile',
- query='keyPair.PrivateKey', after_call_event=after_event, perm=0o600)
+ session=session,
+ name='private-key-outfile',
+ query='keyPair.PrivateKey',
+ after_call_event=after_event,
+ perm=0o600,
+ )
def register_create_keys_from_csr_arguments(session, argument_table, **kwargs):
"""Add certificate-pem-outfile to create-certificate-from-csr"""
argument_table['certificate-pem-outfile'] = QueryOutFileArgument(
- session=session, name='certificate-pem-outfile',
+ session=session,
+ name='certificate-pem-outfile',
query='certificatePem',
- after_call_event='after-call.iot.CreateCertificateFromCsr', perm=0o600)
+ after_call_event='after-call.iot.CreateCertificateFromCsr',
+ perm=0o600,
+ )
diff --git a/awscli/customizations/iot_data.py b/awscli/customizations/iot_data.py
index 62c02ee126dd..2b29c94a9579 100644
--- a/awscli/customizations/iot_data.py
+++ b/awscli/customizations/iot_data.py
@@ -14,7 +14,8 @@
def register_custom_endpoint_note(event_emitter):
event_emitter.register_last(
- 'doc-description.iot-data', add_custom_endpoint_url_note)
+ 'doc-description.iot-data', add_custom_endpoint_url_note
+ )
def add_custom_endpoint_url_note(help_command, **kwargs):
diff --git a/awscli/customizations/opsworks.py b/awscli/customizations/opsworks.py
index e91d47896fd9..b777b1c27c76 100644
--- a/awscli/customizations/opsworks.py
+++ b/awscli/customizations/opsworks.py
@@ -24,11 +24,10 @@
from botocore.exceptions import ClientError
-from awscli.compat import urlopen, ensure_text_type
+from awscli.compat import ensure_text_type, urlopen
from awscli.customizations.commands import BasicCommand
-from awscli.customizations.utils import create_client_from_parsed_globals
from awscli.customizations.exceptions import ParamValidationError
-
+from awscli.customizations.utils import create_client_from_parsed_globals
LOG = logging.getLogger(__name__)
@@ -41,8 +40,9 @@
INSTANCE_ID_RE = re.compile(r"^i-[0-9a-f]+$")
IP_ADDRESS_RE = re.compile(r"^\d+\.\d+\.\d+\.\d+$")
-IDENTITY_URL = \
+IDENTITY_URL = (
"http://169.254.169.254/latest/dynamic/instance-identity/document"
+)
REMOTE_SCRIPT = """
set -e
@@ -78,53 +78,87 @@ class OpsWorksRegister(BasicCommand):
""").strip()
ARG_TABLE = [
- {'name': 'stack-id', 'required': True,
- 'help_text': """A stack ID. The instance will be registered with the
- given stack."""},
- {'name': 'infrastructure-class', 'required': True,
- 'choices': ['ec2', 'on-premises'],
- 'help_text': """Specifies whether to register an EC2 instance (`ec2`)
- or an on-premises instance (`on-premises`)."""},
- {'name': 'override-hostname', 'dest': 'hostname',
- 'help_text': """The instance hostname. If not provided, the current
- hostname of the machine will be used."""},
- {'name': 'override-private-ip', 'dest': 'private_ip',
- 'help_text': """An IP address. If you set this parameter, the given IP
+ {
+ 'name': 'stack-id',
+ 'required': True,
+ 'help_text': """A stack ID. The instance will be registered with the
+ given stack.""",
+ },
+ {
+ 'name': 'infrastructure-class',
+ 'required': True,
+ 'choices': ['ec2', 'on-premises'],
+ 'help_text': """Specifies whether to register an EC2 instance (`ec2`)
+ or an on-premises instance (`on-premises`).""",
+ },
+ {
+ 'name': 'override-hostname',
+ 'dest': 'hostname',
+ 'help_text': """The instance hostname. If not provided, the current
+ hostname of the machine will be used.""",
+ },
+ {
+ 'name': 'override-private-ip',
+ 'dest': 'private_ip',
+ 'help_text': """An IP address. If you set this parameter, the given IP
address will be used as the private IP address within
OpsWorks. Otherwise the private IP address will be
determined automatically. Not to be used with EC2
- instances."""},
- {'name': 'override-public-ip', 'dest': 'public_ip',
- 'help_text': """An IP address. If you set this parameter, the given IP
+ instances.""",
+ },
+ {
+ 'name': 'override-public-ip',
+ 'dest': 'public_ip',
+ 'help_text': """An IP address. If you set this parameter, the given IP
address will be used as the public IP address within
OpsWorks. Otherwise the public IP address will be
determined automatically. Not to be used with EC2
- instances."""},
- {'name': 'override-ssh', 'dest': 'ssh',
- 'help_text': """If you set this parameter, the given command will be
- used to connect to the machine."""},
- {'name': 'ssh-username', 'dest': 'username',
- 'help_text': """If provided, this username will be used to connect to
- the host."""},
- {'name': 'ssh-private-key', 'dest': 'private_key',
- 'help_text': """If provided, the given private key file will be used
- to connect to the machine."""},
- {'name': 'local', 'action': 'store_true',
- 'help_text': """If given, instead of a remote machine, the local
+ instances.""",
+ },
+ {
+ 'name': 'override-ssh',
+ 'dest': 'ssh',
+ 'help_text': """If you set this parameter, the given command will be
+ used to connect to the machine.""",
+ },
+ {
+ 'name': 'ssh-username',
+ 'dest': 'username',
+ 'help_text': """If provided, this username will be used to connect to
+ the host.""",
+ },
+ {
+ 'name': 'ssh-private-key',
+ 'dest': 'private_key',
+ 'help_text': """If provided, the given private key file will be used
+ to connect to the machine.""",
+ },
+ {
+ 'name': 'local',
+ 'action': 'store_true',
+ 'help_text': """If given, instead of a remote machine, the local
machine will be imported. Cannot be used together
- with `target`."""},
- {'name': 'use-instance-profile', 'action': 'store_true',
- 'help_text': """Use the instance profile instead of creating an IAM
- user."""},
- {'name': 'target', 'positional_arg': True, 'nargs': '?',
- 'synopsis': '[]',
- 'help_text': """Either the EC2 instance ID or the hostname of the
+ with `target`.""",
+ },
+ {
+ 'name': 'use-instance-profile',
+ 'action': 'store_true',
+ 'help_text': """Use the instance profile instead of creating an IAM
+ user.""",
+ },
+ {
+ 'name': 'target',
+ 'positional_arg': True,
+ 'nargs': '?',
+ 'synopsis': '[]',
+ 'help_text': """Either the EC2 instance ID or the hostname of the
instance or machine to be registered with OpsWorks.
- Cannot be used together with `--local`."""},
+ Cannot be used together with `--local`.""",
+ },
]
def __init__(self, session):
- super(OpsWorksRegister, self).__init__(session)
+ super().__init__(session)
self._stack = None
self._ec2_instance = None
self._prov_params = None
@@ -136,7 +170,8 @@ def __init__(self, session):
def _create_clients(self, args, parsed_globals):
self.iam = self._session.create_client('iam')
self.opsworks = create_client_from_parsed_globals(
- self._session, 'opsworks', parsed_globals)
+ self._session, 'opsworks', parsed_globals
+ )
def _run_main(self, args, parsed_globals):
self._create_clients(args, parsed_globals)
@@ -157,36 +192,45 @@ def prevalidate_arguments(self, args):
raise ParamValidationError("One of target or --local is required.")
elif args.target and args.local:
raise ParamValidationError(
- "Arguments target and --local are mutually exclusive.")
+ "Arguments target and --local are mutually exclusive."
+ )
if args.local and platform.system() != 'Linux':
raise ParamValidationError(
- "Non-Linux instances are not supported by AWS OpsWorks.")
+ "Non-Linux instances are not supported by AWS OpsWorks."
+ )
if args.ssh and (args.username or args.private_key):
raise ParamValidationError(
"Argument --override-ssh cannot be used together with "
- "--ssh-username or --ssh-private-key.")
+ "--ssh-username or --ssh-private-key."
+ )
if args.infrastructure_class == 'ec2':
if args.private_ip:
raise ParamValidationError(
- "--override-private-ip is not supported for EC2.")
+ "--override-private-ip is not supported for EC2."
+ )
if args.public_ip:
raise ParamValidationError(
- "--override-public-ip is not supported for EC2.")
+ "--override-public-ip is not supported for EC2."
+ )
- if args.infrastructure_class == 'on-premises' and \
- args.use_instance_profile:
+ if (
+ args.infrastructure_class == 'on-premises'
+ and args.use_instance_profile
+ ):
raise ParamValidationError(
- "--use-instance-profile is only supported for EC2.")
+ "--use-instance-profile is only supported for EC2."
+ )
if args.hostname:
if not HOSTNAME_RE.match(args.hostname):
raise ParamValidationError(
- "Invalid hostname: '%s'. Hostnames must consist of "
+ f"Invalid hostname: '{args.hostname}'. Hostnames must consist of "
"letters, digits and dashes only and must not start or "
- "end with a dash." % args.hostname)
+ "end with a dash."
+ )
def retrieve_stack(self, args):
"""
@@ -197,18 +241,20 @@ def retrieve_stack(self, args):
"""
LOG.debug("Retrieving stack and provisioning parameters")
- self._stack = self.opsworks.describe_stacks(
- StackIds=[args.stack_id]
- )['Stacks'][0]
- self._prov_params = \
+ self._stack = self.opsworks.describe_stacks(StackIds=[args.stack_id])[
+ 'Stacks'
+ ][0]
+ self._prov_params = (
self.opsworks.describe_stack_provisioning_parameters(
StackId=self._stack['StackId']
)
+ )
if args.infrastructure_class == 'ec2' and not args.local:
LOG.debug("Retrieving EC2 instance information")
ec2 = self._session.create_client(
- 'ec2', region_name=self._stack['Region'])
+ 'ec2', region_name=self._stack['Region']
+ )
# `desc_args` are arguments for the describe_instances call,
# whereas `conditions` is a list of lambdas for further filtering
@@ -234,9 +280,10 @@ def retrieve_stack(self, args):
# Cannot search for either private or public IP at the same
# time, thus filter afterwards
conditions.append(
- lambda instance:
- instance.get('PrivateIpAddress') == args.target or
- instance.get('PublicIpAddress') == args.target)
+ lambda instance: instance.get('PrivateIpAddress')
+ == args.target
+ or instance.get('PublicIpAddress') == args.target
+ )
# also use the given address to connect
self._use_address = args.target
else:
@@ -255,12 +302,15 @@ def retrieve_stack(self, args):
if not instances:
raise ValueError(
- "Did not find any instance matching %s." % args.target)
+ f"Did not find any instance matching {args.target}."
+ )
elif len(instances) > 1:
raise ValueError(
- "Found multiple instances matching %s: %s." % (
+ "Found multiple instances matching {}: {}.".format(
args.target,
- ", ".join(i['InstanceId'] for i in instances)))
+ ", ".join(i['InstanceId'] for i in instances),
+ )
+ )
self._ec2_instance = instances[0]
@@ -273,19 +323,24 @@ def validate_arguments(self, args):
instances = self.opsworks.describe_instances(
StackId=self._stack['StackId']
)['Instances']
- if any(args.hostname.lower() == instance['Hostname']
- for instance in instances):
+ if any(
+ args.hostname.lower() == instance['Hostname']
+ for instance in instances
+ ):
raise ValueError(
- "Invalid hostname: '%s'. Hostnames must be unique within "
- "a stack." % args.hostname)
+ f"Invalid hostname: '{args.hostname}'. Hostnames must be unique within "
+ "a stack."
+ )
if args.infrastructure_class == 'ec2' and args.local:
# make sure the regions match
region = json.loads(
- ensure_text_type(urlopen(IDENTITY_URL).read()))['region']
+ ensure_text_type(urlopen(IDENTITY_URL).read())
+ )['region']
if region != self._stack['Region']:
raise ValueError(
- "The stack's and the instance's region must match.")
+ "The stack's and the instance's region must match."
+ )
def determine_details(self, args):
"""
@@ -306,12 +361,14 @@ def determine_details(self, args):
elif 'PrivateIpAddress' in self._ec2_instance:
LOG.warning(
"Instance does not have a public IP address. Trying "
- "to use the private address to connect.")
+ "to use the private address to connect."
+ )
self._use_address = self._ec2_instance['PrivateIpAddress']
else:
# Should never happen
raise ValueError(
- "The instance does not seem to have an IP address.")
+ "The instance does not seem to have an IP address."
+ )
elif args.infrastructure_class == 'on-premises':
self._use_address = args.target
@@ -339,12 +396,15 @@ def create_iam_entities(self, args):
return
LOG.debug("Creating the IAM group if necessary")
- group_name = "OpsWorks-%s" % clean_for_iam(self._stack['StackId'])
+ group_name = "OpsWorks-{}".format(clean_for_iam(self._stack['StackId']))
try:
self.iam.create_group(GroupName=group_name, Path=IAM_PATH)
LOG.debug("Created IAM group %s", group_name)
except ClientError as e:
- if e.response.get('Error', {}).get('Code') == 'EntityAlreadyExists':
+ if (
+ e.response.get('Error', {}).get('Code')
+ == 'EntityAlreadyExists'
+ ):
LOG.debug("IAM group %s exists, continuing", group_name)
# group already exists, good
pass
@@ -353,19 +413,22 @@ def create_iam_entities(self, args):
# create the IAM user, trying alternatives if it already exists
LOG.debug("Creating an IAM user")
- base_username = "OpsWorks-%s-%s" % (
+ base_username = "OpsWorks-{}-{}".format(
shorten_name(clean_for_iam(self._stack['Name']), 25),
- shorten_name(clean_for_iam(self._name_for_iam), 25)
+ shorten_name(clean_for_iam(self._name_for_iam), 25),
)
for try_ in range(20):
- username = base_username + ("+%s" % try_ if try_ else "")
+ username = base_username + (f"+{try_}" if try_ else "")
try:
self.iam.create_user(UserName=username, Path=IAM_PATH)
except ClientError as e:
- if e.response.get('Error', {}).get('Code') == 'EntityAlreadyExists':
+ if (
+ e.response.get('Error', {}).get('Code')
+ == 'EntityAlreadyExists'
+ ):
LOG.debug(
"IAM user %s already exists, trying another name",
- username
+ username,
)
# user already exists, try the next one
pass
@@ -382,8 +445,7 @@ def create_iam_entities(self, args):
try:
self.iam.attach_user_policy(
- PolicyArn=IAM_POLICY_ARN,
- UserName=username
+ PolicyArn=IAM_POLICY_ARN, UserName=username
)
except ClientError as e:
if e.response.get('Error', {}).get('Code') == 'AccessDenied':
@@ -391,32 +453,29 @@ def create_iam_entities(self, args):
"Unauthorized to attach policy %s to user %s. Trying "
"to put user policy",
IAM_POLICY_ARN,
- username
+ username,
)
self.iam.put_user_policy(
PolicyName=IAM_USER_POLICY_NAME,
PolicyDocument=self._iam_policy_document(
- self._stack['Arn'], IAM_USER_POLICY_TIMEOUT),
- UserName=username
+ self._stack['Arn'], IAM_USER_POLICY_TIMEOUT
+ ),
+ UserName=username,
)
LOG.debug(
- "Put policy %s to user %s",
- IAM_USER_POLICY_NAME,
- username
+ "Put policy %s to user %s", IAM_USER_POLICY_NAME, username
)
else:
raise
else:
LOG.debug(
- "Attached policy %s to user %s",
- IAM_POLICY_ARN,
- username
+ "Attached policy %s to user %s", IAM_POLICY_ARN, username
)
LOG.debug("Creating an access key")
- self.access_key = self.iam.create_access_key(
- UserName=username
- )['AccessKey']
+ self.access_key = self.iam.create_access_key(UserName=username)[
+ 'AccessKey'
+ ]
def setup_target_machine(self, args):
"""
@@ -425,12 +484,11 @@ def setup_target_machine(self, args):
"""
remote_script = REMOTE_SCRIPT % {
- 'agent_installer_url':
- self._prov_params['AgentInstallerUrl'],
- 'preconfig':
- self._to_ruby_yaml(self._pre_config_document(args)),
- 'assets_download_bucket':
- self._prov_params['Parameters']['assets_download_bucket']
+ 'agent_installer_url': self._prov_params['AgentInstallerUrl'],
+ 'preconfig': self._to_ruby_yaml(self._pre_config_document(args)),
+ 'assets_download_bucket': self._prov_params['Parameters'][
+ 'assets_download_bucket'
+ ],
}
if args.local:
@@ -455,12 +513,12 @@ def ssh(self, args, remote_script):
else:
call = 'plink'
if args.username:
- call += ' -l "%s"' % args.username
+ call += f' -l "{args.username}"'
if args.private_key:
- call += ' -i "%s"' % args.private_key
- call += ' "%s"' % self._use_address
+ call += f' -i "{args.private_key}"'
+ call += f' "{self._use_address}"'
call += ' -m'
- call += ' "%s"' % script_file.name
+ call += f' "{script_file.name}"'
subprocess.check_call(call, shell=True)
finally:
@@ -482,13 +540,13 @@ def ssh(self, args, remote_script):
def _pre_config_document(self, args):
parameters = dict(
- stack_id=self._stack['StackId'],
- **self._prov_params["Parameters"]
+ stack_id=self._stack['StackId'], **self._prov_params["Parameters"]
)
if self.access_key:
parameters['access_key_id'] = self.access_key['AccessKeyId']
- parameters['secret_access_key'] = \
- self.access_key['SecretAccessKey']
+ parameters['secret_access_key'] = self.access_key[
+ 'SecretAccessKey'
+ ]
if self._use_hostname:
parameters['hostname'] = self._use_hostname
if args.private_ip:
@@ -510,20 +568,20 @@ def _iam_policy_document(arn, timeout=None):
valid_until = datetime.datetime.utcnow() + timeout
statement["Condition"] = {
"DateLessThan": {
- "aws:CurrentTime":
- valid_until.strftime("%Y-%m-%dT%H:%M:%SZ")
+ "aws:CurrentTime": valid_until.strftime(
+ "%Y-%m-%dT%H:%M:%SZ"
+ )
}
}
- policy_document = {
- "Statement": [statement],
- "Version": "2012-10-17"
- }
+ policy_document = {"Statement": [statement], "Version": "2012-10-17"}
return json.dumps(policy_document)
@staticmethod
def _to_ruby_yaml(parameters):
- return "\n".join(":%s: %s" % (k, json.dumps(v))
- for k, v in sorted(parameters.items()))
+ return "\n".join(
+ f":{k}: {json.dumps(v)}"
+ for k, v in sorted(parameters.items())
+ )
def clean_for_iam(name):
@@ -542,4 +600,4 @@ def shorten_name(name, max_length):
if len(name) <= max_length:
return name
q, r = divmod(max_length - 3, 2)
- return name[:q + r] + "..." + name[-q:]
+ return name[: q + r] + "..." + name[-q:]
diff --git a/awscli/customizations/paginate.py b/awscli/customizations/paginate.py
index 77b0f3362ec2..86caef41d0f5 100644
--- a/awscli/customizations/paginate.py
+++ b/awscli/customizations/paginate.py
@@ -23,13 +23,13 @@
* Add a ``--starting-token`` and a ``--max-items`` argument.
"""
+
import logging
import sys
from functools import partial
-from botocore import xform_name
+from botocore import model, xform_name
from botocore.exceptions import DataNotFoundError
-from botocore import model
from awscli.arguments import BaseCLIArgument
from awscli.customizations.exceptions import ParamValidationError
@@ -87,7 +87,8 @@ def get_paginator_config(session, service_name, operation_name):
return None
try:
operation_paginator_config = paginator_model.get_paginator(
- operation_name)
+ operation_name
+ )
except ValueError:
return None
return operation_paginator_config
@@ -100,49 +101,66 @@ def add_paging_description(help_command, **kwargs):
return
service_name = help_command.obj.service_model.service_name
paginator_config = get_paginator_config(
- help_command.session, service_name, help_command.obj.name)
+ help_command.session, service_name, help_command.obj.name
+ )
if not paginator_config:
return
help_command.doc.style.new_paragraph()
help_command.doc.writeln(
- ('``%s`` is a paginated operation. Multiple API calls may be issued '
- 'in order to retrieve the entire data set of results. You can '
- 'disable pagination by providing the ``--no-paginate`` argument.')
- % help_command.name)
+
+ f'``{help_command.name}`` is a paginated operation. Multiple API calls may be issued '
+ 'in order to retrieve the entire data set of results. You can '
+ 'disable pagination by providing the ``--no-paginate`` argument.'
+
+ )
# Only include result key information if it is present.
if paginator_config.get('result_key'):
queries = paginator_config['result_key']
if type(queries) is not list:
queries = [queries]
- queries = ", ".join([('``%s``' % s) for s in queries])
+ queries = ", ".join([(f'``{s}``') for s in queries])
help_command.doc.writeln(
- ('When using ``--output text`` and the ``--query`` argument on a '
- 'paginated response, the ``--query`` argument must extract data '
- 'from the results of the following query expressions: %s')
- % queries)
+
+ 'When using ``--output text`` and the ``--query`` argument on a '
+ 'paginated response, the ``--query`` argument must extract data '
+ f'from the results of the following query expressions: {queries}'
+
+ )
-def unify_paging_params(argument_table, operation_model, event_name,
- session, **kwargs):
+def unify_paging_params(
+ argument_table, operation_model, event_name, session, **kwargs
+):
paginator_config = get_paginator_config(
- session, operation_model.service_model.service_name,
- operation_model.name)
+ session,
+ operation_model.service_model.service_name,
+ operation_model.name,
+ )
if paginator_config is None:
# We only apply these customizations to paginated responses.
return
- logger.debug("Modifying paging parameters for operation: %s",
- operation_model.name)
+ logger.debug(
+ "Modifying paging parameters for operation: %s", operation_model.name
+ )
_remove_existing_paging_arguments(argument_table, paginator_config)
- parsed_args_event = event_name.replace('building-argument-table.',
- 'operation-args-parsed.')
- call_parameters_event = event_name.replace('building-argument-table',
- 'calling-command')
+ parsed_args_event = event_name.replace(
+ 'building-argument-table.', 'operation-args-parsed.'
+ )
+ call_parameters_event = event_name.replace(
+ 'building-argument-table', 'calling-command'
+ )
shadowed_args = {}
- add_paging_argument(argument_table, 'starting-token',
- PageArgument('starting-token', STARTING_TOKEN_HELP,
- parse_type='string',
- serialized_name='StartingToken'),
- shadowed_args)
+ add_paging_argument(
+ argument_table,
+ 'starting-token',
+ PageArgument(
+ 'starting-token',
+ STARTING_TOKEN_HELP,
+ parse_type='string',
+ serialized_name='StartingToken',
+ ),
+ shadowed_args,
+ )
input_members = operation_model.input_shape.members
type_name = 'integer'
if 'limit_key' in paginator_config:
@@ -150,21 +168,38 @@ def unify_paging_params(argument_table, operation_model, event_name,
type_name = limit_key_shape.type_name
if type_name not in PageArgument.type_map:
raise TypeError(
- ('Unsupported pagination type {0} for operation {1}'
- ' and parameter {2}').format(
- type_name, operation_model.name,
- paginator_config['limit_key']))
- add_paging_argument(argument_table, 'page-size',
- PageArgument('page-size', PAGE_SIZE_HELP,
- parse_type=type_name,
- serialized_name='PageSize'),
- shadowed_args)
-
- add_paging_argument(argument_table, 'max-items',
- PageArgument('max-items', MAX_ITEMS_HELP,
- parse_type=type_name,
- serialized_name='MaxItems'),
- shadowed_args)
+ (
+ 'Unsupported pagination type {} for operation {}'
+ ' and parameter {}'
+ ).format(
+ type_name,
+ operation_model.name,
+ paginator_config['limit_key'],
+ )
+ )
+ add_paging_argument(
+ argument_table,
+ 'page-size',
+ PageArgument(
+ 'page-size',
+ PAGE_SIZE_HELP,
+ parse_type=type_name,
+ serialized_name='PageSize',
+ ),
+ shadowed_args,
+ )
+
+ add_paging_argument(
+ argument_table,
+ 'max-items',
+ PageArgument(
+ 'max-items',
+ MAX_ITEMS_HELP,
+ parse_type=type_name,
+ serialized_name='MaxItems',
+ ),
+ shadowed_args,
+ )
# We will register two pagination handlers.
#
# The first is focused on analyzing the CLI arguments passed to see
@@ -179,13 +214,20 @@ def unify_paging_params(argument_table, operation_model, event_name,
# directly and this bypasses all of the CLI args processing.
session.register(
parsed_args_event,
- partial(check_should_enable_pagination,
- list(_get_all_cli_input_tokens(paginator_config)),
- shadowed_args, argument_table))
+ partial(
+ check_should_enable_pagination,
+ list(_get_all_cli_input_tokens(paginator_config)),
+ shadowed_args,
+ argument_table,
+ ),
+ )
session.register(
call_parameters_event,
- partial(check_should_enable_pagination_call_parameters,
- list(_get_all_input_tokens(paginator_config))))
+ partial(
+ check_should_enable_pagination_call_parameters,
+ list(_get_all_input_tokens(paginator_config)),
+ ),
+ )
def add_paging_argument(argument_table, arg_name, argument, shadowed_args):
@@ -199,17 +241,27 @@ def add_paging_argument(argument_table, arg_name, argument, shadowed_args):
argument_table[arg_name] = argument
-def check_should_enable_pagination(input_tokens, shadowed_args, argument_table,
- parsed_args, parsed_globals, **kwargs):
+def check_should_enable_pagination(
+ input_tokens,
+ shadowed_args,
+ argument_table,
+ parsed_args,
+ parsed_globals,
+ **kwargs,
+):
normalized_paging_args = ['start_token', 'max_items']
for token in input_tokens:
py_name = token.replace('-', '_')
- if getattr(parsed_args, py_name) is not None and \
- py_name not in normalized_paging_args:
+ if (
+ getattr(parsed_args, py_name) is not None
+ and py_name not in normalized_paging_args
+ ):
# The user has specified a manual (undocumented) pagination arg.
# We need to automatically turn pagination off.
- logger.debug("User has specified a manual pagination arg. "
- "Automatically setting --no-paginate.")
+ logger.debug(
+ "User has specified a manual pagination arg. "
+ "Automatically setting --no-paginate."
+ )
parsed_globals.paginate = False
if not parsed_globals.paginate:
@@ -229,15 +281,19 @@ def check_should_enable_pagination(input_tokens, shadowed_args, argument_table,
def ensure_paging_params_not_set(parsed_args, shadowed_args):
paging_params = ['starting_token', 'page_size', 'max_items']
shadowed_params = [p.replace('-', '_') for p in shadowed_args.keys()]
- params_used = [p for p in paging_params if
- p not in shadowed_params and getattr(parsed_args, p, None)]
+ params_used = [
+ p
+ for p in paging_params
+ if p not in shadowed_params and getattr(parsed_args, p, None)
+ ]
if len(params_used) > 0:
converted_params = ', '.join(
- ["--" + p.replace('_', '-') for p in params_used])
+ ["--" + p.replace('_', '-') for p in params_used]
+ )
raise ParamValidationError(
"Cannot specify --no-paginate along with pagination "
- "arguments: %s" % converted_params
+ f"arguments: {converted_params}"
)
@@ -264,8 +320,7 @@ def _get_all_input_tokens(pagination_config):
# Get all input tokens including the limit_key
# if it exists.
tokens = _get_input_tokens(pagination_config)
- for token_name in tokens:
- yield token_name
+ yield from tokens
if 'limit_key' in pagination_config:
key_name = pagination_config['limit_key']
yield key_name
@@ -291,11 +346,14 @@ def _get_cli_name(param_objects, token_name):
# and would be missed by the processing above. This function gets
# called on the calling-command event.
def check_should_enable_pagination_call_parameters(
- input_tokens, call_parameters, parsed_args, parsed_globals, **kwargs):
+ input_tokens, call_parameters, parsed_args, parsed_globals, **kwargs
+):
for param in call_parameters:
if param in input_tokens:
- logger.debug("User has specified a manual pagination arg. "
- "Automatically setting --no-paginate.")
+ logger.debug(
+ "User has specified a manual pagination arg. "
+ "Automatically setting --no-paginate."
+ )
parsed_globals.paginate = False
@@ -317,7 +375,8 @@ def __init__(self, name, documentation, parse_type, serialized_name):
def _emit_non_positive_max_items_warning(self):
uni_print(
"warning: Non-positive values for --max-items may result in undefined behavior.\n",
- sys.stderr)
+ sys.stderr,
+ )
@property
def cli_name(self):
@@ -340,8 +399,11 @@ def documentation(self):
return self._documentation
def add_to_parser(self, parser):
- parser.add_argument(self.cli_name, dest=self.py_name,
- type=self.type_map[self._parse_type])
+ parser.add_argument(
+ self.cli_name,
+ dest=self.py_name,
+ type=self.type_map[self._parse_type],
+ )
def add_to_params(self, parameters, value):
if value is not None:
diff --git a/awscli/customizations/putmetricdata.py b/awscli/customizations/putmetricdata.py
index 10ef322b2323..9e3723c57f0e 100644
--- a/awscli/customizations/putmetricdata.py
+++ b/awscli/customizations/putmetricdata.py
@@ -23,21 +23,32 @@
* --storage-resolution
"""
+
import decimal
from awscli.arguments import CustomArgument
-from awscli.utils import split_on_commas
from awscli.customizations.utils import validate_mutually_exclusive_handler
+from awscli.utils import split_on_commas
def register_put_metric_data(event_handler):
event_handler.register(
- 'building-argument-table.cloudwatch.put-metric-data', _promote_args)
+ 'building-argument-table.cloudwatch.put-metric-data', _promote_args
+ )
event_handler.register(
'operation-args-parsed.cloudwatch.put-metric-data',
validate_mutually_exclusive_handler(
- ['metric_data'], ['metric_name', 'timestamp', 'unit', 'value',
- 'dimensions', 'statistic_values']))
+ ['metric_data'],
+ [
+ 'metric_name',
+ 'timestamp',
+ 'unit',
+ 'value',
+ 'dimensions',
+ 'statistic_values',
+ ],
+ ),
+ )
def _promote_args(argument_table, operation_model, **kwargs):
@@ -48,25 +59,32 @@ def _promote_args(argument_table, operation_model, **kwargs):
argument_table['metric-data'].required = False
argument_table['metric-name'] = PutMetricArgument(
- 'metric-name', help_text='The name of the metric.')
+ 'metric-name', help_text='The name of the metric.'
+ )
argument_table['timestamp'] = PutMetricArgument(
- 'timestamp', help_text='The time stamp used for the metric. '
- 'If not specified, the default value is '
- 'set to the time the metric data was '
- 'received.')
+ 'timestamp',
+ help_text='The time stamp used for the metric. '
+ 'If not specified, the default value is '
+ 'set to the time the metric data was '
+ 'received.',
+ )
argument_table['unit'] = PutMetricArgument(
- 'unit', help_text='The unit of metric.')
+ 'unit', help_text='The unit of metric.'
+ )
argument_table['value'] = PutMetricArgument(
- 'value', help_text='The value for the metric. Although the --value '
- 'parameter accepts numbers of type Double, '
- 'Amazon CloudWatch truncates values with very '
- 'large exponents. Values with base-10 exponents '
- 'greater than 126 (1 x 10^126) are truncated. '
- 'Likewise, values with base-10 exponents less '
- 'than -130 (1 x 10^-130) are also truncated.')
+ 'value',
+ help_text='The value for the metric. Although the --value '
+ 'parameter accepts numbers of type Double, '
+ 'Amazon CloudWatch truncates values with very '
+ 'large exponents. Values with base-10 exponents '
+ 'greater than 126 (1 x 10^126) are truncated. '
+ 'Likewise, values with base-10 exponents less '
+ 'than -130 (1 x 10^-130) are also truncated.',
+ )
argument_table['dimensions'] = PutMetricArgument(
- 'dimensions', help_text=(
+ 'dimensions',
+ help_text=(
'The --dimensions argument further expands '
'on the identity of a metric using a Name=Value '
'pair, separated by commas, for example: '
@@ -76,11 +94,12 @@ def _promote_args(argument_table, operation_model, **kwargs):
'where for the same example you would use the format '
'--dimensions Name=InstanceID,Value=i-aaba32d4 '
'Name=InstanceType,value=m1.small
.'
- )
+ ),
)
argument_table['statistic-values'] = PutMetricArgument(
- 'statistic-values', help_text='A set of statistical values describing '
- 'the metric.')
+ 'statistic-values',
+ help_text='A set of statistical values describing ' 'the metric.',
+ )
metric_data = operation_model.input_shape.members['MetricData'].member
storage_resolution = metric_data.members['StorageResolution']
@@ -103,13 +122,15 @@ def _add_to_params(self, parameters, value):
parameters[name] = [{}]
first_element = parameters[name][0]
return func(self, first_element, value)
+
return _add_to_params
+
return _wrap_add_to_params
class PutMetricArgument(CustomArgument):
def add_to_params(self, parameters, value):
- method_name = '_add_param_%s' % self.name.replace('-', '_')
+ method_name = '_add_param_{}'.format(self.name.replace('-', '_'))
return getattr(self, method_name)(parameters, value)
@insert_first_element('MetricData')
diff --git a/awscli/customizations/quicksight.py b/awscli/customizations/quicksight.py
index 3cc048452573..6750e0b5b0f2 100644
--- a/awscli/customizations/quicksight.py
+++ b/awscli/customizations/quicksight.py
@@ -16,11 +16,13 @@
_ASSET_BUNDLE_FILE_DOCSTRING = (
'The content of the asset bundle to be uploaded. '
'To specify the content of a local file use the '
- 'fileb:// prefix. Example: fileb://asset-bundle.zip
')
+ 'fileb:// prefix. Example: fileb://asset-bundle.zip
'
+)
_ASSET_BUNDLE_DOCSTRING_ADDENDUM = (
'To specify a local file use '
- '--asset-bundle-import-source-bytes
instead.
')
+ '--asset-bundle-import-source-bytes
instead.
'
+)
def register_quicksight_asset_bundle_customizations(cli):
@@ -31,4 +33,6 @@ def register_quicksight_asset_bundle_customizations(cli):
source_arg_blob_member='Body',
new_arg='asset-bundle-import-source-bytes',
new_arg_doc_string=_ASSET_BUNDLE_FILE_DOCSTRING,
- doc_string_addendum=_ASSET_BUNDLE_DOCSTRING_ADDENDUM))
+ doc_string_addendum=_ASSET_BUNDLE_DOCSTRING_ADDENDUM,
+ ),
+ )
diff --git a/awscli/customizations/rds.py b/awscli/customizations/rds.py
index cac3173f3f76..48fd7c3b042f 100644
--- a/awscli/customizations/rds.py
+++ b/awscli/customizations/rds.py
@@ -24,8 +24,7 @@
"""
-from awscli.clidriver import ServiceOperation
-from awscli.clidriver import CLIOperationCaller
+from awscli.clidriver import CLIOperationCaller, ServiceOperation
from awscli.customizations import utils
from awscli.customizations.commands import BasicCommand
from awscli.customizations.utils import uni_print
@@ -33,10 +32,14 @@
def register_rds_modify_split(cli):
cli.register('building-command-table.rds', _building_command_table)
- cli.register('building-argument-table.rds.add-option-to-option-group',
- _rename_add_option)
- cli.register('building-argument-table.rds.remove-option-from-option-group',
- _rename_remove_option)
+ cli.register(
+ 'building-argument-table.rds.add-option-to-option-group',
+ _rename_add_option,
+ )
+ cli.register(
+ 'building-argument-table.rds.remove-option-from-option-group',
+ _rename_remove_option,
+ )
def register_add_generate_db_auth_token(cli):
@@ -49,14 +52,16 @@ def _add_generate_db_auth_token(command_table, session, **kwargs):
def _rename_add_option(argument_table, **kwargs):
- utils.rename_argument(argument_table, 'options-to-include',
- new_name='options')
+ utils.rename_argument(
+ argument_table, 'options-to-include', new_name='options'
+ )
del argument_table['options-to-remove']
def _rename_remove_option(argument_table, **kwargs):
- utils.rename_argument(argument_table, 'options-to-remove',
- new_name='options')
+ utils.rename_argument(
+ argument_table, 'options-to-remove', new_name='options'
+ )
del argument_table['options-to-include']
@@ -69,15 +74,19 @@ def _building_command_table(command_table, session, **kwargs):
rds_model = session.get_service_model('rds')
modify_operation_model = rds_model.operation_model('ModifyOptionGroup')
command_table['add-option-to-option-group'] = ServiceOperation(
- parent_name='rds', name='add-option-to-option-group',
+ parent_name='rds',
+ name='add-option-to-option-group',
operation_caller=CLIOperationCaller(session),
session=session,
- operation_model=modify_operation_model)
+ operation_model=modify_operation_model,
+ )
command_table['remove-option-from-option-group'] = ServiceOperation(
- parent_name='rds', name='remove-option-from-option-group',
+ parent_name='rds',
+ name='remove-option-from-option-group',
session=session,
operation_model=modify_operation_model,
- operation_caller=CLIOperationCaller(session))
+ operation_caller=CLIOperationCaller(session),
+ )
class GenerateDBAuthTokenCommand(BasicCommand):
@@ -86,23 +95,35 @@ class GenerateDBAuthTokenCommand(BasicCommand):
'Generates an auth token used to connect to a db with IAM credentials.'
)
ARG_TABLE = [
- {'name': 'hostname', 'required': True,
- 'help_text': 'The hostname of the database to connect to.'},
- {'name': 'port', 'cli_type_name': 'integer', 'required': True,
- 'help_text': 'The port number the database is listening on.'},
- {'name': 'username', 'required': True,
- 'help_text': 'The username to log in as.'}
+ {
+ 'name': 'hostname',
+ 'required': True,
+ 'help_text': 'The hostname of the database to connect to.',
+ },
+ {
+ 'name': 'port',
+ 'cli_type_name': 'integer',
+ 'required': True,
+ 'help_text': 'The port number the database is listening on.',
+ },
+ {
+ 'name': 'username',
+ 'required': True,
+ 'help_text': 'The username to log in as.',
+ },
]
def _run_main(self, parsed_args, parsed_globals):
rds = self._session.create_client(
- 'rds', parsed_globals.region, parsed_globals.endpoint_url,
- parsed_globals.verify_ssl
+ 'rds',
+ parsed_globals.region,
+ parsed_globals.endpoint_url,
+ parsed_globals.verify_ssl,
)
token = rds.generate_db_auth_token(
DBHostname=parsed_args.hostname,
Port=parsed_args.port,
- DBUsername=parsed_args.username
+ DBUsername=parsed_args.username,
)
uni_print(token)
uni_print('\n')
diff --git a/awscli/customizations/rekognition.py b/awscli/customizations/rekognition.py
index ba03ef1d7e9f..db60f6668583 100644
--- a/awscli/customizations/rekognition.py
+++ b/awscli/customizations/rekognition.py
@@ -13,12 +13,15 @@
from awscli.customizations.arguments import NestedBlobArgumentHoister
-IMAGE_FILE_DOCSTRING = ('The content of the image to be uploaded. '
- 'To specify the content of a local file use the '
- 'fileb:// prefix. '
- 'Example: fileb://image.png
')
-IMAGE_DOCSTRING_ADDENDUM = ('To specify a local file use --%s
'
- 'instead.
')
+IMAGE_FILE_DOCSTRING = (
+ 'The content of the image to be uploaded. '
+ 'To specify the content of a local file use the '
+ 'fileb:// prefix. '
+ 'Example: fileb://image.png
'
+)
+IMAGE_DOCSTRING_ADDENDUM = (
+ 'To specify a local file use --%s
' 'instead.
'
+)
FILE_PARAMETER_UPDATES = {
@@ -32,10 +35,13 @@ def register_rekognition_detect_labels(cli):
for target, new_param in FILE_PARAMETER_UPDATES.items():
operation, old_param = target.rsplit('.', 1)
doc_string_addendum = IMAGE_DOCSTRING_ADDENDUM % new_param
- cli.register('building-argument-table.rekognition.%s' % operation,
- NestedBlobArgumentHoister(
- source_arg=old_param,
- source_arg_blob_member='Bytes',
- new_arg=new_param,
- new_arg_doc_string=IMAGE_FILE_DOCSTRING,
- doc_string_addendum=doc_string_addendum))
+ cli.register(
+ f'building-argument-table.rekognition.{operation}',
+ NestedBlobArgumentHoister(
+ source_arg=old_param,
+ source_arg_blob_member='Bytes',
+ new_arg=new_param,
+ new_arg_doc_string=IMAGE_FILE_DOCSTRING,
+ doc_string_addendum=doc_string_addendum,
+ ),
+ )
diff --git a/awscli/customizations/removals.py b/awscli/customizations/removals.py
index 5add46dc4f81..788c1223b02c 100644
--- a/awscli/customizations/removals.py
+++ b/awscli/customizations/removals.py
@@ -18,6 +18,7 @@
yet fully supported.
"""
+
import logging
from functools import partial
@@ -26,52 +27,81 @@
def register_removals(event_handler):
cmd_remover = CommandRemover(event_handler)
- cmd_remover.remove(on_event='building-command-table.ses',
- remove_commands=['delete-verified-email-address',
- 'list-verified-email-addresses',
- 'verify-email-address'])
- cmd_remover.remove(on_event='building-command-table.ec2',
- remove_commands=['import-instance', 'import-volume'])
- cmd_remover.remove(on_event='building-command-table.emr',
- remove_commands=['run-job-flow', 'describe-job-flows',
- 'add-job-flow-steps',
- 'terminate-job-flows',
- 'list-bootstrap-actions',
- 'list-instance-groups',
- 'set-termination-protection',
- 'set-keep-job-flow-alive-when-no-steps',
- 'set-visible-to-all-users',
- 'set-unhealthy-node-replacement'])
- cmd_remover.remove(on_event='building-command-table.kinesis',
- remove_commands=['subscribe-to-shard'])
- cmd_remover.remove(on_event='building-command-table.lexv2-runtime',
- remove_commands=['start-conversation'])
- cmd_remover.remove(on_event='building-command-table.lambda',
- remove_commands=['invoke-with-response-stream'])
- cmd_remover.remove(on_event='building-command-table.sagemaker-runtime',
- remove_commands=['invoke-endpoint-with-response-stream'])
- cmd_remover.remove(on_event='building-command-table.bedrock-runtime',
- remove_commands=['invoke-model-with-response-stream',
- 'converse-stream'])
- cmd_remover.remove(on_event='building-command-table.bedrock-agent-runtime',
- remove_commands=['invoke-agent',
- 'invoke-flow',
- 'invoke-inline-agent',
- 'optimize-prompt',
- 'retrieve-and-generate-stream'])
- cmd_remover.remove(on_event='building-command-table.qbusiness',
- remove_commands=['chat'])
- cmd_remover.remove(on_event='building-command-table.iotsitewise',
- remove_commands=['invoke-assistant'])
+ cmd_remover.remove(
+ on_event='building-command-table.ses',
+ remove_commands=[
+ 'delete-verified-email-address',
+ 'list-verified-email-addresses',
+ 'verify-email-address',
+ ],
+ )
+ cmd_remover.remove(
+ on_event='building-command-table.ec2',
+ remove_commands=['import-instance', 'import-volume'],
+ )
+ cmd_remover.remove(
+ on_event='building-command-table.emr',
+ remove_commands=[
+ 'run-job-flow',
+ 'describe-job-flows',
+ 'add-job-flow-steps',
+ 'terminate-job-flows',
+ 'list-bootstrap-actions',
+ 'list-instance-groups',
+ 'set-termination-protection',
+ 'set-keep-job-flow-alive-when-no-steps',
+ 'set-visible-to-all-users',
+ 'set-unhealthy-node-replacement',
+ ],
+ )
+ cmd_remover.remove(
+ on_event='building-command-table.kinesis',
+ remove_commands=['subscribe-to-shard'],
+ )
+ cmd_remover.remove(
+ on_event='building-command-table.lexv2-runtime',
+ remove_commands=['start-conversation'],
+ )
+ cmd_remover.remove(
+ on_event='building-command-table.lambda',
+ remove_commands=['invoke-with-response-stream'],
+ )
+ cmd_remover.remove(
+ on_event='building-command-table.sagemaker-runtime',
+ remove_commands=['invoke-endpoint-with-response-stream'],
+ )
+ cmd_remover.remove(
+ on_event='building-command-table.bedrock-runtime',
+ remove_commands=[
+ 'invoke-model-with-response-stream',
+ 'converse-stream',
+ ],
+ )
+ cmd_remover.remove(
+ on_event='building-command-table.bedrock-agent-runtime',
+ remove_commands=[
+ 'invoke-agent',
+ 'invoke-flow',
+ 'invoke-inline-agent',
+ 'optimize-prompt',
+ 'retrieve-and-generate-stream',
+ ],
+ )
+ cmd_remover.remove(
+ on_event='building-command-table.qbusiness', remove_commands=['chat']
+ )
+ cmd_remover.remove(
+ on_event='building-command-table.iotsitewise',
+ remove_commands=['invoke-assistant'],
+ )
-class CommandRemover(object):
+class CommandRemover:
def __init__(self, events):
self._events = events
def remove(self, on_event, remove_commands):
- self._events.register(on_event,
- self._create_remover(remove_commands))
+ self._events.register(on_event, self._create_remover(remove_commands))
def _create_remover(self, commands_to_remove):
return partial(_remove_commands, commands_to_remove=commands_to_remove)
@@ -84,5 +114,6 @@ def _remove_commands(command_table, commands_to_remove, **kwargs):
LOG.debug("Removing operation: %s", command)
del command_table[command]
except KeyError:
- LOG.warning("Attempting to delete command that does not exist: %s",
- command)
+ LOG.warning(
+ "Attempting to delete command that does not exist: %s", command
+ )
diff --git a/awscli/customizations/route53.py b/awscli/customizations/route53.py
index 686abc40c914..f482ff605827 100644
--- a/awscli/customizations/route53.py
+++ b/awscli/customizations/route53.py
@@ -18,7 +18,8 @@ def register_create_hosted_zone_doc_fix(cli):
# has the necessary documentation.
cli.register(
'doc-option.route53.create-hosted-zone.hosted-zone-config',
- add_private_zone_note)
+ add_private_zone_note,
+ )
def add_private_zone_note(help_command, **kwargs):
diff --git a/awscli/customizations/s3errormsg.py b/awscli/customizations/s3errormsg.py
index a7a0b9eb4f32..adc56ae6aae2 100644
--- a/awscli/customizations/s3errormsg.py
+++ b/awscli/customizations/s3errormsg.py
@@ -10,9 +10,7 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
-"""Give better S3 error messages.
-"""
-
+"""Give better S3 error messages."""
REGION_ERROR_MSG = (
'You can fix this issue by explicitly providing the correct region '
@@ -46,7 +44,7 @@ def enhance_error_msg(parsed, **kwargs):
elif _is_permanent_redirect_message(parsed):
endpoint = parsed['Error']['Endpoint']
message = parsed['Error']['Message']
- new_message = message[:-1] + ': %s\n' % endpoint
+ new_message = message[:-1] + f': {endpoint}\n'
new_message += REGION_ERROR_MSG
parsed['Error']['Message'] = new_message
elif _is_kms_sigv4_error_message(parsed):
@@ -54,8 +52,9 @@ def enhance_error_msg(parsed, **kwargs):
def _is_sigv4_error_message(parsed):
- return ('Please use AWS4-HMAC-SHA256' in
- parsed.get('Error', {}).get('Message', ''))
+ return 'Please use AWS4-HMAC-SHA256' in parsed.get('Error', {}).get(
+ 'Message', ''
+ )
def _is_permanent_redirect_message(parsed):
@@ -63,5 +62,7 @@ def _is_permanent_redirect_message(parsed):
def _is_kms_sigv4_error_message(parsed):
- return ('AWS KMS managed keys require AWS Signature Version 4' in
- parsed.get('Error', {}).get('Message', ''))
+ return (
+ 'AWS KMS managed keys require AWS Signature Version 4'
+ in parsed.get('Error', {}).get('Message', '')
+ )
diff --git a/awscli/customizations/s3events.py b/awscli/customizations/s3events.py
index 122c4ca14be7..f967862f3d66 100644
--- a/awscli/customizations/s3events.py
+++ b/awscli/customizations/s3events.py
@@ -11,8 +11,8 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""Add S3 specific event streaming output arg."""
-from awscli.arguments import CustomArgument
+from awscli.arguments import CustomArgument
STREAM_HELP_TEXT = 'Filename where the records will be saved'
@@ -24,28 +24,29 @@ class DocSectionNotFoundError(Exception):
def register_event_stream_arg(event_handlers):
event_handlers.register(
'building-argument-table.s3api.select-object-content',
- add_event_stream_output_arg)
+ add_event_stream_output_arg,
+ )
event_handlers.register_last(
- 'doc-output.s3api.select-object-content',
- replace_event_stream_docs
+ 'doc-output.s3api.select-object-content', replace_event_stream_docs
)
def register_document_expires_string(event_handlers):
- event_handlers.register_last(
- 'doc-output.s3api',
- document_expires_string
- )
+ event_handlers.register_last('doc-output.s3api', document_expires_string)
-def add_event_stream_output_arg(argument_table, operation_model,
- session, **kwargs):
+def add_event_stream_output_arg(
+ argument_table, operation_model, session, **kwargs
+):
argument_table['outfile'] = S3SelectStreamOutputArgument(
- name='outfile', help_text=STREAM_HELP_TEXT,
- cli_type_name='string', positional_arg=True,
+ name='outfile',
+ help_text=STREAM_HELP_TEXT,
+ cli_type_name='string',
+ positional_arg=True,
stream_key=operation_model.output_shape.serialization['payload'],
- session=session)
+ session=session,
+ )
def replace_event_stream_docs(help_command, **kwargs):
@@ -58,11 +59,13 @@ def replace_event_stream_docs(help_command, **kwargs):
# This should never happen, but in the rare case that it does
# we should be raising something with a helpful error message.
raise DocSectionNotFoundError(
- 'Could not find the "output" section for the command: %s'
- % help_command)
+ f'Could not find the "output" section for the command: {help_command}'
+ )
doc.write('======\nOutput\n======\n')
- doc.write("This command generates no output. The selected "
- "object content is written to the specified outfile.\n")
+ doc.write(
+ "This command generates no output. The selected "
+ "object content is written to the specified outfile.\n"
+ )
def document_expires_string(help_command, **kwargs):
@@ -81,7 +84,7 @@ def document_expires_string(help_command, **kwargs):
f'\n\n{" " * doc.style.indentation * doc.style.indent_width}',
'ExpiresString -> (string)\n\n',
'\tThe raw, unparsed value of the ``Expires`` field.',
- f'\n\n{" " * doc.style.indentation * doc.style.indent_width}'
+ f'\n\n{" " * doc.style.indentation * doc.style.indent_width}',
]
for idx, write in enumerate(deprecation_note_and_expires_string):
@@ -94,7 +97,7 @@ class S3SelectStreamOutputArgument(CustomArgument):
_DOCUMENT_AS_REQUIRED = True
def __init__(self, stream_key, session, **kwargs):
- super(S3SelectStreamOutputArgument, self).__init__(**kwargs)
+ super().__init__(**kwargs)
# This is the key in the response body where we can find the
# streamed contents.
self._stream_key = stream_key
@@ -103,8 +106,9 @@ def __init__(self, stream_key, session, **kwargs):
def add_to_params(self, parameters, value):
self._output_file = value
- self._session.register('after-call.s3.SelectObjectContent',
- self.save_file)
+ self._session.register(
+ 'after-call.s3.SelectObjectContent', self.save_file
+ )
def save_file(self, parsed, **kwargs):
# This method is hooked into after-call which fires
diff --git a/awscli/customizations/s3uploader.py b/awscli/customizations/s3uploader.py
index e640b94ba55a..3eece5589192 100644
--- a/awscli/customizations/s3uploader.py
+++ b/awscli/customizations/s3uploader.py
@@ -13,9 +13,9 @@
import hashlib
import logging
-import threading
import os
import sys
+import threading
import botocore
import botocore.exceptions
@@ -33,14 +33,15 @@ def __init__(self, **kwargs):
Exception.__init__(self, msg)
self.kwargs = kwargs
-
- fmt = ("S3 Bucket does not exist. "
- "Execute the command to create a new bucket"
- "\n"
- "aws s3 mb s3://{bucket_name}")
+ fmt = (
+ "S3 Bucket does not exist. "
+ "Execute the command to create a new bucket"
+ "\n"
+ "aws s3 mb s3://{bucket_name}"
+ )
-class S3Uploader(object):
+class S3Uploader:
"""
Class to upload objects to S3 bucket that use versioning. If bucket
does not already use versioning, this class will turn on versioning.
@@ -59,12 +60,15 @@ def artifact_metadata(self, val):
raise TypeError("Artifact metadata should be in dict type")
self._artifact_metadata = val
- def __init__(self, s3_client,
- bucket_name,
- prefix=None,
- kms_key_id=None,
- force_upload=False,
- transfer_manager=None):
+ def __init__(
+ self,
+ s3_client,
+ bucket_name,
+ prefix=None,
+ kms_key_id=None,
+ force_upload=False,
+ transfer_manager=None,
+ ):
self.bucket_name = bucket_name
self.prefix = prefix
self.kms_key_id = kms_key_id or None
@@ -86,21 +90,20 @@ def upload(self, file_name, remote_path):
"""
if self.prefix and len(self.prefix) > 0:
- remote_path = "{0}/{1}".format(self.prefix, remote_path)
+ remote_path = f"{self.prefix}/{remote_path}"
# Check if a file with same data exists
if not self.force_upload and self.file_exists(remote_path):
- LOG.debug("File with same data already exists at {0}. "
- "Skipping upload".format(remote_path))
+ LOG.debug(
+ f"File with same data already exists at {remote_path}. "
+ "Skipping upload"
+ )
return self.make_url(remote_path)
try:
-
# Default to regular server-side encryption unless customer has
# specified their own KMS keys
- additional_args = {
- "ServerSideEncryption": "AES256"
- }
+ additional_args = {"ServerSideEncryption": "AES256"}
if self.kms_key_id:
additional_args["ServerSideEncryption"] = "aws:kms"
@@ -109,13 +112,16 @@ def upload(self, file_name, remote_path):
if self.artifact_metadata:
additional_args["Metadata"] = self.artifact_metadata
- print_progress_callback = \
- ProgressPercentage(file_name, remote_path)
- future = self.transfer_manager.upload(file_name,
- self.bucket_name,
- remote_path,
- additional_args,
- [print_progress_callback])
+ print_progress_callback = ProgressPercentage(
+ file_name, remote_path
+ )
+ future = self.transfer_manager.upload(
+ file_name,
+ self.bucket_name,
+ remote_path,
+ additional_args,
+ [print_progress_callback],
+ )
future.result()
return self.make_url(remote_path)
@@ -157,8 +163,7 @@ def file_exists(self, remote_path):
try:
# Find the object that matches this ETag
- self.s3.head_object(
- Bucket=self.bucket_name, Key=remote_path)
+ self.s3.head_object(Bucket=self.bucket_name, Key=remote_path)
return True
except botocore.exceptions.ClientError:
# Either File does not exist or we are unable to get
@@ -166,11 +171,9 @@ def file_exists(self, remote_path):
return False
def make_url(self, obj_path):
- return "s3://{0}/{1}".format(
- self.bucket_name, obj_path)
+ return f"s3://{self.bucket_name}/{obj_path}"
def file_checksum(self, file_name):
-
with open(file_name, "rb") as file_handle:
md5 = hashlib.md5()
# Read file in chunks of 4096 bytes
@@ -192,13 +195,13 @@ def file_checksum(self, file_name):
def to_path_style_s3_url(self, key, version=None):
"""
- This link describes the format of Path Style URLs
- http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html#access-bucket-intro
+ This link describes the format of Path Style URLs
+ http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingBucket.html#access-bucket-intro
"""
base = self.s3.meta.endpoint_url
- result = "{0}/{1}/{2}".format(base, self.bucket_name, key)
+ result = f"{base}/{self.bucket_name}/{key}"
if version:
- result = "{0}?versionId={1}".format(result, version)
+ result = f"{result}?versionId={version}"
return result
@@ -214,14 +217,12 @@ def __init__(self, filename, remote_path):
self._lock = threading.Lock()
def on_progress(self, future, bytes_transferred, **kwargs):
-
# To simplify we'll assume this is hooked up
# to a single filename.
with self._lock:
self._seen_so_far += bytes_transferred
percentage = (self._seen_so_far / self._size) * 100
sys.stderr.write(
- "\rUploading to %s %s / %s (%.2f%%)" %
- (self._remote_path, self._seen_so_far,
- self._size, percentage))
+ f"\rUploading to {self._remote_path} {self._seen_so_far} / {self._size} ({percentage:.2f}%)"
+ )
sys.stderr.flush()
diff --git a/awscli/customizations/sessendemail.py b/awscli/customizations/sessendemail.py
index 8215342982bf..350118d03e96 100644
--- a/awscli/customizations/sessendemail.py
+++ b/awscli/customizations/sessendemail.py
@@ -22,52 +22,61 @@
"""
-from awscli.customizations import utils
from awscli.arguments import CustomArgument
+from awscli.customizations import utils
from awscli.customizations.utils import validate_mutually_exclusive_handler
-
-TO_HELP = ('The email addresses of the primary recipients. '
- 'You can specify multiple recipients as space-separated values')
-CC_HELP = ('The email addresses of copy recipients (Cc). '
- 'You can specify multiple recipients as space-separated values')
-BCC_HELP = ('The email addresses of blind-carbon-copy recipients (Bcc). '
- 'You can specify multiple recipients as space-separated values')
+TO_HELP = (
+ 'The email addresses of the primary recipients. '
+ 'You can specify multiple recipients as space-separated values'
+)
+CC_HELP = (
+ 'The email addresses of copy recipients (Cc). '
+ 'You can specify multiple recipients as space-separated values'
+)
+BCC_HELP = (
+ 'The email addresses of blind-carbon-copy recipients (Bcc). '
+ 'You can specify multiple recipients as space-separated values'
+)
SUBJECT_HELP = 'The subject of the message'
TEXT_HELP = 'The raw text body of the message'
HTML_HELP = 'The HTML body of the message'
def register_ses_send_email(event_handler):
- event_handler.register('building-argument-table.ses.send-email',
- _promote_args)
+ event_handler.register(
+ 'building-argument-table.ses.send-email', _promote_args
+ )
event_handler.register(
'operation-args-parsed.ses.send-email',
validate_mutually_exclusive_handler(
- ['destination'], ['to', 'cc', 'bcc']))
+ ['destination'], ['to', 'cc', 'bcc']
+ ),
+ )
event_handler.register(
'operation-args-parsed.ses.send-email',
- validate_mutually_exclusive_handler(
- ['message'], ['text', 'html']))
+ validate_mutually_exclusive_handler(['message'], ['text', 'html']),
+ )
def _promote_args(argument_table, **kwargs):
argument_table['message'].required = False
argument_table['destination'].required = False
- utils.rename_argument(argument_table, 'source',
- new_name='from')
+ utils.rename_argument(argument_table, 'source', new_name='from')
argument_table['to'] = AddressesArgument(
- 'to', 'ToAddresses', help_text=TO_HELP)
+ 'to', 'ToAddresses', help_text=TO_HELP
+ )
argument_table['cc'] = AddressesArgument(
- 'cc', 'CcAddresses', help_text=CC_HELP)
+ 'cc', 'CcAddresses', help_text=CC_HELP
+ )
argument_table['bcc'] = AddressesArgument(
- 'bcc', 'BccAddresses', help_text=BCC_HELP)
+ 'bcc', 'BccAddresses', help_text=BCC_HELP
+ )
argument_table['subject'] = BodyArgument(
- 'subject', 'Subject', help_text=SUBJECT_HELP)
- argument_table['text'] = BodyArgument(
- 'text', 'Text', help_text=TEXT_HELP)
- argument_table['html'] = BodyArgument(
- 'html', 'Html', help_text=HTML_HELP)
+ 'subject', 'Subject', help_text=SUBJECT_HELP
+ )
+ argument_table['text'] = BodyArgument('text', 'Text', help_text=TEXT_HELP)
+ argument_table['html'] = BodyArgument('html', 'Html', help_text=HTML_HELP)
def _build_destination(params, key, value):
@@ -88,11 +97,21 @@ def _build_message(params, key, value):
class AddressesArgument(CustomArgument):
-
- def __init__(self, name, json_key, help_text='', dest=None, default=None,
- action=None, required=None, choices=None, cli_type_name=None):
- super(AddressesArgument, self).__init__(name=name, help_text=help_text,
- required=required, nargs='+')
+ def __init__(
+ self,
+ name,
+ json_key,
+ help_text='',
+ dest=None,
+ default=None,
+ action=None,
+ required=None,
+ choices=None,
+ cli_type_name=None,
+ ):
+ super().__init__(
+ name=name, help_text=help_text, required=required, nargs='+'
+ )
self._json_key = json_key
def add_to_params(self, parameters, value):
@@ -101,13 +120,12 @@ def add_to_params(self, parameters, value):
class BodyArgument(CustomArgument):
-
def __init__(self, name, json_key, help_text='', required=None):
- super(BodyArgument, self).__init__(name=name, help_text=help_text,
- required=required)
+ super().__init__(
+ name=name, help_text=help_text, required=required
+ )
self._json_key = json_key
def add_to_params(self, parameters, value):
if value:
_build_message(parameters, self._json_key, value)
-
diff --git a/awscli/customizations/sessionmanager.py b/awscli/customizations/sessionmanager.py
index cfbffe22a298..f5c29fcb8010 100644
--- a/awscli/customizations/sessionmanager.py
+++ b/awscli/customizations/sessionmanager.py
@@ -10,15 +10,15 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
-import logging
-import json
import errno
+import json
+import logging
import os
import re
-
from subprocess import check_call, check_output
+
+from awscli.clidriver import CLIOperationCaller, ServiceOperation
from awscli.compat import ignore_user_entered_signals
-from awscli.clidriver import ServiceOperation, CLIOperationCaller
logger = logging.getLogger(__name__)
@@ -26,13 +26,14 @@
'SessionManagerPlugin is not found. ',
'Please refer to SessionManager Documentation here: ',
'http://docs.aws.amazon.com/console/systems-manager/',
- 'session-manager-plugin-not-found'
+ 'session-manager-plugin-not-found',
)
def register_ssm_session(event_handlers):
- event_handlers.register('building-command-table.ssm',
- add_custom_start_session)
+ event_handlers.register(
+ 'building-command-table.ssm', add_custom_start_session
+ )
def add_custom_start_session(session, command_table, **kwargs):
@@ -40,8 +41,9 @@ def add_custom_start_session(session, command_table, **kwargs):
name='start-session',
parent_name='ssm',
session=session,
- operation_model=session.get_service_model(
- 'ssm').operation_model('StartSession'),
+ operation_model=session.get_service_model('ssm').operation_model(
+ 'StartSession'
+ ),
operation_caller=StartSessionCaller(session),
)
@@ -84,8 +86,7 @@ def _normalize(self, v1, v2):
class StartSessionCommand(ServiceOperation):
def create_help_command(self):
- help_command = super(
- StartSessionCommand, self).create_help_command()
+ help_command = super().create_help_command()
# Change the output shape because the command provides no output.
self._operation_model.output_shape = None
return help_command
@@ -95,12 +96,13 @@ class StartSessionCaller(CLIOperationCaller):
LAST_PLUGIN_VERSION_WITHOUT_ENV_VAR = "1.2.497.0"
DEFAULT_SSM_ENV_NAME = "AWS_SSM_START_SESSION_RESPONSE"
- def invoke(self, service_name, operation_name, parameters,
- parsed_globals):
+ def invoke(self, service_name, operation_name, parameters, parsed_globals):
client = self._session.create_client(
- service_name, region_name=parsed_globals.region,
+ service_name,
+ region_name=parsed_globals.region,
endpoint_url=parsed_globals.endpoint_url,
- verify=parsed_globals.verify_ssl)
+ verify=parsed_globals.verify_ssl,
+ )
response = client.start_session(**parameters)
session_id = response['SessionId']
region_name = client.meta.region_name
@@ -108,8 +110,11 @@ def invoke(self, service_name, operation_name, parameters,
# to fetch same profile credentials to make an api call in the plugin.
# If --profile flag is configured, pass it to Session Manager plugin.
# If not, set empty string.
- profile_name = parsed_globals.profile \
- if parsed_globals.profile is not None else ''
+ profile_name = (
+ parsed_globals.profile
+ if parsed_globals.profile is not None
+ else ''
+ )
endpoint_url = client.meta.endpoint_url
ssm_env_name = self.DEFAULT_SSM_ENV_NAME
@@ -147,19 +152,25 @@ def invoke(self, service_name, operation_name, parameters,
# and handling in there
with ignore_user_entered_signals():
# call executable with necessary input
- check_call(["session-manager-plugin",
- start_session_response,
- region_name,
- "StartSession",
- profile_name,
- json.dumps(parameters),
- endpoint_url], env=env)
+ check_call(
+ [
+ "session-manager-plugin",
+ start_session_response,
+ region_name,
+ "StartSession",
+ profile_name,
+ json.dumps(parameters),
+ endpoint_url,
+ ],
+ env=env,
+ )
return 0
except OSError as ex:
if ex.errno == errno.ENOENT:
- logger.debug('SessionManagerPlugin is not present',
- exc_info=True)
+ logger.debug(
+ 'SessionManagerPlugin is not present', exc_info=True
+ )
# start-session api call returns response and starts the
# session on ssm-agent and response is forwarded to
# session-manager-plugin. If plugin is not present, terminate
diff --git a/awscli/customizations/streamingoutputarg.py b/awscli/customizations/streamingoutputarg.py
index 2cba59a03ff4..0eea2ca79214 100644
--- a/awscli/customizations/streamingoutputarg.py
+++ b/awscli/customizations/streamingoutputarg.py
@@ -15,8 +15,9 @@
from awscli.arguments import BaseCLIArgument
-def add_streaming_output_arg(argument_table, operation_model,
- session, **kwargs):
+def add_streaming_output_arg(
+ argument_table, operation_model, session, **kwargs
+):
# Implementation detail: hooked up to 'building-argument-table'
# event.
if _has_streaming_output(operation_model):
@@ -24,7 +25,9 @@ def add_streaming_output_arg(argument_table, operation_model,
argument_table['outfile'] = StreamingOutputArgument(
response_key=streaming_argument_name,
operation_model=operation_model,
- session=session, name='outfile')
+ session=session,
+ name='outfile',
+ )
def _has_streaming_output(model):
@@ -36,15 +39,16 @@ def _get_streaming_argument_name(model):
class StreamingOutputArgument(BaseCLIArgument):
-
BUFFER_SIZE = 32768
HELP = 'Filename where the content will be saved'
- def __init__(self, response_key, operation_model, name,
- session, buffer_size=None):
+ def __init__(
+ self, response_key, operation_model, name, session, buffer_size=None
+ ):
self._name = name
- self.argument_model = Shape('StreamingOutputArgument',
- {'type': 'string'})
+ self.argument_model = Shape(
+ 'StreamingOutputArgument', {'type': 'string'}
+ )
if buffer_size is None:
buffer_size = self.BUFFER_SIZE
self._buffer_size = buffer_size
@@ -81,15 +85,15 @@ def documentation(self):
return self.HELP
def add_to_parser(self, parser):
- parser.add_argument(self._name, metavar=self.py_name,
- help=self.HELP)
+ parser.add_argument(self._name, metavar=self.py_name, help=self.HELP)
def add_to_params(self, parameters, value):
self._output_file = value
service_id = self._operation_model.service_model.service_id.hyphenize()
operation_name = self._operation_model.name
- self._session.register('after-call.%s.%s' % (
- service_id, operation_name), self.save_file)
+ self._session.register(
+ f'after-call.{service_id}.{operation_name}', self.save_file
+ )
def save_file(self, parsed, **kwargs):
if self._response_key not in parsed:
diff --git a/awscli/customizations/timestampformat.py b/awscli/customizations/timestampformat.py
index d7e1987b1fd1..b2f094a5decd 100644
--- a/awscli/customizations/timestampformat.py
+++ b/awscli/customizations/timestampformat.py
@@ -27,8 +27,10 @@
in the future.
"""
-from botocore.utils import parse_timestamp
+
from botocore.exceptions import ProfileNotFound
+from botocore.utils import parse_timestamp
+
from awscli.customizations.exceptions import ConfigurationError
@@ -72,7 +74,7 @@ def add_timestamp_parser(session, **kwargs):
timestamp_parser = iso_format
else:
raise ConfigurationError(
- 'Unknown cli_timestamp_format value: %s, valid values'
- ' are "wire" or "iso8601"' % timestamp_format
+ f'Unknown cli_timestamp_format value: {timestamp_format}, valid values'
+ ' are "wire" or "iso8601"'
)
factory.set_parser_defaults(timestamp_parser=timestamp_parser)
diff --git a/awscli/customizations/toplevelbool.py b/awscli/customizations/toplevelbool.py
index 8014d2dd98d5..22f15457a164 100644
--- a/awscli/customizations/toplevelbool.py
+++ b/awscli/customizations/toplevelbool.py
@@ -16,15 +16,14 @@
"""
+
import logging
from functools import partial
-
-from awscli.argprocess import detect_shape_structure
from awscli import arguments
-from awscli.customizations.utils import validate_mutually_exclusive_handler
+from awscli.argprocess import detect_shape_structure
from awscli.customizations.exceptions import ParamValidationError
-
+from awscli.customizations.utils import validate_mutually_exclusive_handler
LOG = logging.getLogger(__name__)
# This sentinel object is used to distinguish when
@@ -34,17 +33,20 @@
def register_bool_params(event_handler):
- event_handler.register('building-argument-table.ec2.*',
- partial(pull_up_bool,
- event_handler=event_handler))
+ event_handler.register(
+ 'building-argument-table.ec2.*',
+ partial(pull_up_bool, event_handler=event_handler),
+ )
def _qualifies_for_simplification(arg_model):
if detect_shape_structure(arg_model) == 'structure(scalar)':
members = arg_model.members
- if (len(members) == 1 and
- list(members.keys())[0] == 'Value' and
- list(members.values())[0].type_name == 'boolean'):
+ if (
+ len(members) == 1
+ and list(members.keys())[0] == 'Value'
+ and list(members.values())[0].type_name == 'boolean'
+ ):
return True
return False
@@ -56,8 +58,8 @@ def pull_up_bool(argument_table, event_handler, **kwargs):
boolean_pairs = []
event_handler.register(
'operation-args-parsed.ec2.*',
- partial(validate_boolean_mutex_groups,
- boolean_pairs=boolean_pairs))
+ partial(validate_boolean_mutex_groups, boolean_pairs=boolean_pairs),
+ )
for value in list(argument_table.values()):
if hasattr(value, 'argument_model'):
arg_model = value.argument_model
@@ -66,18 +68,25 @@ def pull_up_bool(argument_table, event_handler, **kwargs):
# one that supports --option and --option
# and another arg of --no-option.
new_arg = PositiveBooleanArgument(
- value.name, arg_model, value._operation_model,
+ value.name,
+ arg_model,
+ value._operation_model,
value._event_emitter,
group_name=value.name,
- serialized_name=value._serialized_name)
+ serialized_name=value._serialized_name,
+ )
argument_table[value.name] = new_arg
- negative_name = 'no-%s' % value.name
+ negative_name = f'no-{value.name}'
negative_arg = NegativeBooleanParameter(
- negative_name, arg_model, value._operation_model,
+ negative_name,
+ arg_model,
+ value._operation_model,
value._event_emitter,
- action='store_true', dest='no_%s' % new_arg.py_name,
+ action='store_true',
+ dest=f'no_{new_arg.py_name}',
group_name=value.name,
- serialized_name=value._serialized_name)
+ serialized_name=value._serialized_name,
+ )
argument_table[negative_name] = negative_arg
# If we've pulled up a structure(scalar) arg
# into a pair of top level boolean args, we need
@@ -90,19 +99,33 @@ def pull_up_bool(argument_table, event_handler, **kwargs):
def validate_boolean_mutex_groups(boolean_pairs, parsed_args, **kwargs):
# Validate we didn't pass in an --option and a --no-option.
for positive, negative in boolean_pairs:
- if getattr(parsed_args, positive.py_name) is not _NOT_SPECIFIED and \
- getattr(parsed_args, negative.py_name) is not _NOT_SPECIFIED:
+ if (
+ getattr(parsed_args, positive.py_name) is not _NOT_SPECIFIED
+ and getattr(parsed_args, negative.py_name) is not _NOT_SPECIFIED
+ ):
raise ParamValidationError(
- 'Cannot specify both the "%s" option and '
- 'the "%s" option.' % (positive.cli_name, negative.cli_name))
+ f'Cannot specify both the "{positive.cli_name}" option and '
+ f'the "{negative.cli_name}" option.'
+ )
class PositiveBooleanArgument(arguments.CLIArgument):
- def __init__(self, name, argument_model, operation_model,
- event_emitter, serialized_name, group_name):
- super(PositiveBooleanArgument, self).__init__(
- name, argument_model, operation_model, event_emitter,
- serialized_name=serialized_name)
+ def __init__(
+ self,
+ name,
+ argument_model,
+ operation_model,
+ event_emitter,
+ serialized_name,
+ group_name,
+ ):
+ super().__init__(
+ name,
+ argument_model,
+ operation_model,
+ event_emitter,
+ serialized_name=serialized_name,
+ )
self._group_name = group_name
@property
@@ -113,11 +136,13 @@ def add_to_parser(self, parser):
# We need to support three forms:
# --option-name
# --option-name Value=(true|false)
- parser.add_argument(self.cli_name,
- help=self.documentation,
- action='store',
- default=_NOT_SPECIFIED,
- nargs='?')
+ parser.add_argument(
+ self.cli_name,
+ help=self.documentation,
+ action='store',
+ default=_NOT_SPECIFIED,
+ nargs='?',
+ )
def add_to_params(self, parameters, value):
if value is _NOT_SPECIFIED:
@@ -131,17 +156,29 @@ def add_to_params(self, parameters, value):
parameters[self._serialized_name] = {'Value': True}
else:
# Otherwise the arg was specified with a value.
- parameters[self._serialized_name] = self._unpack_argument(
- value)
+ parameters[self._serialized_name] = self._unpack_argument(value)
class NegativeBooleanParameter(arguments.BooleanArgument):
- def __init__(self, name, argument_model, operation_model,
- event_emitter, serialized_name, action='store_true',
- dest=None, group_name=None):
- super(NegativeBooleanParameter, self).__init__(
- name, argument_model, operation_model, event_emitter,
- default=_NOT_SPECIFIED, serialized_name=serialized_name)
+ def __init__(
+ self,
+ name,
+ argument_model,
+ operation_model,
+ event_emitter,
+ serialized_name,
+ action='store_true',
+ dest=None,
+ group_name=None,
+ ):
+ super().__init__(
+ name,
+ argument_model,
+ operation_model,
+ event_emitter,
+ default=_NOT_SPECIFIED,
+ serialized_name=serialized_name,
+ )
self._group_name = group_name
def add_to_params(self, parameters, value):
diff --git a/awscli/customizations/translate.py b/awscli/customizations/translate.py
index 38add1564dc1..f398dd94183b 100644
--- a/awscli/customizations/translate.py
+++ b/awscli/customizations/translate.py
@@ -12,10 +12,10 @@
# language governing permissions and limitations under the License.
import copy
-from awscli.arguments import CustomArgument, CLIArgument
+from awscli.arguments import CLIArgument, CustomArgument
from awscli.customizations.binaryhoist import (
- BinaryBlobArgumentHoister,
ArgumentParameters,
+ BinaryBlobArgumentHoister,
)
FILE_DOCSTRING = (
@@ -41,22 +41,24 @@
def register_translate_import_terminology(cli):
- cli.register(
- "building-argument-table.translate.import-terminology",
- BinaryBlobArgumentHoister(
- new_argument=ArgumentParameters(
- name="data-file",
- help_text=FILE_DOCSTRING,
- required=True,
- ),
- original_argument=ArgumentParameters(
- name="terminology-data",
- member="File",
- required=False,
+ (
+ cli.register(
+ "building-argument-table.translate.import-terminology",
+ BinaryBlobArgumentHoister(
+ new_argument=ArgumentParameters(
+ name="data-file",
+ help_text=FILE_DOCSTRING,
+ required=True,
+ ),
+ original_argument=ArgumentParameters(
+ name="terminology-data",
+ member="File",
+ required=False,
+ ),
+ error_if_original_used=FILE_ERRORSTRING,
),
- error_if_original_used=FILE_ERRORSTRING,
),
- ),
+ )
cli.register(
"building-argument-table.translate.translate-document",
diff --git a/awscli/customizations/utils.py b/awscli/customizations/utils.py
index 2c281cf0e53e..60b9cd68919d 100644
--- a/awscli/customizations/utils.py
+++ b/awscli/customizations/utils.py
@@ -14,20 +14,19 @@
Utility functions to make it easier to work with customizations.
"""
+
import copy
import re
import sys
import xml
from botocore.exceptions import ClientError
-from awscli.customizations.exceptions import ParamValidationError
+from awscli.customizations.exceptions import ParamValidationError
_SENTENCE_DELIMETERS_REGEX = re.compile(r'[.:]+')
-_LINE_BREAK_CHARS = [
- '\n',
- '\u2028'
-]
+_LINE_BREAK_CHARS = ['\n', '\u2028']
+
def rename_argument(argument_table, existing_name, new_name):
current = argument_table[existing_name]
@@ -93,6 +92,7 @@ def alias_command(command_table, existing_name, new_name):
def validate_mutually_exclusive_handler(*groups):
def _handler(parsed_args, **kwargs):
return validate_mutually_exclusive(parsed_args, *groups)
+
return _handler
@@ -114,9 +114,9 @@ def validate_mutually_exclusive(parsed_args, *groups):
current_group = key_group
elif not key_group == current_group:
raise ParamValidationError(
- 'The key "%s" cannot be specified when one '
+ 'The key "{}" cannot be specified when one '
'of the following keys are also specified: '
- '%s' % (key, ', '.join(current_group))
+ '{}'.format(key, ', '.join(current_group))
)
@@ -140,8 +140,9 @@ def s3_bucket_exists(s3_client, bucket_name):
return bucket_exists
-def create_client_from_parsed_globals(session, service_name, parsed_globals,
- overrides=None):
+def create_client_from_parsed_globals(
+ session, service_name, parsed_globals, overrides=None
+):
"""Creates a service client, taking parsed_globals into account
Any values specified in overrides will override the returned dict. Note
@@ -197,8 +198,9 @@ def uni_print(statement, out_file=None):
# ``sys.stdout.encoding`` is ``None``.
if new_encoding is None:
new_encoding = 'ascii'
- new_statement = statement.encode(
- new_encoding, 'replace').decode(new_encoding)
+ new_statement = statement.encode(new_encoding, 'replace').decode(
+ new_encoding
+ )
out_file.write(new_statement)
out_file.flush()
@@ -237,7 +239,7 @@ def _strip_xml_from_documentation(documentation):
# to make sure the dom parser will look at all elements in the
# docstring as some docstrings may not have xml nodes that do
# not all belong to the same root node.
- xml_doc = '%s' % documentation
+ xml_doc = f'{documentation}'
xml_dom = xml.dom.minidom.parseString(xml_doc)
except xml.parsers.expat.ExpatError:
return documentation
diff --git a/awscli/customizations/waiters.py b/awscli/customizations/waiters.py
index dd90bd8aa0f8..b02d5e45fcbe 100644
--- a/awscli/customizations/waiters.py
+++ b/awscli/customizations/waiters.py
@@ -14,8 +14,11 @@
from botocore.exceptions import DataNotFoundError
from awscli.clidriver import ServiceOperation
-from awscli.customizations.commands import BasicCommand, BasicHelp, \
- BasicDocHandler
+from awscli.customizations.commands import (
+ BasicCommand,
+ BasicDocHandler,
+ BasicHelp,
+)
def register_add_waiters(cli):
@@ -29,15 +32,17 @@ def add_waiters(command_table, session, command_object, **kwargs):
service_model = getattr(command_object, 'service_model', None)
if service_model is not None:
# Get a client out of the service object.
- waiter_model = get_waiter_model_from_service_model(session,
- service_model)
+ waiter_model = get_waiter_model_from_service_model(
+ session, service_model
+ )
if waiter_model is None:
return
waiter_names = waiter_model.waiter_names
# If there are waiters make a wait command.
if waiter_names:
command_table['wait'] = WaitCommand(
- session, waiter_model, service_model)
+ session, waiter_model, service_model
+ )
def get_waiter_model_from_service_model(session, service_model):
@@ -50,9 +55,11 @@ def get_waiter_model_from_service_model(session, service_model):
class WaitCommand(BasicCommand):
NAME = 'wait'
- DESCRIPTION = ('Wait until a particular condition is satisfied. Each '
- 'subcommand polls an API until the listed requirement '
- 'is met.')
+ DESCRIPTION = (
+ 'Wait until a particular condition is satisfied. Each '
+ 'subcommand polls an API until the listed requirement '
+ 'is met.'
+ )
def __init__(self, session, waiter_model, service_model):
self._model = waiter_model
@@ -60,9 +67,9 @@ def __init__(self, session, waiter_model, service_model):
self.waiter_cmd_builder = WaiterStateCommandBuilder(
session=session,
model=self._model,
- service_model=self._service_model
+ service_model=self._service_model,
)
- super(WaitCommand, self).__init__(session)
+ super().__init__(session)
def _run_main(self, parsed_args, parsed_globals):
if parsed_args.subcommand is None:
@@ -70,19 +77,22 @@ def _run_main(self, parsed_args, parsed_globals):
return 0
def _build_subcommand_table(self):
- subcommand_table = super(WaitCommand, self)._build_subcommand_table()
+ subcommand_table = super()._build_subcommand_table()
self.waiter_cmd_builder.build_all_waiter_state_cmds(subcommand_table)
self._add_lineage(subcommand_table)
return subcommand_table
def create_help_command(self):
- return BasicHelp(self._session, self,
- command_table=self.subcommand_table,
- arg_table=self.arg_table,
- event_handler_class=WaiterCommandDocHandler)
+ return BasicHelp(
+ self._session,
+ self,
+ command_table=self.subcommand_table,
+ arg_table=self.arg_table,
+ event_handler_class=WaiterCommandDocHandler,
+ )
-class WaiterStateCommandBuilder(object):
+class WaiterStateCommandBuilder:
def __init__(self, session, model, service_model):
self._session = session
self._model = model
@@ -97,8 +107,9 @@ def build_all_waiter_state_cmds(self, subcommand_table):
waiter_names = self._model.waiter_names
for waiter_name in waiter_names:
waiter_cli_name = xform_name(waiter_name, '-')
- subcommand_table[waiter_cli_name] = \
- self._build_waiter_state_cmd(waiter_name)
+ subcommand_table[waiter_cli_name] = self._build_waiter_state_cmd(
+ waiter_name
+ )
def _build_waiter_state_cmd(self, waiter_name):
# Get the waiter
@@ -117,7 +128,8 @@ def _build_waiter_state_cmd(self, waiter_name):
operation_model = self._service_model.operation_model(operation_name)
waiter_state_command = WaiterStateCommand(
- name=waiter_cli_name, parent_name='wait',
+ name=waiter_cli_name,
+ parent_name='wait',
operation_caller=WaiterCaller(self._session, waiter_name),
session=self._session,
operation_model=operation_model,
@@ -131,13 +143,13 @@ def _build_waiter_state_cmd(self, waiter_name):
return waiter_state_command
-class WaiterStateDocBuilder(object):
+class WaiterStateDocBuilder:
SUCCESS_DESCRIPTIONS = {
- 'error': u'%s is thrown ',
- 'path': u'%s ',
- 'pathAll': u'%s for all elements ',
- 'pathAny': u'%s for any element ',
- 'status': u'%s response is received '
+ 'error': '%s is thrown ',
+ 'path': '%s ',
+ 'pathAll': '%s for all elements ',
+ 'pathAny': '%s for any element ',
+ 'status': '%s response is received ',
}
def __init__(self, waiter_config):
@@ -149,7 +161,7 @@ def build_waiter_state_description(self):
# description is provided, use a heuristic to generate a description
# for the waiter.
if not description:
- description = u'Wait until '
+ description = 'Wait until '
# Look at all of the acceptors and find the success state
# acceptor.
for acceptor in self._waiter_config.acceptors:
@@ -159,9 +171,11 @@ def build_waiter_state_description(self):
break
# Include what operation is being used.
description += self._build_operation_description(
- self._waiter_config.operation)
+ self._waiter_config.operation
+ )
description += self._build_polling_description(
- self._waiter_config.delay, self._waiter_config.max_attempts)
+ self._waiter_config.delay, self._waiter_config.max_attempts
+ )
return description
def _build_success_description(self, acceptor):
@@ -172,8 +186,9 @@ def _build_success_description(self, acceptor):
# If success is based off of the state of a resource include the
# description about what resource is looked at.
if matcher in ['path', 'pathAny', 'pathAll']:
- resource_description = u'JMESPath query %s returns ' % \
- acceptor.argument
+ resource_description = (
+ f'JMESPath query {acceptor.argument} returns '
+ )
# Prepend the resource description to the template description
success_description = resource_description + success_description
# Complete the description by filling in the expected success state.
@@ -182,27 +197,29 @@ def _build_success_description(self, acceptor):
def _build_operation_description(self, operation):
operation_name = xform_name(operation).replace('_', '-')
- return u'when polling with ``%s``.' % operation_name
+ return f'when polling with ``{operation_name}``.'
def _build_polling_description(self, delay, max_attempts):
description = (
- ' It will poll every %s seconds until a successful state '
+ f' It will poll every {delay} seconds until a successful state '
'has been reached. This will exit with a return code of 255 '
- 'after %s failed checks.'
- % (delay, max_attempts))
+ f'after {max_attempts} failed checks.'
+ )
return description
-class WaiterCaller(object):
+class WaiterCaller:
def __init__(self, session, waiter_name):
self._session = session
self._waiter_name = waiter_name
def invoke(self, service_name, operation_name, parameters, parsed_globals):
client = self._session.create_client(
- service_name, region_name=parsed_globals.region,
+ service_name,
+ region_name=parsed_globals.region,
endpoint_url=parsed_globals.endpoint_url,
- verify=parsed_globals.verify_ssl)
+ verify=parsed_globals.verify_ssl,
+ )
waiter = client.get_waiter(xform_name(self._waiter_name))
waiter.wait(**parameters)
return 0
@@ -212,7 +229,7 @@ class WaiterStateCommand(ServiceOperation):
DESCRIPTION = ''
def create_help_command(self):
- help_command = super(WaiterStateCommand, self).create_help_command()
+ help_command = super().create_help_command()
# Change the operation object's description by changing it to the
# description for a waiter state command.
self._operation_model.documentation = self.DESCRIPTION
diff --git a/awscli/data/metadata.json b/awscli/data/metadata.json
index ed95c3da54fa..d2763dbe39ee 100644
--- a/awscli/data/metadata.json
+++ b/awscli/data/metadata.json
@@ -1,3 +1,3 @@
{
"distribution_source": "source"
-}
\ No newline at end of file
+}
diff --git a/awscli/paramfile.py b/awscli/paramfile.py
index da5307f214f6..f7c26d7f4f70 100644
--- a/awscli/paramfile.py
+++ b/awscli/paramfile.py
@@ -94,4 +94,4 @@ def get_file(prefix, path, mode):
LOCAL_PREFIX_MAP = {
'file://': (get_file, {'mode': 'r'}),
'fileb://': (get_file, {'mode': 'rb'}),
-}
\ No newline at end of file
+}