Compare commits
10 Commits
c8db699f3c
...
8eaa8788b9
Author | SHA1 | Date | |
---|---|---|---|
|
8eaa8788b9 | ||
|
d767a2799b | ||
|
90adead245 | ||
|
1fc22000d9 | ||
|
e4ec1a40ed | ||
|
31b971f94e | ||
|
ade1001a69 | ||
|
f14749b6b5 | ||
|
ee4c5ed2d3 | ||
|
e3555bbe61 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -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
|
||||||
|
|
||||||
|
2
.github/workflows/tests_sdk_ruby.yml
vendored
2
.github/workflows/tests_sdk_ruby.yml
vendored
@ -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
|
||||||
|
70
CHANGELOG.md
70
CHANGELOG.md
@ -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_
|
||||||
|
@ -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
|
||||||
|
1
Makefile
1
Makefile
@ -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..."
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
96
docs/docs/services/workspaces.rst
Normal file
96
docs/docs/services/workspaces.rst
Normal 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
|
||||||
|
|
@ -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"
|
||||||
|
@ -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)
|
||||||
|
@ -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":
|
||||||
|
@ -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":
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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":
|
||||||
|
@ -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
|
||||||
|
@ -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())
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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"],
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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]
|
||||||
)
|
)
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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", []):
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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"]
|
||||||
|
@ -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"]
|
||||||
|
@ -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
|
||||||
|
@ -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]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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] = []
|
||||||
|
|
||||||
|
@ -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":
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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
|
||||||
"""
|
"""
|
||||||
|
@ -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(
|
||||||
|
@ -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():
|
||||||
|
@ -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 "
|
||||||
|
@ -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})
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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":
|
||||||
|
@ -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
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -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(
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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": {
|
||||||
|
@ -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": {
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
18
setup.cfg
18
setup.cfg
@ -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 =
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
@ -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]}",
|
||||||
|
@ -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
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user