Compare commits

...

10 Commits

87 changed files with 892 additions and 393 deletions

View File

@ -68,7 +68,7 @@ jobs:
run: | run: |
pip install -r requirements-dev.txt pip install -r requirements-dev.txt
- name: Lint - name: Lint
run: run: |
mkdir .mypy_cache mkdir .mypy_cache
make lint make lint

View File

@ -13,7 +13,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Set up Ruby ${{ matrix.ruby-version }} - name: Set up Ruby ${{ matrix.ruby-version }}
uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 uses: ruby/setup-ruby@5f19ec79cedfadb78ab837f95b87734d0003c899
with: with:
ruby-version: ${{ matrix.ruby-version }} ruby-version: ${{ matrix.ruby-version }}
- name: Set up Python 3.8 - name: Set up Python 3.8

View File

@ -1,6 +1,76 @@
Moto Changelog Moto Changelog
============== ==============
5.0.4
-----
Docker Digest for 5.0.4: _sha256:e13e917e563bd1e3bb745b0ce914bdcc3bd4577542e13e1468eac5078774b2aa_
General:
* Lambda: The results of a Dockerless invocation can now be configured.
See http://docs.getmoto.org/en/latest/docs/services/lambda.html
* StepFunctions can now execute the provided StepFunctionMachine (opt-in), instead of returning static data (still the default).
See http://docs.getmoto.org/en/latest/docs/services/stepfunctions.html
New Service:
* ElastiCache:
* list_tags_for_resource()
* ResilienceHub:
* create_app()
* create_app_version_app_component()
* create_app_version_resource()
* create_resiliency_policy()
* describe_app()
* describe_resiliency_policy()
* import_resources_to_draft_app_version()
* list_app_assessments()
* list_app_version_app_components()
* list_app_version_resources()
* list_app_versions()
* list_apps()
* list_resiliency_policies()
* list_tags_for_resource()
* publish_app_version()
* tag_resource()
* untag_resource()
* Workspaces:
* create_tags()
* create_workspace_image()
* create_workspaces()
* deregister_workspace_directory()
* describe_client_properties()
* describe_tags()
* describe_workspace_directories()
* describe_workspace_image_permissions()
* describe_workspace_images()
* describe_workspaces()
* modify_client_properties()
* modify_selfservice_permissions()
* modify_workspace_creation_properties()
* register_workspace_directory()
* update_workspace_image_permission()
Miscellaneous:
* APIGateway: update_usage_plan() now supports some remove-operations
* Autoscaling: describe_auto_scaling_groups() now returns a dynamic CreatedTime
* CloudFormation: Outputs now support Conditions
* CloudFormation: Outputs now return Descriptions
* CognitoIDP: admin_update_user_attributes() and admin_delete_user_attributes now correctly update the UserLastModifiedDate
* DynamoDB: query() no longer requires the LastEvaluatedKey to exist
* EC2: describe_vpc_endpoint_services() now supports all services
* Kinesis: list_streams() now returns StreamSummaries
* Lambda: get_policy() now throws an error when no statements exist
* ResourceGroupsTaggingAPI now supports DynamoDB tables
* ResourceGroupsTaggingAPI now supports SSM documents
* S3: EventBridge notifications are now supported for ObjectRestore:Post
* S3: restore_object() now contains limited validation when supplying both Days- and Type-argument
* S3: select_object_content() now supports Compressed requests and CSV responses
* SecretsManager: list_secrets() now handles negative matches correctly
* SNS: delete_endpoint() is now an idempotent operation, just like AWS
5.0.3 5.0.3
----- -----
Docker Digest for 5.0.3: _sha256:032d8ead42f289d9700e9bc844c6d264575ad11b3f6c22cc76d65ff638c8c7bd_ Docker Digest for 5.0.3: _sha256:032d8ead42f289d9700e9bc844c6d264575ad11b3f6c22cc76d65ff638c8c7bd_

View File

@ -2870,7 +2870,7 @@
## elasticache ## elasticache
<details> <details>
<summary>8% implemented</summary> <summary>9% implemented</summary>
- [ ] add_tags_to_resource - [ ] add_tags_to_resource
- [ ] authorize_cache_security_group_ingress - [ ] authorize_cache_security_group_ingress
@ -2928,7 +2928,7 @@
- [ ] increase_node_groups_in_global_replication_group - [ ] increase_node_groups_in_global_replication_group
- [ ] increase_replica_count - [ ] increase_replica_count
- [ ] list_allowed_node_type_modifications - [ ] list_allowed_node_type_modifications
- [ ] list_tags_for_resource - [X] list_tags_for_resource
- [ ] modify_cache_cluster - [ ] modify_cache_cluster
- [ ] modify_cache_parameter_group - [ ] modify_cache_parameter_group
- [ ] modify_cache_subnet_group - [ ] modify_cache_subnet_group
@ -8015,6 +8015,85 @@
- [X] update_web_acl - [X] update_web_acl
</details> </details>
## workspaces
<details>
<summary>20% implemented</summary>
- [ ] associate_connection_alias
- [ ] associate_ip_groups
- [ ] associate_workspace_application
- [ ] authorize_ip_rules
- [ ] copy_workspace_image
- [ ] create_connect_client_add_in
- [ ] create_connection_alias
- [ ] create_ip_group
- [ ] create_standby_workspaces
- [X] create_tags
- [ ] create_updated_workspace_image
- [ ] create_workspace_bundle
- [X] create_workspace_image
- [X] create_workspaces
- [ ] delete_client_branding
- [ ] delete_connect_client_add_in
- [ ] delete_connection_alias
- [ ] delete_ip_group
- [ ] delete_tags
- [ ] delete_workspace_bundle
- [ ] delete_workspace_image
- [ ] deploy_workspace_applications
- [X] deregister_workspace_directory
- [ ] describe_account
- [ ] describe_account_modifications
- [ ] describe_application_associations
- [ ] describe_applications
- [ ] describe_bundle_associations
- [ ] describe_client_branding
- [X] describe_client_properties
- [ ] describe_connect_client_add_ins
- [ ] describe_connection_alias_permissions
- [ ] describe_connection_aliases
- [ ] describe_image_associations
- [ ] describe_ip_groups
- [X] describe_tags
- [ ] describe_workspace_associations
- [ ] describe_workspace_bundles
- [X] describe_workspace_directories
- [X] describe_workspace_image_permissions
- [X] describe_workspace_images
- [ ] describe_workspace_snapshots
- [X] describe_workspaces
- [ ] describe_workspaces_connection_status
- [ ] disassociate_connection_alias
- [ ] disassociate_ip_groups
- [ ] disassociate_workspace_application
- [ ] import_client_branding
- [ ] import_workspace_image
- [ ] list_available_management_cidr_ranges
- [ ] migrate_workspace
- [ ] modify_account
- [ ] modify_certificate_based_auth_properties
- [X] modify_client_properties
- [ ] modify_saml_properties
- [X] modify_selfservice_permissions
- [ ] modify_workspace_access_properties
- [X] modify_workspace_creation_properties
- [ ] modify_workspace_properties
- [ ] modify_workspace_state
- [ ] reboot_workspaces
- [ ] rebuild_workspaces
- [X] register_workspace_directory
- [ ] restore_workspace
- [ ] revoke_ip_rules
- [ ] start_workspaces
- [ ] stop_workspaces
- [ ] terminate_workspaces
- [ ] update_connect_client_add_in
- [ ] update_connection_alias_permission
- [ ] update_rules_of_ip_group
- [ ] update_workspace_bundle
- [X] update_workspace_image_permission
</details>
## Unimplemented: ## Unimplemented:
<details> <details>
@ -8269,7 +8348,6 @@
- worklink - worklink
- workmail - workmail
- workmailmessageflow - workmailmessageflow
- workspaces
- workspaces-thin-client - workspaces-thin-client
- workspaces-web - workspaces-web
- xray - xray

View File

@ -20,6 +20,7 @@ init:
lint: lint:
@echo "Running ruff..." @echo "Running ruff..."
ruff check moto tests ruff check moto tests
ruff format --check moto tests
@echo "Running pylint..." @echo "Running pylint..."
pylint -j 0 moto tests pylint -j 0 moto tests
@echo "Running MyPy..." @echo "Running MyPy..."

View File

@ -65,7 +65,8 @@ The following options can also be configured when running the MotoServer:
options = { options = {
"batch": {"use_docker": True}, "batch": {"use_docker": True},
"lambda": {"use_docker": True} "lambda": {"use_docker": True},
"stepfunctions": {"execute_state_machine": True}
} }
requests.post(f"http://localhost:5000/moto-api/config", json=options) requests.post(f"http://localhost:5000/moto-api/config", json=options)

View File

@ -155,7 +155,7 @@ apigateway
The following PatchOperations are currently supported: The following PatchOperations are currently supported:
add : Everything except /apiStages/{apidId:stageName}/throttle/ and children add : Everything except /apiStages/{apidId:stageName}/throttle/ and children
replace: Everything except /apiStages/{apidId:stageName}/throttle/ and children replace: Everything except /apiStages/{apidId:stageName}/throttle/ and children
remove : Nothing yet remove : Everything except /apiStages/{apidId:stageName}/throttle/ and children
copy : Nothing yet copy : Nothing yet

View File

@ -78,7 +78,7 @@ athena
], ],
} }
resp = requests.post( resp = requests.post(
"http://motoapi.amazonaws.com:5000/moto-api/static/athena/query-results", "http://motoapi.amazonaws.com/moto-api/static/athena/query-results",
json=expected_results, json=expected_results,
) )
assert resp.status_code == 201 assert resp.status_code == 201

View File

@ -74,7 +74,7 @@ ce
] ]
} }
resp = requests.post( resp = requests.post(
"http://motoapi.amazonaws.com:5000/moto-api/static/ce/cost-and-usage-results", "http://motoapi.amazonaws.com/moto-api/static/ce/cost-and-usage-results",
json=expected_results, json=expected_results,
) )
assert resp.status_code == 201 assert resp.status_code == 201

View File

@ -77,7 +77,7 @@ elasticache
- [ ] increase_node_groups_in_global_replication_group - [ ] increase_node_groups_in_global_replication_group
- [ ] increase_replica_count - [ ] increase_replica_count
- [ ] list_allowed_node_type_modifications - [ ] list_allowed_node_type_modifications
- [ ] list_tags_for_resource - [X] list_tags_for_resource
- [ ] modify_cache_cluster - [ ] modify_cache_cluster
- [ ] modify_cache_parameter_group - [ ] modify_cache_parameter_group
- [ ] modify_cache_subnet_group - [ ] modify_cache_subnet_group

View File

@ -82,7 +82,7 @@ inspector2
"region": "us-east-1", # This is the default - can be omitted "region": "us-east-1", # This is the default - can be omitted
} }
resp = requests.post( resp = requests.post(
"http://motoapi.amazonaws.com:5000/moto-api/static/inspector2/findings-results", "http://motoapi.amazonaws.com/moto-api/static/inspector2/findings-results",
json=findings, json=findings,
) )

View File

@ -81,16 +81,16 @@ lambda
expected_results = {"results": ["test", "test 2"], "region": "us-east-1"} expected_results = {"results": ["test", "test 2"], "region": "us-east-1"}
resp = requests.post( resp = requests.post(
"http://motoapi.amazonaws.com:5000/moto-api/static/lambda-simple/response", "http://motoapi.amazonaws.com/moto-api/static/lambda-simple/response",
json=expected_results, json=expected_results
) )
assert resp.status_code == 201 assert resp.status_code == 201
client = boto3.client("lambda", region_name="us-east-1") client = boto3.client("lambda", region_name="us-east-1")
resp = client.invoke(...) # resp["Payload"].read().decode() == "test" resp = client.invoke(...) # resp["Payload"].read().decode() == "test"
resp = client.invoke(...) # resp["Payload"].read().decode() == "test2" resp = client.invoke(...) # resp["Payload"].read().decode() == "test2"
- [ ] invoke_async - [ ] invoke_async
- [ ] invoke_with_response_stream - [ ] invoke_with_response_stream
- [X] list_aliases - [X] list_aliases

View File

@ -47,7 +47,7 @@ rds-data
], ],
} }
resp = requests.post( resp = requests.post(
"http://motoapi.amazonaws.com:5000/moto-api/static/rds-data/statement-results", "http://motoapi.amazonaws.com/moto-api/static/rds-data/statement-results",
json=expected_results, json=expected_results,
) )
assert resp.status_code == 201 assert resp.status_code == 201

View File

@ -22,7 +22,7 @@ resourcegroupstaggingapi
- [ ] start_report_creation - [ ] start_report_creation
- [X] tag_resources - [X] tag_resources
Only Logs and RDS resources are currently supported Only DynamoDB, Logs and RDS resources are currently supported
- [ ] untag_resources - [ ] untag_resources

View File

@ -114,6 +114,7 @@ s3
- 's3:ObjectCreated:Post' - 's3:ObjectCreated:Post'
- 's3:ObjectCreated:Put' - 's3:ObjectCreated:Put'
- 's3:ObjectDeleted' - 's3:ObjectDeleted'
- 's3:ObjectRestore:Post'
- [X] put_bucket_ownership_controls - [X] put_bucket_ownership_controls

View File

@ -42,7 +42,7 @@ sagemaker-runtime
], ],
} }
requests.post( requests.post(
"http://motoapi.amazonaws.com:5000/moto-api/static/sagemaker/endpoint-results", "http://motoapi.amazonaws.com/moto-api/static/sagemaker/endpoint-results",
json=expected_results, json=expected_results,
) )

View File

@ -0,0 +1,96 @@
.. _implementedservice_workspaces:
.. |start-h3| raw:: html
<h3>
.. |end-h3| raw:: html
</h3>
==========
workspaces
==========
.. autoclass:: moto.workspaces.models.WorkSpacesBackend
|start-h3| Implemented features for this service |end-h3|
- [ ] associate_connection_alias
- [ ] associate_ip_groups
- [ ] associate_workspace_application
- [ ] authorize_ip_rules
- [ ] copy_workspace_image
- [ ] create_connect_client_add_in
- [ ] create_connection_alias
- [ ] create_ip_group
- [ ] create_standby_workspaces
- [X] create_tags
- [ ] create_updated_workspace_image
- [ ] create_workspace_bundle
- [X] create_workspace_image
- [X] create_workspaces
- [ ] delete_client_branding
- [ ] delete_connect_client_add_in
- [ ] delete_connection_alias
- [ ] delete_ip_group
- [ ] delete_tags
- [ ] delete_workspace_bundle
- [ ] delete_workspace_image
- [ ] deploy_workspace_applications
- [X] deregister_workspace_directory
Deregister Workspace Directory with the matching ID.
- [ ] describe_account
- [ ] describe_account_modifications
- [ ] describe_application_associations
- [ ] describe_applications
- [ ] describe_bundle_associations
- [ ] describe_client_branding
- [X] describe_client_properties
- [ ] describe_connect_client_add_ins
- [ ] describe_connection_alias_permissions
- [ ] describe_connection_aliases
- [ ] describe_image_associations
- [ ] describe_ip_groups
- [X] describe_tags
- [ ] describe_workspace_associations
- [ ] describe_workspace_bundles
- [X] describe_workspace_directories
Return info on all directories or directories with matching IDs.
- [X] describe_workspace_image_permissions
- [X] describe_workspace_images
- [ ] describe_workspace_snapshots
- [X] describe_workspaces
- [ ] describe_workspaces_connection_status
- [ ] disassociate_connection_alias
- [ ] disassociate_ip_groups
- [ ] disassociate_workspace_application
- [ ] import_client_branding
- [ ] import_workspace_image
- [ ] list_available_management_cidr_ranges
- [ ] migrate_workspace
- [ ] modify_account
- [ ] modify_certificate_based_auth_properties
- [X] modify_client_properties
- [ ] modify_saml_properties
- [X] modify_selfservice_permissions
- [ ] modify_workspace_access_properties
- [X] modify_workspace_creation_properties
- [ ] modify_workspace_properties
- [ ] modify_workspace_state
- [ ] reboot_workspaces
- [ ] rebuild_workspaces
- [X] register_workspace_directory
- [ ] restore_workspace
- [ ] revoke_ip_rules
- [ ] start_workspaces
- [ ] stop_workspaces
- [ ] terminate_workspaces
- [ ] update_connect_client_add_in
- [ ] update_connection_alias_permission
- [ ] update_rules_of_ip_group
- [ ] update_workspace_bundle
- [X] update_workspace_image_permission

View File

@ -1,4 +1,4 @@
from moto.core.decorator import mock_aws as mock_aws from moto.core.decorator import mock_aws as mock_aws
__title__ = "moto" __title__ = "moto"
__version__ = "5.0.4.dev" __version__ = "5.0.5.dev"

View File

@ -136,9 +136,9 @@ class CertificateAuthority(BaseModel):
"S3ObjectAcl", None "S3ObjectAcl", None
) )
if acl is None: if acl is None:
self.revocation_configuration["CrlConfiguration"][ self.revocation_configuration["CrlConfiguration"]["S3ObjectAcl"] = (
"S3ObjectAcl" "PUBLIC_READ"
] = "PUBLIC_READ" )
else: else:
if acl not in ["PUBLIC_READ", "BUCKET_OWNER_FULL_CONTROL"]: if acl not in ["PUBLIC_READ", "BUCKET_OWNER_FULL_CONTROL"]:
raise InvalidS3ObjectAclInCrlConfiguration(acl) raise InvalidS3ObjectAclInCrlConfiguration(acl)

View File

@ -39,9 +39,9 @@ class APIGatewayResponse(BaseResponse):
).format(api_key_source=api_key_source), ).format(api_key_source=api_key_source),
) )
def __validate_endpoint_configuration( def __validate_endpoint_configuration( # type: ignore[return]
self, endpoint_configuration: Dict[str, str] self, endpoint_configuration: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
if endpoint_configuration and "types" in endpoint_configuration: if endpoint_configuration and "types" in endpoint_configuration:
invalid_types = list( invalid_types = list(
set(endpoint_configuration["types"]) - set(ENDPOINT_CONFIGURATION_TYPES) set(endpoint_configuration["types"]) - set(ENDPOINT_CONFIGURATION_TYPES)
@ -57,9 +57,9 @@ class APIGatewayResponse(BaseResponse):
).format(endpoint_type=invalid_types[0]), ).format(endpoint_type=invalid_types[0]),
) )
def restapis( def restapis( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -105,9 +105,9 @@ class APIGatewayResponse(BaseResponse):
return 200, {}, json.dumps(rest_api.to_dict()) return 200, {}, json.dumps(rest_api.to_dict())
def __validte_rest_patch_operations( def __validte_rest_patch_operations( # type: ignore[return]
self, patch_operations: List[Dict[str, str]] self, patch_operations: List[Dict[str, str]]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
for op in patch_operations: for op in patch_operations:
path = op["path"] path = op["path"]
if "apiKeySource" in path: if "apiKeySource" in path:
@ -142,9 +142,9 @@ class APIGatewayResponse(BaseResponse):
return 200, {}, json.dumps(rest_api.to_dict()) return 200, {}, json.dumps(rest_api.to_dict())
def resources( def resources( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
function_id = self.path.replace("/restapis/", "", 1).split("/")[0] function_id = self.path.replace("/restapis/", "", 1).split("/")[0]
@ -156,9 +156,9 @@ class APIGatewayResponse(BaseResponse):
json.dumps({"item": [resource.to_dict() for resource in resources]}), json.dumps({"item": [resource.to_dict() for resource in resources]}),
) )
def gateway_response( def gateway_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "PUT": if request.method == "PUT":
return self.put_gateway_response() return self.put_gateway_response()
@ -167,16 +167,16 @@ class APIGatewayResponse(BaseResponse):
elif request.method == "DELETE": elif request.method == "DELETE":
return self.delete_gateway_response() return self.delete_gateway_response()
def gateway_responses( def gateway_responses( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "GET": if request.method == "GET":
return self.get_gateway_responses() return self.get_gateway_responses()
def resource_individual( def resource_individual( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
function_id = self.path.replace("/restapis/", "", 1).split("/")[0] function_id = self.path.replace("/restapis/", "", 1).split("/")[0]
resource_id = self.path.split("/")[-1] resource_id = self.path.split("/")[-1]
@ -268,9 +268,9 @@ class APIGatewayResponse(BaseResponse):
return 204, {}, json.dumps(method_response.to_json()) # type: ignore[union-attr] return 204, {}, json.dumps(method_response.to_json()) # type: ignore[union-attr]
raise Exception(f'Unexpected HTTP method "{self.method}"') raise Exception(f'Unexpected HTTP method "{self.method}"')
def restapis_authorizers( def restapis_authorizers( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
restapi_id = url_path_parts[2] restapi_id = url_path_parts[2]
@ -320,9 +320,9 @@ class APIGatewayResponse(BaseResponse):
authorizers = self.backend.get_authorizers(restapi_id) authorizers = self.backend.get_authorizers(restapi_id)
return 200, {}, json.dumps({"item": [a.to_json() for a in authorizers]}) return 200, {}, json.dumps({"item": [a.to_json() for a in authorizers]})
def request_validators( def request_validators( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
restapi_id = url_path_parts[2] restapi_id = url_path_parts[2]
@ -342,9 +342,9 @@ class APIGatewayResponse(BaseResponse):
) )
return 201, {}, json.dumps(validator.to_dict()) return 201, {}, json.dumps(validator.to_dict())
def request_validator_individual( def request_validator_individual( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
restapi_id = url_path_parts[2] restapi_id = url_path_parts[2]
@ -363,9 +363,9 @@ class APIGatewayResponse(BaseResponse):
) )
return 200, {}, json.dumps(validator.to_dict()) return 200, {}, json.dumps(validator.to_dict())
def authorizers( def authorizers( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
restapi_id = url_path_parts[2] restapi_id = url_path_parts[2]
@ -384,9 +384,9 @@ class APIGatewayResponse(BaseResponse):
self.backend.delete_authorizer(restapi_id, authorizer_id) self.backend.delete_authorizer(restapi_id, authorizer_id)
return 202, {}, "{}" return 202, {}, "{}"
def restapis_stages( def restapis_stages( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
function_id = url_path_parts[2] function_id = url_path_parts[2]
@ -417,9 +417,9 @@ class APIGatewayResponse(BaseResponse):
stages = self.backend.get_stages(function_id) stages = self.backend.get_stages(function_id)
return 200, {}, json.dumps({"item": [s.to_json() for s in stages]}) return 200, {}, json.dumps({"item": [s.to_json() for s in stages]})
def restapis_stages_tags( def restapis_stages_tags( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
function_id = url_path_parts[4] function_id = url_path_parts[4]
@ -437,9 +437,9 @@ class APIGatewayResponse(BaseResponse):
stage.tags.pop(tag, None) # type: ignore[union-attr] stage.tags.pop(tag, None) # type: ignore[union-attr]
return 200, {}, json.dumps({"item": ""}) return 200, {}, json.dumps({"item": ""})
def stages( def stages( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
function_id = url_path_parts[2] function_id = url_path_parts[2]
@ -476,9 +476,9 @@ class APIGatewayResponse(BaseResponse):
} }
return 200, headers, json.dumps(body).encode("utf-8") return 200, headers, json.dumps(body).encode("utf-8")
def integrations( def integrations( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
function_id = url_path_parts[2] function_id = url_path_parts[2]
@ -534,9 +534,9 @@ class APIGatewayResponse(BaseResponse):
) )
return 204, {}, json.dumps(integration_response.to_json()) return 204, {}, json.dumps(integration_response.to_json())
def integration_responses( def integration_responses( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
function_id = url_path_parts[2] function_id = url_path_parts[2]
@ -574,9 +574,9 @@ class APIGatewayResponse(BaseResponse):
) )
return 204, {}, json.dumps(integration_response.to_json()) return 204, {}, json.dumps(integration_response.to_json())
def deployments( def deployments( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
function_id = self.path.replace("/restapis/", "", 1).split("/")[0] function_id = self.path.replace("/restapis/", "", 1).split("/")[0]
@ -592,9 +592,9 @@ class APIGatewayResponse(BaseResponse):
) )
return 201, {}, json.dumps(deployment.to_json()) return 201, {}, json.dumps(deployment.to_json())
def individual_deployment( def individual_deployment( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
function_id = url_path_parts[2] function_id = url_path_parts[2]
@ -607,9 +607,9 @@ class APIGatewayResponse(BaseResponse):
deployment = self.backend.delete_deployment(function_id, deployment_id) deployment = self.backend.delete_deployment(function_id, deployment_id)
return 202, {}, json.dumps(deployment.to_json()) return 202, {}, json.dumps(deployment.to_json())
def apikeys( def apikeys( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":
@ -649,9 +649,9 @@ class APIGatewayResponse(BaseResponse):
return 200, {}, json.dumps(apikey_resp) return 200, {}, json.dumps(apikey_resp)
def usage_plans( def usage_plans( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":
usage_plan_response = self.backend.create_usage_plan(json.loads(self.body)) usage_plan_response = self.backend.create_usage_plan(json.loads(self.body))
@ -665,9 +665,9 @@ class APIGatewayResponse(BaseResponse):
json.dumps({"item": [u.to_json() for u in usage_plans_response]}), json.dumps({"item": [u.to_json() for u in usage_plans_response]}),
) )
def usage_plan_individual( def usage_plan_individual( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
@ -686,9 +686,9 @@ class APIGatewayResponse(BaseResponse):
) )
return 200, {}, json.dumps(usage_plan_response.to_json()) return 200, {}, json.dumps(usage_plan_response.to_json())
def usage_plan_keys( def usage_plan_keys( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
@ -707,9 +707,9 @@ class APIGatewayResponse(BaseResponse):
json.dumps({"item": [u.to_json() for u in usage_plans_response]}), json.dumps({"item": [u.to_json() for u in usage_plans_response]}),
) )
def usage_plan_key_individual( def usage_plan_key_individual( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
@ -723,9 +723,9 @@ class APIGatewayResponse(BaseResponse):
self.backend.delete_usage_plan_key(usage_plan_id, key_id) self.backend.delete_usage_plan_key(usage_plan_id, key_id)
return 202, {}, "{}" return 202, {}, "{}"
def domain_names( def domain_names( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -780,9 +780,9 @@ class APIGatewayResponse(BaseResponse):
msg = f'Method "{self.method}" for API GW domain names not implemented' msg = f'Method "{self.method}" for API GW domain names not implemented'
return 404, {}, json.dumps({"error": msg}) return 404, {}, json.dumps({"error": msg})
def models( def models( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
rest_api_id = self.path.replace("/restapis/", "", 1).split("/")[0] rest_api_id = self.path.replace("/restapis/", "", 1).split("/")[0]
@ -817,9 +817,9 @@ class APIGatewayResponse(BaseResponse):
return 200, {}, json.dumps(model_info.to_json()) return 200, {}, json.dumps(model_info.to_json())
return 200, {}, "{}" return 200, {}, "{}"
def base_path_mappings( def base_path_mappings( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
@ -842,9 +842,9 @@ class APIGatewayResponse(BaseResponse):
) )
return 201, {}, json.dumps(base_path_mapping_resp.to_json()) return 201, {}, json.dumps(base_path_mapping_resp.to_json())
def base_path_mapping_individual( def base_path_mapping_individual( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
@ -866,9 +866,9 @@ class APIGatewayResponse(BaseResponse):
) )
return 200, {}, json.dumps(base_path_mapping.to_json()) return 200, {}, json.dumps(base_path_mapping.to_json())
def vpc_link( def vpc_link( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
url_path_parts = self.path.split("/") url_path_parts = self.path.split("/")
vpc_link_id = url_path_parts[-1] vpc_link_id = url_path_parts[-1]
@ -880,9 +880,9 @@ class APIGatewayResponse(BaseResponse):
vpc_link = self.backend.get_vpc_link(vpc_link_id=vpc_link_id) vpc_link = self.backend.get_vpc_link(vpc_link_id=vpc_link_id)
return 200, {}, json.dumps(vpc_link.to_json()) return 200, {}, json.dumps(vpc_link.to_json())
def vpc_links( def vpc_links( # type: ignore[return]
self, request: Any, full_url: str, headers: Dict[str, str] self, request: Any, full_url: str, headers: Dict[str, str]
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":

View File

@ -63,9 +63,9 @@ class ApiGatewayV2Response(BaseResponse):
if self.method == "DELETE": if self.method == "DELETE":
return self.delete_cors_configuration() return self.delete_cors_configuration()
def route_request_parameter( def route_request_parameter( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "DELETE": if self.method == "DELETE":
@ -105,9 +105,9 @@ class ApiGatewayV2Response(BaseResponse):
if self.method == "POST": if self.method == "POST":
return self.create_integration() return self.create_integration()
def integration_response( def integration_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "DELETE": if self.method == "DELETE":
@ -117,9 +117,9 @@ class ApiGatewayV2Response(BaseResponse):
if self.method == "PATCH": if self.method == "PATCH":
return self.update_integration_response() return self.update_integration_response()
def integration_responses( def integration_responses( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -145,9 +145,9 @@ class ApiGatewayV2Response(BaseResponse):
if self.method == "POST": if self.method == "POST":
return self.create_route() return self.create_route()
def route_response( def route_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "DELETE": if self.method == "DELETE":
@ -155,9 +155,9 @@ class ApiGatewayV2Response(BaseResponse):
if self.method == "GET": if self.method == "GET":
return self.get_route_response() return self.get_route_response()
def route_responses( def route_responses( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":

View File

@ -27,9 +27,9 @@ class AppSyncResponse(BaseResponse):
if request.method == "GET": if request.method == "GET":
return self.list_graphql_apis() return self.list_graphql_apis()
def graph_ql_individual( def graph_ql_individual( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "GET": if request.method == "GET":
return self.get_graphql_api() return self.get_graphql_api()
@ -45,18 +45,18 @@ class AppSyncResponse(BaseResponse):
if request.method == "GET": if request.method == "GET":
return self.list_api_keys() return self.list_api_keys()
def schemacreation( def schemacreation( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "POST": if request.method == "POST":
return self.start_schema_creation() return self.start_schema_creation()
if request.method == "GET": if request.method == "GET":
return self.get_schema_creation_status() return self.get_schema_creation_status()
def api_key_individual( def api_key_individual( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "DELETE": if request.method == "DELETE":
return self.delete_api_key() return self.delete_api_key()

View File

@ -259,7 +259,7 @@ class AthenaBackend(BaseBackend):
], ],
} }
resp = requests.post( resp = requests.post(
"http://motoapi.amazonaws.com:5000/moto-api/static/athena/query-results", "http://motoapi.amazonaws.com/moto-api/static/athena/query-results",
json=expected_results, json=expected_results,
) )
assert resp.status_code == 201 assert resp.status_code == 201

View File

@ -2375,6 +2375,26 @@ class LambdaBackend(BaseBackend):
) -> Optional[Union[str, bytes]]: ) -> Optional[Union[str, bytes]]:
""" """
Invoking a Function with PackageType=Image is not yet supported. Invoking a Function with PackageType=Image is not yet supported.
Invoking a Funcation against Lambda without docker now supports customised responses, the default being `Simple Lambda happy path OK`.
You can use a dedicated API to override this, by configuring a queue of expected results.
A request to `invoke` will take the first result from that queue.
Configure this queue by making an HTTP request to `/moto-api/static/lambda-simple/response`. An example invocation looks like this:
.. sourcecode:: python
expected_results = {"results": ["test", "test 2"], "region": "us-east-1"}
resp = requests.post(
"http://motoapi.amazonaws.com/moto-api/static/lambda-simple/response",
json=expected_results
)
assert resp.status_code == 201
client = boto3.client("lambda", region_name="us-east-1")
resp = client.invoke(...) # resp["Payload"].read().decode() == "test"
resp = client.invoke(...) # resp["Payload"].read().decode() == "test2"
""" """
fn = self.get_function(function_name, qualifier) fn = self.get_function(function_name, qualifier)
payload = fn.invoke(body, headers, response_headers) payload = fn.invoke(body, headers, response_headers)

View File

@ -89,9 +89,9 @@ class LambdaResponse(BaseResponse):
if request.method == "GET": if request.method == "GET":
return self._list_layers() return self._list_layers()
def layers_version( def layers_version( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
layer_name = unquote(self.path.split("/")[-3]) layer_name = unquote(self.path.split("/")[-3])
layer_version = self.path.split("/")[-1] layer_version = self.path.split("/")[-1]
@ -100,9 +100,9 @@ class LambdaResponse(BaseResponse):
elif request.method == "GET": elif request.method == "GET":
return self._get_layer_version(layer_name, layer_version) return self._get_layer_version(layer_name, layer_version)
def layers_versions( def layers_versions( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "GET": if request.method == "GET":
return self._get_layer_versions() return self._get_layer_versions()
@ -190,9 +190,9 @@ class LambdaResponse(BaseResponse):
else: else:
raise ValueError("Cannot handle request") raise ValueError("Cannot handle request")
def code_signing_config( def code_signing_config( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "GET": if request.method == "GET":
return self._get_code_signing_config() return self._get_code_signing_config()
@ -212,9 +212,9 @@ class LambdaResponse(BaseResponse):
else: else:
raise ValueError("Cannot handle request") raise ValueError("Cannot handle request")
def function_url_config( def function_url_config( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
http_method = request.method http_method = request.method
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
@ -417,9 +417,9 @@ class LambdaResponse(BaseResponse):
return 204, {}, "" return 204, {}, ""
@staticmethod @staticmethod
def _set_configuration_qualifier( def _set_configuration_qualifier( # type: ignore[misc]
configuration: Dict[str, Any], function_name: str, qualifier: str configuration: Dict[str, Any], function_name: str, qualifier: str
) -> Dict[str, Any]: # type: ignore[misc] ) -> Dict[str, Any]:
# Qualifier may be explicitly passed or part of function name or ARN, extract it here # Qualifier may be explicitly passed or part of function name or ARN, extract it here
if function_name.startswith("arn:aws"): if function_name.startswith("arn:aws"):
# Extract from ARN # Extract from ARN

View File

@ -23,7 +23,7 @@ class LambdaSimpleBackend(LambdaBackend):
headers: Any, headers: Any,
response_headers: Any, response_headers: Any,
) -> Optional[Union[str, bytes]]: ) -> Optional[Union[str, bytes]]:
default_result = "Simple Lambda happy path OK" default_result = body or "Simple Lambda happy path OK"
if self.lambda_simple_results_queue: if self.lambda_simple_results_queue:
default_result = self.lambda_simple_results_queue.pop(0) default_result = self.lambda_simple_results_queue.pop(0)
return str.encode(default_result) return str.encode(default_result)

View File

@ -191,7 +191,7 @@ class CostExplorerBackend(BaseBackend):
] ]
} }
resp = requests.post( resp = requests.post(
"http://motoapi.amazonaws.com:5000/moto-api/static/ce/cost-and-usage-results", "http://motoapi.amazonaws.com/moto-api/static/ce/cost-and-usage-results",
json=expected_results, json=expected_results,
) )
assert resp.status_code == 201 assert resp.status_code == 201

View File

@ -343,8 +343,8 @@ def parse_resource_and_generate_name(
generated_resource_name = generate_resource_name( generated_resource_name = generate_resource_name(
resource_type, resource_type,
resources_map["AWS::StackName"], resources_map["AWS::StackName"], # type: ignore[arg-type]
logical_id, # type: ignore[arg-type] logical_id,
) )
resource_name_property = resource_name_property_from_type(resource_type) resource_name_property = resource_name_property_from_type(resource_type)
@ -438,11 +438,11 @@ def parse_and_delete_resource(
) )
def parse_condition( def parse_condition( # type: ignore[return]
condition: Union[Dict[str, Any], bool], condition: Union[Dict[str, Any], bool],
resources_map: "ResourceMap", resources_map: "ResourceMap",
condition_map: Dict[str, Any], condition_map: Dict[str, Any],
) -> bool: # type: ignore[return] ) -> bool:
if isinstance(condition, bool): if isinstance(condition, bool):
return condition return condition

View File

@ -40,18 +40,18 @@ class CloudFrontResponse(BaseResponse):
if request.method == "GET": if request.method == "GET":
return self.list_tags_for_resource() return self.list_tags_for_resource()
def origin_access_controls( def origin_access_controls( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "POST": if request.method == "POST":
return self.create_origin_access_control() return self.create_origin_access_control()
if request.method == "GET": if request.method == "GET":
return self.list_origin_access_controls() return self.list_origin_access_controls()
def origin_access_control( def origin_access_control( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "GET": if request.method == "GET":
return self.get_origin_access_control() return self.get_origin_access_control()
@ -86,9 +86,9 @@ class CloudFrontResponse(BaseResponse):
response = template.render(distributions=distributions) response = template.render(distributions=distributions)
return 200, {}, response return 200, {}, response
def individual_distribution( def individual_distribution( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
distribution_id = full_url.split("/")[-1] distribution_id = full_url.split("/")[-1]
if request.method == "DELETE": if request.method == "DELETE":

View File

@ -1,4 +1,4 @@
from typing import Dict, List, Optional from typing import Dict, Optional
from moto.core.base_backend import BackendDict, BaseBackend from moto.core.base_backend import BackendDict, BaseBackend
from moto.core.common_models import BaseModel from moto.core.common_models import BaseModel

View File

@ -29,9 +29,9 @@ class DataBrewResponse(BaseResponse):
tags = self.parameters.get("Tags") tags = self.parameters.get("Tags")
return json.dumps( return json.dumps(
self.databrew_backend.create_recipe( self.databrew_backend.create_recipe(
recipe_name, recipe_name, # type: ignore[arg-type]
recipe_description, recipe_description, # type: ignore[arg-type]
recipe_steps, recipe_steps, # type: ignore[arg-type]
tags, # type: ignore[arg-type] tags, # type: ignore[arg-type]
).as_dict() ).as_dict()
) )
@ -102,7 +102,7 @@ class DataBrewResponse(BaseResponse):
self.databrew_backend.update_recipe( self.databrew_backend.update_recipe(
recipe_name, recipe_name,
recipe_description, recipe_description, # type: ignore[arg-type]
recipe_steps, # type: ignore[arg-type] recipe_steps, # type: ignore[arg-type]
) )
return json.dumps({"Name": recipe_name}) return json.dumps({"Name": recipe_name})
@ -147,8 +147,8 @@ class DataBrewResponse(BaseResponse):
ruleset = self.databrew_backend.update_ruleset( ruleset = self.databrew_backend.update_ruleset(
ruleset_name, ruleset_name,
ruleset_description, ruleset_description, # type: ignore[arg-type]
ruleset_rules, ruleset_rules, # type: ignore[arg-type]
tags, # type: ignore[arg-type] tags, # type: ignore[arg-type]
) )
return json.dumps(ruleset.as_dict()) return json.dumps(ruleset.as_dict())

View File

@ -1,5 +1,5 @@
from collections import OrderedDict from collections import OrderedDict
from typing import Any, Dict, List, Optional from typing import Any, Dict, Optional
from moto.core.base_backend import BackendDict, BaseBackend from moto.core.base_backend import BackendDict, BaseBackend
from moto.core.common_models import BaseModel from moto.core.common_models import BaseModel

View File

@ -478,8 +478,8 @@ class DynamoDBBackend(BaseBackend):
try: try:
UpdateExpressionExecutor( UpdateExpressionExecutor(
validated_ast, validated_ast,
item, item, # type: ignore[arg-type]
expression_attribute_names, # type: ignore[arg-type] expression_attribute_names,
).execute() ).execute()
except ItemSizeTooLarge: except ItemSizeTooLarge:
raise ItemSizeToUpdateTooLarge() raise ItemSizeToUpdateTooLarge()

View File

@ -76,9 +76,9 @@ class LocalSecondaryIndex(SecondaryIndex):
} }
@staticmethod @staticmethod
def create( def create( # type: ignore[misc]
dct: Dict[str, Any], table_key_attrs: List[str] dct: Dict[str, Any], table_key_attrs: List[str]
) -> "LocalSecondaryIndex": # type: ignore[misc] ) -> "LocalSecondaryIndex":
return LocalSecondaryIndex( return LocalSecondaryIndex(
index_name=dct["IndexName"], index_name=dct["IndexName"],
schema=dct["KeySchema"], schema=dct["KeySchema"],
@ -114,9 +114,9 @@ class GlobalSecondaryIndex(SecondaryIndex):
} }
@staticmethod @staticmethod
def create( def create( # type: ignore[misc]
dct: Dict[str, Any], table_key_attrs: List[str] dct: Dict[str, Any], table_key_attrs: List[str]
) -> "GlobalSecondaryIndex": # type: ignore[misc] ) -> "GlobalSecondaryIndex":
return GlobalSecondaryIndex( return GlobalSecondaryIndex(
index_name=dct["IndexName"], index_name=dct["IndexName"],
schema=dct["KeySchema"], schema=dct["KeySchema"],

View File

@ -257,9 +257,9 @@ class UpdateExpressionFunctionEvaluator(DepthFirstTraverser): # type: ignore[mi
raise NotImplementedError(f"Unsupported function for moto {function_name}") raise NotImplementedError(f"Unsupported function for moto {function_name}")
@classmethod @classmethod
def get_list_from_ddb_typed_value( def get_list_from_ddb_typed_value( # type: ignore[misc]
cls, node: DDBTypedValue, function_name: str cls, node: DDBTypedValue, function_name: str
) -> DynamoType: # type: ignore[misc] ) -> DynamoType:
assert isinstance(node, DDBTypedValue) assert isinstance(node, DDBTypedValue)
dynamo_value = node.get_value() dynamo_value = node.get_value()
assert isinstance(dynamo_value, DynamoType) assert isinstance(dynamo_value, DynamoType)
@ -324,9 +324,9 @@ class ExecuteOperations(DepthFirstTraverser): # type: ignore[misc]
return dynamo_value return dynamo_value
@classmethod @classmethod
def get_sum( def get_sum( # type: ignore[misc]
cls, left_operand: DynamoType, right_operand: DynamoType cls, left_operand: DynamoType, right_operand: DynamoType
) -> DDBTypedValue: # type: ignore[misc] ) -> DDBTypedValue:
""" """
Args: Args:
left_operand(DynamoType): left_operand(DynamoType):
@ -341,9 +341,9 @@ class ExecuteOperations(DepthFirstTraverser): # type: ignore[misc]
raise IncorrectOperandType("+", left_operand.type) raise IncorrectOperandType("+", left_operand.type)
@classmethod @classmethod
def get_subtraction( def get_subtraction( # type: ignore[misc]
cls, left_operand: DynamoType, right_operand: DynamoType cls, left_operand: DynamoType, right_operand: DynamoType
) -> DDBTypedValue: # type: ignore[misc] ) -> DDBTypedValue:
""" """
Args: Args:
left_operand(DynamoType): left_operand(DynamoType):

View File

@ -166,8 +166,8 @@ class Table(BaseModel):
hash_value = DynamoType(item_attrs.get(self.hash_key_attr)) # type: ignore[arg-type] hash_value = DynamoType(item_attrs.get(self.hash_key_attr)) # type: ignore[arg-type]
if self.has_range_key: if self.has_range_key:
range_value: Optional[DynamoType] = DynamoType( range_value: Optional[DynamoType] = DynamoType(
item_attrs.get(self.range_key_attr) item_attrs.get(self.range_key_attr) # type: ignore[arg-type]
) # type: ignore[arg-type] )
else: else:
range_value = None range_value = None

View File

@ -129,7 +129,7 @@ class DynamoDBStreamsBackend(BaseBackend):
shard_iterator = ShardIterator( shard_iterator = ShardIterator(
self, self,
table.stream_shard, table.stream_shard, # type: ignore[arg-type]
shard_iterator_type, shard_iterator_type,
sequence_number, # type: ignore[arg-type] sequence_number, # type: ignore[arg-type]
) )

View File

@ -25,18 +25,18 @@ class EBSResponse(BaseResponse):
if request.method == "POST": if request.method == "POST":
return self.start_snapshot() return self.start_snapshot()
def snapshot_block( def snapshot_block( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers, use_raw_body=True) self.setup_class(request, full_url, headers, use_raw_body=True)
if request.method == "PUT": if request.method == "PUT":
return self.put_snapshot_block(full_url, headers) return self.put_snapshot_block(full_url, headers)
if request.method == "GET": if request.method == "GET":
return self.get_snapshot_block() return self.get_snapshot_block()
def snapshot_blocks( def snapshot_blocks( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "GET": if request.method == "GET":
return self.list_snapshot_blocks() return self.list_snapshot_blocks()

View File

@ -1,4 +1,4 @@
from typing import Any, Dict, List from typing import List
from moto.core.base_backend import BackendDict, BaseBackend from moto.core.base_backend import BackendDict, BaseBackend

View File

@ -50,9 +50,9 @@ class IamInstanceProfileAssociationBackend:
iam_association_id = random_iam_instance_profile_association_id() iam_association_id = random_iam_instance_profile_association_id()
instance_profile = filter_iam_instance_profiles( instance_profile = filter_iam_instance_profiles(
self.account_id, self.account_id, # type: ignore[attr-defined]
iam_instance_profile_arn, iam_instance_profile_arn,
iam_instance_profile_name, # type: ignore[attr-defined] iam_instance_profile_name,
) )
if instance_id in self.iam_instance_profile_associations.keys(): if instance_id in self.iam_instance_profile_associations.keys():
@ -127,9 +127,9 @@ class IamInstanceProfileAssociationBackend:
iam_instance_profile_arn: Optional[str] = None, iam_instance_profile_arn: Optional[str] = None,
) -> IamInstanceProfileAssociation: ) -> IamInstanceProfileAssociation:
instance_profile = filter_iam_instance_profiles( instance_profile = filter_iam_instance_profiles(
self.account_id, self.account_id, # type: ignore[attr-defined]
iam_instance_profile_arn, iam_instance_profile_arn,
iam_instance_profile_name, # type: ignore[attr-defined] iam_instance_profile_name,
) )
iam_instance_profile_association = None iam_instance_profile_association = None

View File

@ -668,8 +668,8 @@ class InstanceBackend:
raise InvalidInstanceTypeError(kwargs["instance_type"]) raise InvalidInstanceTypeError(kwargs["instance_type"])
security_groups = [ security_groups = [
self.get_security_group_by_name_or_id(name) self.get_security_group_by_name_or_id(name) # type: ignore[attr-defined]
for name in security_group_names # type: ignore[attr-defined] for name in security_group_names
] ]
for sg_id in kwargs.pop("security_group_ids", []): for sg_id in kwargs.pop("security_group_ids", []):

View File

@ -489,8 +489,8 @@ class RouteBackend:
route.instance = self.get_instance(instance_id) if instance_id else None # type: ignore[attr-defined] route.instance = self.get_instance(instance_id) if instance_id else None # type: ignore[attr-defined]
route.interface = ( route.interface = (
self.get_network_interface(interface_id) if interface_id else None self.get_network_interface(interface_id) if interface_id else None # type: ignore[attr-defined]
) # type: ignore[attr-defined] )
route.vpc_pcx = ( route.vpc_pcx = (
self.get_vpc_peering_connection(vpc_peering_connection_id) # type: ignore[attr-defined] self.get_vpc_peering_connection(vpc_peering_connection_id) # type: ignore[attr-defined]
if vpc_peering_connection_id if vpc_peering_connection_id

View File

@ -629,9 +629,9 @@ class SecurityGroupBackend:
return results return results
@staticmethod @staticmethod
def _match_sg_rules( def _match_sg_rules( # type: ignore[misc]
rules_list: List[SecurityRule], filters: Any rules_list: List[SecurityRule], filters: Any
) -> List[SecurityRule]: # type: ignore[misc] ) -> List[SecurityRule]:
results = [] results = []
for rule in rules_list: for rule in rules_list:
if rule.match_tags(filters): if rule.match_tags(filters):

View File

@ -235,8 +235,8 @@ class TransitGatewayAttachmentBackend:
if remove_subnet_ids: if remove_subnet_ids:
tgw_attachment.subnet_ids = [ # type: ignore[attr-defined] tgw_attachment.subnet_ids = [ # type: ignore[attr-defined]
id id
for id in tgw_attachment.subnet_ids for id in tgw_attachment.subnet_ids # type: ignore[attr-defined]
if id not in remove_subnet_ids # type: ignore[attr-defined] if id not in remove_subnet_ids
] ]
if options: if options:
@ -359,16 +359,16 @@ class TransitGatewayAttachmentBackend:
# For cross-account peering, must be accepted by the accepter # For cross-account peering, must be accepted by the accepter
if ( if (
requester_account_id != accepter_account_id requester_account_id != accepter_account_id
and self.account_id != accepter_account_id and self.account_id != accepter_account_id # type: ignore[attr-defined]
): # type: ignore[attr-defined] ):
raise InvalidParameterValueErrorPeeringAttachment( raise InvalidParameterValueErrorPeeringAttachment(
"accept", transit_gateway_attachment_id "accept", transit_gateway_attachment_id
) )
if ( if (
requester_region_name != accepter_region_name requester_region_name != accepter_region_name
and self.region_name != accepter_region_name and self.region_name != accepter_region_name # type: ignore[attr-defined]
): # type: ignore[attr-defined] ):
raise InvalidParameterValueErrorPeeringAttachment( raise InvalidParameterValueErrorPeeringAttachment(
"accept", transit_gateway_attachment_id "accept", transit_gateway_attachment_id
) )
@ -393,16 +393,16 @@ class TransitGatewayAttachmentBackend:
if ( if (
requester_account_id != accepter_account_id requester_account_id != accepter_account_id
and self.account_id != accepter_account_id and self.account_id != accepter_account_id # type: ignore[attr-defined]
): # type: ignore[attr-defined] ):
raise InvalidParameterValueErrorPeeringAttachment( raise InvalidParameterValueErrorPeeringAttachment(
"reject", transit_gateway_attachment_id "reject", transit_gateway_attachment_id
) )
if ( if (
requester_region_name != accepter_region_name requester_region_name != accepter_region_name
and self.region_name != accepter_region_name and self.region_name != accepter_region_name # type: ignore[attr-defined]
): # type: ignore[attr-defined] ):
raise InvalidParameterValueErrorPeeringAttachment( raise InvalidParameterValueErrorPeeringAttachment(
"reject", transit_gateway_attachment_id "reject", transit_gateway_attachment_id
) )

View File

@ -1044,15 +1044,17 @@ class VPCBackend:
# Return sensible defaults, for services that do not offer a custom implementation # Return sensible defaults, for services that do not offer a custom implementation
for aws_service in AWS_ENDPOINT_SERVICES: for aws_service in AWS_ENDPOINT_SERVICES:
if aws_service not in COVERED_ENDPOINT_SERVICES: if aws_service not in COVERED_ENDPOINT_SERVICES:
service_configs = BaseBackend.default_vpc_endpoint_service_factory(region, zones, aws_service) service_configs = BaseBackend.default_vpc_endpoint_service_factory(
region, zones, aws_service
)
DEFAULT_VPC_ENDPOINT_SERVICES[region].extend(service_configs) DEFAULT_VPC_ENDPOINT_SERVICES[region].extend(service_configs)
return DEFAULT_VPC_ENDPOINT_SERVICES[region] return DEFAULT_VPC_ENDPOINT_SERVICES[region]
@staticmethod @staticmethod
def _matches_service_by_tags( def _matches_service_by_tags( # type: ignore[misc]
service: Dict[str, Any], filter_item: Dict[str, Any] service: Dict[str, Any], filter_item: Dict[str, Any]
) -> bool: # type: ignore[misc] ) -> bool:
"""Return True if service tags are not filtered by their tags. """Return True if service tags are not filtered by their tags.
Note that the API specifies a key of "Values" for a filter, but Note that the API specifies a key of "Values" for a filter, but
@ -1084,11 +1086,11 @@ class VPCBackend:
return matched return matched
@staticmethod @staticmethod
def _filter_endpoint_services( def _filter_endpoint_services( # type: ignore[misc]
service_names_filters: List[str], service_names_filters: List[str],
filters: List[Dict[str, Any]], filters: List[Dict[str, Any]],
services: List[Dict[str, Any]], services: List[Dict[str, Any]],
) -> List[Dict[str, Any]]: # type: ignore[misc] ) -> List[Dict[str, Any]]:
"""Return filtered list of VPC endpoint services.""" """Return filtered list of VPC endpoint services."""
if not service_names_filters and not filters: if not service_names_filters and not filters:
return services return services
@ -1161,8 +1163,8 @@ class VPCBackend:
The DryRun parameter is ignored. The DryRun parameter is ignored.
""" """
default_services = self._collect_default_endpoint_services( default_services = self._collect_default_endpoint_services(
self.account_id, self.account_id, # type: ignore[attr-defined]
region, # type: ignore[attr-defined] region,
) )
custom_services = [x.to_dict() for x in self.configurations.values()] # type: ignore custom_services = [x.to_dict() for x in self.configurations.values()] # type: ignore
all_services = default_services + custom_services all_services = default_services + custom_services

View File

@ -403,9 +403,9 @@ class ECRBackend(BaseBackend):
self.tagger = TaggingService(tag_name="tags") self.tagger = TaggingService(tag_name="tags")
@staticmethod @staticmethod
def default_vpc_endpoint_service( def default_vpc_endpoint_service( # type: ignore[misc]
service_region: str, zones: List[str] service_region: str, zones: List[str]
) -> List[Dict[str, Any]]: # type: ignore[misc] ) -> List[Dict[str, Any]]:
"""Default VPC endpoint service.""" """Default VPC endpoint service."""
docker_endpoint = { docker_endpoint = {
"AcceptanceRequired": False, "AcceptanceRequired": False,

View File

@ -1207,11 +1207,11 @@ class EC2ContainerServiceBackend(BaseBackend):
return task_definition return task_definition
@staticmethod @staticmethod
def _validate_container_defs( def _validate_container_defs( # type: ignore[misc]
memory: Optional[str], memory: Optional[str],
container_definitions: List[Dict[str, Any]], container_definitions: List[Dict[str, Any]],
requires_compatibilities: Optional[List[str]], requires_compatibilities: Optional[List[str]],
) -> None: # type: ignore[misc] ) -> None:
# The capitalised keys are passed by Cloudformation # The capitalised keys are passed by Cloudformation
for cd in container_definitions: for cd in container_definitions:
if "name" not in cd and "Name" not in cd: if "name" not in cd and "Name" not in cd:
@ -1356,9 +1356,9 @@ class EC2ContainerServiceBackend(BaseBackend):
return tasks return tasks
@staticmethod @staticmethod
def _calculate_task_resource_requirements( def _calculate_task_resource_requirements( # type: ignore[misc]
task_definition: TaskDefinition, task_definition: TaskDefinition,
) -> Dict[str, Any]: # type: ignore[misc] ) -> Dict[str, Any]:
resource_requirements: Dict[str, Any] = { resource_requirements: Dict[str, Any] = {
"CPU": 0, "CPU": 0,
"MEMORY": 0, "MEMORY": 0,
@ -1400,10 +1400,10 @@ class EC2ContainerServiceBackend(BaseBackend):
return resource_requirements return resource_requirements
@staticmethod @staticmethod
def _can_be_placed( def _can_be_placed( # type: ignore[misc]
container_instance: ContainerInstance, container_instance: ContainerInstance,
task_resource_requirements: Dict[str, Any], task_resource_requirements: Dict[str, Any],
) -> bool: # type: ignore[misc] ) -> bool:
""" """
:param container_instance: The container instance trying to be placed onto :param container_instance: The container instance trying to be placed onto

View File

@ -405,7 +405,7 @@ class ELBResponse(BaseResponse):
subnets = params.get("Subnets") subnets = params.get("Subnets")
all_subnets = self.elb_backend.attach_load_balancer_to_subnets( all_subnets = self.elb_backend.attach_load_balancer_to_subnets(
load_balancer_name, load_balancer_name, # type: ignore[arg-type]
subnets, # type: ignore[arg-type] subnets, # type: ignore[arg-type]
) )
template = self.response_template(ATTACH_LB_TO_SUBNETS_TEMPLATE) template = self.response_template(ATTACH_LB_TO_SUBNETS_TEMPLATE)
@ -417,7 +417,7 @@ class ELBResponse(BaseResponse):
subnets = params.get("Subnets") subnets = params.get("Subnets")
all_subnets = self.elb_backend.detach_load_balancer_from_subnets( all_subnets = self.elb_backend.detach_load_balancer_from_subnets(
load_balancer_name, load_balancer_name, # type: ignore[arg-type]
subnets, # type: ignore[arg-type] subnets, # type: ignore[arg-type]
) )
template = self.response_template(DETACH_LB_FROM_SUBNETS_TEMPLATE) template = self.response_template(DETACH_LB_FROM_SUBNETS_TEMPLATE)

View File

@ -455,9 +455,9 @@ class EmrSecurityGroupManager:
pass pass
@staticmethod @staticmethod
def _render_rules( def _render_rules( # type: ignore[misc]
rules: Any, managed_groups: Dict[str, Any] rules: Any, managed_groups: Dict[str, Any]
) -> List[Dict[str, Any]]: # type: ignore[misc] ) -> List[Dict[str, Any]]:
rendered_rules = copy.deepcopy(rules) rendered_rules = copy.deepcopy(rules)
for rule in rendered_rules: for rule in rendered_rules:
rule["group_name_or_id"] = managed_groups[rule["group_name_or_id"]].id rule["group_name_or_id"] = managed_groups[rule["group_name_or_id"]].id

View File

@ -1389,9 +1389,9 @@ class EventsBackend(BaseBackend):
) )
@staticmethod @staticmethod
def _condition_param_to_stmt_condition( def _condition_param_to_stmt_condition( # type: ignore[misc]
condition: Optional[Dict[str, Any]], condition: Optional[Dict[str, Any]],
) -> Optional[Dict[str, Any]]: # type: ignore[misc] ) -> Optional[Dict[str, Any]]:
if condition: if condition:
key = condition["Key"] key = condition["Key"]
value = condition["Value"] value = condition["Value"]

View File

@ -413,9 +413,9 @@ class FirehoseBackend(BaseBackend):
} }
@staticmethod @staticmethod
def put_http_records( def put_http_records( # type: ignore[misc]
http_destination: Dict[str, Any], records: List[Dict[str, bytes]] http_destination: Dict[str, Any], records: List[Dict[str, bytes]]
) -> List[Dict[str, str]]: # type: ignore[misc] ) -> List[Dict[str, str]]:
"""Put records to a HTTP destination.""" """Put records to a HTTP destination."""
# Mostly copied from localstack # Mostly copied from localstack
url = http_destination["EndpointConfiguration"]["Url"] url = http_destination["EndpointConfiguration"]["Url"]

View File

@ -37,9 +37,9 @@ class GlacierResponse(BaseResponse):
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
return self._vault_response(request, full_url, headers) return self._vault_response(request, full_url, headers)
def _vault_response( def _vault_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
method = request.method method = request.method
vault_name = vault_from_glacier_url(full_url) vault_name = vault_from_glacier_url(full_url)
@ -103,9 +103,9 @@ class GlacierResponse(BaseResponse):
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
return self._vault_archive_individual_response(request, full_url, headers) return self._vault_archive_individual_response(request, full_url, headers)
def _vault_archive_individual_response( def _vault_archive_individual_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
method = request.method method = request.method
vault_name = full_url.split("/")[-3] vault_name = full_url.split("/")[-3]
archive_id = full_url.split("/")[-1] archive_id = full_url.split("/")[-1]
@ -121,9 +121,9 @@ class GlacierResponse(BaseResponse):
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
return self._vault_jobs_response(request, full_url, headers) return self._vault_jobs_response(request, full_url, headers)
def _vault_jobs_response( def _vault_jobs_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
method = request.method method = request.method
if hasattr(request, "body"): if hasattr(request, "body"):
body = request.body body = request.body

View File

@ -32,8 +32,10 @@ class GlueResponse(BaseResponse):
if "CatalogId" in self.parameters: if "CatalogId" in self.parameters:
database_input["CatalogId"] = self.parameters.get("CatalogId") # type: ignore database_input["CatalogId"] = self.parameters.get("CatalogId") # type: ignore
self.glue_backend.create_database( self.glue_backend.create_database(
database_name, database_input, self.parameters.get("Tags") database_name,
) # type: ignore[arg-type] database_input, # type: ignore[arg-type]
self.parameters.get("Tags"), # type: ignore[arg-type]
)
return "" return ""
def get_database(self) -> str: def get_database(self) -> str:
@ -136,8 +138,8 @@ class GlueResponse(BaseResponse):
table_name = self.parameters.get("TableName") table_name = self.parameters.get("TableName")
expression = self.parameters.get("Expression") expression = self.parameters.get("Expression")
partitions = self.glue_backend.get_partitions( partitions = self.glue_backend.get_partitions(
database_name, database_name, # type: ignore[arg-type]
table_name, table_name, # type: ignore[arg-type]
expression, # type: ignore[arg-type] expression, # type: ignore[arg-type]
) )
@ -158,8 +160,8 @@ class GlueResponse(BaseResponse):
partitions_to_get = self.parameters.get("PartitionsToGet") partitions_to_get = self.parameters.get("PartitionsToGet")
partitions = self.glue_backend.batch_get_partition( partitions = self.glue_backend.batch_get_partition(
database_name, database_name, # type: ignore[arg-type]
table_name, table_name, # type: ignore[arg-type]
partitions_to_get, # type: ignore[arg-type] partitions_to_get, # type: ignore[arg-type]
) )
@ -178,8 +180,8 @@ class GlueResponse(BaseResponse):
table_name = self.parameters.get("TableName") table_name = self.parameters.get("TableName")
partition_input = self.parameters.get("PartitionInputList") partition_input = self.parameters.get("PartitionInputList")
errors_output = self.glue_backend.batch_create_partition( errors_output = self.glue_backend.batch_create_partition(
database_name, database_name, # type: ignore[arg-type]
table_name, table_name, # type: ignore[arg-type]
partition_input, # type: ignore[arg-type] partition_input, # type: ignore[arg-type]
) )
@ -196,9 +198,9 @@ class GlueResponse(BaseResponse):
part_to_update = self.parameters.get("PartitionValueList") part_to_update = self.parameters.get("PartitionValueList")
self.glue_backend.update_partition( self.glue_backend.update_partition(
database_name, database_name, # type: ignore[arg-type]
table_name, table_name, # type: ignore[arg-type]
part_input, part_input, # type: ignore[arg-type]
part_to_update, # type: ignore[arg-type] part_to_update, # type: ignore[arg-type]
) )
return "" return ""
@ -209,8 +211,8 @@ class GlueResponse(BaseResponse):
entries = self.parameters.get("Entries") entries = self.parameters.get("Entries")
errors_output = self.glue_backend.batch_update_partition( errors_output = self.glue_backend.batch_update_partition(
database_name, database_name, # type: ignore[arg-type]
table_name, table_name, # type: ignore[arg-type]
entries, # type: ignore[arg-type] entries, # type: ignore[arg-type]
) )
@ -234,8 +236,8 @@ class GlueResponse(BaseResponse):
parts = self.parameters.get("PartitionsToDelete") parts = self.parameters.get("PartitionsToDelete")
errors_output = self.glue_backend.batch_delete_partition( errors_output = self.glue_backend.batch_delete_partition(
database_name, database_name, # type: ignore[arg-type]
table_name, table_name, # type: ignore[arg-type]
parts, # type: ignore[arg-type] parts, # type: ignore[arg-type]
) )

View File

@ -916,9 +916,9 @@ class GreengrassBackend(BaseBackend):
return False return False
@staticmethod @staticmethod
def _validate_subscription_target_or_source( def _validate_subscription_target_or_source( # type: ignore[misc]
subscriptions: List[Dict[str, Any]], subscriptions: List[Dict[str, Any]],
) -> None: # type: ignore[misc] ) -> None:
target_errors: List[str] = [] target_errors: List[str] = []
source_errors: List[str] = [] source_errors: List[str] = []

View File

@ -16,9 +16,9 @@ class GreengrassResponse(BaseResponse):
def greengrass_backend(self) -> GreengrassBackend: def greengrass_backend(self) -> GreengrassBackend:
return greengrass_backends[self.current_account][self.region] return greengrass_backends[self.current_account][self.region]
def core_definitions( def core_definitions( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -45,9 +45,9 @@ class GreengrassResponse(BaseResponse):
) )
return 201, {"status": 201}, json.dumps(res.to_dict()) return 201, {"status": 201}, json.dumps(res.to_dict())
def core_definition( def core_definition( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -81,9 +81,9 @@ class GreengrassResponse(BaseResponse):
) )
return 200, {"status": 200}, json.dumps({}) return 200, {"status": 200}, json.dumps({})
def core_definition_versions( def core_definition_versions( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -110,9 +110,9 @@ class GreengrassResponse(BaseResponse):
json.dumps({"Versions": [core_def_ver.to_dict() for core_def_ver in res]}), json.dumps({"Versions": [core_def_ver.to_dict() for core_def_ver in res]}),
) )
def core_definition_version( def core_definition_version( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -127,9 +127,9 @@ class GreengrassResponse(BaseResponse):
) )
return 200, {"status": 200}, json.dumps(res.to_dict(include_detail=True)) return 200, {"status": 200}, json.dumps(res.to_dict(include_detail=True))
def device_definitions( def device_definitions( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":
@ -160,9 +160,9 @@ class GreengrassResponse(BaseResponse):
), ),
) )
def device_definition_versions( def device_definition_versions( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":
@ -193,9 +193,9 @@ class GreengrassResponse(BaseResponse):
), ),
) )
def device_definition( def device_definition( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -229,9 +229,9 @@ class GreengrassResponse(BaseResponse):
) )
return 200, {"status": 200}, json.dumps({}) return 200, {"status": 200}, json.dumps({})
def device_definition_version( def device_definition_version( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -246,9 +246,9 @@ class GreengrassResponse(BaseResponse):
) )
return 200, {"status": 200}, json.dumps(res.to_dict(include_detail=True)) return 200, {"status": 200}, json.dumps(res.to_dict(include_detail=True))
def resource_definitions( def resource_definitions( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":
@ -273,9 +273,9 @@ class GreengrassResponse(BaseResponse):
json.dumps({"Definitions": [i.to_dict() for i in res]}), json.dumps({"Definitions": [i.to_dict() for i in res]}),
) )
def resource_definition( def resource_definition( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -309,9 +309,9 @@ class GreengrassResponse(BaseResponse):
) )
return 200, {"status": 200}, json.dumps({}) return 200, {"status": 200}, json.dumps({})
def resource_definition_versions( def resource_definition_versions( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":
@ -343,9 +343,9 @@ class GreengrassResponse(BaseResponse):
), ),
) )
def resource_definition_version( def resource_definition_version( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -360,9 +360,9 @@ class GreengrassResponse(BaseResponse):
) )
return 200, {"status": 200}, json.dumps(res.to_dict()) return 200, {"status": 200}, json.dumps(res.to_dict())
def function_definitions( def function_definitions( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":
@ -389,9 +389,9 @@ class GreengrassResponse(BaseResponse):
), ),
) )
def function_definition( def function_definition( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -425,9 +425,9 @@ class GreengrassResponse(BaseResponse):
) )
return 200, {"status": 200}, json.dumps({}) return 200, {"status": 200}, json.dumps({})
def function_definition_versions( def function_definition_versions( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":
@ -456,9 +456,9 @@ class GreengrassResponse(BaseResponse):
versions = [i.to_dict() for i in res.values()] versions = [i.to_dict() for i in res.values()]
return 200, {"status": 200}, json.dumps({"Versions": versions}) return 200, {"status": 200}, json.dumps({"Versions": versions})
def function_definition_version( def function_definition_version( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -473,9 +473,9 @@ class GreengrassResponse(BaseResponse):
) )
return 200, {"status": 200}, json.dumps(res.to_dict()) return 200, {"status": 200}, json.dumps(res.to_dict())
def subscription_definitions( def subscription_definitions( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":
@ -507,9 +507,9 @@ class GreengrassResponse(BaseResponse):
), ),
) )
def subscription_definition( def subscription_definition( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -543,9 +543,9 @@ class GreengrassResponse(BaseResponse):
) )
return 200, {"status": 200}, json.dumps({}) return 200, {"status": 200}, json.dumps({})
def subscription_definition_versions( def subscription_definition_versions( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":
@ -571,9 +571,9 @@ class GreengrassResponse(BaseResponse):
versions = [i.to_dict() for i in res.values()] versions = [i.to_dict() for i in res.values()]
return 200, {"status": 200}, json.dumps({"Versions": versions}) return 200, {"status": 200}, json.dumps({"Versions": versions})
def subscription_definition_version( def subscription_definition_version( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -643,9 +643,9 @@ class GreengrassResponse(BaseResponse):
self.greengrass_backend.update_group(group_id=group_id, name=name) self.greengrass_backend.update_group(group_id=group_id, name=name)
return 200, {"status": 200}, json.dumps({}) return 200, {"status": 200}, json.dumps({})
def group_versions( def group_versions( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":
@ -742,9 +742,9 @@ class GreengrassResponse(BaseResponse):
json.dumps({"Deployments": deployments}), json.dumps({"Deployments": deployments}),
) )
def deployment_satus( def deployment_satus( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "GET": if self.method == "GET":
@ -760,9 +760,9 @@ class GreengrassResponse(BaseResponse):
) )
return 200, {"status": 200}, json.dumps(res.to_dict()) return 200, {"status": 200}, json.dumps(res.to_dict())
def deployments_reset( def deployments_reset( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if self.method == "POST": if self.method == "POST":

View File

@ -463,9 +463,9 @@ class AWSManagedPolicy(ManagedPolicy):
"""AWS-managed policy.""" """AWS-managed policy."""
@classmethod @classmethod
def from_data( def from_data( # type: ignore[misc]
cls, name: str, account_id: str, data: Dict[str, Any] cls, name: str, account_id: str, data: Dict[str, Any]
) -> "AWSManagedPolicy": # type: ignore[misc] ) -> "AWSManagedPolicy":
return cls( return cls(
name, name,
account_id=account_id, account_id=account_id,

View File

@ -222,9 +222,10 @@ class BaseIAMPolicyValidator:
) )
@staticmethod @staticmethod
def _validate_string_or_list_of_strings_syntax( def _validate_string_or_list_of_strings_syntax( # type: ignore[misc]
statement: Dict[str, Any], key: str statement: Dict[str, Any],
) -> None: # type: ignore[misc] key: str,
) -> None:
if key in statement: if key in statement:
assert isinstance(statement[key], (str, list)) assert isinstance(statement[key], (str, list))
if isinstance(statement[key], list): if isinstance(statement[key], list):
@ -456,9 +457,10 @@ class BaseIAMPolicyValidator:
assert resource[2] != "" assert resource[2] != ""
@staticmethod @staticmethod
def _legacy_parse_condition( def _legacy_parse_condition( # type: ignore[misc]
condition_key: str, condition_value: Dict[str, Any] condition_key: str,
) -> None: # type: ignore[misc] condition_value: Dict[str, Any],
) -> None:
stripped_condition_key = IAMPolicyDocumentValidator._strip_condition_key( stripped_condition_key = IAMPolicyDocumentValidator._strip_condition_key(
condition_key condition_key
) )

View File

@ -196,7 +196,7 @@ class Inspector2Backend(BaseBackend):
"region": "us-east-1", # This is the default - can be omitted "region": "us-east-1", # This is the default - can be omitted
} }
resp = requests.post( resp = requests.post(
"http://motoapi.amazonaws.com:5000/moto-api/static/inspector2/findings-results", "http://motoapi.amazonaws.com/moto-api/static/inspector2/findings-results",
json=findings, json=findings,
) )

View File

@ -44,9 +44,9 @@ class FakeShadow(BaseModel):
) )
@classmethod @classmethod
def create_from_previous_version( def create_from_previous_version( # type: ignore[misc]
cls, previous_shadow: Optional["FakeShadow"], payload: Optional[Dict[str, Any]] cls, previous_shadow: Optional["FakeShadow"], payload: Optional[Dict[str, Any]]
) -> "FakeShadow": # type: ignore[misc] ) -> "FakeShadow":
""" """
set None to payload when you want to delete shadow set None to payload when you want to delete shadow
""" """

View File

@ -734,8 +734,8 @@ class KinesisBackend(BaseBackend):
data = record.get("Data") data = record.get("Data")
sequence_number, shard_id = stream.put_record( sequence_number, shard_id = stream.put_record(
partition_key, partition_key, # type: ignore[arg-type]
explicit_hash_key, explicit_hash_key, # type: ignore[arg-type]
data, # type: ignore[arg-type] data, # type: ignore[arg-type]
) )
response["Records"].append( response["Records"].append(

View File

@ -8,8 +8,8 @@ def get_body_from_form_data(
body: bytes, boundary: str body: bytes, boundary: str
) -> Tuple[Optional[bytes], Dict[str, str]]: ) -> Tuple[Optional[bytes], Dict[str, str]]:
body_stream = io.BytesIO(body) body_stream = io.BytesIO(body)
parser = multipart.MultipartParser(body_stream, boundary=boundary) parser = multipart.MultipartParser(boundary=boundary)
parser.write(body_stream)
data = None data = None
headers: Dict[str, str] = {} headers: Dict[str, str] = {}
for prt in parser.parts(): for prt in parser.parts():

View File

@ -588,9 +588,9 @@ class OpsWorksBackend(BaseBackend):
raise ResourceNotFoundException(", ".join(unknown_apps)) raise ResourceNotFoundException(", ".join(unknown_apps))
return [self.apps[id].to_dict() for id in app_ids] return [self.apps[id].to_dict() for id in app_ids]
def describe_instances( def describe_instances( # type: ignore[return]
self, instance_ids: List[str], layer_id: str, stack_id: str self, instance_ids: List[str], layer_id: str, stack_id: str
) -> List[Dict[str, Any]]: # type: ignore[return] ) -> List[Dict[str, Any]]:
if len(list(filter(None, (instance_ids, layer_id, stack_id)))) != 1: if len(list(filter(None, (instance_ids, layer_id, stack_id)))) != 1:
raise ValidationException( raise ValidationException(
"Please provide either one or more " "Please provide either one or more "

View File

@ -2754,9 +2754,9 @@ class RDSBackend(BaseBackend):
"InvalidParameterValue", f"Invalid resource name: {arn}" "InvalidParameterValue", f"Invalid resource name: {arn}"
) )
def add_tags_to_resource( def add_tags_to_resource( # type: ignore[return]
self, arn: str, tags: List[Dict[str, str]] self, arn: str, tags: List[Dict[str, str]]
) -> List[Dict[str, str]]: # type: ignore[return] ) -> List[Dict[str, str]]:
if self.arn_regex.match(arn): if self.arn_regex.match(arn):
arn_breakdown = arn.split(":") arn_breakdown = arn.split(":")
resource_type = arn_breakdown[-2] resource_type = arn_breakdown[-2]
@ -2813,9 +2813,9 @@ class RDSBackend(BaseBackend):
raise InvalidParameterCombination(str(e)) raise InvalidParameterCombination(str(e))
@staticmethod @staticmethod
def _merge_tags( def _merge_tags( # type: ignore[misc]
old_tags: List[Dict[str, Any]], new_tags: List[Dict[str, Any]] old_tags: List[Dict[str, Any]], new_tags: List[Dict[str, Any]]
) -> List[Dict[str, Any]]: # type: ignore[misc] ) -> List[Dict[str, Any]]:
tags_dict = dict() tags_dict = dict()
tags_dict.update({d["Key"]: d["Value"] for d in old_tags}) tags_dict.update({d["Key"]: d["Value"] for d in old_tags})
tags_dict.update({d["Key"]: d["Value"] for d in new_tags}) tags_dict.update({d["Key"]: d["Value"] for d in new_tags})

View File

@ -63,7 +63,7 @@ class RDSDataServiceBackend(BaseBackend):
], ],
} }
resp = requests.post( resp = requests.post(
"http://motoapi.amazonaws.com:5000/moto-api/static/rds-data/statement-results", "http://motoapi.amazonaws.com/moto-api/static/rds-data/statement-results",
json=expected_results, json=expected_results,
) )
assert resp.status_code == 201 assert resp.status_code == 201

View File

@ -23,8 +23,8 @@ from moto.s3.models import S3Backend, s3_backends
from moto.sns.models import SNSBackend, sns_backends from moto.sns.models import SNSBackend, sns_backends
from moto.sqs.models import SQSBackend, sqs_backends from moto.sqs.models import SQSBackend, sqs_backends
from moto.ssm.models import SimpleSystemManagerBackend, ssm_backends from moto.ssm.models import SimpleSystemManagerBackend, ssm_backends
from moto.workspaces.models import WorkSpacesBackend, workspaces_backends
from moto.utilities.tagging_service import TaggingService from moto.utilities.tagging_service import TaggingService
from moto.workspaces.models import WorkSpacesBackend, workspaces_backends
# Left: EC2 ElastiCache RDS ELB CloudFront Lambda EMR Glacier Kinesis Redshift Route53 # Left: EC2 ElastiCache RDS ELB CloudFront Lambda EMR Glacier Kinesis Redshift Route53
# StorageGateway DynamoDB MachineLearning ACM DirectConnect DirectoryService CloudHSM # StorageGateway DynamoDB MachineLearning ACM DirectConnect DirectoryService CloudHSM

View File

@ -36,9 +36,9 @@ class Route53(BaseResponse):
def backend(self) -> Route53Backend: def backend(self) -> Route53Backend:
return route53_backends[self.current_account]["global"] return route53_backends[self.current_account]["global"]
def list_or_create_hostzone_response( def list_or_create_hostzone_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
# Set these here outside the scope of the try/except # Set these here outside the scope of the try/except
@ -136,9 +136,9 @@ class Route53(BaseResponse):
template = Template(GET_HOSTED_ZONE_COUNT_RESPONSE) template = Template(GET_HOSTED_ZONE_COUNT_RESPONSE)
return 200, headers, template.render(zone_count=num_zones, xmlns=XMLNS) return 200, headers, template.render(zone_count=num_zones, xmlns=XMLNS)
def get_or_delete_hostzone_response( def get_or_delete_hostzone_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
zoneid = self.parsed_url.path.rstrip("/").rsplit("/", 1)[1] zoneid = self.parsed_url.path.rstrip("/").rsplit("/", 1)[1]
@ -158,9 +158,9 @@ class Route53(BaseResponse):
template = Template(UPDATE_HOSTED_ZONE_COMMENT_RESPONSE) template = Template(UPDATE_HOSTED_ZONE_COMMENT_RESPONSE)
return 200, headers, template.render(zone=zone) return 200, headers, template.render(zone=zone)
def get_dnssec_response( def get_dnssec_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
# returns static response # returns static response
# TODO: implement enable/disable dnssec apis # TODO: implement enable/disable dnssec apis
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
@ -212,9 +212,9 @@ class Route53(BaseResponse):
template = Template(DISASSOCIATE_VPC_RESPONSE) template = Template(DISASSOCIATE_VPC_RESPONSE)
return 200, headers, template.render(comment=comment) return 200, headers, template.render(comment=comment)
def rrset_response( def rrset_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
method = request.method method = request.method
@ -285,9 +285,9 @@ class Route53(BaseResponse):
) )
return 200, headers, r_template return 200, headers, r_template
def health_check_response1( def health_check_response1( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
method = request.method method = request.method
@ -327,9 +327,9 @@ class Route53(BaseResponse):
template.render(health_checks=health_checks, xmlns=XMLNS), template.render(health_checks=health_checks, xmlns=XMLNS),
) )
def health_check_response2( def health_check_response2( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
method = request.method method = request.method
@ -365,9 +365,9 @@ class Route53(BaseResponse):
template = Template(UPDATE_HEALTH_CHECK_RESPONSE) template = Template(UPDATE_HEALTH_CHECK_RESPONSE)
return 200, headers, template.render(health_check=health_check) return 200, headers, template.render(health_check=health_check)
def health_check_status_response( def health_check_status_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
method = request.method method = request.method
@ -402,9 +402,9 @@ class Route53(BaseResponse):
f"The action for {action} has not been implemented for route 53" f"The action for {action} has not been implemented for route 53"
) )
def list_or_change_tags_for_resource_request( def list_or_change_tags_for_resource_request( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
id_ = self.parsed_url.path.split("/")[-1] id_ = self.parsed_url.path.split("/")[-1]
@ -439,9 +439,9 @@ class Route53(BaseResponse):
template = Template(GET_CHANGE_RESPONSE) template = Template(GET_CHANGE_RESPONSE)
return 200, headers, template.render(change_id=change_id, xmlns=XMLNS) return 200, headers, template.render(change_id=change_id, xmlns=XMLNS)
def list_or_create_query_logging_config_response( def list_or_create_query_logging_config_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "POST": if request.method == "POST":
@ -488,9 +488,9 @@ class Route53(BaseResponse):
), ),
) )
def get_or_delete_query_logging_config_response( def get_or_delete_query_logging_config_response( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
query_logging_config_id = self.parsed_url.path.rstrip("/").rsplit("/", 1)[1] query_logging_config_id = self.parsed_url.path.rstrip("/").rsplit("/", 1)[1]
@ -509,9 +509,9 @@ class Route53(BaseResponse):
self.backend.delete_query_logging_config(query_logging_config_id) self.backend.delete_query_logging_config(query_logging_config_id)
return 200, headers, "" return 200, headers, ""
def reusable_delegation_sets( def reusable_delegation_sets( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "GET": if request.method == "GET":
delegation_sets = self.backend.list_reusable_delegation_sets() delegation_sets = self.backend.list_reusable_delegation_sets()
@ -541,9 +541,9 @@ class Route53(BaseResponse):
template.render(delegation_set=delegation_set), template.render(delegation_set=delegation_set),
) )
def reusable_delegation_set( def reusable_delegation_set( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
ds_id = self.parsed_url.path.rstrip("/").rsplit("/")[-1] ds_id = self.parsed_url.path.rstrip("/").rsplit("/")[-1]
if request.method == "GET": if request.method == "GET":

View File

@ -1,7 +1,9 @@
import base64 import base64
import bz2
import codecs import codecs
import copy import copy
import datetime import datetime
import gzip
import itertools import itertools
import json import json
import os import os
@ -12,6 +14,7 @@ import threading
import urllib.parse import urllib.parse
from bisect import insort from bisect import insort
from importlib import reload from importlib import reload
from io import BytesIO
from typing import Any, Dict, Iterator, List, Optional, Set, Tuple, Union from typing import Any, Dict, Iterator, List, Optional, Set, Tuple, Union
from moto.cloudwatch.models import MetricDatum from moto.cloudwatch.models import MetricDatum
@ -374,13 +377,13 @@ class FakeKey(BaseModel, ManagedState):
now = utcnow() now = utcnow()
try: try:
until = datetime.datetime.strptime( until = datetime.datetime.strptime(
self.lock_until, self.lock_until, # type: ignore
"%Y-%m-%dT%H:%M:%SZ", # type: ignore "%Y-%m-%dT%H:%M:%SZ",
) )
except ValueError: except ValueError:
until = datetime.datetime.strptime( until = datetime.datetime.strptime(
self.lock_until, self.lock_until, # type: ignore
"%Y-%m-%dT%H:%M:%S.%fZ", # type: ignore "%Y-%m-%dT%H:%M:%S.%fZ",
) )
if until > now: if until > now:
@ -478,11 +481,11 @@ class FakeMultipart(BaseModel):
raise NoSuchUpload(upload_id=part_id) raise NoSuchUpload(upload_id=part_id)
key = FakeKey( key = FakeKey(
part_id, part_id, # type: ignore
value, value,
account_id=self.account_id, account_id=self.account_id,
encryption=self.sse_encryption, encryption=self.sse_encryption,
kms_key_id=self.kms_key_id, # type: ignore kms_key_id=self.kms_key_id,
) )
if part_id in self.parts: if part_id in self.parts:
# We're overwriting the current part - dispose of it first # We're overwriting the current part - dispose of it first
@ -2376,6 +2379,7 @@ class S3Backend(BaseBackend, CloudWatchMetricProvider):
- 's3:ObjectCreated:Post' - 's3:ObjectCreated:Post'
- 's3:ObjectCreated:Put' - 's3:ObjectCreated:Put'
- 's3:ObjectDeleted' - 's3:ObjectDeleted'
- 's3:ObjectRestore:Post'
""" """
bucket = self.get_bucket(bucket_name) bucket = self.get_bucket(bucket_name)
bucket.set_notification_configuration(notification_config) bucket.set_notification_configuration(notification_config)
@ -2858,6 +2862,7 @@ class S3Backend(BaseBackend, CloudWatchMetricProvider):
key_name: str, key_name: str,
select_query: str, select_query: str,
input_details: Dict[str, Any], input_details: Dict[str, Any],
output_details: Dict[str, Any],
) -> List[bytes]: ) -> List[bytes]:
""" """
Highly experimental. Please raise an issue if you find any inconsistencies/bugs. Highly experimental. Please raise an issue if you find any inconsistencies/bugs.
@ -2870,22 +2875,51 @@ class S3Backend(BaseBackend, CloudWatchMetricProvider):
""" """
self.get_bucket(bucket_name) self.get_bucket(bucket_name)
key = self.get_object(bucket_name, key_name) key = self.get_object(bucket_name, key_name)
query_input = key.value.decode("utf-8") # type: ignore if key is None:
raise MissingKey(key=key_name)
if input_details.get("CompressionType") == "GZIP":
with gzip.open(BytesIO(key.value), "rt") as f:
query_input = f.read()
elif input_details.get("CompressionType") == "BZIP2":
query_input = bz2.decompress(key.value).decode("utf-8")
else:
query_input = key.value.decode("utf-8")
if "CSV" in input_details: if "CSV" in input_details:
# input is in CSV - we need to convert it to JSON before parsing # input is in CSV - we need to convert it to JSON before parsing
from py_partiql_parser._internal.csv_converter import ( # noqa # pylint: disable=unused-import from py_partiql_parser import csv_to_json
csv_to_json,
)
use_headers = input_details["CSV"].get("FileHeaderInfo", "") == "USE" use_headers = (input_details.get("CSV") or {}).get(
"FileHeaderInfo", ""
) == "USE"
query_input = csv_to_json(query_input, use_headers) query_input = csv_to_json(query_input, use_headers)
query_result = parse_query(query_input, select_query) query_result = parse_query(query_input, select_query) # type: ignore
record_delimiter = "\n"
if "JSON" in output_details:
record_delimiter = (output_details.get("JSON") or {}).get(
"RecordDelimiter"
) or "\n"
elif "CSV" in output_details:
record_delimiter = (output_details.get("CSV") or {}).get(
"RecordDelimiter"
) or "\n"
if "CSV" in output_details:
field_delim = (output_details.get("CSV") or {}).get("FieldDelimiter") or ","
from py_partiql_parser import json_to_csv
query_result = json_to_csv(query_result, field_delim, record_delimiter)
return [query_result.encode("utf-8")] # type: ignore
else:
from py_partiql_parser import SelectEncoder from py_partiql_parser import SelectEncoder
return [ return [
json.dumps(x, indent=None, separators=(",", ":"), cls=SelectEncoder).encode( (
"utf-8" json.dumps(x, indent=None, separators=(",", ":"), cls=SelectEncoder)
) + record_delimiter
).encode("utf-8")
for x in query_result for x in query_result
] ]

View File

@ -2291,9 +2291,9 @@ class S3Response(BaseResponse):
input_details = request["InputSerialization"] input_details = request["InputSerialization"]
output_details = request["OutputSerialization"] output_details = request["OutputSerialization"]
results = self.backend.select_object_content( results = self.backend.select_object_content(
bucket_name, key_name, select_query, input_details bucket_name, key_name, select_query, input_details, output_details
) )
return 200, {}, serialize_select(results, output_details) return 200, {}, serialize_select(results)
else: else:
raise NotImplementedError( raise NotImplementedError(

View File

@ -49,11 +49,8 @@ def _create_end_message() -> bytes:
return _create_message(content_type=None, event_type=b"End", payload=b"") return _create_message(content_type=None, event_type=b"End", payload=b"")
def serialize_select(data_list: List[bytes], output_details: Dict[str, Any]) -> bytes: def serialize_select(data_list: List[bytes]) -> bytes:
delimiter = (
(output_details.get("JSON") or {}).get("RecordDelimiter") or "\n"
).encode("utf-8")
response = b"" response = b""
for data in data_list: for data in data_list:
response += _create_data_message(data + delimiter) response += _create_data_message(data)
return response + _create_stats_message() + _create_end_message() return response + _create_stats_message() + _create_end_message()

View File

@ -19,9 +19,9 @@ class S3ControlResponse(BaseResponse):
def backend(self) -> S3ControlBackend: def backend(self) -> S3ControlBackend:
return s3control_backends[self.current_account]["global"] return s3control_backends[self.current_account]["global"]
def public_access_block( def public_access_block( # type: ignore
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
try: try:
if request.method == "GET": if request.method == "GET":
@ -70,9 +70,9 @@ class S3ControlResponse(BaseResponse):
if request.method == "DELETE": if request.method == "DELETE":
return self.delete_access_point(full_url) return self.delete_access_point(full_url)
def access_point_policy( def access_point_policy( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "PUT": if request.method == "PUT":
return self.create_access_point_policy(full_url) return self.create_access_point_policy(full_url)
@ -81,9 +81,9 @@ class S3ControlResponse(BaseResponse):
if request.method == "DELETE": if request.method == "DELETE":
return self.delete_access_point_policy(full_url) return self.delete_access_point_policy(full_url)
def access_point_policy_status( def access_point_policy_status( # type: ignore[return]
self, request: Any, full_url: str, headers: Any self, request: Any, full_url: str, headers: Any
) -> TYPE_RESPONSE: # type: ignore[return] ) -> TYPE_RESPONSE:
self.setup_class(request, full_url, headers) self.setup_class(request, full_url, headers)
if request.method == "PUT": if request.method == "PUT":
return self.create_access_point(full_url) return self.create_access_point(full_url)

View File

@ -9,7 +9,7 @@ def name_filter(secret: "FakeSecret", names: List[str]) -> bool:
def description_filter(secret: "FakeSecret", descriptions: List[str]) -> bool: def description_filter(secret: "FakeSecret", descriptions: List[str]) -> bool:
return _matcher(descriptions, [secret.description]) # type: ignore return _matcher(descriptions, [secret.description], match_prefix=False) # type: ignore
def tag_key(secret: "FakeSecret", tag_keys: List[str]) -> bool: def tag_key(secret: "FakeSecret", tag_keys: List[str]) -> bool:
@ -30,21 +30,31 @@ def filter_all(secret: "FakeSecret", values: List[str]) -> bool:
return _matcher(values, attributes) # type: ignore return _matcher(values, attributes) # type: ignore
def _matcher(patterns: List[str], strings: List[str]) -> bool: def _matcher(
patterns: List[str], strings: List[str], match_prefix: bool = True
) -> bool:
for pattern in [p for p in patterns if p.startswith("!")]: for pattern in [p for p in patterns if p.startswith("!")]:
for string in strings: for string in strings:
if _match_pattern(pattern[1:], string): if not _match_pattern(pattern[1:], string, match_prefix):
return False return True
for pattern in [p for p in patterns if not p.startswith("!")]: for pattern in [p for p in patterns if not p.startswith("!")]:
for string in strings: for string in strings:
if _match_pattern(pattern, string): if _match_pattern(pattern, string, match_prefix):
return True return True
return False return False
def _match_pattern(pattern: str, value: str) -> bool: def _match_pattern(pattern: str, value: str, match_prefix: bool = True) -> bool:
for word in pattern.split(" "): if match_prefix:
if word not in value: return value.startswith(pattern)
else:
pattern_words = pattern.split(" ")
value_words = value.split(" ")
for pattern_word in pattern_words:
# all words in value must start with pattern_word
if not any(
value_word.startswith(pattern_word) for value_word in value_words
):
return False return False
return True return True

View File

@ -143,9 +143,9 @@ class EmailResponse(BaseResponse):
message = self.backend.send_bulk_templated_email( message = self.backend.send_bulk_templated_email(
source, source,
template, template, # type: ignore
template_data, template_data, # type: ignore
destinations, # type: ignore destinations,
) )
template = self.response_template(SEND_BULK_TEMPLATED_EMAIL_RESPONSE) template = self.response_template(SEND_BULK_TEMPLATED_EMAIL_RESPONSE)
result = template.render(message=message) result = template.render(message=message)

View File

@ -46,7 +46,7 @@ class EachBlockProcessor(BlockProcessor):
_processor = get_processor(self.tokenizer)( _processor = get_processor(self.tokenizer)(
self.template, self.template,
template_data, template_data, # type: ignore
self.tokenizer, # type: ignore self.tokenizer, # type: ignore
) )
# If we've reached the end, we should stop processing # If we've reached the end, we should stop processing

View File

@ -715,7 +715,7 @@ class SNSBackend(BaseBackend):
try: try:
del self.platform_endpoints[arn] del self.platform_endpoints[arn]
except KeyError: except KeyError:
raise SNSNotFoundError(f"Endpoint with arn {arn} not found") pass # idempotent operation
def get_subscription_attributes(self, arn: str) -> Dict[str, Any]: def get_subscription_attributes(self, arn: str) -> Dict[str, Any]:
subscription = self.subscriptions.get(arn) subscription = self.subscriptions.get(arn)

View File

@ -1531,15 +1531,6 @@
"Value": "HTTPS" "Value": "HTTPS"
} }
}, },
"support": {
"Value": "support",
"endpoint": {
"Value": "support.us-east-1.amazonaws.com"
},
"protocols": {
"Value": "HTTPS"
}
},
"swf": { "swf": {
"Value": "swf", "Value": "swf",
"endpoint": { "endpoint": {
@ -9380,6 +9371,15 @@
"Value": "HTTPS" "Value": "HTTPS"
} }
}, },
"neptune": {
"Value": "neptune",
"endpoint": {
"Value": "rds.ap-northeast-3.amazonaws.com"
},
"protocols": {
"Value": "HTTPS, HTTP"
}
},
"network-firewall": { "network-firewall": {
"Value": "network-firewall", "Value": "network-firewall",
"endpoint": { "endpoint": {
@ -57883,6 +57883,24 @@
"Value": "HTTPS" "Value": "HTTPS"
} }
}, },
"lex-runtime": {
"Value": "lex-runtime",
"endpoint": {
"Value": "runtime-v2-lex.us-gov-west-1.amazonaws.com"
},
"protocols": {
"Value": "HTTPS"
}
},
"lexv2-models": {
"Value": "lexv2-models",
"endpoint": {
"Value": "models-v2-lex.us-gov-west-1.amazonaws.com"
},
"protocols": {
"Value": "HTTPS"
}
},
"license-manager": { "license-manager": {
"Value": "license-manager", "Value": "license-manager",
"endpoint": { "endpoint": {

View File

@ -36832,6 +36832,15 @@
"Value": "HTTPS" "Value": "HTTPS"
} }
}, },
"us-gov-west-1": {
"Value": "us-gov-west-1",
"endpoint": {
"Value": "runtime-v2-lex.us-gov-west-1.amazonaws.com"
},
"protocols": {
"Value": "HTTPS"
}
},
"us-west-2": { "us-west-2": {
"Value": "us-west-2", "Value": "us-west-2",
"endpoint": { "endpoint": {
@ -36939,6 +36948,15 @@
"Value": "HTTPS" "Value": "HTTPS"
} }
}, },
"us-gov-west-1": {
"Value": "us-gov-west-1",
"endpoint": {
"Value": "models-v2-lex.us-gov-west-1.amazonaws.com"
},
"protocols": {
"Value": "HTTPS"
}
},
"us-west-2": { "us-west-2": {
"Value": "us-west-2", "Value": "us-west-2",
"endpoint": { "endpoint": {
@ -42676,6 +42694,15 @@
"Value": "HTTPS, HTTP" "Value": "HTTPS, HTTP"
} }
}, },
"ap-northeast-3": {
"Value": "ap-northeast-3",
"endpoint": {
"Value": "rds.ap-northeast-3.amazonaws.com"
},
"protocols": {
"Value": "HTTPS, HTTP"
}
},
"ap-south-1": { "ap-south-1": {
"Value": "ap-south-1", "Value": "ap-south-1",
"endpoint": { "endpoint": {
@ -60961,15 +60988,6 @@
"Value": "https://aws.amazon.com/premiumsupport/" "Value": "https://aws.amazon.com/premiumsupport/"
}, },
"regions": { "regions": {
"af-south-1": {
"Value": "af-south-1",
"endpoint": {
"Value": "support.us-east-1.amazonaws.com"
},
"protocols": {
"Value": "HTTPS"
}
},
"ap-east-1": { "ap-east-1": {
"Value": "ap-east-1", "Value": "ap-east-1",
"endpoint": { "endpoint": {

View File

@ -106,9 +106,9 @@ class StepFunctionsParserBackend(StepFunctionBackend):
raise InvalidToken() raise InvalidToken()
def send_task_success( def send_task_success(
self, task_token: TaskToken, output: SensitiveData self, task_token: TaskToken, outcome: SensitiveData
) -> SendTaskSuccessOutput: ) -> SendTaskSuccessOutput:
outcome = CallbackOutcomeSuccess(callback_id=task_token, output=output) outcome = CallbackOutcomeSuccess(callback_id=task_token, output=outcome)
running_executions = self._get_executions(ExecutionStatus.RUNNING) running_executions = self._get_executions(ExecutionStatus.RUNNING)
for execution in running_executions: for execution in running_executions:
try: try:

View File

@ -1,7 +1,7 @@
import datetime import datetime
import re import re
from base64 import b64decode from base64 import b64decode
from typing import Any, Dict, List, Optional, Tuple from typing import Any, List, Optional, Tuple
import xmltodict import xmltodict

View File

@ -61,9 +61,9 @@ class Domain(BaseModel):
"configuration": {"workflowExecutionRetentionPeriodInDays": self.retention}, "configuration": {"workflowExecutionRetentionPeriodInDays": self.retention},
} }
def get_type( def get_type( # type: ignore
self, kind: str, name: str, version: str, ignore_empty: bool = False self, kind: str, name: str, version: str, ignore_empty: bool = False
) -> "GenericType": # type: ignore ) -> "GenericType":
try: try:
return self.types[kind][name][version] return self.types[kind][name][version]
except KeyError: except KeyError:

View File

@ -54,7 +54,7 @@ all =
openapi-spec-validator>=0.5.0 openapi-spec-validator>=0.5.0
pyparsing>=3.0.7 pyparsing>=3.0.7
jsondiff>=1.1.2 jsondiff>=1.1.2
py-partiql-parser==0.5.1 py-partiql-parser==0.5.2
aws-xray-sdk!=0.96,>=0.93 aws-xray-sdk!=0.96,>=0.93
setuptools setuptools
multipart multipart
@ -69,7 +69,7 @@ proxy =
openapi-spec-validator>=0.5.0 openapi-spec-validator>=0.5.0
pyparsing>=3.0.7 pyparsing>=3.0.7
jsondiff>=1.1.2 jsondiff>=1.1.2
py-partiql-parser==0.5.1 py-partiql-parser==0.5.2
aws-xray-sdk!=0.96,>=0.93 aws-xray-sdk!=0.96,>=0.93
setuptools setuptools
multipart multipart
@ -84,7 +84,7 @@ server =
openapi-spec-validator>=0.5.0 openapi-spec-validator>=0.5.0
pyparsing>=3.0.7 pyparsing>=3.0.7
jsondiff>=1.1.2 jsondiff>=1.1.2
py-partiql-parser==0.5.1 py-partiql-parser==0.5.2
aws-xray-sdk!=0.96,>=0.93 aws-xray-sdk!=0.96,>=0.93
setuptools setuptools
flask!=2.2.0,!=2.2.1 flask!=2.2.0,!=2.2.1
@ -119,7 +119,7 @@ cloudformation =
openapi-spec-validator>=0.5.0 openapi-spec-validator>=0.5.0
pyparsing>=3.0.7 pyparsing>=3.0.7
jsondiff>=1.1.2 jsondiff>=1.1.2
py-partiql-parser==0.5.1 py-partiql-parser==0.5.2
aws-xray-sdk!=0.96,>=0.93 aws-xray-sdk!=0.96,>=0.93
setuptools setuptools
cloudfront = cloudfront =
@ -141,10 +141,10 @@ dms =
ds = ds =
dynamodb = dynamodb =
docker>=3.0.0 docker>=3.0.0
py-partiql-parser==0.5.1 py-partiql-parser==0.5.2
dynamodbstreams = dynamodbstreams =
docker>=3.0.0 docker>=3.0.0
py-partiql-parser==0.5.1 py-partiql-parser==0.5.2
ebs = ebs =
ec2 = ec2 =
ec2instanceconnect = ec2instanceconnect =
@ -208,15 +208,15 @@ resourcegroupstaggingapi =
openapi-spec-validator>=0.5.0 openapi-spec-validator>=0.5.0
pyparsing>=3.0.7 pyparsing>=3.0.7
jsondiff>=1.1.2 jsondiff>=1.1.2
py-partiql-parser==0.5.1 py-partiql-parser==0.5.2
route53 = route53 =
route53resolver = route53resolver =
s3 = s3 =
PyYAML>=5.1 PyYAML>=5.1
py-partiql-parser==0.5.1 py-partiql-parser==0.5.2
s3crc32c = s3crc32c =
PyYAML>=5.1 PyYAML>=5.1
py-partiql-parser==0.5.1 py-partiql-parser==0.5.2
crc32c crc32c
s3control = s3control =
sagemaker = sagemaker =

View File

@ -41,6 +41,13 @@ def test_run_function_no_log():
# Execute # Execute
result = client.invoke(FunctionName=FUNCTION_NAME, Payload=json.dumps(payload)) result = client.invoke(FunctionName=FUNCTION_NAME, Payload=json.dumps(payload))
# Verify
assert result["StatusCode"] == 200
assert json.loads(result["Payload"].read().decode("utf-8")) == payload
# Execute
result = client.invoke(FunctionName=FUNCTION_NAME)
# Verify # Verify
assert result["StatusCode"] == 200 assert result["StatusCode"] == 200
assert result["Payload"].read().decode("utf-8") == "Simple Lambda happy path OK" assert result["Payload"].read().decode("utf-8") == "Simple Lambda happy path OK"

View File

@ -85,9 +85,9 @@ def test_decorater_wrapped_gets_set() -> None:
Moto decorator's __wrapped__ should get set to the tests function Moto decorator's __wrapped__ should get set to the tests function
""" """
assert ( assert (
test_decorater_wrapped_gets_set.__wrapped__.__name__ test_decorater_wrapped_gets_set.__wrapped__.__name__ # type: ignore
== "test_decorater_wrapped_gets_set" == "test_decorater_wrapped_gets_set"
) # type: ignore )
@mock_aws @mock_aws

View File

@ -143,8 +143,8 @@ def test_create_export_task_happy_path(logs, s3, log_group_name, bucket_name):
@pytest.mark.aws_verified @pytest.mark.aws_verified
def test_create_export_task_raises_ClientError_when_bucket_not_found( def test_create_export_task_raises_ClientError_when_bucket_not_found(
logs, logs,
log_group_name, # pylint: disable=redefined-outer-name log_group_name,
): ): # pylint: disable=redefined-outer-name
destination = "368a7022dea3dd621" destination = "368a7022dea3dd621"
fromTime = 1611316574 fromTime = 1611316574
to = 1642852574 to = 1642852574
@ -166,8 +166,8 @@ def test_create_export_task_raises_ClientError_when_bucket_not_found(
@pytest.mark.aws_verified @pytest.mark.aws_verified
def test_create_export_raises_ResourceNotFoundException_log_group_not_found( def test_create_export_raises_ResourceNotFoundException_log_group_not_found(
logs, logs,
bucket_name, # pylint: disable=redefined-outer-name bucket_name,
): ): # pylint: disable=redefined-outer-name
with pytest.raises(logs.exceptions.ResourceNotFoundException) as exc: with pytest.raises(logs.exceptions.ResourceNotFoundException) as exc:
logs.create_export_task( logs.create_export_task(
logGroupName=f"/aws/nonexisting/{str(uuid4())[0:6]}", logGroupName=f"/aws/nonexisting/{str(uuid4())[0:6]}",

View File

@ -886,8 +886,6 @@ def test_get_resources_sns():
@mock_aws @mock_aws
def test_get_resources_ssm(): def test_get_resources_ssm():
import json
import yaml import yaml
from tests.test_ssm.test_ssm_docs import _get_yaml_template from tests.test_ssm.test_ssm_docs import _get_yaml_template

View File

@ -1,7 +1,10 @@
import bz2
import gzip
import json import json
import boto3 import boto3
import pytest import pytest
from botocore.exceptions import ClientError
from . import s3_aws_verified from . import s3_aws_verified
@ -45,6 +48,24 @@ def create_test_files(bucket_name):
Key="nested.json", Key="nested.json",
Body=json.dumps(NESTED_JSON), Body=json.dumps(NESTED_JSON),
) )
client.put_object(
Bucket=bucket_name,
Key="json.gzip",
Body=gzip.compress(json.dumps(NESTED_JSON).encode("utf-8")),
)
client.put_object(
Bucket=bucket_name,
Key="json.bz2",
Body=bz2.compress(json.dumps(NESTED_JSON).encode("utf-8")),
)
client.put_object(
Bucket=bucket_name,
Key="csv.gzip",
Body=gzip.compress(SIMPLE_CSV.encode("utf-8")),
)
client.put_object(
Bucket=bucket_name, Key="csv.bz2", Body=bz2.compress(SIMPLE_CSV.encode("utf-8"))
)
@pytest.mark.aws_verified @pytest.mark.aws_verified
@ -226,3 +247,113 @@ def test_nested_json__select_all(bucket_name=None):
assert records[-1] == "," assert records[-1] == ","
assert json.loads(records[:-1]) == NESTED_JSON assert json.loads(records[:-1]) == NESTED_JSON
@pytest.mark.aws_verified
@s3_aws_verified
def test_gzipped_json(bucket_name=None):
client = boto3.client("s3", "us-east-1")
create_test_files(bucket_name)
content = client.select_object_content(
Bucket=bucket_name,
Key="json.gzip",
Expression="SELECT count(*) FROM S3Object",
ExpressionType="SQL",
InputSerialization={"JSON": {"Type": "DOCUMENT"}, "CompressionType": "GZIP"},
OutputSerialization={"JSON": {"RecordDelimiter": ","}},
)
result = list(content["Payload"])
assert {"Records": {"Payload": b'{"_1":1},'}} in result
@pytest.mark.aws_verified
@s3_aws_verified
def test_bzipped_json(bucket_name=None):
client = boto3.client("s3", "us-east-1")
create_test_files(bucket_name)
content = client.select_object_content(
Bucket=bucket_name,
Key="json.bz2",
Expression="SELECT count(*) FROM S3Object",
ExpressionType="SQL",
InputSerialization={"JSON": {"Type": "DOCUMENT"}, "CompressionType": "BZIP2"},
OutputSerialization={"JSON": {"RecordDelimiter": ","}},
)
result = list(content["Payload"])
assert {"Records": {"Payload": b'{"_1":1},'}} in result
@pytest.mark.aws_verified
@s3_aws_verified
def test_bzipped_csv_to_csv(bucket_name=None):
client = boto3.client("s3", "us-east-1")
create_test_files(bucket_name)
# Count Records
content = client.select_object_content(
Bucket=bucket_name,
Key="csv.bz2",
Expression="SELECT count(*) FROM S3Object",
ExpressionType="SQL",
InputSerialization={"CSV": {}, "CompressionType": "BZIP2"},
OutputSerialization={"CSV": {"RecordDelimiter": "_", "FieldDelimiter": ":"}},
)
result = list(content["Payload"])
assert {"Records": {"Payload": b"4_"}} in result
# Count Records
content = client.select_object_content(
Bucket=bucket_name,
Key="csv.bz2",
Expression="SELECT count(*) FROM S3Object",
ExpressionType="SQL",
InputSerialization={"CSV": {}, "CompressionType": "BZIP2"},
OutputSerialization={"CSV": {}},
)
result = list(content["Payload"])
assert {"Records": {"Payload": b"4\n"}} in result
# Mirror records
content = client.select_object_content(
Bucket=bucket_name,
Key="csv.bz2",
Expression="SELECT * FROM S3Object",
ExpressionType="SQL",
InputSerialization={"CSV": {}, "CompressionType": "BZIP2"},
OutputSerialization={"CSV": {}},
)
result = list(content["Payload"])
assert {"Records": {"Payload": b"a,b,c\ne,r,f\ny,u,i\nq,w,y\n"}} in result
# Mirror records, specifying output format
content = client.select_object_content(
Bucket=bucket_name,
Key="csv.bz2",
Expression="SELECT * FROM S3Object",
ExpressionType="SQL",
InputSerialization={"CSV": {}, "CompressionType": "BZIP2"},
OutputSerialization={"CSV": {"RecordDelimiter": "\n", "FieldDelimiter": ":"}},
)
result = list(content["Payload"])
assert {"Records": {"Payload": b"a:b:c\ne:r:f\ny:u:i\nq:w:y\n"}} in result
@pytest.mark.aws_verified
@s3_aws_verified
def test_select_unknown_key(bucket_name=None):
client = boto3.client("s3", "us-east-1")
with pytest.raises(ClientError) as exc:
client.select_object_content(
Bucket=bucket_name,
Key="unknown",
Expression="SELECT count(*) FROM S3Object",
ExpressionType="SQL",
InputSerialization={"CSV": {}, "CompressionType": "BZIP2"},
OutputSerialization={
"CSV": {"RecordDelimiter": "\n", "FieldDelimiter": ":"}
},
)
err = exc.value.response["Error"]
assert err["Code"] == "NoSuchKey"
assert err["Message"] == "The specified key does not exist."
assert err["Key"] == "unknown"

View File

@ -268,7 +268,13 @@ def test_with_filter_with_negation():
) )
secret_names = list(map(lambda s: s["Name"], secrets["SecretList"])) secret_names = list(map(lambda s: s["Name"], secrets["SecretList"]))
assert secret_names == ["baz"] for secret_name in ["foo", "bar", "baz"]:
assert secret_name in secret_names
secrets = conn.list_secrets(Filters=[{"Key": "description", "Values": ["!o"]}])
secret_names = list(map(lambda s: s["Name"], secrets["SecretList"]))
for secret_name in ["qux", "none"]:
assert secret_name in secret_names
@mock_aws @mock_aws

View File

@ -266,6 +266,13 @@ def test_get_list_endpoints_by_platform_application(api_key=None):
assert len(endpoint_list) == 1 assert len(endpoint_list) == 1
assert endpoint_list[0]["Attributes"]["CustomUserData"] == "some data" assert endpoint_list[0]["Attributes"]["CustomUserData"] == "some data"
assert endpoint_list[0]["EndpointArn"] == endpoint_arn assert endpoint_list[0]["EndpointArn"] == endpoint_arn
resp = conn.delete_endpoint(EndpointArn=endpoint_arn)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
# Idempotent operation
resp = conn.delete_endpoint(EndpointArn=endpoint_arn)
assert resp["ResponseMetadata"]["HTTPStatusCode"] == 200
finally: finally:
if application_arn is not None: if application_arn is not None:
conn.delete_platform_application(PlatformApplicationArn=application_arn) conn.delete_platform_application(PlatformApplicationArn=application_arn)