From e7ebda6f69ef806042b6febf4e37f03561457514 Mon Sep 17 00:00:00 2001 From: Kenneth Daily Date: Fri, 20 Dec 2024 09:36:31 -0800 Subject: [PATCH 1/6] Basic precommit fixes --- awscli/clidriver.py | 4 ++-- awscli/customizations/sessendemail.py | 1 - awscli/data/metadata.json | 2 +- awscli/paramfile.py | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) 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/sessendemail.py b/awscli/customizations/sessendemail.py index 8215342982bf..938bb0d3ff5e 100644 --- a/awscli/customizations/sessendemail.py +++ b/awscli/customizations/sessendemail.py @@ -110,4 +110,3 @@ def __init__(self, name, json_key, help_text='', required=None): def add_to_params(self, parameters, value): if value: _build_message(parameters, self._json_key, value) - 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 +} From 1e6a6b5f1f71c754b94ce44085b5ab12d28b0217 Mon Sep 17 00:00:00 2001 From: Kenneth Daily Date: Fri, 20 Dec 2024 09:37:00 -0800 Subject: [PATCH 2/6] Run isort --- awscli/autocomplete/autogen.py | 3 +-- awscli/autocomplete/custom.py | 6 ++++-- awscli/autocomplete/db.py | 3 +-- awscli/autocomplete/generator.py | 4 ++-- awscli/autocomplete/main.py | 6 ++---- awscli/autoprompt/core.py | 6 +++--- awscli/autoprompt/doc.py | 1 + awscli/autoprompt/factory.py | 25 +++++++++++----------- awscli/autoprompt/history.py | 5 ++--- awscli/autoprompt/logger.py | 2 +- awscli/autoprompt/output.py | 5 ++--- awscli/autoprompt/prompttoolkit.py | 10 ++++----- awscli/autoprompt/widgets.py | 22 +++++++++---------- awscli/bcdoc/restdoc.py | 1 + awscli/customizations/addexamples.py | 3 +-- awscli/customizations/argrename.py | 1 - awscli/customizations/arguments.py | 3 ++- awscli/customizations/assumerole.py | 4 ++-- awscli/customizations/awslambda.py | 7 +++--- awscli/customizations/binaryhoist.py | 4 ++-- awscli/customizations/cliinput.py | 2 +- awscli/customizations/cloudfront.py | 7 +++--- awscli/customizations/cloudsearch.py | 5 +++-- awscli/customizations/cloudsearchdomain.py | 1 + awscli/customizations/codecommit.py | 9 ++++---- awscli/customizations/commands.py | 6 +++--- awscli/customizations/ecr.py | 6 +++--- awscli/customizations/ecr_public.py | 6 +++--- awscli/customizations/globalargs.py | 4 ++-- awscli/customizations/iamvirtmfa.py | 7 +++--- awscli/customizations/opsworks.py | 5 ++--- awscli/customizations/paginate.py | 3 +-- awscli/customizations/putmetricdata.py | 2 +- awscli/customizations/rds.py | 3 +-- awscli/customizations/s3events.py | 1 - awscli/customizations/s3uploader.py | 2 +- awscli/customizations/sessendemail.py | 3 +-- awscli/customizations/sessionmanager.py | 8 +++---- awscli/customizations/timestampformat.py | 3 ++- awscli/customizations/toplevelbool.py | 6 ++---- awscli/customizations/translate.py | 8 +++---- awscli/customizations/utils.py | 2 +- awscli/customizations/waiters.py | 4 ++-- 43 files changed, 105 insertions(+), 119 deletions(-) diff --git a/awscli/autocomplete/autogen.py b/awscli/autocomplete/autogen.py index 5ac01d266ecb..83de4635b946 100644 --- a/awscli/autocomplete/autogen.py +++ b/awscli/autocomplete/autogen.py @@ -6,9 +6,8 @@ """ 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', diff --git a/awscli/autocomplete/custom.py b/awscli/autocomplete/custom.py index d9ea75c25e3f..dce40bacbf88 100644 --- a/awscli/autocomplete/custom.py +++ b/awscli/autocomplete/custom.py @@ -10,8 +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.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..d73c688799d1 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 diff --git a/awscli/autocomplete/generator.py b/awscli/autocomplete/generator.py index 733fd505e546..5c2ef6bce879 100644 --- a/awscli/autocomplete/generator.py +++ b/awscli/autocomplete/generator.py @@ -13,10 +13,10 @@ """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): diff --git a/awscli/autocomplete/main.py b/awscli/autocomplete/main.py index 8055768a1bd8..f6bb05203449 100644 --- a/awscli/autocomplete/main.py +++ b/awscli/autocomplete/main.py @@ -16,10 +16,8 @@ # 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, diff --git a/awscli/autoprompt/core.py b/awscli/autoprompt/core.py index 3b0bb900e47f..921141d328be 100644 --- a/awscli/autoprompt/core.py +++ b/awscli/autoprompt/core.py @@ -12,10 +12,10 @@ # 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 diff --git a/awscli/autoprompt/doc.py b/awscli/autoprompt/doc.py index 12933cca0eec..a269d4067fe5 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 diff --git a/awscli/autoprompt/factory.py b/awscli/autoprompt/factory.py index 1b35f4b88d66..508a3ee93e13 100644 --- a/awscli/autoprompt/factory.py +++ b/awscli/autoprompt/factory.py @@ -15,24 +15,25 @@ 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 -) +from awscli.autoprompt.filters import (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) class PrompterKeyboardInterrupt(KeyboardInterrupt): diff --git a/awscli/autoprompt/history.py b/awscli/autoprompt/history.py index 1a2c6dc6cf3f..4ea50942214d 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__) diff --git a/awscli/autoprompt/logger.py b/awscli/autoprompt/logger.py index 1a5653a09f75..9283e7f99188 100644 --- a/awscli/autoprompt/logger.py +++ b/awscli/autoprompt/logger.py @@ -12,8 +12,8 @@ # 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): diff --git a/awscli/autoprompt/output.py b/awscli/autoprompt/output.py index 01528ca181d9..c931948611de 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__) diff --git a/awscli/autoprompt/prompttoolkit.py b/awscli/autoprompt/prompttoolkit.py index b7e81f364df7..9b115924feb5 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__) diff --git a/awscli/autoprompt/widgets.py b/awscli/autoprompt/widgets.py index cfd4adefc556..488922d80132 100644 --- a/awscli/autoprompt/widgets.py +++ b/awscli/autoprompt/widgets.py @@ -14,28 +14,26 @@ 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 -) +from prompt_toolkit.widgets import (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, -) +from awscli.autoprompt.filters import (doc_window_has_focus, + help_section_visible, + input_buffer_has_focus, is_debug_mode, + is_history_mode, search_input_has_focus) class FormatTextProcessor(Processor): diff --git a/awscli/bcdoc/restdoc.py b/awscli/bcdoc/restdoc.py index d194d0e9f0ac..d5df92845e98 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 diff --git a/awscli/customizations/addexamples.py b/awscli/customizations/addexamples.py index db34371adfdd..e21dd53a3715 100644 --- a/awscli/customizations/addexamples.py +++ b/awscli/customizations/addexamples.py @@ -26,9 +26,8 @@ For example, ``examples/ec2/ec2-create-key-pair.rst``. """ -import os import logging - +import os LOG = logging.getLogger(__name__) diff --git a/awscli/customizations/argrename.py b/awscli/customizations/argrename.py index eb905df769a9..d5ab60e1073d 100644 --- a/awscli/customizations/argrename.py +++ b/awscli/customizations/argrename.py @@ -15,7 +15,6 @@ from awscli.customizations import utils - ARGUMENT_RENAMES = { # Mapping of original arg to renamed arg. # The key is ..argname diff --git a/awscli/customizations/arguments.py b/awscli/customizations/arguments.py index 43ec260a7aa4..48c63436edfe 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): diff --git a/awscli/customizations/assumerole.py b/awscli/customizations/assumerole.py index b25a80b2def6..0a997e3518e4 100644 --- a/awscli/customizations/assumerole.py +++ b/awscli/customizations/assumerole.py @@ -1,8 +1,8 @@ -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')) diff --git a/awscli/customizations/awslambda.py b/awscli/customizations/awslambda.py index 121488ef18ed..1e7138478b83 100644 --- a/awscli/customizations/awslambda.py +++ b/awscli/customizations/awslambda.py @@ -10,14 +10,13 @@ # 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" 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..2a5b92d691ba 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): diff --git a/awscli/customizations/cloudfront.py b/awscli/customizations/cloudfront.py index 6c02bf260dbe..2939a9c51cc6 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): diff --git a/awscli/customizations/cloudsearch.py b/awscli/customizations/cloudsearch.py index 8ea8f0a5f265..9c2d245878ff 100644 --- a/awscli/customizations/cloudsearch.py +++ b/awscli/customizations/cloudsearch.py @@ -13,10 +13,11 @@ 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 = { diff --git a/awscli/customizations/cloudsearchdomain.py b/awscli/customizations/cloudsearchdomain.py index 9a6b16610a6e..5a4ef7a81bfb 100644 --- a/awscli/customizations/cloudsearchdomain.py +++ b/awscli/customizations/cloudsearchdomain.py @@ -19,6 +19,7 @@ """ from awscli.customizations.exceptions import ParamValidationError + def register_cloudsearchdomain(cli): cli.register_last('calling-command.cloudsearchdomain', validate_endpoint_url) diff --git a/awscli/customizations/codecommit.py b/awscli/customizations/codecommit.py index 6b30e834f67f..2baa1c55008f 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') diff --git a/awscli/customizations/commands.py b/awscli/customizations/commands.py index 55722888704e..5466bffdd686 100644 --- a/awscli/customizations/commands.py +++ b/awscli/customizations/commands.py @@ -1,5 +1,5 @@ -import logging import copy +import logging import os from botocore import model @@ -10,13 +10,13 @@ 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 diff --git a/awscli/customizations/ecr.py b/awscli/customizations/ecr.py index 71e7abe19b51..10a4e3769d4e 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) diff --git a/awscli/customizations/ecr_public.py b/awscli/customizations/ecr_public.py index 01a5458907a2..9d5ed84371e9 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) diff --git a/awscli/customizations/globalargs.py b/awscli/customizations/globalargs.py index 3a84223f93ce..1646fe9eec59 100644 --- a/awscli/customizations/globalargs.py +++ b/awscli/customizations/globalargs.py @@ -10,13 +10,13 @@ # 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 diff --git a/awscli/customizations/iamvirtmfa.py b/awscli/customizations/iamvirtmfa.py index c0ee3582d6b4..745e5c99f10c 100644 --- a/awscli/customizations/iamvirtmfa.py +++ b/awscli/customizations/iamvirtmfa.py @@ -24,10 +24,9 @@ """ 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 - +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 ' diff --git a/awscli/customizations/opsworks.py b/awscli/customizations/opsworks.py index e91d47896fd9..a30b259a8dce 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__) diff --git a/awscli/customizations/paginate.py b/awscli/customizations/paginate.py index 77b0f3362ec2..69a40e5321fe 100644 --- a/awscli/customizations/paginate.py +++ b/awscli/customizations/paginate.py @@ -27,9 +27,8 @@ 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 diff --git a/awscli/customizations/putmetricdata.py b/awscli/customizations/putmetricdata.py index 10ef322b2323..366af9625519 100644 --- a/awscli/customizations/putmetricdata.py +++ b/awscli/customizations/putmetricdata.py @@ -26,8 +26,8 @@ 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): diff --git a/awscli/customizations/rds.py b/awscli/customizations/rds.py index cac3173f3f76..6a57ccbcb6bd 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 diff --git a/awscli/customizations/s3events.py b/awscli/customizations/s3events.py index 122c4ca14be7..0b51ff85bc54 100644 --- a/awscli/customizations/s3events.py +++ b/awscli/customizations/s3events.py @@ -13,7 +13,6 @@ """Add S3 specific event streaming output arg.""" from awscli.arguments import CustomArgument - STREAM_HELP_TEXT = 'Filename where the records will be saved' diff --git a/awscli/customizations/s3uploader.py b/awscli/customizations/s3uploader.py index e640b94ba55a..101890db6ac3 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 diff --git a/awscli/customizations/sessendemail.py b/awscli/customizations/sessendemail.py index 938bb0d3ff5e..438aac16a5bf 100644 --- a/awscli/customizations/sessendemail.py +++ b/awscli/customizations/sessendemail.py @@ -22,11 +22,10 @@ """ -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). ' diff --git a/awscli/customizations/sessionmanager.py b/awscli/customizations/sessionmanager.py index cfbffe22a298..c7fa8f17635a 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__) diff --git a/awscli/customizations/timestampformat.py b/awscli/customizations/timestampformat.py index d7e1987b1fd1..7d1e8743ec8f 100644 --- a/awscli/customizations/timestampformat.py +++ b/awscli/customizations/timestampformat.py @@ -27,8 +27,9 @@ 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 diff --git a/awscli/customizations/toplevelbool.py b/awscli/customizations/toplevelbool.py index 8014d2dd98d5..b252c87f621c 100644 --- a/awscli/customizations/toplevelbool.py +++ b/awscli/customizations/toplevelbool.py @@ -19,12 +19,10 @@ 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 diff --git a/awscli/customizations/translate.py b/awscli/customizations/translate.py index 38add1564dc1..9f66c1ab23ce 100644 --- a/awscli/customizations/translate.py +++ b/awscli/customizations/translate.py @@ -12,11 +12,9 @@ # language governing permissions and limitations under the License. import copy -from awscli.arguments import CustomArgument, CLIArgument -from awscli.customizations.binaryhoist import ( - BinaryBlobArgumentHoister, - ArgumentParameters, -) +from awscli.arguments import CLIArgument, CustomArgument +from awscli.customizations.binaryhoist import (ArgumentParameters, + BinaryBlobArgumentHoister) FILE_DOCSTRING = ( "

The path to the file of the code you are uploading. " diff --git a/awscli/customizations/utils.py b/awscli/customizations/utils.py index 2c281cf0e53e..dc3da3a7fa80 100644 --- a/awscli/customizations/utils.py +++ b/awscli/customizations/utils.py @@ -20,8 +20,8 @@ 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 = [ diff --git a/awscli/customizations/waiters.py b/awscli/customizations/waiters.py index dd90bd8aa0f8..da00b6a3ada0 100644 --- a/awscli/customizations/waiters.py +++ b/awscli/customizations/waiters.py @@ -14,8 +14,8 @@ 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): From 7be84544c5854e3c67cbc507bb47a4a773812adf Mon Sep 17 00:00:00 2001 From: Kenneth Daily Date: Fri, 20 Dec 2024 09:40:19 -0800 Subject: [PATCH 3/6] Run ruff format --- awscli/autocomplete/__init__.py | 15 +- awscli/autocomplete/autogen.py | 137 ++++++---- awscli/autocomplete/completer.py | 34 ++- awscli/autocomplete/custom.py | 10 +- awscli/autocomplete/db.py | 8 +- awscli/autocomplete/filters.py | 31 ++- awscli/autocomplete/generator.py | 2 + awscli/autocomplete/main.py | 26 +- awscli/autocomplete/parser.py | 87 ++++-- awscli/autoprompt/core.py | 15 +- awscli/autoprompt/doc.py | 9 +- awscli/autoprompt/factory.py | 158 ++++++----- awscli/autoprompt/filters.py | 4 +- awscli/autoprompt/history.py | 22 +- awscli/autoprompt/logger.py | 1 - awscli/autoprompt/output.py | 23 +- awscli/autoprompt/prompttoolkit.py | 111 +++++--- awscli/autoprompt/widgets.py | 144 ++++++---- awscli/bcdoc/docevents.py | 144 ++++++---- awscli/bcdoc/docstringparser.py | 3 + awscli/bcdoc/restdoc.py | 6 +- awscli/bcdoc/style.py | 2 - awscli/bcdoc/textwriter.py | 51 ++-- awscli/customizations/addexamples.py | 35 +-- awscli/customizations/argrename.py | 33 +-- awscli/customizations/arguments.py | 46 ++-- awscli/customizations/assumerole.py | 16 +- awscli/customizations/awslambda.py | 35 ++- awscli/customizations/cliinput.py | 11 +- awscli/customizations/cloudfront.py | 141 ++++++---- awscli/customizations/cloudsearch.py | 92 ++++--- awscli/customizations/cloudsearchdomain.py | 6 +- awscli/customizations/codecommit.py | 89 ++++--- awscli/customizations/commands.py | 102 +++++--- awscli/customizations/devcommands.py | 5 +- awscli/customizations/dsql.py | 73 ++++-- awscli/customizations/ecr.py | 9 +- awscli/customizations/ecr_public.py | 9 +- awscli/customizations/flatten.py | 49 +++- awscli/customizations/generatecliskeleton.py | 60 +++-- awscli/customizations/globalargs.py | 33 ++- awscli/customizations/iamvirtmfa.py | 39 ++- awscli/customizations/iot.py | 32 ++- awscli/customizations/iot_data.py | 3 +- awscli/customizations/opsworks.py | 262 ++++++++++++------- awscli/customizations/paginate.py | 186 ++++++++----- awscli/customizations/putmetricdata.py | 61 +++-- awscli/customizations/quicksight.py | 10 +- awscli/customizations/rds.py | 64 +++-- awscli/customizations/rekognition.py | 32 ++- awscli/customizations/removals.py | 113 +++++--- awscli/customizations/route53.py | 3 +- awscli/customizations/s3errormsg.py | 15 +- awscli/customizations/s3events.py | 42 +-- awscli/customizations/s3uploader.py | 77 +++--- awscli/customizations/sessendemail.py | 78 ++++-- awscli/customizations/sessionmanager.py | 55 ++-- awscli/customizations/streamingoutputarg.py | 28 +- awscli/customizations/timestampformat.py | 1 + awscli/customizations/toplevelbool.py | 103 +++++--- awscli/customizations/translate.py | 36 +-- awscli/customizations/utils.py | 18 +- awscli/customizations/waiters.py | 79 +++--- 63 files changed, 2023 insertions(+), 1201 deletions(-) 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 83de4635b946..6f5792399a22 100644 --- a/awscli/autocomplete/autogen.py +++ b/awscli/autocomplete/autogen.py @@ -5,13 +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 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): @@ -25,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. @@ -47,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 { @@ -60,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) @@ -96,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( @@ -113,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): @@ -138,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 @@ -173,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 @@ -186,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()) @@ -248,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 dce40bacbf88..6deee16eedff 100644 --- a/awscli/autocomplete/custom.py +++ b/awscli/autocomplete/custom.py @@ -10,10 +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 d73c688799d1..3b41f4082468 100644 --- a/awscli/autocomplete/db.py +++ b/awscli/autocomplete/db.py @@ -13,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', ) @@ -33,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 5c2ef6bce879..4b228b49a466 100644 --- a/awscli/autocomplete/generator.py +++ b/awscli/autocomplete/generator.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. """Generates auto completion index.""" + import os from awscli import clidriver @@ -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 f6bb05203449..6a1ae444767a 100644 --- a/awscli/autocomplete/main.py +++ b/awscli/autocomplete/main.py @@ -20,8 +20,12 @@ 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: @@ -34,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 921141d328be..47d9b5d54a78 100644 --- a/awscli/autoprompt/core.py +++ b/awscli/autoprompt/core.py @@ -20,7 +20,6 @@ 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 a269d4067fe5..38d866df50f3 100644 --- a/awscli/autoprompt/doc.py +++ b/awscli/autoprompt/doc.py @@ -24,6 +24,7 @@ class DocsGetter: service commands and service operations. """ + def __init__(self, driver): self._driver = driver self._cache = {} @@ -38,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): @@ -58,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', '') @@ -93,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 508a3ee93e13..59cffbc6daea 100644 --- a/awscli/autoprompt/factory.py +++ b/awscli/autoprompt/factory.py @@ -21,19 +21,29 @@ from prompt_toolkit.layout.controls import BufferControl from prompt_toolkit.layout.dimension import Dimension from prompt_toolkit.layout.layout import ConditionalContainer, Layout -from prompt_toolkit.layout.menus import (CompletionsMenu, - MultiColumnCompletionsMenu) +from prompt_toolkit.layout.menus import ( + CompletionsMenu, + MultiColumnCompletionsMenu, +) from prompt_toolkit.layout.processors import BeforeInput from prompt_toolkit.widgets import SearchToolbar, VerticalLine -from awscli.autoprompt.filters import (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.filters import ( + 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) +from awscli.autoprompt.widgets import ( + DebugPanelWidget, + HelpPanelWidget, + TitleLine, + ToolbarWidget, +) class PrompterKeyboardInterrupt(KeyboardInterrupt): @@ -41,7 +51,6 @@ class PrompterKeyboardInterrupt(KeyboardInterrupt): class CLIPromptBuffer(Buffer): - def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._completer = self.completer @@ -74,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) @@ -96,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( @@ -109,7 +122,7 @@ def create_input_buffer_container(self, input_buffer): ycursor=True, content=MultiColumnCompletionsMenu( extra_filter=is_multi_column - ) + ), ), Float( xcursor=True, @@ -117,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. @@ -161,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): @@ -211,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) @@ -232,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 4ea50942214d..2a8ba8932c51 100644 --- a/awscli/autoprompt/history.py +++ b/awscli/autoprompt/history.py @@ -36,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): @@ -49,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: @@ -57,7 +58,6 @@ def store_string(self, string): class HistoryCompleter(Completer): - def __init__(self, buffer): self.buffer = buffer @@ -72,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 9283e7f99188..a7eda934e5c5 100644 --- a/awscli/autoprompt/logger.py +++ b/awscli/autoprompt/logger.py @@ -17,7 +17,6 @@ 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 c931948611de..ba7806ad282e 100644 --- a/awscli/autoprompt/output.py +++ b/awscli/autoprompt/output.py @@ -33,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: @@ -47,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 @@ -64,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 9b115924feb5..8f5f91512e37 100644 --- a/awscli/autoprompt/prompttoolkit.py +++ b/awscli/autoprompt/prompttoolkit.py @@ -52,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 @@ -71,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 @@ -91,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 @@ -130,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) @@ -180,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): @@ -238,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. @@ -253,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 = '' @@ -281,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): @@ -319,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 @@ -334,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 488922d80132..7f446ff7e031 100644 --- a/awscli/autoprompt/widgets.py +++ b/awscli/autoprompt/widgets.py @@ -21,19 +21,35 @@ from prompt_toolkit.formatted_text.utils import fragment_list_to_text 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 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.widgets import (Button, Dialog, Frame, HorizontalLine, - Label, TextArea) +from prompt_toolkit.widgets import ( + Button, + Dialog, + Frame, + HorizontalLine, + Label, + TextArea, +) from prompt_toolkit.widgets.base import Border -from awscli.autoprompt.filters import (doc_window_has_focus, - help_section_visible, - input_buffer_has_focus, is_debug_mode, - is_history_mode, search_input_has_focus) +from awscli.autoprompt.filters import ( + doc_window_has_focus, + help_section_visible, + input_buffer_has_focus, + is_debug_mode, + is_history_mode, + search_input_has_focus, +) class FormatTextProcessor(Processor): @@ -41,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 @@ -90,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, ) @@ -104,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, ) @@ -201,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): @@ -215,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): @@ -224,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): @@ -244,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): @@ -287,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( @@ -297,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): @@ -345,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 d5df92845e98..b93792798426 100644 --- a/awscli/bcdoc/restdoc.py +++ b/awscli/bcdoc/restdoc.py @@ -21,7 +21,6 @@ class ReSTDocument(object): - def __init__(self, target='man'): self.style = ReSTStyle(self) self.target = target @@ -195,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/customizations/addexamples.py b/awscli/customizations/addexamples.py index e21dd53a3715..49a9ed65b55c 100644 --- a/awscli/customizations/addexamples.py +++ b/awscli/customizations/addexamples.py @@ -26,6 +26,7 @@ For example, ``examples/ec2/ec2-create-key-pair.rst``. """ + import logging import os @@ -34,27 +35,29 @@ 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 d5ab60e1073d..ac87215c2f00 100644 --- a/awscli/customizations/argrename.py +++ b/awscli/customizations/argrename.py @@ -10,8 +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. -""" -""" +""" """ from awscli.customizations import utils @@ -75,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', @@ -116,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( + 'building-argument-table.%s' % 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( + 'building-argument-table.%s' % 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 48c63436edfe..768c9f20bbec 100644 --- a/awscli/customizations/arguments.py +++ b/awscli/customizations/arguments.py @@ -63,8 +63,10 @@ def __init__(self, session): super(OverrideRequiredArgsArgument, self).__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 @@ -94,16 +96,19 @@ 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) + kwargs['help_text'] = ( + 'Saves the command output contents of %s ' + 'to the given filename' % self.query + ) super(QueryOutFileArgument, self).__init__(name, *args, **kwargs) @property @@ -130,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('') @@ -153,8 +159,14 @@ class NestedBlobArgumentHoister(object): 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 @@ -164,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 @@ -174,16 +185,18 @@ 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 @@ -191,7 +204,8 @@ def _update_arg(self, argument_table, source_arg, new_arg): class _NestedBlobArgumentParamOverwrite(CustomArgument): def __init__(self, new_arg, source_arg, source_arg_blob_member, **kwargs): super(_NestedBlobArgumentParamOverwrite, self).__init__( - new_arg, **kwargs) + 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 0a997e3518e4..760918a62a70 100644 --- a/awscli/customizations/assumerole.py +++ b/awscli/customizations/assumerole.py @@ -9,9 +9,11 @@ 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 1e7138478b83..a1dad12163d3 100644 --- a/awscli/customizations/awslambda.py +++ b/awscli/customizations/awslambda.py @@ -20,7 +20,8 @@ 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. ' @@ -30,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): @@ -54,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() @@ -61,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) @@ -106,6 +117,7 @@ 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) @@ -130,6 +142,7 @@ 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'] diff --git a/awscli/customizations/cliinput.py b/awscli/customizations/cliinput.py index 2a5b92d691ba..d145e967eac2 100644 --- a/awscli/customizations/cliinput.py +++ b/awscli/customizations/cliinput.py @@ -49,6 +49,7 @@ 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 @@ -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) + "received %s" % 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 2939a9c51cc6..7bfd8371fa94 100644 --- a/awscli/customizations/cloudfront.py +++ b/awscli/customizations/cloudfront.py @@ -29,37 +29,52 @@ 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'): @@ -72,7 +87,6 @@ def _add_paths(argument_table, **kwargs): class PathsArgument(CustomArgument): - def __init__(self): doc = ( 'The space-separated paths to be invalidated.' @@ -85,17 +99,23 @@ def add_to_params(self, parameters, value): 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)) + name, help_text=self.DOC % (help_text, exclusive_to) + ) def distribution_config_template(self): return { @@ -107,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,14 +139,17 @@ 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.') + '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'): @@ -139,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 ( + '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=( + 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): @@ -177,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'] @@ -209,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', @@ -217,39 +253,49 @@ 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 @@ -260,6 +306,5 @@ def __init__(self, private_key): 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 9c2d245878ff..45a10a0149e8 100644 --- a/awscli/customizations/cloudsearch.py +++ b/awscli/customizations/cloudsearch.py @@ -24,7 +24,7 @@ 'Int': int, 'Double': float, 'IntArray': int, - 'DoubleArray': float + 'DoubleArray': float, } @@ -72,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": { @@ -86,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 5a4ef7a81bfb..27ac41d1457c 100644 --- a/awscli/customizations/cloudsearchdomain.py +++ b/awscli/customizations/cloudsearchdomain.py @@ -17,12 +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 2baa1c55008f..7f25ffdac964 100644 --- a/awscli/customizations/codecommit.py +++ b/awscli/customizations/codecommit.py @@ -44,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 @@ -56,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 @@ -68,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', @@ -87,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) 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) @@ -130,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 = '{0}://{1}/{2}'.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: @@ -157,9 +167,8 @@ def sign_request(self, region, url_to_sign): # 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) + request.method, split.path, hostname + ) logger.debug("Calculating signature using v4 auth.") logger.debug('CanonicalRequest:\n%s', canonical_request) string_to_sign = signer.string_to_sign(request, canonical_request) @@ -171,7 +180,7 @@ def sign_request(self, region, url_to_sign): class CodeCommitCommand(BasicCommand): NAME = 'credential-helper' - SYNOPSIS = ('aws codecommit credential-helper') + SYNOPSIS = 'aws codecommit credential-helper' EXAMPLES = '' SUBCOMMANDS = [ @@ -179,14 +188,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 5466bffdd686..70d10ac8e1f5 100644 --- a/awscli/customizations/commands.py +++ b/awscli/customizations/commands.py @@ -23,7 +23,6 @@ class _FromFile(object): - def __init__(self, *paths, **kwargs): """ ``**kwargs`` can contain a ``root_module`` argument @@ -43,7 +42,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 +138,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.%s' % ".".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 +170,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.%s.%s' % ('custom', self.name), + cli_argument=cli_argument, + value=value, + operation=None, + ) if override is not None: # A plugin supplied a conversion @@ -189,7 +191,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'): @@ -213,8 +216,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 +238,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( + 'building-command-table.%s' % name, + command_table=subcommand_table, + session=self._session, + command_object=self, + ) self._add_lineage(subcommand_table) return subcommand_table @@ -251,8 +255,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 +276,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( + 'building-arg-table.%s' % 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) @@ -325,15 +334,23 @@ def _raise_usage_error(self): 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(BasicHelp, self).__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 +393,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,7 +413,6 @@ def __call__(self, args, parsed_globals): class BasicDocHandler(OperationDocumentEventHandler): - def __init__(self, help_command): super(BasicDocHandler, self).__init__(help_command) self.doc = help_command.doc @@ -407,7 +425,8 @@ 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) + help_command=help_command, **kwargs + ) else: self.doc.style.h2('Synopsis') self.doc.style.start_codeblock() @@ -424,8 +443,8 @@ 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 @@ -445,7 +464,8 @@ 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) + 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 10a4e3769d4e..ae141b9ee7ac 100644 --- a/awscli/customizations/ecr.py +++ b/awscli/customizations/ecr.py @@ -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 9d5ed84371e9..c48f81a32b5f 100644 --- a/awscli/customizations/ecr_public.py +++ b/awscli/customizations/ecr_public.py @@ -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..5b1348c8311b 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(FlattenedArgument, self).__init__( + name=name, help_text=help_text, required=required + ) @property def cli_type_name(self): @@ -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( + 'building-argument-table.{0}.{1}'.format(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 {0} argument {1} into {2}'.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): @@ -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..9dd40963b119 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': ( @@ -86,17 +88,18 @@ def override_required_args(self, argument_table, args, **kwargs): except IndexError: pass super(GenerateCliSkeletonArgument, self).override_required_args( - argument_table, args, **kwargs) + 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_%s_skeleton' % 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,16 +139,20 @@ 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) @@ -153,13 +161,14 @@ def _make_client_call(self, client, operation_name, parameters, class _Bytes(object): @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) + use_member_names=use_member_names + ) self._yaml = yaml if self._yaml is None: self._yaml = YAML() @@ -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]') @@ -208,6 +220,6 @@ 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(YAMLArgumentGenerator, self)._generate_type_map(shape, stack) + ) diff --git a/awscli/customizations/globalargs.py b/awscli/customizations/globalargs.py index 1646fe9eec59..94d84649eab2 100644 --- a/awscli/customizations/globalargs.py +++ b/awscli/customizations/globalargs.py @@ -23,16 +23,25 @@ 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): @@ -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 745e5c99f10c..ce40c41c3003 100644 --- a/awscli/customizations/iamvirtmfa.py +++ b/awscli/customizations/iamvirtmfa.py @@ -22,21 +22,27 @@ to the specified file. It will also remove the two bootstrap data fields from the response. """ + import base64 -from awscli.customizations.arguments import (StatefulArgument, - is_parsed_result_successful, - resolve_given_outfile_path) +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: %s | %s' % 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. @@ -45,19 +51,24 @@ def add_to_params(self, parameters, value): class IAMVMFAWrapper(object): - 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 a30b259a8dce..ac23cd5237a2 100644 --- a/awscli/customizations/opsworks.py +++ b/awscli/customizations/opsworks.py @@ -40,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 @@ -77,49 +78,83 @@ 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): @@ -135,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) @@ -156,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 " "letters, digits and dashes only and must not start or " - "end with a dash." % args.hostname) + "end with a dash." % args.hostname + ) def retrieve_stack(self, args): """ @@ -196,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 @@ -233,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: @@ -254,12 +302,16 @@ def retrieve_stack(self, args): if not instances: raise ValueError( - "Did not find any instance matching %s." % args.target) + "Did not find any instance matching %s." % args.target + ) elif len(instances) > 1: raise ValueError( - "Found multiple instances matching %s: %s." % ( + "Found multiple instances matching %s: %s." + % ( args.target, - ", ".join(i['InstanceId'] for i in instances))) + ", ".join(i['InstanceId'] for i in instances), + ) + ) self._ec2_instance = instances[0] @@ -272,19 +324,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) + "a stack." % args.hostname + ) 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): """ @@ -305,12 +362,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 @@ -343,7 +402,10 @@ def create_iam_entities(self, args): 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 @@ -354,17 +416,20 @@ def create_iam_entities(self, args): LOG.debug("Creating an IAM user") base_username = "OpsWorks-%s-%s" % ( 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 "") 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 @@ -381,8 +446,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': @@ -390,32 +454,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): """ @@ -424,12 +485,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: @@ -481,13 +541,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: @@ -509,20 +569,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( + ":%s: %s" % (k, json.dumps(v)) + for k, v in sorted(parameters.items()) + ) def clean_for_iam(name): @@ -541,4 +601,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 69a40e5321fe..bb8f31914dc4 100644 --- a/awscli/customizations/paginate.py +++ b/awscli/customizations/paginate.py @@ -23,6 +23,7 @@ * Add a ``--starting-token`` and a ``--max-items`` argument. """ + import logging import sys from functools import partial @@ -86,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 @@ -99,15 +101,19 @@ 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) + ( + '``%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 + ) # Only include result key information if it is present. if paginator_config.get('result_key'): queries = paginator_config['result_key'] @@ -115,33 +121,48 @@ def add_paging_description(help_command, **kwargs): queries = [queries] queries = ", ".join([('``%s``' % 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 ' + 'from the results of the following query expressions: %s' + ) + % 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: @@ -149,21 +170,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 {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, + ) # We will register two pagination handlers. # # The first is focused on analyzing the CLI arguments passed to see @@ -178,13 +216,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): @@ -198,17 +243,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: @@ -228,12 +283,16 @@ 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 @@ -290,11 +349,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 @@ -316,7 +378,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): @@ -339,8 +402,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 366af9625519..da63967bdd8b 100644 --- a/awscli/customizations/putmetricdata.py +++ b/awscli/customizations/putmetricdata.py @@ -23,6 +23,7 @@ * --storage-resolution """ + import decimal from awscli.arguments import CustomArgument @@ -32,12 +33,22 @@ 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,7 +122,9 @@ 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 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 6a57ccbcb6bd..48fd7c3b042f 100644 --- a/awscli/customizations/rds.py +++ b/awscli/customizations/rds.py @@ -32,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): @@ -48,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'] @@ -68,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): @@ -85,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..267376015b36 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( + '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, + ), + ) diff --git a/awscli/customizations/removals.py b/awscli/customizations/removals.py index 5add46dc4f81..a7d99862f42e 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,43 +27,73 @@ 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): @@ -70,8 +101,7 @@ 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..e4eabf442d96 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 ' @@ -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 0b51ff85bc54..2a0c31d307a7 100644 --- a/awscli/customizations/s3events.py +++ b/awscli/customizations/s3events.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. """Add S3 specific event streaming output arg.""" + from awscli.arguments import CustomArgument STREAM_HELP_TEXT = 'Filename where the records will be saved' @@ -23,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,10 +60,13 @@ def replace_event_stream_docs(help_command, **kwargs): # we should be raising something with a helpful error message. raise DocSectionNotFoundError( 'Could not find the "output" section for the command: %s' - % help_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): @@ -80,7 +85,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): @@ -102,8 +107,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 101890db6ac3..01ebeda6af66 100644 --- a/awscli/customizations/s3uploader.py +++ b/awscli/customizations/s3uploader.py @@ -33,11 +33,12 @@ 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): @@ -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 @@ -90,17 +94,16 @@ def upload(self, file_name, 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( + "File with same data already exists at {0}. " + "Skipping upload".format(remote_path) + ) 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 "s3://{0}/{1}".format(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,8 +195,8 @@ 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) @@ -214,14 +217,18 @@ 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)) + "\rUploading to %s %s / %s (%.2f%%)" + % ( + self._remote_path, + self._seen_so_far, + self._size, + percentage, + ) + ) sys.stderr.flush() diff --git a/awscli/customizations/sessendemail.py b/awscli/customizations/sessendemail.py index 438aac16a5bf..ea290a63b685 100644 --- a/awscli/customizations/sessendemail.py +++ b/awscli/customizations/sessendemail.py @@ -26,47 +26,57 @@ 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): @@ -87,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(AddressesArgument, self).__init__( + name=name, help_text=help_text, required=required, nargs='+' + ) self._json_key = json_key def add_to_params(self, parameters, value): @@ -100,10 +120,10 @@ 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(BodyArgument, self).__init__( + name=name, help_text=help_text, required=required + ) self._json_key = json_key def add_to_params(self, parameters, value): diff --git a/awscli/customizations/sessionmanager.py b/awscli/customizations/sessionmanager.py index c7fa8f17635a..16e0868cb0e2 100644 --- a/awscli/customizations/sessionmanager.py +++ b/awscli/customizations/sessionmanager.py @@ -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(StartSessionCommand, self).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..c4decbb6844d 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( + 'after-call.%s.%s' % (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 7d1e8743ec8f..efc765668b68 100644 --- a/awscli/customizations/timestampformat.py +++ b/awscli/customizations/timestampformat.py @@ -27,6 +27,7 @@ in the future. """ + from botocore.exceptions import ProfileNotFound from botocore.utils import parse_timestamp diff --git a/awscli/customizations/toplevelbool.py b/awscli/customizations/toplevelbool.py index b252c87f621c..826d6c5ccb04 100644 --- a/awscli/customizations/toplevelbool.py +++ b/awscli/customizations/toplevelbool.py @@ -16,6 +16,7 @@ """ + import logging from functools import partial @@ -32,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 @@ -54,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 @@ -64,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_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='no_%s' % 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 @@ -88,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)) + 'the "%s" option.' % (positive.cli_name, negative.cli_name) + ) class PositiveBooleanArgument(arguments.CLIArgument): - def __init__(self, name, argument_model, operation_model, - event_emitter, serialized_name, group_name): + 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) + name, + argument_model, + operation_model, + event_emitter, + serialized_name=serialized_name, + ) self._group_name = group_name @property @@ -111,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: @@ -129,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): + 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) + 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 9f66c1ab23ce..f398dd94183b 100644 --- a/awscli/customizations/translate.py +++ b/awscli/customizations/translate.py @@ -13,8 +13,10 @@ import copy from awscli.arguments import CLIArgument, CustomArgument -from awscli.customizations.binaryhoist import (ArgumentParameters, - BinaryBlobArgumentHoister) +from awscli.customizations.binaryhoist import ( + ArgumentParameters, + BinaryBlobArgumentHoister, +) FILE_DOCSTRING = ( "

The path to the file of the code you are uploading. " @@ -39,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 dc3da3a7fa80..fd135a8714a2 100644 --- a/awscli/customizations/utils.py +++ b/awscli/customizations/utils.py @@ -14,6 +14,7 @@ Utility functions to make it easier to work with customizations. """ + import copy import re import sys @@ -24,10 +25,8 @@ 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 @@ -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() diff --git a/awscli/customizations/waiters.py b/awscli/customizations/waiters.py index da00b6a3ada0..22b332f558c9 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, BasicDocHandler, - BasicHelp) +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,7 +67,7 @@ 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) @@ -76,10 +83,13 @@ def _build_subcommand_table(self): 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): @@ -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, @@ -133,11 +145,11 @@ def _build_waiter_state_cmd(self, waiter_name): class WaiterStateDocBuilder(object): 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 = ( + 'JMESPath query %s returns ' % acceptor.argument + ) # 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,14 +197,14 @@ 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 'when polling with ``%s``.' % operation_name def _build_polling_description(self, delay, max_attempts): description = ( ' It will poll every %s seconds until a successful state ' 'has been reached. This will exit with a return code of 255 ' - 'after %s failed checks.' - % (delay, max_attempts)) + 'after %s failed checks.' % (delay, max_attempts) + ) return description @@ -200,9 +215,11 @@ def __init__(self, session, 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 From d44cbea7bc5e0149037beec510e39c2110d4c609 Mon Sep 17 00:00:00 2001 From: Kenneth Daily Date: Mon, 23 Dec 2024 11:51:57 -0800 Subject: [PATCH 4/6] Run ruff check --fix --- .../cloudformation/artifact_exporter.py | 20 ++++++------- .../customizations/cloudformation/deployer.py | 19 ++++++------ .../cloudformation/yamlhelper.py | 2 +- .../customizations/cloudtrail/validation.py | 12 ++++---- awscli/customizations/codeartifact/login.py | 29 ++++++++----------- .../customizations/configservice/subscribe.py | 4 +-- awscli/customizations/configure/__init__.py | 2 +- awscli/customizations/configure/configure.py | 2 +- .../customizations/configure/exportcreds.py | 2 +- awscli/customizations/configure/get.py | 2 +- awscli/customizations/configure/importer.py | 4 +-- awscli/customizations/configure/sso.py | 8 ++--- awscli/customizations/configure/writer.py | 4 +-- 13 files changed, 52 insertions(+), 58 deletions(-) diff --git a/awscli/customizations/cloudformation/artifact_exporter.py b/awscli/customizations/cloudformation/artifact_exporter.py index 8a4c18a28460..20f955305066 100644 --- a/awscli/customizations/cloudformation/artifact_exporter.py +++ b/awscli/customizations/cloudformation/artifact_exporter.py @@ -94,7 +94,7 @@ def parse_s3_url(url, return result raise ValueError("URL given to the parse method is not a valid S3 url " - "{0}".format(url)) + f"{url}") def upload_local_artifacts(resource_id, resource_dict, property_name, @@ -134,8 +134,8 @@ def upload_local_artifacts(resource_id, resource_dict, property_name, # This check is supporting the case where your resource does not # refer to local artifacts # Nothing to do if property value is an S3 URL - LOG.debug("Property {0} of {1} is already a S3 URL" - .format(property_name, resource_id)) + LOG.debug(f"Property {property_name} of {resource_id} is already a S3 URL" + ) return local_path local_path = make_abs_path(parent_dir, local_path) @@ -181,7 +181,7 @@ def zip_folder(folder_path): def make_zip(filename, source_root): - zipfile_name = "{0}.zip".format(filename) + zipfile_name = f"{filename}.zip" source_root = os.path.abspath(source_root) with open(zipfile_name, 'wb') as f: zip_file = zipfile.ZipFile(f, 'w', zipfile.ZIP_DEFLATED) @@ -216,7 +216,7 @@ def copy_to_temp_dir(filepath): return tmp_dir -class Resource(object): +class Resource: """ Base class representing a CloudFormation resource that can be exported """ @@ -241,8 +241,8 @@ def export(self, resource_id, resource_dict, parent_dir): return if isinstance(property_value, dict): - LOG.debug("Property {0} of {1} resource is not a URL" - .format(self.PROPERTY_NAME, resource_id)) + LOG.debug(f"Property {self.PROPERTY_NAME} of {resource_id} resource is not a URL" + ) return # If property is a file but not a zip file, place file in temp @@ -576,7 +576,7 @@ def include_transform_export_handler(template_dict, uploader, parent_dir): } -class Template(object): +class Template: """ Class to export a CloudFormation template """ @@ -590,8 +590,8 @@ def __init__(self, template_path, parent_dir, uploader, if not (is_local_folder(parent_dir) and os.path.isabs(parent_dir)): raise ValueError("parent_dir parameter must be " - "an absolute path to a folder {0}" - .format(parent_dir)) + f"an absolute path to a folder {parent_dir}" + ) abs_template_path = make_abs_path(parent_dir, template_path) template_dir = os.path.dirname(abs_template_path) diff --git a/awscli/customizations/cloudformation/deployer.py b/awscli/customizations/cloudformation/deployer.py index 3733c55ebc8a..f29be3cece87 100644 --- a/awscli/customizations/cloudformation/deployer.py +++ b/awscli/customizations/cloudformation/deployer.py @@ -28,7 +28,7 @@ "ChangeSetResult", ["changeset_id", "changeset_type"]) -class Deployer(object): +class Deployer: def __init__(self, cloudformation_client, changeset_prefix="awscli-cloudformation-package-deploy-"): @@ -62,9 +62,8 @@ def has_stack(self, stack_name): # the exception msg to understand the nature of this exception. msg = str(e) - if "Stack with id {0} does not exist".format(stack_name) in msg: - LOG.debug("Stack with id {0} does not exist".format( - stack_name)) + if f"Stack with id {stack_name} does not exist" in msg: + LOG.debug(f"Stack with id {stack_name} does not exist") return False else: # We don't know anything about this exception. Don't handle @@ -86,7 +85,7 @@ def create_changeset(self, stack_name, cfn_template, """ now = datetime.utcnow().isoformat() - description = "Created by AWS CLI at {0} UTC".format(now) + description = f"Created by AWS CLI at {now} UTC" # Each changeset will get a unique name based on time changeset_name = self.changeset_prefix + str(int(time.time())) @@ -173,9 +172,9 @@ def wait_for_changeset(self, changeset_id, stack_name): "No updates are to be performed" in reason: raise exceptions.ChangeEmptyError(stack_name=stack_name) - raise RuntimeError("Failed to create the changeset: {0} " - "Status: {1}. Reason: {2}" - .format(ex, status, reason)) + raise RuntimeError(f"Failed to create the changeset: {ex} " + f"Status: {status}. Reason: {reason}" + ) def execute_changeset(self, changeset_id, stack_name, disable_rollback=False): @@ -203,8 +202,8 @@ def wait_for_execute(self, stack_name, changeset_type): elif changeset_type == "UPDATE": waiter = self._client.get_waiter("stack_update_complete") else: - raise RuntimeError("Invalid changeset type {0}" - .format(changeset_type)) + raise RuntimeError(f"Invalid changeset type {changeset_type}" + ) # Poll every 30 seconds. Polling too frequently risks hitting rate limits # on CloudFormation's DescribeStacks API diff --git a/awscli/customizations/cloudformation/yamlhelper.py b/awscli/customizations/cloudformation/yamlhelper.py index 4d5f641768e2..8b96d046ce6b 100644 --- a/awscli/customizations/cloudformation/yamlhelper.py +++ b/awscli/customizations/cloudformation/yamlhelper.py @@ -73,7 +73,7 @@ def _add_yaml_1_1_boolean_resolvers(resolver_cls): '|true|True|TRUE|false|False|FALSE' '|on|On|ON|off|Off|OFF)$' ) - boolean_first_chars = list(u'yYnNtTfFoO') + boolean_first_chars = list('yYnNtTfFoO') resolver_cls.add_implicit_resolver( 'tag:yaml.org,2002:bool', boolean_regex, boolean_first_chars) diff --git a/awscli/customizations/cloudtrail/validation.py b/awscli/customizations/cloudtrail/validation.py index aabce6c70f43..fb4518535c66 100644 --- a/awscli/customizations/cloudtrail/validation.py +++ b/awscli/customizations/cloudtrail/validation.py @@ -159,7 +159,7 @@ def create_digest_traverser(cloudtrail_client, organization_client, public_key_provider=PublicKeyProvider(cloudtrail_client)) -class S3ClientProvider(object): +class S3ClientProvider: """Creates Amazon S3 clients and determines the region name of a client. This class will cache the location constraints of previously requested @@ -215,7 +215,7 @@ def __init__(self, bucket, key): super(InvalidDigestFormat, self).__init__(message) -class DigestProvider(object): +class DigestProvider: """ Retrieves digest keys and digests from Amazon S3. @@ -348,7 +348,7 @@ def _create_digest_key_regex(self, key_prefix): return '^' + key + '$' -class DigestTraverser(object): +class DigestTraverser: """Retrieves and validates digests within a date range.""" # These keys are required to be present before validating the contents # of a digest. @@ -529,7 +529,7 @@ def _load_public_keys(self, start_date, end_date): return public_keys -class Sha256RSADigestValidator(object): +class Sha256RSADigestValidator: """ Validates SHA256withRSA signed digests. @@ -790,8 +790,8 @@ def _download_log(self, log): self._on_log_invalid(log) else: self._valid_logs += 1 - self._write_status(('Log file\ts3://%s/%s\tvalid' - % (log['s3Bucket'], log['s3Object']))) + self._write_status('Log file\ts3://%s/%s\tvalid' + % (log['s3Bucket'], log['s3Object'])) except ClientError as e: if e.response['Error']['Code'] != 'NoSuchKey': raise diff --git a/awscli/customizations/codeartifact/login.py b/awscli/customizations/codeartifact/login.py index 884c31d9f5c5..e68f7193ba1a 100644 --- a/awscli/customizations/codeartifact/login.py +++ b/awscli/customizations/codeartifact/login.py @@ -82,12 +82,11 @@ def _write_success_message(self, tool): self.expiration, datetime.now(tzutc())) + relativedelta(seconds=30) expiration_message = get_relative_expiration_time(remaining) - sys.stdout.write('Successfully configured {} to use ' - 'AWS CodeArtifact repository {} ' - .format(tool, self.repository_endpoint)) + sys.stdout.write(f'Successfully configured {tool} to use ' + f'AWS CodeArtifact repository {self.repository_endpoint} ' + ) sys.stdout.write(os.linesep) - sys.stdout.write('Login expires in {} at {}'.format( - expiration_message, self.expiration)) + sys.stdout.write(f'Login expires in {expiration_message} at {self.expiration}') sys.stdout.write(os.linesep) def _run_commands(self, tool, commands, dry_run=False): @@ -126,7 +125,7 @@ def get_commands(cls, endpoint, auth_token, **kwargs): class SwiftLogin(BaseLogin): DEFAULT_NETRC_FMT = \ - u'machine {hostname} login token password {auth_token}' + 'machine {hostname} login token password {auth_token}' NETRC_REGEX_FMT = \ r'(?P\bmachine\s+{escaped_hostname}\s+login\s+\S+\s+password\s+)' \ @@ -176,7 +175,7 @@ def _update_netrc_entry(self, hostname, new_entry, netrc_path): if not os.path.isfile(netrc_path): self._create_netrc_file(netrc_path, new_entry) else: - with open(netrc_path, 'r') as f: + with open(netrc_path) as f: contents = f.read() escaped_auth_token = self.auth_token.replace('\\', r'\\') new_contents = re.sub( @@ -356,7 +355,7 @@ def _get_source_to_url_dict(self): return source_to_url_dict def _get_source_name(self, codeartifact_url, source_dict): - default_name = '{}/{}'.format(self.domain, self.repository) + default_name = f'{self.domain}/{self.repository}' # Check if the CodeArtifact URL is already present in the # NuGet.Config file. If the URL already exists, use the source name @@ -465,7 +464,7 @@ def get_scope(cls, namespace): if namespace.startswith('@'): scope = namespace else: - scope = '@{}'.format(namespace) + scope = f'@{namespace}' if not valid_scope_name.match(scope): raise ValueError( @@ -481,7 +480,7 @@ def get_commands(cls, endpoint, auth_token, **kwargs): scope = kwargs.get('scope') # prepend scope if it exists - registry = '{}:registry'.format(scope) if scope else 'registry' + registry = f'{scope}:registry' if scope else 'registry' # set up the codeartifact repository as the npm registry. commands.append( @@ -491,17 +490,13 @@ def get_commands(cls, endpoint, auth_token, **kwargs): repo_uri = urlsplit(endpoint) # configure npm to always require auth for the repository. - always_auth_config = '//{}{}:always-auth'.format( - repo_uri.netloc, repo_uri.path - ) + always_auth_config = f'//{repo_uri.netloc}{repo_uri.path}:always-auth' commands.append( [cls.NPM_CMD, 'config', 'set', always_auth_config, 'true'] ) # set auth info for the repository. - auth_token_config = '//{}{}:_authToken'.format( - repo_uri.netloc, repo_uri.path - ) + auth_token_config = f'//{repo_uri.netloc}{repo_uri.path}:_authToken' commands.append( [cls.NPM_CMD, 'config', 'set', auth_token_config, auth_token] ) @@ -749,7 +744,7 @@ def _get_namespace(self, tool, parsed_args): if not namespace_compatible and parsed_args.namespace: raise ValueError( - 'Argument --namespace is not supported for {}'.format(tool) + f'Argument --namespace is not supported for {tool}' ) else: return parsed_args.namespace diff --git a/awscli/customizations/configservice/subscribe.py b/awscli/customizations/configservice/subscribe.py index 38a391efa1fb..0a3c1b2def31 100644 --- a/awscli/customizations/configservice/subscribe.py +++ b/awscli/customizations/configservice/subscribe.py @@ -130,7 +130,7 @@ def _setup_clients(self, parsed_globals): **client_args) -class S3BucketHelper(object): +class S3BucketHelper: def __init__(self, s3_client): self._s3_client = s3_client @@ -158,7 +158,7 @@ def _create_bucket(self, bucket): self._s3_client.create_bucket(**params) -class SNSTopicHelper(object): +class SNSTopicHelper: def __init__(self, sns_client): self._sns_client = sns_client diff --git a/awscli/customizations/configure/__init__.py b/awscli/customizations/configure/__init__.py index 8728ee6046a8..2ef7369ea23a 100644 --- a/awscli/customizations/configure/__init__.py +++ b/awscli/customizations/configure/__init__.py @@ -18,7 +18,7 @@ _WHITESPACE = ' \t' -class ConfigValue(object): +class ConfigValue: def __init__(self, value, config_type, config_variable): self.value = value diff --git a/awscli/customizations/configure/configure.py b/awscli/customizations/configure/configure.py index e1365d1b9c75..aa8fc88ea9fd 100644 --- a/awscli/customizations/configure/configure.py +++ b/awscli/customizations/configure/configure.py @@ -40,7 +40,7 @@ def register_configure_cmd(cli): ConfigureCommand.add_command) -class InteractivePrompter(object): +class InteractivePrompter: def get_value(self, current_value, config_name, prompt_text=''): if config_name in ('aws_access_key_id', 'aws_secret_access_key'): diff --git a/awscli/customizations/configure/exportcreds.py b/awscli/customizations/configure/exportcreds.py index 2358efca5405..7082f0c5b8ba 100644 --- a/awscli/customizations/configure/exportcreds.py +++ b/awscli/customizations/configure/exportcreds.py @@ -46,7 +46,7 @@ def convert_botocore_credentials(credentials): ) -class BaseCredentialFormatter(object): +class BaseCredentialFormatter: FORMAT = None DOCUMENTATION = "" diff --git a/awscli/customizations/configure/get.py b/awscli/customizations/configure/get.py index 5edad7e2d933..624b8768d793 100644 --- a/awscli/customizations/configure/get.py +++ b/awscli/customizations/configure/get.py @@ -53,7 +53,7 @@ def _run_main(self, args, parsed_globals): else: value = self._get_dotted_config_value(varname) - LOG.debug(u'Config value retrieved: %s' % value) + LOG.debug('Config value retrieved: %s' % value) if isinstance(value, str): self._stream.write(value) diff --git a/awscli/customizations/configure/importer.py b/awscli/customizations/configure/importer.py index dc7e6e088ba9..2aeb4627c787 100644 --- a/awscli/customizations/configure/importer.py +++ b/awscli/customizations/configure/importer.py @@ -100,7 +100,7 @@ class CredentialParserError(Exception): pass -class CSVCredentialParser(object): +class CSVCredentialParser: _USERNAME_HEADER = 'User Name' _AKID_HEADER = 'Access Key ID' _SAK_HEADER = 'Secret Access key' @@ -185,7 +185,7 @@ def parse_credentials(self, contents): return self._convert_rows_to_credentials(parsed_rows) -class CredentialImporter(object): +class CredentialImporter: def __init__(self, writer): self._config_writer = writer diff --git a/awscli/customizations/configure/sso.py b/awscli/customizations/configure/sso.py index fc5feb83d729..d10e9a4703ee 100644 --- a/awscli/customizations/configure/sso.py +++ b/awscli/customizations/configure/sso.py @@ -105,7 +105,7 @@ def _is_comma_separated_list(self, value): return True -class PTKPrompt(object): +class PTKPrompt: _DEFAULT_PROMPT_FORMAT = '{prompt_text} [{current_value}]: ' def __init__(self, prompter=None): @@ -424,7 +424,7 @@ def _prompt_for_account(self, sso, sso_token): sso_account_id = self._handle_single_account(accounts) else: sso_account_id = self._handle_multiple_accounts(accounts) - uni_print('Using the account ID {}\n'.format(sso_account_id)) + uni_print(f'Using the account ID {sso_account_id}\n') self._new_profile_config_values['sso_account_id'] = sso_account_id return sso_account_id @@ -458,7 +458,7 @@ def _prompt_for_role(self, sso, sso_token, sso_account_id): sso_role_name = self._handle_single_role(roles) else: sso_role_name = self._handle_multiple_roles(roles) - uni_print('Using the role name "{}"\n'.format(sso_role_name)) + uni_print(f'Using the role name "{sso_role_name}"\n') self._new_profile_config_values['sso_role_name'] = sso_role_name return sso_role_name @@ -634,7 +634,7 @@ def _prompt_for_sso_account_and_role(self, sso, sso_token): sso_account_id = self._prompt_for_account(sso, sso_token) sso_role_name = self._prompt_for_role( sso, sso_token, sso_account_id) - except sso.exceptions.UnauthorizedException as e: + except sso.exceptions.UnauthorizedException: uni_print( 'Unable to list AWS accounts and/or roles. ' 'Skipping configuring AWS credential provider for profile.\n' diff --git a/awscli/customizations/configure/writer.py b/awscli/customizations/configure/writer.py index 4aedabc43792..077196c085e9 100644 --- a/awscli/customizations/configure/writer.py +++ b/awscli/customizations/configure/writer.py @@ -16,7 +16,7 @@ from . import SectionNotFoundError -class ConfigFileWriter(object): +class ConfigFileWriter: SECTION_REGEX = re.compile(r'^\s*\[(?P

[^]]+)\]') OPTION_REGEX = re.compile( r'(?P