From c8b4b7b671c18afd5daf46f03ee3ae0b497ad6ee Mon Sep 17 00:00:00 2001
From: aemous
Date: Wed, 13 May 2026 14:06:37 -0400
Subject: [PATCH 1/6] Wrap plugins that directly register against events in
handlers.py in a thin initialization function.
---
awscli/argprocess.py | 7 +
awscli/clidriver.py | 7 +
awscli/customizations/addexamples.py | 14 ++
awscli/customizations/binaryformat.py | 7 +
.../customizations/codedeploy/codedeploy.py | 8 +-
awscli/customizations/ec2/decryptpassword.py | 7 +
awscli/customizations/iot.py | 14 ++
awscli/customizations/s3/s3.py | 21 +--
awscli/customizations/streamingoutputarg.py | 7 +
awscli/handlers.py | 73 ++++-----
awscli/paramfile.py | 7 +
tests/functional/test_handlers_registry.py | 155 ++++++++++++++++++
tests/unit/customizations/s3/test_s3.py | 9 +-
13 files changed, 272 insertions(+), 64 deletions(-)
create mode 100644 tests/functional/test_handlers_registry.py
diff --git a/awscli/argprocess.py b/awscli/argprocess.py
index fdc5eee8ba85..529ca1cd53e2 100644
--- a/awscli/argprocess.py
+++ b/awscli/argprocess.py
@@ -270,6 +270,13 @@ def _is_complex_shape(model):
return True
+def register_param_shorthand_parser(event_emitter):
+ event_emitter.register(
+ 'process-cli-arg',
+ ParamShorthandParser(),
+ )
+
+
class ParamShorthand:
def _uses_old_list_case(self, command_name, operation_name, argument_name):
"""
diff --git a/awscli/clidriver.py b/awscli/clidriver.py
index 643331c50d46..f7ba957fd94f 100644
--- a/awscli/clidriver.py
+++ b/awscli/clidriver.py
@@ -214,6 +214,13 @@ def _set_user_agent_for_session(session):
add_session_id_component_to_user_agent_extra(session)
+def register_no_pager_handler(event_emitter):
+ event_emitter.register(
+ 'session-initialized',
+ no_pager_handler,
+ )
+
+
def no_pager_handler(session, parsed_args, **kwargs):
if parsed_args.no_cli_pager:
config_store = session.get_component('config_store')
diff --git a/awscli/customizations/addexamples.py b/awscli/customizations/addexamples.py
index 49a9ed65b55c..9ccf670ec6e8 100644
--- a/awscli/customizations/addexamples.py
+++ b/awscli/customizations/addexamples.py
@@ -33,6 +33,20 @@
LOG = logging.getLogger(__name__)
+def register_docs_add_examples(event_emitter):
+
+ # The following will get fired for every option we are
+ # documenting. It will attempt to add an example_fn on to
+ # the parameter object if the parameter supports shorthand
+ # syntax. The documentation event handlers will then use
+ # the examplefn to generate the sample shorthand syntax
+ # in the docs. Registering here should ensure that this
+ # handler gets called first, but it still feels a bit brittle.
+ # event_handlers.register('doc-option-example.*.*.*',
+ # param_shorthand.add_example_fn)
+ event_emitter.register('doc-examples.*.*', add_examples)
+
+
def add_examples(help_command, **kwargs):
doc_path = os.path.join(
os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'examples'
diff --git a/awscli/customizations/binaryformat.py b/awscli/customizations/binaryformat.py
index 7ac8030231c7..4812047fdf39 100644
--- a/awscli/customizations/binaryformat.py
+++ b/awscli/customizations/binaryformat.py
@@ -18,6 +18,13 @@
from awscli.shorthand import ModelVisitor
+def register_init_binary_formatter(event_emitter):
+ event_emitter.register(
+ 'session-initialized',
+ add_binary_formatter,
+ )
+
+
def add_binary_formatter(session, parsed_args, **kwargs):
binary_format = parsed_args.cli_binary_format
if binary_format is None:
diff --git a/awscli/customizations/codedeploy/codedeploy.py b/awscli/customizations/codedeploy/codedeploy.py
index b1c78d648f0e..873511958909 100644
--- a/awscli/customizations/codedeploy/codedeploy.py
+++ b/awscli/customizations/codedeploy/codedeploy.py
@@ -22,11 +22,11 @@
from awscli.customizations.codedeploy.uninstall import Uninstall
-def initialize(cli):
- """
- The entry point for CodeDeploy high level commands.
- """
+def register_rename_codedeploy(cli):
cli.register('building-command-table.main', change_name)
+
+
+def register_codedeploy(cli):
cli.register('building-command-table.deploy', inject_commands)
cli.register(
'building-argument-table.deploy.get-application-revision',
diff --git a/awscli/customizations/ec2/decryptpassword.py b/awscli/customizations/ec2/decryptpassword.py
index 4fba23fb59f0..902cd4c800cd 100644
--- a/awscli/customizations/ec2/decryptpassword.py
+++ b/awscli/customizations/ec2/decryptpassword.py
@@ -27,6 +27,13 @@
password data sent from EC2 will be decrypted before display.
"""
+def register_ec2_add_priv_launch_key(event_emitter, **kwargs):
+ event_emitter.register(
+ 'building-argument-table.ec2.get-password-data',
+ ec2_add_priv_launch_key,
+ )
+
+
def ec2_add_priv_launch_key(
argument_table, operation_model, session, **kwargs
):
diff --git a/awscli/customizations/iot.py b/awscli/customizations/iot.py
index f4e4b9770513..8b0153d6fcc5 100644
--- a/awscli/customizations/iot.py
+++ b/awscli/customizations/iot.py
@@ -26,6 +26,20 @@
from awscli.customizations.arguments import QueryOutFileArgument
+def register_iot_create_keys_from_csr(event_emitter):
+ event_emitter.register(
+ 'building-argument-table.iot.create-certificate-from-csr',
+ register_create_keys_from_csr_arguments,
+ )
+
+
+def register_iot_create_keys_and_cert_args(event_emitter):
+ event_emitter.register(
+ 'building-argument-table.iot.create-keys-and-certificate',
+ register_create_keys_and_cert_arguments,
+ )
+
+
def register_create_keys_and_cert_arguments(session, argument_table, **kwargs):
"""Add outfile save arguments to create-keys-and-certificate
diff --git a/awscli/customizations/s3/s3.py b/awscli/customizations/s3/s3.py
index 725bd0ca9bf7..9dad2aaa03d1 100644
--- a/awscli/customizations/s3/s3.py
+++ b/awscli/customizations/s3/s3.py
@@ -28,23 +28,14 @@
)
-def awscli_initialize(cli):
- """
- This function is require to use the plugin. It calls the functions
- required to add all necessary commands and parameters to the CLI.
- This function is necessary to install the plugin using a configuration
- file
- """
- cli.register("building-command-table.main", add_s3)
- cli.register('building-command-table.s3_sync', register_sync_strategies)
+def register_s3_main(event_handlers):
+ event_handlers.register('building-command-table.main', add_s3)
-def s3_plugin_initialize(event_handlers):
- """
- This is a wrapper to make the plugin built-in to the cli as opposed
- to specifying it in the configuration file.
- """
- awscli_initialize(event_handlers)
+def register_s3_sync_strategies(event_handlers):
+ event_handlers.register(
+ 'building-command-table.s3_sync', register_sync_strategies
+ )
def add_s3(command_table, session, **kwargs):
diff --git a/awscli/customizations/streamingoutputarg.py b/awscli/customizations/streamingoutputarg.py
index c4decbb6844d..6c289c0ec140 100644
--- a/awscli/customizations/streamingoutputarg.py
+++ b/awscli/customizations/streamingoutputarg.py
@@ -15,6 +15,13 @@
from awscli.arguments import BaseCLIArgument
+def register_streaming_output_arg(event_emitter):
+ event_emitter.register(
+ 'building-argument-table.*',
+ add_streaming_output_arg,
+ )
+
+
def add_streaming_output_arg(
argument_table, operation_model, session, **kwargs
):
diff --git a/awscli/handlers.py b/awscli/handlers.py
index 3f0aa0180078..bc5234a4a7f9 100644
--- a/awscli/handlers.py
+++ b/awscli/handlers.py
@@ -18,14 +18,14 @@
"""
from awscli.alias import register_alias_commands
-from awscli.argprocess import ParamShorthandParser
-from awscli.clidriver import no_pager_handler
+from awscli.argprocess import register_param_shorthand_parser
+from awscli.clidriver import register_no_pager_handler
from awscli.customizations import datapipeline
-from awscli.customizations.addexamples import add_examples
+from awscli.customizations.addexamples import register_docs_add_examples
from awscli.customizations.argrename import register_arg_renames
from awscli.customizations.assumerole import register_assume_role_provider
from awscli.customizations.awslambda import register_lambda_create_function
-from awscli.customizations.binaryformat import add_binary_formatter
+from awscli.customizations.binaryformat import register_init_binary_formatter
from awscli.customizations.cliinput import register_cli_input_args
from awscli.customizations.cloudformation import (
initialize as cloudformation_init,
@@ -38,7 +38,8 @@
from awscli.customizations.codeartifact import register_codeartifact_commands
from awscli.customizations.codecommit import initialize as codecommit_init
from awscli.customizations.codedeploy.codedeploy import (
- initialize as codedeploy_init,
+ register_codedeploy,
+ register_rename_codedeploy as codedeploy_init,
)
from awscli.customizations.configservice.getstatus import register_get_status
from awscli.customizations.configservice.putconfigurationrecorder import (
@@ -58,7 +59,9 @@
)
from awscli.customizations.ec2.addcount import register_count_events
from awscli.customizations.ec2.bundleinstance import register_bundleinstance
-from awscli.customizations.ec2.decryptpassword import ec2_add_priv_launch_key
+from awscli.customizations.ec2.decryptpassword import (
+ register_ec2_add_priv_launch_key
+)
from awscli.customizations.ec2.paginate import register_ec2_page_size_injector
from awscli.customizations.ec2.protocolarg import register_protocol_args
from awscli.customizations.ec2.runinstances import register_runinstances
@@ -88,8 +91,8 @@
)
from awscli.customizations.iamvirtmfa import IAMVMFAWrapper
from awscli.customizations.iot import (
- register_create_keys_and_cert_arguments,
- register_create_keys_from_csr_arguments,
+ register_iot_create_keys_and_cert_args,
+ register_iot_create_keys_from_csr,
)
from awscli.customizations.iot_data import register_custom_endpoint_note
from awscli.customizations.kinesis import (
@@ -113,7 +116,10 @@
)
from awscli.customizations.removals import register_removals
from awscli.customizations.route53 import register_create_hosted_zone_doc_fix
-from awscli.customizations.s3.s3 import s3_plugin_initialize
+from awscli.customizations.s3.s3 import (
+ register_s3_main,
+ register_s3_sync_strategies
+)
from awscli.customizations.s3errormsg import register_s3_error_msg
from awscli.customizations.s3events import (
register_document_expires_string,
@@ -125,7 +131,7 @@
from awscli.customizations.sessendemail import register_ses_send_email
from awscli.customizations.sessionmanager import register_ssm_session
from awscli.customizations.sso import register_sso_commands
-from awscli.customizations.streamingoutputarg import add_streaming_output_arg
+from awscli.customizations.streamingoutputarg import register_streaming_output_arg
from awscli.customizations.timestampformat import register_timestamp_format
from awscli.customizations.toplevelbool import register_bool_params
from awscli.customizations.translate import (
@@ -133,42 +139,28 @@
)
from awscli.customizations.waiters import register_add_waiters
from awscli.customizations.wizard.commands import register_wizard_commands
-from awscli.paramfile import register_uri_param_handler
+from awscli.paramfile import register_init_uri_param_handler
def awscli_initialize(event_handlers):
- event_handlers.register('session-initialized', register_uri_param_handler)
- event_handlers.register('session-initialized', add_binary_formatter)
- event_handlers.register('session-initialized', no_pager_handler)
- param_shorthand = ParamShorthandParser()
- event_handlers.register('process-cli-arg', param_shorthand)
- # The s3 error mesage needs to registered before the
+ register_init_uri_param_handler(event_handlers)
+ register_init_binary_formatter(event_handlers)
+ register_no_pager_handler(event_handlers)
+ register_param_shorthand_parser(event_handlers)
+ # The s3 error message needs to registered before the
# generic error handler.
register_s3_error_msg(event_handlers)
- # # The following will get fired for every option we are
- # # documenting. It will attempt to add an example_fn on to
- # # the parameter object if the parameter supports shorthand
- # # syntax. The documentation event handlers will then use
- # # the examplefn to generate the sample shorthand syntax
- # # in the docs. Registering here should ensure that this
- # # handler gets called first but it still feels a bit brittle.
- # event_handlers.register('doc-option-example.*.*.*',
- # param_shorthand.add_example_fn)
- event_handlers.register('doc-examples.*.*', add_examples)
+ register_docs_add_examples(event_handlers)
register_cli_input_args(event_handlers)
- event_handlers.register(
- 'building-argument-table.*', add_streaming_output_arg
- )
+ register_streaming_output_arg(event_handlers)
register_count_events(event_handlers)
- event_handlers.register(
- 'building-argument-table.ec2.get-password-data',
- ec2_add_priv_launch_key,
- )
+ register_ec2_add_priv_launch_key(event_handlers)
register_parse_global_args(event_handlers)
register_pagination(event_handlers)
register_secgroup(event_handlers)
register_bundleinstance(event_handlers)
- s3_plugin_initialize(event_handlers)
+ register_s3_main(event_handlers)
+ register_s3_sync_strategies(event_handlers)
register_ddb(event_handlers)
register_runinstances(event_handlers)
register_removals(event_handlers)
@@ -199,6 +191,7 @@ def awscli_initialize(event_handlers):
register_assume_role_provider(event_handlers)
register_add_waiters(event_handlers)
codedeploy_init(event_handlers)
+ register_codedeploy(event_handlers)
register_subscribe(event_handlers)
register_get_status(event_handlers)
register_rename_config(event_handlers)
@@ -210,14 +203,8 @@ def awscli_initialize(event_handlers):
register_codeartifact_commands(event_handlers)
codecommit_init(event_handlers)
register_custom_endpoint_note(event_handlers)
- event_handlers.register(
- 'building-argument-table.iot.create-keys-and-certificate',
- register_create_keys_and_cert_arguments,
- )
- event_handlers.register(
- 'building-argument-table.iot.create-certificate-from-csr',
- register_create_keys_from_csr_arguments,
- )
+ register_iot_create_keys_and_cert_args(event_handlers)
+ register_iot_create_keys_from_csr(event_handlers)
register_cloudfront(event_handlers)
register_gamelift_commands(event_handlers)
register_ec2_page_size_injector(event_handlers)
diff --git a/awscli/paramfile.py b/awscli/paramfile.py
index 975470062594..a14b3c56b3fa 100644
--- a/awscli/paramfile.py
+++ b/awscli/paramfile.py
@@ -24,6 +24,13 @@ class ResourceLoadingError(Exception):
pass
+def register_init_uri_param_handler(event_emitter):
+ event_emitter.register(
+ 'session-initialized',
+ register_uri_param_handler,
+ )
+
+
def register_uri_param_handler(session, **kwargs):
prefix_map = copy.deepcopy(LOCAL_PREFIX_MAP)
handler = URIArgumentHandler(prefix_map)
diff --git a/tests/functional/test_handlers_registry.py b/tests/functional/test_handlers_registry.py
new file mode 100644
index 000000000000..7856fa3caf91
--- /dev/null
+++ b/tests/functional/test_handlers_registry.py
@@ -0,0 +1,155 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"). You
+# may not use this file except in compliance with the License. A copy of
+# the License is located at
+#
+# http://aws.amazon.com/apache2.0/
+#
+# or in the "license" file accompanying this file. This file is
+# 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 importlib
+from collections import OrderedDict
+
+import botocore.session
+
+from awscli.handlers_registry import PLUGIN_REGISTRY
+
+
+class _AuditEmitter:
+ """Minimal emitter that records event names without side effects."""
+
+ def __init__(self):
+ self.registrations = []
+
+ def register(self, event_name, *args, **kwargs):
+ self.registrations.append(event_name)
+
+ register_first = register
+ register_last = register
+
+
+class _CallbackCollector:
+ """Emitter that captures callbacks registered against a specific event."""
+
+ def __init__(self, target_event):
+ self._target_event = target_event
+ self.callbacks = []
+
+ def register(self, event_name, handler, *args, **kwargs):
+ if event_name == self._target_event:
+ self.callbacks.append(handler)
+
+ register_first = register
+ register_last = register
+
+
+def test_main_command_table_plugins_only_register_against_main():
+ """Plugins listed under building-command-table.main must not register
+ against any other events.
+
+ This invariant allows the lazy-loading system to skip importing these
+ plugin modules entirely and instead apply pre-computed renames and
+ LazyCommand additions from MAIN_COMMAND_TABLE_OPS. If a plugin
+ mixes building-command-table.main registrations with other events,
+ split it into separate functions: one that only registers against
+ building-command-table.main, and another for the remaining events.
+ """
+ main_entries = PLUGIN_REGISTRY.get('building-command-table.main', [])
+ violations = []
+ for module_path, fn_name, entry_type in main_entries:
+ emitter = _AuditEmitter()
+ mod = importlib.import_module(module_path)
+ fn = getattr(mod, fn_name)
+ fn(emitter)
+ non_main = [
+ e
+ for e in emitter.registrations
+ if e != 'building-command-table.main'
+ ]
+ if non_main:
+ violations.append(
+ f'{module_path}.{fn_name} also registers against: '
+ f'{non_main}'
+ )
+ assert not violations, (
+ 'The following building-command-table.main plugins register '
+ 'against additional events. Split each into separate functions '
+ 'so that the building-command-table.main function only registers '
+ 'against that single event:\n'
+ + '\n'.join(f' - {v}' for v in violations)
+ )
+
+
+def test_main_command_table_callbacks_only_add_or_rename():
+ """Callbacks registered against building-command-table.main must only
+ add new commands or rename existing ones.
+
+ MAIN_COMMAND_TABLE_OPS replaces these callbacks at runtime with
+ LazyCommand additions and direct renames. If a callback also
+ modifies existing command table entries (e.g. changes properties on
+ a command object), that modification would be silently lost.
+ """
+ session = botocore.session.Session()
+ services = session.get_available_services()
+
+ main_entries = PLUGIN_REGISTRY.get('building-command-table.main', [])
+ violations = []
+
+ for module_path, fn_name, entry_type in main_entries:
+ collector = _CallbackCollector('building-command-table.main')
+ mod = importlib.import_module(module_path)
+ fn = getattr(mod, fn_name)
+ fn(collector)
+
+ for callback in collector.callbacks:
+ cb_name = f'{callback.__module__}.{callback.__qualname__}'
+
+ # Build a fresh command table for each callback.
+ class _Placeholder:
+ def __init__(self, name):
+ self.name = name
+
+ command_table = OrderedDict()
+ for svc in services:
+ command_table[svc] = _Placeholder(svc)
+
+ snap_id_to_key = {id(v): k for k, v in command_table.items()}
+ snap_id_to_name = {id(v): v.name for k, v in command_table.items()}
+
+ callback(command_table=command_table, session=session)
+
+ # Classify every change.
+ new_id_to_key = {id(v): k for k, v in command_table.items()}
+ renamed_ids = set()
+
+ # Detect renames.
+ for obj_id, new_key in new_id_to_key.items():
+ old_key = snap_id_to_key.get(obj_id)
+ if old_key is not None and old_key != new_key:
+ renamed_ids.add(obj_id)
+
+ # Detect modifications: an existing (non-renamed) entry whose
+ # .name property changed, or any entry that was removed.
+ for obj_id, old_key in snap_id_to_key.items():
+ if obj_id in renamed_ids:
+ continue
+ if obj_id not in new_id_to_key:
+ violations.append(f'{cb_name} removed command {old_key!r}')
+ continue
+ new_key = new_id_to_key[obj_id]
+ cmd = command_table[new_key]
+ if cmd.name != snap_id_to_name[obj_id]:
+ violations.append(
+ f'{cb_name} modified .name on {new_key!r} '
+ f'without renaming'
+ )
+
+ assert not violations, (
+ 'Callbacks registered against building-command-table.main must '
+ 'only add or rename commands. The following callbacks perform '
+ 'other modifications that would be lost when replaced by '
+ 'MAIN_COMMAND_TABLE_OPS:\n' + '\n'.join(f' - {v}' for v in violations)
+ )
diff --git a/tests/unit/customizations/s3/test_s3.py b/tests/unit/customizations/s3/test_s3.py
index 29f7fbf151b7..a8a4e4870178 100644
--- a/tests/unit/customizations/s3/test_s3.py
+++ b/tests/unit/customizations/s3/test_s3.py
@@ -10,7 +10,11 @@
# 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.s3.s3 import add_s3, awscli_initialize
+from awscli.customizations.s3.s3 import (
+ add_s3,
+ register_s3_main,
+ register_s3_sync_strategies,
+)
from awscli.testutils import BaseAWSCommandParamsTest, mock, unittest
@@ -24,7 +28,8 @@ def setUp(self):
self.cli = mock.Mock()
def test_initialize(self):
- awscli_initialize(self.cli)
+ register_s3_main(self.cli)
+ register_s3_sync_strategies(self.cli)
reference = []
reference.append("building-command-table.main")
reference.append("building-command-table.s3_sync")
From 975f57a9aa1b7f7d2ab1bb8e54e8dedb2db486fb Mon Sep 17 00:00:00 2001
From: aemous
Date: Wed, 13 May 2026 14:24:34 -0400
Subject: [PATCH 2/6] Add handlers_registry.py which maps events to plugins and
declares command-table operations.
---
awscli/handlers_registry.py | 738 ++++++++++++++++++++++++++++++++++++
1 file changed, 738 insertions(+)
create mode 100644 awscli/handlers_registry.py
diff --git a/awscli/handlers_registry.py b/awscli/handlers_registry.py
new file mode 100644
index 000000000000..c20c40183f72
--- /dev/null
+++ b/awscli/handlers_registry.py
@@ -0,0 +1,738 @@
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"). You
+# may not use this file except in compliance with the License. A copy of
+# the License is located at
+#
+# http://aws.amazon.com/apache2.0/
+#
+# or in the "license" file accompanying this file. This file is
+# 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.
+"""Maps event patterns to initializer entries.
+
+At runtime, the LazyInitEmitter triggers entries on demand:
+before emitting event X, it finds entries whose event patterns
+match X, calls each init function at most once (passing the
+event_handlers emitter), then proceeds with normal event dispatch.
+
+Entry format:
+ (module, fn_name) call fn(event_handlers)
+"""
+PLUGIN_REGISTRY = {
+ 'after-call.data-pipeline.GetPipelineDefinition': [
+ ('awscli.customizations.datapipeline', 'register_customizations')
+ ],
+ 'after-call.ecs.CreateExpressGatewayService': [
+ ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ ],
+ 'after-call.ecs.DeleteExpressGatewayService': [
+ ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ ],
+ 'after-call.ecs.UpdateExpressGatewayService': [
+ ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ ],
+ 'after-call.iam.CreateVirtualMFADevice': [
+ ('awscli.customizations.iamvirtmfa', 'IAMVMFAWrapper')
+ ],
+ 'after-call.s3': [
+ ('awscli.customizations.s3errormsg', 'register_s3_error_msg')
+ ],
+ 'before-building-argument-table-parser.ecs.create-express-gateway-service': [
+ ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ ],
+ 'before-building-argument-table-parser.ecs.delete-express-gateway-service': [
+ ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ ],
+ 'before-building-argument-table-parser.ecs.update-express-gateway-service': [
+ ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ ],
+ 'before-building-argument-table-parser.emr.*': [
+ ('awscli.customizations.emr.emr', 'emr_initialize')
+ ],
+ 'before-parameter-build.ec2.BundleInstance': [
+ ('awscli.customizations.ec2.bundleinstance', 'register_bundleinstance')
+ ],
+ 'before-parameter-build.ec2.CreateNetworkAclEntry': [
+ ('awscli.customizations.ec2.protocolarg', 'register_protocol_args')
+ ],
+ 'before-parameter-build.ec2.ReplaceNetworkAclEntry': [
+ ('awscli.customizations.ec2.protocolarg', 'register_protocol_args')
+ ],
+ 'before-parameter-build.ec2.RunInstances': [
+ ('awscli.customizations.ec2.addcount', 'register_count_events'),
+ ('awscli.customizations.ec2.runinstances', 'register_runinstances')
+ ],
+ 'building-argument-table': [
+ ('awscli.customizations.cliinput', 'register_cli_input_args'),
+ ('awscli.customizations.paginate', 'register_pagination'),
+ ('awscli.customizations.generatecliskeleton', 'register_generate_cli_skeleton')
+ ],
+ 'building-argument-table.*': [
+ ('awscli.customizations.streamingoutputarg', 'register_streaming_output_arg')
+ ],
+ 'building-argument-table.apigateway.create-rest-api': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.apigatewayv2.create-api': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.apigatewayv2.update-api': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.clouddirectory.publish-schema': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.cloudfront.create-distribution': [
+ ('awscli.customizations.cloudfront', 'register')
+ ],
+ 'building-argument-table.cloudfront.create-invalidation': [
+ ('awscli.customizations.cloudfront', 'register')
+ ],
+ 'building-argument-table.cloudfront.update-distribution': [
+ ('awscli.customizations.cloudfront', 'register')
+ ],
+ 'building-argument-table.cloudsearch.define-expression': [
+ ('awscli.customizations.cloudsearch', 'initialize')
+ ],
+ 'building-argument-table.cloudsearch.define-index-field': [
+ ('awscli.customizations.cloudsearch', 'initialize')
+ ],
+ 'building-argument-table.cloudsearchdomain.search': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.cloudsearchdomain.suggest': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.cloudwatch.put-metric-data': [
+ ('awscli.customizations.putmetricdata', 'register_put_metric_data')
+ ],
+ 'building-argument-table.codepipeline.create-custom-action-type': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.codepipeline.delete-custom-action-type': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.codepipeline.get-action-type': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.codepipeline.get-pipeline': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.configservice.put-configuration-recorder': [
+ ('awscli.customizations.configservice.putconfigurationrecorder', 'register_modify_put_configuration_recorder')
+ ],
+ 'building-argument-table.controltower.create-landing-zone': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.controltower.update-landing-zone': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.datapipeline.*': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.datapipeline.activate-pipeline': [
+ ('awscli.customizations.datapipeline', 'register_customizations')
+ ],
+ 'building-argument-table.datapipeline.get-pipeline-definition': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.datapipeline.put-pipeline-definition': [
+ ('awscli.customizations.datapipeline', 'register_customizations')
+ ],
+ 'building-argument-table.deploy.*': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.deploy.create-deployment': [
+ ('awscli.customizations.codedeploy.codedeploy', 'register_codedeploy')
+ ],
+ 'building-argument-table.deploy.get-application-revision': [
+ ('awscli.customizations.codedeploy.codedeploy', 'register_codedeploy')
+ ],
+ 'building-argument-table.deploy.register-application-revision': [
+ ('awscli.customizations.codedeploy.codedeploy', 'register_codedeploy')
+ ],
+ 'building-argument-table.ec2.*': [
+ ('awscli.customizations.argrename', 'register_arg_renames'),
+ ('awscli.customizations.toplevelbool', 'register_bool_params')
+ ],
+ 'building-argument-table.ec2.authorize-security-group-egress': [
+ ('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
+ ],
+ 'building-argument-table.ec2.authorize-security-group-ingress': [
+ ('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
+ ],
+ 'building-argument-table.ec2.bundle-instance': [
+ ('awscli.customizations.ec2.bundleinstance', 'register_bundleinstance')
+ ],
+ 'building-argument-table.ec2.create-image': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.ec2.get-password-data': [
+ ('awscli.customizations.ec2.decryptpassword', 'register_ec2_add_priv_launch_key')
+ ],
+ 'building-argument-table.ec2.revoke-security-group-egress': [
+ ('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
+ ],
+ 'building-argument-table.ec2.revoke-security-group-ingress': [
+ ('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
+ ],
+ 'building-argument-table.ec2.run-instances': [
+ ('awscli.customizations.ec2.addcount', 'register_count_events'),
+ ('awscli.customizations.ec2.runinstances', 'register_runinstances')
+ ],
+ 'building-argument-table.ecs.*': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.ecs.create-express-gateway-service': [
+ ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ ],
+ 'building-argument-table.ecs.delete-express-gateway-service': [
+ ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ ],
+ 'building-argument-table.ecs.execute-command': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.ecs.update-express-gateway-service': [
+ ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ ],
+ 'building-argument-table.eks.create-cluster': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.eks.create-nodegroup': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.eks.update-cluster-components-version': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.eks.update-cluster-version': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.eks.update-nodegroup-version': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.elasticache.create-replication-group': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.emr.*': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.emr.add-tags': [
+ ('awscli.customizations.emr.emr', 'emr_initialize')
+ ],
+ 'building-argument-table.emr.list-clusters': [
+ ('awscli.customizations.emr.emr', 'emr_initialize')
+ ],
+ 'building-argument-table.gamelift.create-build': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.gamelift.create-script': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.gamelift.update-build': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.gamelift.update-script': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.glue.get-unfiltered-partition-metadata': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.glue.get-unfiltered-partitions-metadata': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.glue.get-unfiltered-table-metadata': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.iam.create-virtual-mfa-device': [
+ ('awscli.customizations.iamvirtmfa', 'IAMVMFAWrapper')
+ ],
+ 'building-argument-table.iot.create-certificate-from-csr': [
+ ('awscli.customizations.iot', 'register_iot_create_keys_from_csr')
+ ],
+ 'building-argument-table.iot.create-keys-and-certificate': [
+ ('awscli.customizations.iot', 'register_iot_create_keys_and_cert_args')
+ ],
+ 'building-argument-table.iotwireless.*': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.kinesis.list-streams': [
+ ('awscli.customizations.kinesis', 'register_kinesis_list_streams_pagination_backcompat')
+ ],
+ 'building-argument-table.kinesisanalytics.add-application-output': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.kinesisanalyticsv2.add-application-output': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.lambda.create-function': [
+ ('awscli.customizations.awslambda', 'register_lambda_create_function')
+ ],
+ 'building-argument-table.lambda.publish-layer-version': [
+ ('awscli.customizations.awslambda', 'register_lambda_create_function')
+ ],
+ 'building-argument-table.lambda.update-function-code': [
+ ('awscli.customizations.awslambda', 'register_lambda_create_function')
+ ],
+ 'building-argument-table.lex-models.delete-bot': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.lex-models.delete-bot-version': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.lex-models.delete-intent': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.lex-models.delete-intent-version': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.lex-models.delete-slot-type': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.lex-models.delete-slot-type-version': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.lex-models.get-export': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.lex-models.get-intent': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.lex-models.get-slot-type': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.license-manager.delete-grant': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.license-manager.get-grant': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.license-manager.get-license': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.mgn.*': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.mturk.list-qualification-types': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.delete-email-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.delete-in-app-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.delete-push-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.delete-sms-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.delete-voice-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.get-campaign-version': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.get-email-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.get-in-app-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.get-push-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.get-segment-version': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.get-sms-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.get-voice-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.update-email-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.update-in-app-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.update-push-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.update-sms-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.pinpoint.update-voice-template': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.quicksight.start-asset-bundle-import-job': [
+ ('awscli.customizations.quicksight', 'register_quicksight_asset_bundle_customizations')
+ ],
+ 'building-argument-table.rds.add-option-to-option-group': [
+ ('awscli.customizations.rds', 'register_rds_modify_split')
+ ],
+ 'building-argument-table.rds.remove-option-from-option-group': [
+ ('awscli.customizations.rds', 'register_rds_modify_split')
+ ],
+ 'building-argument-table.rekognition.*': [
+ ('awscli.customizations.rekognition', 'register_rekognition_detect_labels')
+ ],
+ 'building-argument-table.rekognition.compare-faces': [
+ ('awscli.customizations.rekognition', 'register_rekognition_detect_labels')
+ ],
+ 'building-argument-table.rekognition.create-stream-processor': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.route53.delete-traffic-policy': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.route53.get-traffic-policy': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.route53.update-traffic-policy-comment': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.route53domains.view-billing': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.s3api.select-object-content': [
+ ('awscli.customizations.s3events', 'register_event_stream_arg')
+ ],
+ 'building-argument-table.sagemaker.delete-image-version': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.sagemaker.describe-image-version': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.sagemaker.list-aliases': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.sagemaker.update-image-version': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.schemas.*': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.ses.send-email': [
+ ('awscli.customizations.sessendemail', 'register_ses_send_email')
+ ],
+ 'building-argument-table.sns.subscribe': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.stepfunctions.send-task-success': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.swf.register-activity-type': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.swf.register-workflow-type': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.translate.import-terminology': [
+ ('awscli.customizations.translate', 'register_translate_import_terminology')
+ ],
+ 'building-argument-table.translate.translate-document': [
+ ('awscli.customizations.translate', 'register_translate_import_terminology')
+ ],
+ 'building-argument-table.workdocs.create-notification-subscription': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-argument-table.workdocs.describe-users': [
+ ('awscli.customizations.argrename', 'register_arg_renames')
+ ],
+ 'building-command-table': [
+ ('awscli.customizations.waiters', 'register_add_waiters'),
+ ('awscli.alias', 'register_alias_commands')
+ ],
+ 'building-command-table.bedrock-agent-runtime': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.bedrock-agentcore': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.bedrock-runtime': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.cli-dev': [
+ ('awscli.customizations.wizard.commands', 'register_wizard_commands')
+ ],
+ 'building-command-table.cloudformation': [
+ ('awscli.customizations.cloudformation', 'initialize')
+ ],
+ 'building-command-table.cloudfront': [
+ ('awscli.customizations.cloudfront', 'register')
+ ],
+ 'building-command-table.cloudtrail': [
+ ('awscli.customizations.cloudtrail', 'initialize')
+ ],
+ 'building-command-table.cloudwatch': [
+ ('awscli.customizations.cloudwatch', 'register_rename_otel_commands')
+ ],
+ 'building-command-table.codeartifact': [
+ ('awscli.customizations.codeartifact', 'register_codeartifact_commands')
+ ],
+ 'building-command-table.codecommit': [
+ ('awscli.customizations.codecommit', 'initialize')
+ ],
+ 'building-command-table.configservice': [
+ ('awscli.customizations.configservice.subscribe', 'register_subscribe'),
+ ('awscli.customizations.configservice.getstatus', 'register_get_status')
+ ],
+ 'building-command-table.configure': [
+ ('awscli.customizations.wizard.commands', 'register_wizard_commands')
+ ],
+ 'building-command-table.connecthealth': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.datapipeline': [
+ ('awscli.customizations.datapipeline', 'register_customizations')
+ ],
+ 'building-command-table.deploy': [
+ ('awscli.customizations.codedeploy.codedeploy', 'register_codedeploy')
+ ],
+ 'building-command-table.devops-agent': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.dlm': [
+ ('awscli.customizations.dlm.dlm', 'dlm_initialize')
+ ],
+ 'building-command-table.dsql': [
+ ('awscli.customizations.dsql', 'register_dsql_customizations')
+ ],
+ 'building-command-table.dynamodb': [
+ ('awscli.customizations.wizard.commands', 'register_wizard_commands')
+ ],
+ 'building-command-table.ec2': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.ec2-instance-connect': [
+ ('awscli.customizations.ec2instanceconnect', 'register_ec2_instance_connect_commands')
+ ],
+ 'building-command-table.ecr': [
+ ('awscli.customizations.ecr', 'register_ecr_commands')
+ ],
+ 'building-command-table.ecr-public': [
+ ('awscli.customizations.ecr_public', 'register_ecr_public_commands')
+ ],
+ 'building-command-table.ecs': [
+ ('awscli.customizations.ecs', 'initialize')
+ ],
+ 'building-command-table.eks': [
+ ('awscli.customizations.eks', 'initialize')
+ ],
+ 'building-command-table.emr': [
+ ('awscli.customizations.removals', 'register_removals'),
+ ('awscli.customizations.emr.emr', 'emr_initialize')
+ ],
+ 'building-command-table.emr-containers': [
+ ('awscli.customizations.emrcontainers', 'initialize')
+ ],
+ 'building-command-table.events': [
+ ('awscli.customizations.wizard.commands', 'register_wizard_commands')
+ ],
+ 'building-command-table.gamelift': [
+ ('awscli.customizations.gamelift', 'register_gamelift_commands')
+ ],
+ 'building-command-table.iam': [
+ ('awscli.customizations.wizard.commands', 'register_wizard_commands')
+ ],
+ 'building-command-table.iotsitewise': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.kinesis': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.lambda': [
+ ('awscli.customizations.removals', 'register_removals'),
+ ('awscli.customizations.wizard.commands', 'register_wizard_commands')
+ ],
+ 'building-command-table.lexv2-runtime': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.lightsail': [
+ ('awscli.customizations.lightsail', 'initialize')
+ ],
+ 'building-command-table.logs': [
+ ('awscli.customizations.removals', 'register_removals'),
+ ('awscli.customizations.logs', 'register_logs_commands')
+ ],
+ 'building-command-table.main': [
+ ('awscli.customizations.s3.s3', 'register_s3_main'),
+ ('awscli.customizations.dynamodb.ddb', 'register_ddb'),
+ ('awscli.customizations.configure.configure', 'register_configure_cmd'),
+ ('awscli.customizations.codedeploy.codedeploy', 'register_rename_codedeploy'),
+ ('awscli.customizations.configservice.rename_cmd', 'register_rename_config'),
+ ('awscli.customizations.history', 'register_history_commands'),
+ ('awscli.customizations.devcommands', 'register_dev_commands'),
+ ('awscli.customizations.login', 'register_login_cmds')
+ ],
+ 'building-command-table.polly': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.qbusiness': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.rds': [
+ ('awscli.customizations.rds', 'register_rds_modify_split'),
+ ('awscli.customizations.rds', 'register_add_generate_db_auth_token')
+ ],
+ 'building-command-table.s3_sync': [
+ ('awscli.customizations.s3.s3', 'register_s3_sync_strategies')
+ ],
+ 'building-command-table.sagemaker-runtime': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.servicecatalog': [
+ ('awscli.customizations.servicecatalog', 'register_servicecatalog_commands')
+ ],
+ 'building-command-table.ses': [
+ ('awscli.customizations.removals', 'register_removals')
+ ],
+ 'building-command-table.ssm': [
+ ('awscli.customizations.sessionmanager', 'register_ssm_session')
+ ],
+ 'building-command-table.sso': [
+ ('awscli.customizations.sso', 'register_sso_commands')
+ ],
+ 'calling-command.cloudsearchdomain': [
+ ('awscli.customizations.cloudsearchdomain', 'register_cloudsearchdomain')
+ ],
+ 'calling-command.dynamodb.*': [
+ ('awscli.customizations.dynamodb.paginatorfix', 'register_dynamodb_paginator_fix')
+ ],
+ 'calling-command.ec2.describe-snapshots': [
+ ('awscli.customizations.ec2.paginate', 'register_ec2_page_size_injector')
+ ],
+ 'calling-command.ec2.describe-volumes': [
+ ('awscli.customizations.ec2.paginate', 'register_ec2_page_size_injector')
+ ],
+ 'doc-description': [
+ ('awscli.customizations.paginate', 'register_pagination')
+ ],
+ 'doc-description.ec2.authorize-security-group-egress': [
+ ('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
+ ],
+ 'doc-description.ec2.authorize-security-group-ingress': [
+ ('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
+ ],
+ 'doc-description.ec2.revoke-security-group-ingress': [
+ ('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
+ ],
+ 'doc-description.ec2.revoke-security-groupdoc-ingress': [
+ ('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
+ ],
+ 'doc-description.iot-data': [
+ ('awscli.customizations.iot_data', 'register_custom_endpoint_note')
+ ],
+ 'doc-examples.*.*': [
+ ('awscli.customizations.addexamples', 'register_docs_add_examples')
+ ],
+ 'doc-option.route53.create-hosted-zone.hosted-zone-config': [
+ ('awscli.customizations.route53', 'register_create_hosted_zone_doc_fix')
+ ],
+ 'doc-output.datapipeline.get-pipeline-definition': [
+ ('awscli.customizations.datapipeline', 'register_customizations')
+ ],
+ 'doc-output.s3api': [
+ ('awscli.customizations.s3events', 'register_document_expires_string')
+ ],
+ 'doc-output.s3api.select-object-content': [
+ ('awscli.customizations.s3events', 'register_event_stream_arg')
+ ],
+ 'doc-title.kms.create-grant': [
+ ('awscli.customizations.kms', 'register_fix_kms_create_grant_docs')
+ ],
+ 'operation-args-parsed.cloudfront.create-distribution': [
+ ('awscli.customizations.cloudfront', 'register')
+ ],
+ 'operation-args-parsed.cloudfront.create-invalidation': [
+ ('awscli.customizations.cloudfront', 'register')
+ ],
+ 'operation-args-parsed.cloudfront.update-distribution': [
+ ('awscli.customizations.cloudfront', 'register')
+ ],
+ 'operation-args-parsed.cloudwatch.put-metric-data': [
+ ('awscli.customizations.putmetricdata', 'register_put_metric_data')
+ ],
+ 'operation-args-parsed.ec2.authorize-security-group-egress': [
+ ('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
+ ],
+ 'operation-args-parsed.ec2.authorize-security-group-ingress': [
+ ('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
+ ],
+ 'operation-args-parsed.ec2.bundle-instance': [
+ ('awscli.customizations.ec2.bundleinstance', 'register_bundleinstance')
+ ],
+ 'operation-args-parsed.ec2.revoke-security-group-egress': [
+ ('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
+ ],
+ 'operation-args-parsed.ec2.revoke-security-group-ingress': [
+ ('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
+ ],
+ 'operation-args-parsed.ec2.run-instances': [
+ ('awscli.customizations.ec2.runinstances', 'register_runinstances')
+ ],
+ 'operation-args-parsed.ecs.create-express-gateway-service': [
+ ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ ],
+ 'operation-args-parsed.ecs.delete-express-gateway-service': [
+ ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ ],
+ 'operation-args-parsed.ecs.update-express-gateway-service': [
+ ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ ],
+ 'operation-args-parsed.kinesis.list-streams': [
+ ('awscli.customizations.kinesis', 'register_kinesis_list_streams_pagination_backcompat')
+ ],
+ 'operation-args-parsed.ses.send-email': [
+ ('awscli.customizations.sessendemail', 'register_ses_send_email')
+ ],
+ 'process-cli-arg': [
+ ('awscli.argprocess', 'register_param_shorthand_parser')
+ ],
+ 'process-cli-arg.lambda.update-function-code': [
+ ('awscli.customizations.awslambda', 'register_lambda_create_function')
+ ],
+ 'session-initialized': [
+ ('awscli.paramfile', 'register_init_uri_param_handler'),
+ ('awscli.customizations.binaryformat', 'register_init_binary_formatter'),
+ ('awscli.clidriver', 'register_no_pager_handler'),
+ ('awscli.customizations.assumerole', 'register_assume_role_provider'),
+ ('awscli.customizations.timestampformat', 'register_timestamp_format'),
+ ('awscli.customizations.history', 'register_history_mode'),
+ ('awscli.customizations.sso', 'register_sso_commands')
+ ],
+ 'top-level-args-parsed': [
+ ('awscli.customizations.globalargs', 'register_parse_global_args'),
+ ('awscli.customizations.cloudfront', 'register')
+ ]
+}
+
+# Declarative model of changes made to the command table by plugins
+# that register against building-command-table.main.
+#
+# At runtime, plugins listed in building-command-table.main above
+# are NOT called as init functions. Instead, these pre-computed
+# operations are applied directly, allowing added commands to be
+# wrapped in LazyCommand and deferring heavy module imports until
+# the command is actually invoked.
+#
+# Entry formats:
+# ('rename', old_name, new_name)
+# ('add', cmd_name, cmd_module, cmd_class)
+
+MAIN_COMMAND_TABLE_OPS = [
+ ('rename', 's3', 's3api'),
+ ('add', 's3', 'awscli.customizations.s3.s3', 'S3'),
+ ('add', 'ddb', 'awscli.customizations.dynamodb.ddb', 'DDB'),
+ ('add', 'configure', 'awscli.customizations.configure.configure', 'ConfigureCommand'),
+ ('rename', 'codedeploy', 'deploy'),
+ ('rename', 'config', 'configservice'),
+ ('add', 'history', 'awscli.customizations.history', 'HistoryCommand'),
+ ('add', 'cli-dev', 'awscli.customizations.devcommands', 'CLIDevCommand'),
+ ('add', 'login', 'awscli.customizations.login.login', 'LoginCommand'),
+ ('add', 'logout', 'awscli.customizations.login.logout', 'LogoutCommand'),
+]
From 75d5343c8bc95c40d2fdd3824fadeb4247290c41 Mon Sep 17 00:00:00 2001
From: aemous
Date: Wed, 13 May 2026 14:25:16 -0400
Subject: [PATCH 3/6] Formatting.
---
awscli/customizations/addexamples.py | 1 -
awscli/handlers.py | 10 +-
awscli/handlers_registry.py | 217 +++++++++++++++++++++------
3 files changed, 174 insertions(+), 54 deletions(-)
diff --git a/awscli/customizations/addexamples.py b/awscli/customizations/addexamples.py
index 9ccf670ec6e8..5e91cc547aed 100644
--- a/awscli/customizations/addexamples.py
+++ b/awscli/customizations/addexamples.py
@@ -34,7 +34,6 @@
def register_docs_add_examples(event_emitter):
-
# The following will get fired for every option we are
# documenting. It will attempt to add an example_fn on to
# the parameter object if the parameter supports shorthand
diff --git a/awscli/handlers.py b/awscli/handlers.py
index bc5234a4a7f9..2dab06ba171a 100644
--- a/awscli/handlers.py
+++ b/awscli/handlers.py
@@ -39,6 +39,8 @@
from awscli.customizations.codecommit import initialize as codecommit_init
from awscli.customizations.codedeploy.codedeploy import (
register_codedeploy,
+)
+from awscli.customizations.codedeploy.codedeploy import (
register_rename_codedeploy as codedeploy_init,
)
from awscli.customizations.configservice.getstatus import register_get_status
@@ -60,7 +62,7 @@
from awscli.customizations.ec2.addcount import register_count_events
from awscli.customizations.ec2.bundleinstance import register_bundleinstance
from awscli.customizations.ec2.decryptpassword import (
- register_ec2_add_priv_launch_key
+ register_ec2_add_priv_launch_key,
)
from awscli.customizations.ec2.paginate import register_ec2_page_size_injector
from awscli.customizations.ec2.protocolarg import register_protocol_args
@@ -118,7 +120,7 @@
from awscli.customizations.route53 import register_create_hosted_zone_doc_fix
from awscli.customizations.s3.s3 import (
register_s3_main,
- register_s3_sync_strategies
+ register_s3_sync_strategies,
)
from awscli.customizations.s3errormsg import register_s3_error_msg
from awscli.customizations.s3events import (
@@ -131,7 +133,9 @@
from awscli.customizations.sessendemail import register_ses_send_email
from awscli.customizations.sessionmanager import register_ssm_session
from awscli.customizations.sso import register_sso_commands
-from awscli.customizations.streamingoutputarg import register_streaming_output_arg
+from awscli.customizations.streamingoutputarg import (
+ register_streaming_output_arg,
+)
from awscli.customizations.timestampformat import register_timestamp_format
from awscli.customizations.toplevelbool import register_bool_params
from awscli.customizations.translate import (
diff --git a/awscli/handlers_registry.py b/awscli/handlers_registry.py
index c20c40183f72..0aa2bef59223 100644
--- a/awscli/handlers_registry.py
+++ b/awscli/handlers_registry.py
@@ -20,18 +20,28 @@
Entry format:
(module, fn_name) call fn(event_handlers)
"""
+
PLUGIN_REGISTRY = {
'after-call.data-pipeline.GetPipelineDefinition': [
('awscli.customizations.datapipeline', 'register_customizations')
],
'after-call.ecs.CreateExpressGatewayService': [
- ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ (
+ 'awscli.customizations.ecs.monitormutatinggatewayservice',
+ 'register_monitor_mutating_gateway_service',
+ )
],
'after-call.ecs.DeleteExpressGatewayService': [
- ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ (
+ 'awscli.customizations.ecs.monitormutatinggatewayservice',
+ 'register_monitor_mutating_gateway_service',
+ )
],
'after-call.ecs.UpdateExpressGatewayService': [
- ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ (
+ 'awscli.customizations.ecs.monitormutatinggatewayservice',
+ 'register_monitor_mutating_gateway_service',
+ )
],
'after-call.iam.CreateVirtualMFADevice': [
('awscli.customizations.iamvirtmfa', 'IAMVMFAWrapper')
@@ -40,13 +50,22 @@
('awscli.customizations.s3errormsg', 'register_s3_error_msg')
],
'before-building-argument-table-parser.ecs.create-express-gateway-service': [
- ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ (
+ 'awscli.customizations.ecs.monitormutatinggatewayservice',
+ 'register_monitor_mutating_gateway_service',
+ )
],
'before-building-argument-table-parser.ecs.delete-express-gateway-service': [
- ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ (
+ 'awscli.customizations.ecs.monitormutatinggatewayservice',
+ 'register_monitor_mutating_gateway_service',
+ )
],
'before-building-argument-table-parser.ecs.update-express-gateway-service': [
- ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ (
+ 'awscli.customizations.ecs.monitormutatinggatewayservice',
+ 'register_monitor_mutating_gateway_service',
+ )
],
'before-building-argument-table-parser.emr.*': [
('awscli.customizations.emr.emr', 'emr_initialize')
@@ -62,15 +81,21 @@
],
'before-parameter-build.ec2.RunInstances': [
('awscli.customizations.ec2.addcount', 'register_count_events'),
- ('awscli.customizations.ec2.runinstances', 'register_runinstances')
+ ('awscli.customizations.ec2.runinstances', 'register_runinstances'),
],
'building-argument-table': [
('awscli.customizations.cliinput', 'register_cli_input_args'),
('awscli.customizations.paginate', 'register_pagination'),
- ('awscli.customizations.generatecliskeleton', 'register_generate_cli_skeleton')
+ (
+ 'awscli.customizations.generatecliskeleton',
+ 'register_generate_cli_skeleton',
+ ),
],
'building-argument-table.*': [
- ('awscli.customizations.streamingoutputarg', 'register_streaming_output_arg')
+ (
+ 'awscli.customizations.streamingoutputarg',
+ 'register_streaming_output_arg',
+ )
],
'building-argument-table.apigateway.create-rest-api': [
('awscli.customizations.argrename', 'register_arg_renames')
@@ -121,7 +146,10 @@
('awscli.customizations.argrename', 'register_arg_renames')
],
'building-argument-table.configservice.put-configuration-recorder': [
- ('awscli.customizations.configservice.putconfigurationrecorder', 'register_modify_put_configuration_recorder')
+ (
+ 'awscli.customizations.configservice.putconfigurationrecorder',
+ 'register_modify_put_configuration_recorder',
+ )
],
'building-argument-table.controltower.create-landing-zone': [
('awscli.customizations.argrename', 'register_arg_renames')
@@ -155,7 +183,7 @@
],
'building-argument-table.ec2.*': [
('awscli.customizations.argrename', 'register_arg_renames'),
- ('awscli.customizations.toplevelbool', 'register_bool_params')
+ ('awscli.customizations.toplevelbool', 'register_bool_params'),
],
'building-argument-table.ec2.authorize-security-group-egress': [
('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
@@ -170,7 +198,10 @@
('awscli.customizations.argrename', 'register_arg_renames')
],
'building-argument-table.ec2.get-password-data': [
- ('awscli.customizations.ec2.decryptpassword', 'register_ec2_add_priv_launch_key')
+ (
+ 'awscli.customizations.ec2.decryptpassword',
+ 'register_ec2_add_priv_launch_key',
+ )
],
'building-argument-table.ec2.revoke-security-group-egress': [
('awscli.customizations.ec2.secgroupsimplify', 'register_secgroup')
@@ -180,22 +211,31 @@
],
'building-argument-table.ec2.run-instances': [
('awscli.customizations.ec2.addcount', 'register_count_events'),
- ('awscli.customizations.ec2.runinstances', 'register_runinstances')
+ ('awscli.customizations.ec2.runinstances', 'register_runinstances'),
],
'building-argument-table.ecs.*': [
('awscli.customizations.argrename', 'register_arg_renames')
],
'building-argument-table.ecs.create-express-gateway-service': [
- ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ (
+ 'awscli.customizations.ecs.monitormutatinggatewayservice',
+ 'register_monitor_mutating_gateway_service',
+ )
],
'building-argument-table.ecs.delete-express-gateway-service': [
- ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ (
+ 'awscli.customizations.ecs.monitormutatinggatewayservice',
+ 'register_monitor_mutating_gateway_service',
+ )
],
'building-argument-table.ecs.execute-command': [
('awscli.customizations.argrename', 'register_arg_renames')
],
'building-argument-table.ecs.update-express-gateway-service': [
- ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ (
+ 'awscli.customizations.ecs.monitormutatinggatewayservice',
+ 'register_monitor_mutating_gateway_service',
+ )
],
'building-argument-table.eks.create-cluster': [
('awscli.customizations.argrename', 'register_arg_renames')
@@ -258,7 +298,10 @@
('awscli.customizations.argrename', 'register_arg_renames')
],
'building-argument-table.kinesis.list-streams': [
- ('awscli.customizations.kinesis', 'register_kinesis_list_streams_pagination_backcompat')
+ (
+ 'awscli.customizations.kinesis',
+ 'register_kinesis_list_streams_pagination_backcompat',
+ )
],
'building-argument-table.kinesisanalytics.add-application-output': [
('awscli.customizations.argrename', 'register_arg_renames')
@@ -369,7 +412,10 @@
('awscli.customizations.argrename', 'register_arg_renames')
],
'building-argument-table.quicksight.start-asset-bundle-import-job': [
- ('awscli.customizations.quicksight', 'register_quicksight_asset_bundle_customizations')
+ (
+ 'awscli.customizations.quicksight',
+ 'register_quicksight_asset_bundle_customizations',
+ )
],
'building-argument-table.rds.add-option-to-option-group': [
('awscli.customizations.rds', 'register_rds_modify_split')
@@ -378,10 +424,16 @@
('awscli.customizations.rds', 'register_rds_modify_split')
],
'building-argument-table.rekognition.*': [
- ('awscli.customizations.rekognition', 'register_rekognition_detect_labels')
+ (
+ 'awscli.customizations.rekognition',
+ 'register_rekognition_detect_labels',
+ )
],
'building-argument-table.rekognition.compare-faces': [
- ('awscli.customizations.rekognition', 'register_rekognition_detect_labels')
+ (
+ 'awscli.customizations.rekognition',
+ 'register_rekognition_detect_labels',
+ )
],
'building-argument-table.rekognition.create-stream-processor': [
('awscli.customizations.argrename', 'register_arg_renames')
@@ -432,10 +484,16 @@
('awscli.customizations.argrename', 'register_arg_renames')
],
'building-argument-table.translate.import-terminology': [
- ('awscli.customizations.translate', 'register_translate_import_terminology')
+ (
+ 'awscli.customizations.translate',
+ 'register_translate_import_terminology',
+ )
],
'building-argument-table.translate.translate-document': [
- ('awscli.customizations.translate', 'register_translate_import_terminology')
+ (
+ 'awscli.customizations.translate',
+ 'register_translate_import_terminology',
+ )
],
'building-argument-table.workdocs.create-notification-subscription': [
('awscli.customizations.argrename', 'register_arg_renames')
@@ -445,7 +503,7 @@
],
'building-command-table': [
('awscli.customizations.waiters', 'register_add_waiters'),
- ('awscli.alias', 'register_alias_commands')
+ ('awscli.alias', 'register_alias_commands'),
],
'building-command-table.bedrock-agent-runtime': [
('awscli.customizations.removals', 'register_removals')
@@ -472,14 +530,23 @@
('awscli.customizations.cloudwatch', 'register_rename_otel_commands')
],
'building-command-table.codeartifact': [
- ('awscli.customizations.codeartifact', 'register_codeartifact_commands')
+ (
+ 'awscli.customizations.codeartifact',
+ 'register_codeartifact_commands',
+ )
],
'building-command-table.codecommit': [
('awscli.customizations.codecommit', 'initialize')
],
'building-command-table.configservice': [
- ('awscli.customizations.configservice.subscribe', 'register_subscribe'),
- ('awscli.customizations.configservice.getstatus', 'register_get_status')
+ (
+ 'awscli.customizations.configservice.subscribe',
+ 'register_subscribe',
+ ),
+ (
+ 'awscli.customizations.configservice.getstatus',
+ 'register_get_status',
+ ),
],
'building-command-table.configure': [
('awscli.customizations.wizard.commands', 'register_wizard_commands')
@@ -509,7 +576,10 @@
('awscli.customizations.removals', 'register_removals')
],
'building-command-table.ec2-instance-connect': [
- ('awscli.customizations.ec2instanceconnect', 'register_ec2_instance_connect_commands')
+ (
+ 'awscli.customizations.ec2instanceconnect',
+ 'register_ec2_instance_connect_commands',
+ )
],
'building-command-table.ecr': [
('awscli.customizations.ecr', 'register_ecr_commands')
@@ -525,7 +595,7 @@
],
'building-command-table.emr': [
('awscli.customizations.removals', 'register_removals'),
- ('awscli.customizations.emr.emr', 'emr_initialize')
+ ('awscli.customizations.emr.emr', 'emr_initialize'),
],
'building-command-table.emr-containers': [
('awscli.customizations.emrcontainers', 'initialize')
@@ -547,7 +617,7 @@
],
'building-command-table.lambda': [
('awscli.customizations.removals', 'register_removals'),
- ('awscli.customizations.wizard.commands', 'register_wizard_commands')
+ ('awscli.customizations.wizard.commands', 'register_wizard_commands'),
],
'building-command-table.lexv2-runtime': [
('awscli.customizations.removals', 'register_removals')
@@ -557,17 +627,26 @@
],
'building-command-table.logs': [
('awscli.customizations.removals', 'register_removals'),
- ('awscli.customizations.logs', 'register_logs_commands')
+ ('awscli.customizations.logs', 'register_logs_commands'),
],
'building-command-table.main': [
('awscli.customizations.s3.s3', 'register_s3_main'),
('awscli.customizations.dynamodb.ddb', 'register_ddb'),
- ('awscli.customizations.configure.configure', 'register_configure_cmd'),
- ('awscli.customizations.codedeploy.codedeploy', 'register_rename_codedeploy'),
- ('awscli.customizations.configservice.rename_cmd', 'register_rename_config'),
+ (
+ 'awscli.customizations.configure.configure',
+ 'register_configure_cmd',
+ ),
+ (
+ 'awscli.customizations.codedeploy.codedeploy',
+ 'register_rename_codedeploy',
+ ),
+ (
+ 'awscli.customizations.configservice.rename_cmd',
+ 'register_rename_config',
+ ),
('awscli.customizations.history', 'register_history_commands'),
('awscli.customizations.devcommands', 'register_dev_commands'),
- ('awscli.customizations.login', 'register_login_cmds')
+ ('awscli.customizations.login', 'register_login_cmds'),
],
'building-command-table.polly': [
('awscli.customizations.removals', 'register_removals')
@@ -577,7 +656,7 @@
],
'building-command-table.rds': [
('awscli.customizations.rds', 'register_rds_modify_split'),
- ('awscli.customizations.rds', 'register_add_generate_db_auth_token')
+ ('awscli.customizations.rds', 'register_add_generate_db_auth_token'),
],
'building-command-table.s3_sync': [
('awscli.customizations.s3.s3', 'register_s3_sync_strategies')
@@ -586,7 +665,10 @@
('awscli.customizations.removals', 'register_removals')
],
'building-command-table.servicecatalog': [
- ('awscli.customizations.servicecatalog', 'register_servicecatalog_commands')
+ (
+ 'awscli.customizations.servicecatalog',
+ 'register_servicecatalog_commands',
+ )
],
'building-command-table.ses': [
('awscli.customizations.removals', 'register_removals')
@@ -598,16 +680,28 @@
('awscli.customizations.sso', 'register_sso_commands')
],
'calling-command.cloudsearchdomain': [
- ('awscli.customizations.cloudsearchdomain', 'register_cloudsearchdomain')
+ (
+ 'awscli.customizations.cloudsearchdomain',
+ 'register_cloudsearchdomain',
+ )
],
'calling-command.dynamodb.*': [
- ('awscli.customizations.dynamodb.paginatorfix', 'register_dynamodb_paginator_fix')
+ (
+ 'awscli.customizations.dynamodb.paginatorfix',
+ 'register_dynamodb_paginator_fix',
+ )
],
'calling-command.ec2.describe-snapshots': [
- ('awscli.customizations.ec2.paginate', 'register_ec2_page_size_injector')
+ (
+ 'awscli.customizations.ec2.paginate',
+ 'register_ec2_page_size_injector',
+ )
],
'calling-command.ec2.describe-volumes': [
- ('awscli.customizations.ec2.paginate', 'register_ec2_page_size_injector')
+ (
+ 'awscli.customizations.ec2.paginate',
+ 'register_ec2_page_size_injector',
+ )
],
'doc-description': [
('awscli.customizations.paginate', 'register_pagination')
@@ -631,7 +725,10 @@
('awscli.customizations.addexamples', 'register_docs_add_examples')
],
'doc-option.route53.create-hosted-zone.hosted-zone-config': [
- ('awscli.customizations.route53', 'register_create_hosted_zone_doc_fix')
+ (
+ 'awscli.customizations.route53',
+ 'register_create_hosted_zone_doc_fix',
+ )
],
'doc-output.datapipeline.get-pipeline-definition': [
('awscli.customizations.datapipeline', 'register_customizations')
@@ -676,16 +773,28 @@
('awscli.customizations.ec2.runinstances', 'register_runinstances')
],
'operation-args-parsed.ecs.create-express-gateway-service': [
- ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ (
+ 'awscli.customizations.ecs.monitormutatinggatewayservice',
+ 'register_monitor_mutating_gateway_service',
+ )
],
'operation-args-parsed.ecs.delete-express-gateway-service': [
- ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ (
+ 'awscli.customizations.ecs.monitormutatinggatewayservice',
+ 'register_monitor_mutating_gateway_service',
+ )
],
'operation-args-parsed.ecs.update-express-gateway-service': [
- ('awscli.customizations.ecs.monitormutatinggatewayservice', 'register_monitor_mutating_gateway_service')
+ (
+ 'awscli.customizations.ecs.monitormutatinggatewayservice',
+ 'register_monitor_mutating_gateway_service',
+ )
],
'operation-args-parsed.kinesis.list-streams': [
- ('awscli.customizations.kinesis', 'register_kinesis_list_streams_pagination_backcompat')
+ (
+ 'awscli.customizations.kinesis',
+ 'register_kinesis_list_streams_pagination_backcompat',
+ )
],
'operation-args-parsed.ses.send-email': [
('awscli.customizations.sessendemail', 'register_ses_send_email')
@@ -698,17 +807,20 @@
],
'session-initialized': [
('awscli.paramfile', 'register_init_uri_param_handler'),
- ('awscli.customizations.binaryformat', 'register_init_binary_formatter'),
+ (
+ 'awscli.customizations.binaryformat',
+ 'register_init_binary_formatter',
+ ),
('awscli.clidriver', 'register_no_pager_handler'),
('awscli.customizations.assumerole', 'register_assume_role_provider'),
('awscli.customizations.timestampformat', 'register_timestamp_format'),
('awscli.customizations.history', 'register_history_mode'),
- ('awscli.customizations.sso', 'register_sso_commands')
+ ('awscli.customizations.sso', 'register_sso_commands'),
],
'top-level-args-parsed': [
('awscli.customizations.globalargs', 'register_parse_global_args'),
- ('awscli.customizations.cloudfront', 'register')
- ]
+ ('awscli.customizations.cloudfront', 'register'),
+ ],
}
# Declarative model of changes made to the command table by plugins
@@ -728,7 +840,12 @@
('rename', 's3', 's3api'),
('add', 's3', 'awscli.customizations.s3.s3', 'S3'),
('add', 'ddb', 'awscli.customizations.dynamodb.ddb', 'DDB'),
- ('add', 'configure', 'awscli.customizations.configure.configure', 'ConfigureCommand'),
+ (
+ 'add',
+ 'configure',
+ 'awscli.customizations.configure.configure',
+ 'ConfigureCommand',
+ ),
('rename', 'codedeploy', 'deploy'),
('rename', 'config', 'configservice'),
('add', 'history', 'awscli.customizations.history', 'HistoryCommand'),
From 511d6cbdf080725c4dbce6aade0263af9b2bef94 Mon Sep 17 00:00:00 2001
From: aemous
Date: Wed, 13 May 2026 14:39:27 -0400
Subject: [PATCH 4/6] Update test_handlers_registry against the simplified
format of handlers_registry.
---
tests/functional/test_handlers_registry.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/functional/test_handlers_registry.py b/tests/functional/test_handlers_registry.py
index 7856fa3caf91..97b53f2097dc 100644
--- a/tests/functional/test_handlers_registry.py
+++ b/tests/functional/test_handlers_registry.py
@@ -59,7 +59,7 @@ def test_main_command_table_plugins_only_register_against_main():
"""
main_entries = PLUGIN_REGISTRY.get('building-command-table.main', [])
violations = []
- for module_path, fn_name, entry_type in main_entries:
+ for module_path, fn_name in main_entries:
emitter = _AuditEmitter()
mod = importlib.import_module(module_path)
fn = getattr(mod, fn_name)
@@ -98,7 +98,7 @@ def test_main_command_table_callbacks_only_add_or_rename():
main_entries = PLUGIN_REGISTRY.get('building-command-table.main', [])
violations = []
- for module_path, fn_name, entry_type in main_entries:
+ for module_path, fn_name in main_entries:
collector = _CallbackCollector('building-command-table.main')
mod = importlib.import_module(module_path)
fn = getattr(mod, fn_name)
From 11b07cde48c721a200cafc3b3b51a7d8418fc546 Mon Sep 17 00:00:00 2001
From: aemous
Date: Wed, 13 May 2026 15:04:20 -0400
Subject: [PATCH 5/6] Add new functional tests to assert that all modules
referenced in handlers_registry.py are importable.
---
tests/functional/test_handlers_registry.py | 59 +++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/tests/functional/test_handlers_registry.py b/tests/functional/test_handlers_registry.py
index 97b53f2097dc..48ac38554035 100644
--- a/tests/functional/test_handlers_registry.py
+++ b/tests/functional/test_handlers_registry.py
@@ -15,7 +15,7 @@
import botocore.session
-from awscli.handlers_registry import PLUGIN_REGISTRY
+from awscli.handlers_registry import MAIN_COMMAND_TABLE_OPS, PLUGIN_REGISTRY
class _AuditEmitter:
@@ -46,6 +46,63 @@ def register(self, event_name, handler, *args, **kwargs):
register_last = register
+def test_all_registry_entries_are_importable():
+ """Every (module, fn_name) in PLUGIN_REGISTRY must resolve to a
+ callable. This catches typos, stale entries, and missing modules.
+ """
+ violations = []
+ seen = set()
+ for entries in PLUGIN_REGISTRY.values():
+ for module_path, fn_name in entries:
+ if (module_path, fn_name) in seen:
+ continue
+ seen.add((module_path, fn_name))
+ try:
+ mod = importlib.import_module(module_path)
+ except ImportError as e:
+ violations.append(f'{module_path}: {e}')
+ continue
+ fn = getattr(mod, fn_name, None)
+ if fn is None:
+ violations.append(
+ f'{module_path}.{fn_name} does not exist'
+ )
+ elif not callable(fn):
+ violations.append(
+ f'{module_path}.{fn_name} is not callable'
+ )
+ assert not violations, (
+ 'The following PLUGIN_REGISTRY entries are invalid:\n'
+ + '\n'.join(f' - {v}' for v in violations)
+ )
+
+
+def test_all_main_command_table_ops_modules_are_importable():
+ """Every module referenced in MAIN_COMMAND_TABLE_OPS 'add' entries
+ must be importable and contain the specified class.
+ """
+ violations = []
+ for op in MAIN_COMMAND_TABLE_OPS:
+ if op[0] != 'add':
+ continue
+ _, cmd_name, cmd_module, cmd_class = op
+ try:
+ mod = importlib.import_module(cmd_module)
+ except ImportError as e:
+ violations.append(f'{cmd_module}: {e}')
+ continue
+ cls_name = cmd_class.split('.')[-1]
+ if not hasattr(mod, cls_name):
+ violations.append(
+ f'{cmd_module}.{cls_name} does not exist '
+ f'(referenced by add {cmd_name!r})'
+ )
+ assert not violations, (
+ 'The following MAIN_COMMAND_TABLE_OPS entries are invalid:\n'
+ + '\n'.join(f' - {v}' for v in violations)
+ )
+
+
def test_main_command_table_plugins_only_register_against_main():
"""Plugins listed under building-command-table.main must not register
against any other events.
From 844dcceef7d129a4878222376da17ef4550c6126 Mon Sep 17 00:00:00 2001
From: aemous
Date: Wed, 13 May 2026 15:04:43 -0400
Subject: [PATCH 6/6] Formatting.
---
tests/functional/test_handlers_registry.py | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/tests/functional/test_handlers_registry.py b/tests/functional/test_handlers_registry.py
index 48ac38554035..93d0e36f4854 100644
--- a/tests/functional/test_handlers_registry.py
+++ b/tests/functional/test_handlers_registry.py
@@ -64,13 +64,9 @@ def test_all_registry_entries_are_importable():
continue
fn = getattr(mod, fn_name, None)
if fn is None:
- violations.append(
- f'{module_path}.{fn_name} does not exist'
- )
+ violations.append(f'{module_path}.{fn_name} does not exist')
elif not callable(fn):
- violations.append(
- f'{module_path}.{fn_name} is not callable'
- )
+ violations.append(f'{module_path}.{fn_name} is not callable')
assert not violations, (
'The following PLUGIN_REGISTRY entries are invalid:\n'
+ '\n'.join(f' - {v}' for v in violations)