localstack-core 4.7.1.dev139__py3-none-any.whl → 4.10.1.dev42__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of localstack-core might be problematic. Click here for more details.
- localstack/aws/api/acm/__init__.py +122 -122
- localstack/aws/api/apigateway/__init__.py +560 -559
- localstack/aws/api/cloudcontrol/__init__.py +63 -63
- localstack/aws/api/cloudformation/__init__.py +1041 -969
- localstack/aws/api/cloudwatch/__init__.py +408 -368
- localstack/aws/api/config/__init__.py +788 -786
- localstack/aws/api/core.py +4 -0
- localstack/aws/api/dynamodb/__init__.py +753 -759
- localstack/aws/api/dynamodbstreams/__init__.py +74 -74
- localstack/aws/api/ec2/__init__.py +9713 -8573
- localstack/aws/api/es/__init__.py +453 -453
- localstack/aws/api/events/__init__.py +552 -552
- localstack/aws/api/firehose/__init__.py +541 -543
- localstack/aws/api/iam/__init__.py +646 -572
- localstack/aws/api/kinesis/__init__.py +251 -144
- localstack/aws/api/kms/__init__.py +343 -333
- localstack/aws/api/lambda_/__init__.py +585 -571
- localstack/aws/api/logs/__init__.py +682 -666
- localstack/aws/api/opensearch/__init__.py +814 -785
- localstack/aws/api/pipes/__init__.py +336 -336
- localstack/aws/api/redshift/__init__.py +1192 -1164
- localstack/aws/api/resource_groups/__init__.py +175 -175
- localstack/aws/api/resourcegroupstaggingapi/__init__.py +67 -67
- localstack/aws/api/route53/__init__.py +256 -254
- localstack/aws/api/route53resolver/__init__.py +396 -396
- localstack/aws/api/s3/__init__.py +1358 -1345
- localstack/aws/api/s3control/__init__.py +616 -584
- localstack/aws/api/scheduler/__init__.py +118 -118
- localstack/aws/api/secretsmanager/__init__.py +193 -193
- localstack/aws/api/ses/__init__.py +227 -227
- localstack/aws/api/sns/__init__.py +115 -115
- localstack/aws/api/sqs/__init__.py +100 -100
- localstack/aws/api/ssm/__init__.py +1978 -1970
- localstack/aws/api/stepfunctions/__init__.py +323 -323
- localstack/aws/api/sts/__init__.py +90 -66
- localstack/aws/api/support/__init__.py +112 -112
- localstack/aws/api/swf/__init__.py +378 -386
- localstack/aws/api/transcribe/__init__.py +425 -425
- localstack/aws/client.py +7 -2
- localstack/aws/forwarder.py +52 -5
- localstack/aws/handlers/analytics.py +1 -1
- localstack/aws/handlers/logging.py +12 -2
- localstack/aws/handlers/metric_handler.py +41 -1
- localstack/aws/handlers/service.py +43 -10
- localstack/aws/protocol/parser.py +440 -21
- localstack/aws/protocol/serializer.py +684 -64
- localstack/aws/protocol/service_router.py +120 -20
- localstack/aws/scaffold.py +15 -17
- localstack/aws/skeleton.py +4 -2
- localstack/aws/spec-patches.json +58 -0
- localstack/aws/spec.py +33 -13
- localstack/cli/exceptions.py +1 -1
- localstack/cli/localstack.py +10 -5
- localstack/cli/lpm.py +3 -4
- localstack/cli/profiles.py +1 -2
- localstack/config.py +18 -12
- localstack/constants.py +4 -29
- localstack/dev/kubernetes/__main__.py +39 -4
- localstack/dev/run/paths.py +1 -1
- localstack/dns/plugins.py +5 -1
- localstack/dns/server.py +12 -3
- localstack/packages/api.py +9 -8
- localstack/packages/core.py +2 -2
- localstack/packages/plugins.py +0 -8
- localstack/runtime/init.py +1 -1
- localstack/services/apigateway/helpers.py +5 -9
- localstack/services/apigateway/legacy/provider.py +85 -12
- localstack/services/apigateway/next_gen/execute_api/integrations/aws.py +3 -0
- localstack/services/apigateway/next_gen/execute_api/integrations/http.py +3 -3
- localstack/services/apigateway/next_gen/execute_api/test_invoke.py +50 -6
- localstack/services/apigateway/next_gen/provider.py +5 -0
- localstack/services/apigateway/patches.py +0 -9
- localstack/services/cloudformation/engine/entities.py +12 -1
- localstack/services/cloudformation/engine/v2/change_set_model.py +0 -3
- localstack/services/cloudformation/engine/v2/change_set_model_describer.py +14 -0
- localstack/services/cloudformation/engine/v2/change_set_model_executor.py +13 -15
- localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +118 -24
- localstack/services/cloudformation/engine/v2/change_set_model_transform.py +4 -1
- localstack/services/cloudformation/engine/v2/change_set_model_validator.py +5 -14
- localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +1 -0
- localstack/services/cloudformation/engine/v2/resolving.py +6 -4
- localstack/services/cloudformation/engine/yaml_parser.py +9 -2
- localstack/services/cloudformation/provider.py +2 -2
- localstack/services/cloudformation/resource_provider.py +5 -1
- localstack/services/cloudformation/resources.py +24149 -0
- localstack/services/cloudformation/v2/entities.py +6 -3
- localstack/services/cloudformation/v2/provider.py +178 -33
- localstack/services/cloudformation/v2/types.py +8 -4
- localstack/services/cloudwatch/provider_v2.py +25 -28
- localstack/services/dynamodb/packages.py +2 -1
- localstack/services/dynamodb/provider.py +42 -0
- localstack/services/dynamodb/v2/provider.py +42 -0
- localstack/services/ecr/resource_providers/aws_ecr_repository.py +5 -2
- localstack/services/es/provider.py +2 -2
- localstack/services/events/event_rule_engine.py +31 -13
- localstack/services/events/models.py +4 -5
- localstack/services/events/target.py +17 -9
- localstack/services/iam/provider.py +11 -116
- localstack/services/iam/resources/policy_simulator.py +133 -0
- localstack/services/kinesis/models.py +15 -2
- localstack/services/kinesis/packages.py +1 -1
- localstack/services/kinesis/provider.py +77 -0
- localstack/services/kms/models.py +34 -4
- localstack/services/kms/provider.py +107 -21
- localstack/services/lambda_/api_utils.py +3 -1
- localstack/services/lambda_/invocation/internal_sqs_queue.py +5 -9
- localstack/services/lambda_/packages.py +1 -1
- localstack/services/lambda_/provider.py +1 -1
- localstack/services/lambda_/runtimes.py +8 -3
- localstack/services/logs/provider.py +36 -19
- localstack/services/moto.py +2 -1
- localstack/services/opensearch/cluster.py +15 -7
- localstack/services/opensearch/packages.py +26 -7
- localstack/services/opensearch/provider.py +6 -1
- localstack/services/opensearch/versions.py +56 -7
- localstack/services/s3/constants.py +5 -2
- localstack/services/s3/cors.py +4 -4
- localstack/services/s3/notifications.py +1 -1
- localstack/services/s3/presigned_url.py +27 -43
- localstack/services/s3/provider.py +68 -12
- localstack/services/s3/utils.py +42 -11
- localstack/services/ses/provider.py +16 -7
- localstack/services/sns/constants.py +7 -1
- localstack/services/sns/v2/models.py +190 -0
- localstack/services/sns/v2/provider.py +992 -2
- localstack/services/sns/v2/utils.py +138 -0
- localstack/services/sqs/developer_api.py +205 -0
- localstack/services/sqs/models.py +79 -13
- localstack/services/sqs/provider.py +8 -309
- localstack/services/sqs/query_api.py +1 -1
- localstack/services/sqs/utils.py +121 -2
- localstack/services/stepfunctions/asl/jsonata/jsonata.py +1 -1
- localstack/testing/aws/cloudformation_utils.py +1 -1
- localstack/testing/pytest/cloudformation/fixtures.py +3 -3
- localstack/testing/pytest/container.py +4 -5
- localstack/testing/pytest/fixtures.py +20 -19
- localstack/testing/pytest/in_memory_localstack.py +0 -4
- localstack/testing/pytest/marking.py +13 -4
- localstack/testing/pytest/stepfunctions/utils.py +4 -3
- localstack/testing/pytest/util.py +1 -1
- localstack/testing/pytest/validation_tracking.py +1 -2
- localstack/testing/snapshots/transformer_utility.py +7 -0
- localstack/testing/testselection/matching.py +0 -1
- localstack/utils/analytics/events.py +2 -2
- localstack/utils/analytics/metadata.py +1 -2
- localstack/utils/analytics/metrics/counter.py +6 -8
- localstack/utils/analytics/publisher.py +1 -2
- localstack/utils/analytics/service_request_aggregator.py +2 -2
- localstack/utils/archives.py +11 -11
- localstack/utils/aws/arns.py +17 -9
- localstack/utils/aws/aws_responses.py +7 -7
- localstack/utils/aws/aws_stack.py +2 -3
- localstack/utils/aws/client_types.py +0 -8
- localstack/utils/aws/message_forwarding.py +1 -2
- localstack/utils/aws/request_context.py +4 -5
- localstack/utils/batch_policy.py +3 -3
- localstack/utils/bootstrap.py +7 -7
- localstack/utils/catalog/catalog.py +139 -0
- localstack/utils/catalog/catalog_loader.py +119 -0
- localstack/utils/catalog/common.py +58 -0
- localstack/utils/catalog/plugins.py +28 -0
- localstack/utils/cloudwatch/cloudwatch_util.py +5 -5
- localstack/utils/collections.py +7 -8
- localstack/utils/config_listener.py +1 -1
- localstack/utils/container_networking.py +2 -3
- localstack/utils/container_utils/container_client.py +115 -131
- localstack/utils/container_utils/docker_cmd_client.py +42 -42
- localstack/utils/container_utils/docker_sdk_client.py +63 -62
- localstack/utils/crypto.py +109 -0
- localstack/utils/diagnose.py +2 -3
- localstack/utils/docker_utils.py +3 -4
- localstack/utils/files.py +31 -7
- localstack/utils/functions.py +3 -2
- localstack/utils/http.py +4 -5
- localstack/utils/json.py +19 -5
- localstack/utils/kinesis/kinesis_connector.py +2 -1
- localstack/utils/net.py +6 -6
- localstack/utils/no_exit_argument_parser.py +2 -2
- localstack/utils/numbers.py +9 -2
- localstack/utils/objects.py +6 -5
- localstack/utils/patch.py +2 -1
- localstack/utils/run.py +10 -9
- localstack/utils/scheduler.py +11 -11
- localstack/utils/server/tcp_proxy.py +2 -2
- localstack/utils/serving.py +2 -3
- localstack/utils/strings.py +10 -11
- localstack/utils/sync.py +126 -1
- localstack/utils/tagging.py +1 -4
- localstack/utils/testutil.py +5 -4
- localstack/utils/threads.py +2 -2
- localstack/utils/time.py +11 -3
- localstack/utils/urls.py +1 -3
- localstack/version.py +2 -2
- {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev42.dist-info}/METADATA +19 -13
- {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev42.dist-info}/RECORD +203 -199
- {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev42.dist-info}/entry_points.txt +4 -2
- localstack_core-4.10.1.dev42.dist-info/plux.json +1 -0
- localstack/packages/terraform.py +0 -46
- localstack/services/cloudformation/deploy.html +0 -144
- localstack/services/cloudformation/deploy_ui.py +0 -47
- localstack/services/cloudformation/plugins.py +0 -12
- localstack_core-4.7.1.dev139.dist-info/plux.json +0 -1
- {localstack_core-4.7.1.dev139.data → localstack_core-4.10.1.dev42.data}/scripts/localstack +0 -0
- {localstack_core-4.7.1.dev139.data → localstack_core-4.10.1.dev42.data}/scripts/localstack-supervisor +0 -0
- {localstack_core-4.7.1.dev139.data → localstack_core-4.10.1.dev42.data}/scripts/localstack.bat +0 -0
- {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev42.dist-info}/WHEEL +0 -0
- {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev42.dist-info}/licenses/LICENSE.txt +0 -0
- {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev42.dist-info}/top_level.txt +0 -0
|
@@ -6,7 +6,8 @@ import os
|
|
|
6
6
|
import re
|
|
7
7
|
import textwrap
|
|
8
8
|
import time
|
|
9
|
-
from
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
from typing import TYPE_CHECKING, Any, Unpack
|
|
10
11
|
|
|
11
12
|
import botocore.auth
|
|
12
13
|
import botocore.config
|
|
@@ -357,8 +358,8 @@ def sqs_create_queue(aws_client):
|
|
|
357
358
|
def sqs_receive_messages_delete(aws_client):
|
|
358
359
|
def factory(
|
|
359
360
|
queue_url: str,
|
|
360
|
-
expected_messages:
|
|
361
|
-
wait_time:
|
|
361
|
+
expected_messages: int | None = None,
|
|
362
|
+
wait_time: int | None = 5,
|
|
362
363
|
):
|
|
363
364
|
response = aws_client.sqs.receive_message(
|
|
364
365
|
QueueUrl=queue_url,
|
|
@@ -706,7 +707,7 @@ def route53_hosted_zone(aws_client):
|
|
|
706
707
|
def transcribe_create_job(s3_bucket, aws_client):
|
|
707
708
|
job_names = []
|
|
708
709
|
|
|
709
|
-
def _create_job(audio_file: str, params:
|
|
710
|
+
def _create_job(audio_file: str, params: dict[str, Any] | None = None) -> str:
|
|
710
711
|
s3_key = "test-clip.wav"
|
|
711
712
|
|
|
712
713
|
if not params:
|
|
@@ -1085,18 +1086,18 @@ def deploy_cfn_template(
|
|
|
1085
1086
|
|
|
1086
1087
|
def _deploy(
|
|
1087
1088
|
*,
|
|
1088
|
-
is_update:
|
|
1089
|
-
stack_name:
|
|
1090
|
-
change_set_name:
|
|
1091
|
-
template:
|
|
1092
|
-
template_path:
|
|
1093
|
-
template_mapping:
|
|
1094
|
-
parameters:
|
|
1095
|
-
role_arn:
|
|
1096
|
-
max_wait:
|
|
1097
|
-
delay_between_polls:
|
|
1098
|
-
custom_aws_client:
|
|
1099
|
-
raw_parameters:
|
|
1089
|
+
is_update: bool | None = False,
|
|
1090
|
+
stack_name: str | None = None,
|
|
1091
|
+
change_set_name: str | None = None,
|
|
1092
|
+
template: str | None = None,
|
|
1093
|
+
template_path: str | os.PathLike | None = None,
|
|
1094
|
+
template_mapping: dict[str, Any] | None = None,
|
|
1095
|
+
parameters: dict[str, str] | None = None,
|
|
1096
|
+
role_arn: str | None = None,
|
|
1097
|
+
max_wait: int | None = None,
|
|
1098
|
+
delay_between_polls: int | None = 2,
|
|
1099
|
+
custom_aws_client: ServiceLevelClientFactory | None = None,
|
|
1100
|
+
raw_parameters: list[Parameter] | None = None,
|
|
1100
1101
|
) -> DeployResult:
|
|
1101
1102
|
if is_update:
|
|
1102
1103
|
assert stack_name
|
|
@@ -1262,7 +1263,7 @@ def _has_stack_status(cfn_client, statuses: list[str]):
|
|
|
1262
1263
|
|
|
1263
1264
|
@pytest.fixture
|
|
1264
1265
|
def is_change_set_finished(aws_client):
|
|
1265
|
-
def _is_change_set_finished(change_set_id: str, stack_name:
|
|
1266
|
+
def _is_change_set_finished(change_set_id: str, stack_name: str | None = None):
|
|
1266
1267
|
def _inner():
|
|
1267
1268
|
kwargs = {"ChangeSetName": change_set_id}
|
|
1268
1269
|
if stack_name:
|
|
@@ -1993,7 +1994,7 @@ def setup_sender_email_address(ses_verify_identity):
|
|
|
1993
1994
|
email address and verify them.
|
|
1994
1995
|
"""
|
|
1995
1996
|
|
|
1996
|
-
def inner(sender_email_address:
|
|
1997
|
+
def inner(sender_email_address: str | None = None) -> str:
|
|
1997
1998
|
if is_aws_cloud():
|
|
1998
1999
|
if sender_email_address is None:
|
|
1999
2000
|
raise ValueError(
|
|
@@ -2252,7 +2253,7 @@ def assert_host_customisation(monkeypatch):
|
|
|
2252
2253
|
def asserter(
|
|
2253
2254
|
url: str,
|
|
2254
2255
|
*,
|
|
2255
|
-
custom_host:
|
|
2256
|
+
custom_host: str | None = None,
|
|
2256
2257
|
):
|
|
2257
2258
|
if custom_host is not None:
|
|
2258
2259
|
assert custom_host in url, f"Could not find `{custom_host}` in `{url}`"
|
|
@@ -63,8 +63,6 @@ def pytest_runtestloop(session: Session):
|
|
|
63
63
|
return
|
|
64
64
|
LOG.info("TEST_FORCE_LOCALSTACK_START is set, a Localstack instance will be created.")
|
|
65
65
|
|
|
66
|
-
from localstack.utils.common import safe_requests
|
|
67
|
-
|
|
68
66
|
if is_aws_cloud():
|
|
69
67
|
localstack_config.DEFAULT_DELAY = 5
|
|
70
68
|
localstack_config.DEFAULT_MAX_ATTEMPTS = 60
|
|
@@ -73,8 +71,6 @@ def pytest_runtestloop(session: Session):
|
|
|
73
71
|
os.environ[ENV_INTERNAL_TEST_RUN] = "1"
|
|
74
72
|
localstack_config.INCLUDE_STACK_TRACES_IN_HTTP_RESPONSE = True
|
|
75
73
|
|
|
76
|
-
safe_requests.verify_ssl = False
|
|
77
|
-
|
|
78
74
|
from localstack.runtime import current
|
|
79
75
|
|
|
80
76
|
_started.set()
|
|
@@ -3,7 +3,8 @@ Custom pytest mark typings
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
|
-
from
|
|
6
|
+
from collections.abc import Callable
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
7
8
|
|
|
8
9
|
import pytest
|
|
9
10
|
from _pytest.config import PytestPluginManager
|
|
@@ -36,13 +37,13 @@ class SkipSnapshotVerifyMarker:
|
|
|
36
37
|
def __call__(
|
|
37
38
|
self,
|
|
38
39
|
*,
|
|
39
|
-
paths: "
|
|
40
|
-
condition: "
|
|
40
|
+
paths: "list[str] | None" = None,
|
|
41
|
+
condition: "Callable[[...], bool] | None" = None,
|
|
41
42
|
): ...
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
class MultiRuntimeMarker:
|
|
45
|
-
def __call__(self, *, scenario: str, runtimes:
|
|
46
|
+
def __call__(self, *, scenario: str, runtimes: list[str] | None = None): ...
|
|
46
47
|
|
|
47
48
|
|
|
48
49
|
class SnapshotMarkers:
|
|
@@ -75,6 +76,10 @@ class Markers:
|
|
|
75
76
|
"""The test requires docker or a compatible container engine - will not work on kubernetes"""
|
|
76
77
|
lambda_runtime_update = pytest.mark.lambda_runtime_update
|
|
77
78
|
"""Tests to execute when updating snapshots for a new Lambda runtime"""
|
|
79
|
+
k8s_always_run = pytest.mark.k8s_always_run
|
|
80
|
+
"""This tests will always run against k8s environment"""
|
|
81
|
+
skip_k8s = pytest.mark.skip_k8s
|
|
82
|
+
"""This test will be skipped in k8s environment"""
|
|
78
83
|
|
|
79
84
|
|
|
80
85
|
# pytest plugin
|
|
@@ -226,3 +231,7 @@ def pytest_configure(config):
|
|
|
226
231
|
"markers",
|
|
227
232
|
"requires_in_process: mark the test as requiring the test to run inside the same process as LocalStack - will not work if tests are run against a running LS container.",
|
|
228
233
|
)
|
|
234
|
+
config.addinivalue_line(
|
|
235
|
+
"markers",
|
|
236
|
+
"k8s_always_run: mark the test to always run in k8s environment. This allows us to run tests that would otherwise be skipped, such as localstack_only tests.",
|
|
237
|
+
)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
-
from
|
|
3
|
+
from collections.abc import Callable
|
|
4
|
+
from typing import Final
|
|
4
5
|
|
|
5
6
|
from botocore.exceptions import ClientError
|
|
6
7
|
from jsonpath_ng.ext import parse
|
|
@@ -402,8 +403,8 @@ def create_state_machine_with_iam_role(
|
|
|
402
403
|
create_state_machine,
|
|
403
404
|
snapshot,
|
|
404
405
|
definition: Definition,
|
|
405
|
-
logging_configuration:
|
|
406
|
-
state_machine_name:
|
|
406
|
+
logging_configuration: LoggingConfiguration | None = None,
|
|
407
|
+
state_machine_name: str | None = None,
|
|
407
408
|
state_machine_type: StateMachineType = StateMachineType.STANDARD,
|
|
408
409
|
):
|
|
409
410
|
snf_role_arn = create_state_machine_iam_role(target_aws_client=target_aws_client)
|
|
@@ -9,7 +9,6 @@ import datetime
|
|
|
9
9
|
import json
|
|
10
10
|
import os
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Optional
|
|
13
12
|
|
|
14
13
|
import pytest
|
|
15
14
|
from pluggy import Result
|
|
@@ -28,7 +27,7 @@ Stores information from call execution phase about whether the test failed.
|
|
|
28
27
|
"""
|
|
29
28
|
|
|
30
29
|
|
|
31
|
-
def find_validation_data_for_item(item: pytest.Item) ->
|
|
30
|
+
def find_validation_data_for_item(item: pytest.Item) -> dict | None:
|
|
32
31
|
base_path = os.path.join(item.fspath.dirname, item.fspath.purebasename)
|
|
33
32
|
snapshot_path = f"{base_path}.validation.json"
|
|
34
33
|
|
|
@@ -45,6 +45,10 @@ PATTERN_KEY_ARN = re.compile(
|
|
|
45
45
|
r"arn:(aws[a-zA-Z-]*)?:([a-zA-Z0-9-_.]+)?:([^:]+)?:(\d{12})?:key/[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"
|
|
46
46
|
)
|
|
47
47
|
|
|
48
|
+
PATTERN_MRK_KEY_ARN = re.compile(
|
|
49
|
+
r"arn:(aws[a-zA-Z-]*)?:([a-zA-Z0-9-_.]+)?:([^:]+)?:(\d{12})?:key/mrk-[a-fA-F0-9]{32}"
|
|
50
|
+
)
|
|
51
|
+
|
|
48
52
|
|
|
49
53
|
# TODO: split into generic/aws and put into lib
|
|
50
54
|
class TransformerUtility:
|
|
@@ -562,6 +566,8 @@ class TransformerUtility:
|
|
|
562
566
|
"""
|
|
563
567
|
return [
|
|
564
568
|
TransformerUtility.key_value("KeyId"),
|
|
569
|
+
TransformerUtility.key_value("KeyMaterialId"),
|
|
570
|
+
TransformerUtility.key_value("CurrentKeyMaterialId"),
|
|
565
571
|
TransformerUtility.jsonpath(
|
|
566
572
|
jsonpath="$..Signature",
|
|
567
573
|
value_replacement="<signature>",
|
|
@@ -573,6 +579,7 @@ class TransformerUtility:
|
|
|
573
579
|
TransformerUtility.key_value("CiphertextBlob", reference_replacement=False),
|
|
574
580
|
TransformerUtility.key_value("Plaintext", reference_replacement=False),
|
|
575
581
|
RegexTransformer(PATTERN_KEY_ARN, replacement="<key-arn>"),
|
|
582
|
+
RegexTransformer(PATTERN_MRK_KEY_ARN, replacement="<mrk-key-arn>"),
|
|
576
583
|
]
|
|
577
584
|
|
|
578
585
|
@staticmethod
|
|
@@ -181,7 +181,6 @@ MATCHING_RULES: list[MatchingRule] = [
|
|
|
181
181
|
).passthrough(), # changes in a test file should always at least test that file
|
|
182
182
|
# CI
|
|
183
183
|
Matchers.glob(".github/**").full_suite(),
|
|
184
|
-
Matchers.glob(".circleci/**").full_suite(),
|
|
185
184
|
# dependencies / project setup
|
|
186
185
|
Matchers.glob("requirements*.txt").full_suite(),
|
|
187
186
|
Matchers.glob("setup.cfg").full_suite(),
|
|
@@ -2,7 +2,6 @@ import dataclasses
|
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
4
|
import platform
|
|
5
|
-
from typing import Optional
|
|
6
5
|
|
|
7
6
|
from localstack import config
|
|
8
7
|
from localstack.constants import VERSION
|
|
@@ -201,7 +200,7 @@ def _generate_machine_id() -> str:
|
|
|
201
200
|
return f"gen_{long_uid()[:12]}"
|
|
202
201
|
|
|
203
202
|
|
|
204
|
-
def get_api_key_or_auth_token() ->
|
|
203
|
+
def get_api_key_or_auth_token() -> str | None:
|
|
205
204
|
# TODO: this is duplicated code from ext, but should probably migrate that to localstack
|
|
206
205
|
auth_token = os.environ.get("LOCALSTACK_AUTH_TOKEN", "").strip("'\" ")
|
|
207
206
|
if auth_token:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import threading
|
|
2
2
|
from collections import defaultdict
|
|
3
3
|
from dataclasses import dataclass
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
5
5
|
|
|
6
6
|
from localstack import config
|
|
7
7
|
|
|
@@ -38,7 +38,7 @@ class LabeledCounterPayload:
|
|
|
38
38
|
value: int
|
|
39
39
|
type: str
|
|
40
40
|
schema_version: int
|
|
41
|
-
labels: dict[str,
|
|
41
|
+
labels: dict[str, str | float]
|
|
42
42
|
|
|
43
43
|
def as_dict(self) -> dict[str, Any]:
|
|
44
44
|
payload_dict = {
|
|
@@ -140,10 +140,8 @@ class LabeledCounter(Metric):
|
|
|
140
140
|
|
|
141
141
|
_type: str
|
|
142
142
|
_labels: list[str]
|
|
143
|
-
_label_values: tuple[
|
|
144
|
-
_counters_by_label_values: defaultdict[
|
|
145
|
-
tuple[Optional[Union[str, float]], ...], ThreadSafeCounter
|
|
146
|
-
]
|
|
143
|
+
_label_values: tuple[str | float | None, ...]
|
|
144
|
+
_counters_by_label_values: defaultdict[tuple[str | float | None, ...], ThreadSafeCounter]
|
|
147
145
|
|
|
148
146
|
def __init__(self, namespace: str, name: str, labels: list[str], schema_version: int = 1):
|
|
149
147
|
super().__init__(namespace=namespace, name=name, schema_version=schema_version)
|
|
@@ -162,7 +160,7 @@ class LabeledCounter(Metric):
|
|
|
162
160
|
self._counters_by_label_values = defaultdict(ThreadSafeCounter)
|
|
163
161
|
MetricRegistry().register(self)
|
|
164
162
|
|
|
165
|
-
def labels(self, **kwargs:
|
|
163
|
+
def labels(self, **kwargs: str | float | None) -> ThreadSafeCounter:
|
|
166
164
|
"""
|
|
167
165
|
Create a scoped counter instance with specific label values.
|
|
168
166
|
|
|
@@ -198,7 +196,7 @@ class LabeledCounter(Metric):
|
|
|
198
196
|
)
|
|
199
197
|
|
|
200
198
|
# Create labels dictionary
|
|
201
|
-
labels_dict = dict(zip(self._labels, label_values))
|
|
199
|
+
labels_dict = dict(zip(self._labels, label_values, strict=False))
|
|
202
200
|
|
|
203
201
|
payload.append(
|
|
204
202
|
LabeledCounterPayload(
|
|
@@ -4,7 +4,6 @@ import logging
|
|
|
4
4
|
import threading
|
|
5
5
|
import time
|
|
6
6
|
from queue import Full, Queue
|
|
7
|
-
from typing import Optional
|
|
8
7
|
|
|
9
8
|
from localstack import config
|
|
10
9
|
from localstack.utils.threads import start_thread, start_worker_thread
|
|
@@ -93,7 +92,7 @@ class PublisherBuffer(EventHandler):
|
|
|
93
92
|
self._stopping.set()
|
|
94
93
|
self._command_queue.put(self._cmd_stop)
|
|
95
94
|
|
|
96
|
-
def close_sync(self, timeout:
|
|
95
|
+
def close_sync(self, timeout: float | None = None):
|
|
97
96
|
self.close()
|
|
98
97
|
return self._stopped.wait(timeout)
|
|
99
98
|
|
|
@@ -2,7 +2,7 @@ import datetime
|
|
|
2
2
|
import logging
|
|
3
3
|
import threading
|
|
4
4
|
from collections import Counter
|
|
5
|
-
from typing import NamedTuple
|
|
5
|
+
from typing import NamedTuple
|
|
6
6
|
|
|
7
7
|
from localstack import config
|
|
8
8
|
from localstack.runtime.shutdown import SHUTDOWN_HANDLERS
|
|
@@ -20,7 +20,7 @@ class ServiceRequestInfo(NamedTuple):
|
|
|
20
20
|
service: str
|
|
21
21
|
operation: str
|
|
22
22
|
status_code: int
|
|
23
|
-
err_type:
|
|
23
|
+
err_type: str | None = None
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class ServiceRequestAggregator:
|
localstack/utils/archives.py
CHANGED
|
@@ -8,7 +8,7 @@ import tempfile
|
|
|
8
8
|
import time
|
|
9
9
|
import zipfile
|
|
10
10
|
from subprocess import Popen
|
|
11
|
-
from typing import IO, Literal
|
|
11
|
+
from typing import IO, Literal
|
|
12
12
|
|
|
13
13
|
from localstack.constants import MAVEN_REPO_URL
|
|
14
14
|
from localstack.utils.files import load_file, mkdir, new_tmp_file, rm_rf, save_file
|
|
@@ -22,7 +22,7 @@ from .strings import truncate
|
|
|
22
22
|
LOG = logging.getLogger(__name__)
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
StrPath =
|
|
25
|
+
StrPath = str | os.PathLike
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def is_zip_file(content):
|
|
@@ -30,13 +30,13 @@ def is_zip_file(content):
|
|
|
30
30
|
return zipfile.is_zipfile(stream)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
def get_unzipped_size(zip_file:
|
|
33
|
+
def get_unzipped_size(zip_file: str | IO[bytes]):
|
|
34
34
|
"""Returns the size of the unzipped file."""
|
|
35
35
|
with zipfile.ZipFile(zip_file, "r") as zip_ref:
|
|
36
36
|
return sum(f.file_size for f in zip_ref.infolist())
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
def unzip(path: str, target_dir: str, overwrite: bool = True) ->
|
|
39
|
+
def unzip(path: str, target_dir: str, overwrite: bool = True) -> str | Popen | None:
|
|
40
40
|
from localstack.utils.platform import is_debian
|
|
41
41
|
|
|
42
42
|
use_native_cmd = is_debian() or is_command_available("unzip")
|
|
@@ -99,7 +99,7 @@ def create_zip_file_python(
|
|
|
99
99
|
base_dir: StrPath,
|
|
100
100
|
zip_file: StrPath,
|
|
101
101
|
mode: Literal["r", "w", "x", "a"] = "w",
|
|
102
|
-
content_root:
|
|
102
|
+
content_root: str | None = None,
|
|
103
103
|
):
|
|
104
104
|
with zipfile.ZipFile(zip_file, mode) as zip_file:
|
|
105
105
|
for root, dirs, files in os.walk(base_dir):
|
|
@@ -122,7 +122,7 @@ def add_file_to_jar(class_file, class_url, target_jar, base_dir=None):
|
|
|
122
122
|
|
|
123
123
|
|
|
124
124
|
def update_jar_manifest(
|
|
125
|
-
jar_file_name: str, parent_dir: str, search:
|
|
125
|
+
jar_file_name: str, parent_dir: str, search: str | re.Pattern, replace: str
|
|
126
126
|
):
|
|
127
127
|
manifest_file_path = "META-INF/MANIFEST.MF"
|
|
128
128
|
jar_path = os.path.join(parent_dir, jar_file_name)
|
|
@@ -174,10 +174,10 @@ def upgrade_jar_file(base_dir: str, file_glob: str, maven_asset: str):
|
|
|
174
174
|
def download_and_extract(
|
|
175
175
|
archive_url: str,
|
|
176
176
|
target_dir: str,
|
|
177
|
-
retries:
|
|
178
|
-
sleep:
|
|
179
|
-
tmp_archive:
|
|
180
|
-
checksum_url:
|
|
177
|
+
retries: int | None = 0,
|
|
178
|
+
sleep: int | None = 3,
|
|
179
|
+
tmp_archive: str | None = None,
|
|
180
|
+
checksum_url: str | None = None,
|
|
181
181
|
) -> None:
|
|
182
182
|
"""
|
|
183
183
|
Download and extract an archive to a target directory with optional checksum verification.
|
|
@@ -250,7 +250,7 @@ def download_and_extract_with_retry(
|
|
|
250
250
|
archive_url,
|
|
251
251
|
tmp_archive,
|
|
252
252
|
target_dir,
|
|
253
|
-
checksum_url:
|
|
253
|
+
checksum_url: str | None = None,
|
|
254
254
|
):
|
|
255
255
|
try:
|
|
256
256
|
download_and_extract(
|
localstack/utils/aws/arns.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import re
|
|
3
3
|
from functools import cache
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import TypedDict
|
|
5
5
|
|
|
6
6
|
from botocore.utils import ArnParser, InvalidArnException
|
|
7
7
|
|
|
@@ -27,7 +27,7 @@ PARTITION_NAMES = list(REGION_PREFIX_TO_PARTITION.values()) + [DEFAULT_PARTITION
|
|
|
27
27
|
ARN_PARTITION_REGEX = r"^arn:(" + "|".join(sorted(PARTITION_NAMES)) + ")"
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def get_partition(region:
|
|
30
|
+
def get_partition(region: str | None) -> str:
|
|
31
31
|
if not region:
|
|
32
32
|
return DEFAULT_PARTITION
|
|
33
33
|
if region in PARTITION_NAMES:
|
|
@@ -65,28 +65,28 @@ def parse_arn(arn: str) -> ArnData:
|
|
|
65
65
|
return _arn_parser.parse_arn(arn)
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
def extract_account_id_from_arn(arn: str) ->
|
|
68
|
+
def extract_account_id_from_arn(arn: str) -> str | None:
|
|
69
69
|
try:
|
|
70
70
|
return parse_arn(arn).get("account")
|
|
71
71
|
except InvalidArnException:
|
|
72
72
|
return None
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
def extract_region_from_arn(arn: str) ->
|
|
75
|
+
def extract_region_from_arn(arn: str) -> str | None:
|
|
76
76
|
try:
|
|
77
77
|
return parse_arn(arn).get("region")
|
|
78
78
|
except InvalidArnException:
|
|
79
79
|
return None
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-
def extract_service_from_arn(arn: str) ->
|
|
82
|
+
def extract_service_from_arn(arn: str) -> str | None:
|
|
83
83
|
try:
|
|
84
84
|
return parse_arn(arn).get("service")
|
|
85
85
|
except InvalidArnException:
|
|
86
86
|
return None
|
|
87
87
|
|
|
88
88
|
|
|
89
|
-
def extract_resource_from_arn(arn: str) ->
|
|
89
|
+
def extract_resource_from_arn(arn: str) -> str | None:
|
|
90
90
|
try:
|
|
91
91
|
return parse_arn(arn).get("resource")
|
|
92
92
|
except InvalidArnException:
|
|
@@ -98,8 +98,10 @@ def extract_resource_from_arn(arn: str) -> Optional[str]:
|
|
|
98
98
|
#
|
|
99
99
|
|
|
100
100
|
|
|
101
|
-
def _resource_arn(
|
|
102
|
-
|
|
101
|
+
def _resource_arn(
|
|
102
|
+
name: str, pattern: str, account_id: str, region_name: str, allow_colons=False
|
|
103
|
+
) -> str:
|
|
104
|
+
if ":" in name and not allow_colons:
|
|
103
105
|
return name
|
|
104
106
|
if len(pattern.split("%s")) == 4:
|
|
105
107
|
return pattern % (get_partition(region_name), account_id, name)
|
|
@@ -285,7 +287,7 @@ def lambda_event_source_mapping_arn(uuid: str, account_id: str, region_name: str
|
|
|
285
287
|
def lambda_function_or_layer_arn(
|
|
286
288
|
type: str,
|
|
287
289
|
entity_name: str,
|
|
288
|
-
version:
|
|
290
|
+
version: str | None,
|
|
289
291
|
account_id: str,
|
|
290
292
|
region_name: str,
|
|
291
293
|
) -> str:
|
|
@@ -474,6 +476,12 @@ def sns_topic_arn(topic_name: str, account_id: str, region_name: str) -> str:
|
|
|
474
476
|
return f"arn:{get_partition(region_name)}:sns:{region_name}:{account_id}:{topic_name}"
|
|
475
477
|
|
|
476
478
|
|
|
479
|
+
def sns_platform_application_arn(
|
|
480
|
+
platform_application_name: str, platform: str, account_id: str, region_name: str
|
|
481
|
+
) -> str:
|
|
482
|
+
return f"arn:{get_partition(region_name)}:sns:{region_name}:{account_id}:app/{platform}/{platform_application_name}"
|
|
483
|
+
|
|
484
|
+
|
|
477
485
|
#
|
|
478
486
|
# ECR
|
|
479
487
|
#
|
|
@@ -3,7 +3,7 @@ import datetime
|
|
|
3
3
|
import json
|
|
4
4
|
import re
|
|
5
5
|
from binascii import crc32
|
|
6
|
-
from typing import Any
|
|
6
|
+
from typing import Any
|
|
7
7
|
from urllib.parse import parse_qs
|
|
8
8
|
|
|
9
9
|
import xmltodict
|
|
@@ -36,10 +36,10 @@ def requests_error_response_json(message, code=500, error_type="InternalFailure"
|
|
|
36
36
|
|
|
37
37
|
def requests_error_response_xml(
|
|
38
38
|
message: str,
|
|
39
|
-
code:
|
|
40
|
-
code_string:
|
|
41
|
-
service:
|
|
42
|
-
xmlns:
|
|
39
|
+
code: int | None = 400,
|
|
40
|
+
code_string: str | None = "InvalidParameter",
|
|
41
|
+
service: str | None = None,
|
|
42
|
+
xmlns: str | None = None,
|
|
43
43
|
):
|
|
44
44
|
response = RequestsResponse()
|
|
45
45
|
xmlns = xmlns or f"http://{service}.amazonaws.com/doc/2010-03-31/"
|
|
@@ -100,7 +100,7 @@ def requests_error_response_xml_signature_calculation(
|
|
|
100
100
|
|
|
101
101
|
def requests_error_response(
|
|
102
102
|
req_headers: dict,
|
|
103
|
-
message:
|
|
103
|
+
message: str | bytes,
|
|
104
104
|
code: int = 500,
|
|
105
105
|
error_type: str = "InternalFailure",
|
|
106
106
|
service: str = None,
|
|
@@ -201,7 +201,7 @@ def parse_query_string(url_or_qs: str, multi_values=False) -> dict[str, str]:
|
|
|
201
201
|
return result
|
|
202
202
|
|
|
203
203
|
|
|
204
|
-
def calculate_crc32(content:
|
|
204
|
+
def calculate_crc32(content: str | bytes) -> int:
|
|
205
205
|
return crc32(to_bytes(content)) & 0xFFFFFFFF
|
|
206
206
|
|
|
207
207
|
|
|
@@ -2,7 +2,6 @@ import logging
|
|
|
2
2
|
import re
|
|
3
3
|
import socket
|
|
4
4
|
from functools import lru_cache
|
|
5
|
-
from typing import Union
|
|
6
5
|
|
|
7
6
|
import boto3
|
|
8
7
|
|
|
@@ -46,7 +45,7 @@ def get_boto3_region() -> str:
|
|
|
46
45
|
return boto3.session.Session().region_name
|
|
47
46
|
|
|
48
47
|
|
|
49
|
-
def get_local_service_url(service_name_or_port:
|
|
48
|
+
def get_local_service_url(service_name_or_port: str | int) -> str:
|
|
50
49
|
"""Return the local service URL for the given service name or port."""
|
|
51
50
|
# TODO(srw): we don't need to differentiate on service name any more, so remove the argument
|
|
52
51
|
if isinstance(service_name_or_port, int):
|
|
@@ -68,7 +67,7 @@ def get_s3_hostname():
|
|
|
68
67
|
|
|
69
68
|
|
|
70
69
|
def fix_account_id_in_arns(
|
|
71
|
-
response, replacement: str, colon_delimiter: str = ":", existing:
|
|
70
|
+
response, replacement: str, colon_delimiter: str = ":", existing: str | list[str] = None
|
|
72
71
|
):
|
|
73
72
|
"""Fix the account ID in the ARNs returned in the given Flask response or string"""
|
|
74
73
|
from moto.core import DEFAULT_ACCOUNT_ID
|
|
@@ -65,7 +65,6 @@ if TYPE_CHECKING:
|
|
|
65
65
|
from mypy_boto3_iotwireless import IoTWirelessClient
|
|
66
66
|
from mypy_boto3_kafka import KafkaClient
|
|
67
67
|
from mypy_boto3_kinesis import KinesisClient
|
|
68
|
-
from mypy_boto3_kinesisanalytics import KinesisAnalyticsClient
|
|
69
68
|
from mypy_boto3_kinesisanalyticsv2 import KinesisAnalyticsV2Client
|
|
70
69
|
from mypy_boto3_kms import KMSClient
|
|
71
70
|
from mypy_boto3_lakeformation import LakeFormationClient
|
|
@@ -82,8 +81,6 @@ if TYPE_CHECKING:
|
|
|
82
81
|
from mypy_boto3_pi import PIClient
|
|
83
82
|
from mypy_boto3_pinpoint import PinpointClient
|
|
84
83
|
from mypy_boto3_pipes import EventBridgePipesClient
|
|
85
|
-
from mypy_boto3_qldb import QLDBClient
|
|
86
|
-
from mypy_boto3_qldb_session import QLDBSessionClient
|
|
87
84
|
from mypy_boto3_rds import RDSClient
|
|
88
85
|
from mypy_boto3_rds_data import RDSDataServiceClient
|
|
89
86
|
from mypy_boto3_redshift import RedshiftClient
|
|
@@ -191,9 +188,6 @@ class TypedServiceClientFactory(abc.ABC):
|
|
|
191
188
|
iotwireless: Union["IoTWirelessClient", "MetadataRequestInjector[IoTWirelessClient]"]
|
|
192
189
|
kafka: Union["KafkaClient", "MetadataRequestInjector[KafkaClient]"]
|
|
193
190
|
kinesis: Union["KinesisClient", "MetadataRequestInjector[KinesisClient]"]
|
|
194
|
-
kinesisanalytics: Union[
|
|
195
|
-
"KinesisAnalyticsClient", "MetadataRequestInjector[KinesisAnalyticsClient]"
|
|
196
|
-
]
|
|
197
191
|
kinesisanalyticsv2: Union[
|
|
198
192
|
"KinesisAnalyticsV2Client", "MetadataRequestInjector[KinesisAnalyticsV2Client]"
|
|
199
193
|
]
|
|
@@ -214,8 +208,6 @@ class TypedServiceClientFactory(abc.ABC):
|
|
|
214
208
|
pi: Union["PIClient", "MetadataRequestInjector[PIClient]"]
|
|
215
209
|
pinpoint: Union["PinpointClient", "MetadataRequestInjector[PinpointClient]"]
|
|
216
210
|
pipes: Union["EventBridgePipesClient", "MetadataRequestInjector[EventBridgePipesClient]"]
|
|
217
|
-
qldb: Union["QLDBClient", "MetadataRequestInjector[QLDBClient]"]
|
|
218
|
-
qldb_session: Union["QLDBSessionClient", "MetadataRequestInjector[QLDBSessionClient]"]
|
|
219
211
|
rds: Union["RDSClient", "MetadataRequestInjector[RDSClient]"]
|
|
220
212
|
rds_data: Union["RDSDataServiceClient", "MetadataRequestInjector[RDSDataServiceClient]"]
|
|
221
213
|
redshift: Union["RedshiftClient", "MetadataRequestInjector[RedshiftClient]"]
|
|
@@ -3,7 +3,6 @@ import json
|
|
|
3
3
|
import logging
|
|
4
4
|
import re
|
|
5
5
|
import uuid
|
|
6
|
-
from typing import Optional
|
|
7
6
|
|
|
8
7
|
from moto.events.models import events_backends
|
|
9
8
|
|
|
@@ -214,7 +213,7 @@ def list_of_parameters_to_object(items):
|
|
|
214
213
|
return {item.get("Key"): item.get("Value") for item in items}
|
|
215
214
|
|
|
216
215
|
|
|
217
|
-
def send_event_to_api_destination(target_arn, event, http_parameters:
|
|
216
|
+
def send_event_to_api_destination(target_arn, event, http_parameters: dict | None = None):
|
|
218
217
|
"""Send an event to an EventBridge API destination
|
|
219
218
|
See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-api-destinations.html"""
|
|
220
219
|
|