localstack-core 4.7.1.dev139__py3-none-any.whl → 4.10.1.dev7__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.
Files changed (173) hide show
  1. localstack/aws/api/cloudformation/__init__.py +1 -0
  2. localstack/aws/api/cloudwatch/__init__.py +41 -1
  3. localstack/aws/api/config/__init__.py +4 -0
  4. localstack/aws/api/core.py +4 -0
  5. localstack/aws/api/ec2/__init__.py +1113 -56
  6. localstack/aws/api/iam/__init__.py +7 -0
  7. localstack/aws/api/kinesis/__init__.py +19 -0
  8. localstack/aws/api/kms/__init__.py +6 -0
  9. localstack/aws/api/lambda_/__init__.py +13 -0
  10. localstack/aws/api/logs/__init__.py +15 -0
  11. localstack/aws/api/redshift/__init__.py +9 -3
  12. localstack/aws/api/route53/__init__.py +2 -0
  13. localstack/aws/api/s3/__init__.py +12 -0
  14. localstack/aws/api/s3control/__init__.py +32 -0
  15. localstack/aws/api/ssm/__init__.py +2 -0
  16. localstack/aws/client.py +7 -2
  17. localstack/aws/forwarder.py +52 -5
  18. localstack/aws/handlers/analytics.py +1 -1
  19. localstack/aws/handlers/logging.py +12 -2
  20. localstack/aws/handlers/metric_handler.py +41 -1
  21. localstack/aws/handlers/service.py +32 -9
  22. localstack/aws/protocol/parser.py +440 -21
  23. localstack/aws/protocol/serializer.py +684 -64
  24. localstack/aws/protocol/service_router.py +120 -20
  25. localstack/aws/skeleton.py +4 -2
  26. localstack/aws/spec-patches.json +58 -0
  27. localstack/aws/spec.py +33 -13
  28. localstack/cli/exceptions.py +1 -1
  29. localstack/cli/localstack.py +4 -4
  30. localstack/cli/lpm.py +3 -4
  31. localstack/cli/profiles.py +1 -2
  32. localstack/config.py +18 -12
  33. localstack/constants.py +4 -29
  34. localstack/dev/kubernetes/__main__.py +1 -1
  35. localstack/dev/run/paths.py +1 -1
  36. localstack/dns/plugins.py +5 -1
  37. localstack/dns/server.py +12 -3
  38. localstack/packages/api.py +9 -8
  39. localstack/packages/core.py +2 -2
  40. localstack/packages/plugins.py +0 -8
  41. localstack/runtime/init.py +1 -1
  42. localstack/services/apigateway/legacy/provider.py +53 -3
  43. localstack/services/apigateway/next_gen/execute_api/integrations/aws.py +3 -0
  44. localstack/services/apigateway/next_gen/execute_api/integrations/http.py +3 -3
  45. localstack/services/apigateway/next_gen/execute_api/test_invoke.py +50 -6
  46. localstack/services/apigateway/next_gen/provider.py +5 -0
  47. localstack/services/cloudformation/engine/entities.py +12 -1
  48. localstack/services/cloudformation/engine/v2/change_set_model.py +0 -3
  49. localstack/services/cloudformation/engine/v2/change_set_model_describer.py +14 -0
  50. localstack/services/cloudformation/engine/v2/change_set_model_executor.py +13 -15
  51. localstack/services/cloudformation/engine/v2/change_set_model_preproc.py +118 -24
  52. localstack/services/cloudformation/engine/v2/change_set_model_transform.py +4 -1
  53. localstack/services/cloudformation/engine/v2/change_set_model_validator.py +5 -14
  54. localstack/services/cloudformation/engine/v2/change_set_model_visitor.py +1 -0
  55. localstack/services/cloudformation/engine/v2/resolving.py +6 -4
  56. localstack/services/cloudformation/engine/yaml_parser.py +9 -2
  57. localstack/services/cloudformation/resource_provider.py +5 -1
  58. localstack/services/cloudformation/resources.py +24149 -0
  59. localstack/services/cloudformation/v2/entities.py +6 -3
  60. localstack/services/cloudformation/v2/provider.py +172 -27
  61. localstack/services/cloudformation/v2/types.py +8 -4
  62. localstack/services/cloudwatch/provider_v2.py +25 -28
  63. localstack/services/dynamodb/packages.py +2 -1
  64. localstack/services/dynamodb/provider.py +42 -0
  65. localstack/services/dynamodb/v2/provider.py +42 -0
  66. localstack/services/ecr/resource_providers/aws_ecr_repository.py +5 -2
  67. localstack/services/es/provider.py +2 -2
  68. localstack/services/events/event_rule_engine.py +31 -13
  69. localstack/services/events/models.py +4 -5
  70. localstack/services/events/target.py +17 -9
  71. localstack/services/iam/provider.py +11 -116
  72. localstack/services/iam/resources/policy_simulator.py +133 -0
  73. localstack/services/kinesis/models.py +15 -2
  74. localstack/services/kinesis/provider.py +77 -0
  75. localstack/services/kms/provider.py +14 -5
  76. localstack/services/lambda_/invocation/internal_sqs_queue.py +5 -9
  77. localstack/services/lambda_/packages.py +1 -1
  78. localstack/services/logs/provider.py +1 -1
  79. localstack/services/moto.py +2 -1
  80. localstack/services/opensearch/cluster.py +15 -7
  81. localstack/services/opensearch/packages.py +26 -7
  82. localstack/services/opensearch/provider.py +6 -1
  83. localstack/services/opensearch/versions.py +56 -7
  84. localstack/services/s3/constants.py +5 -2
  85. localstack/services/s3/cors.py +4 -4
  86. localstack/services/s3/notifications.py +1 -1
  87. localstack/services/s3/presigned_url.py +27 -43
  88. localstack/services/s3/provider.py +67 -11
  89. localstack/services/s3/utils.py +42 -11
  90. localstack/services/ses/provider.py +16 -7
  91. localstack/services/sns/constants.py +7 -1
  92. localstack/services/sns/v2/models.py +167 -0
  93. localstack/services/sns/v2/provider.py +860 -2
  94. localstack/services/sns/v2/utils.py +130 -0
  95. localstack/services/sqs/developer_api.py +205 -0
  96. localstack/services/sqs/models.py +42 -3
  97. localstack/services/sqs/provider.py +8 -309
  98. localstack/services/sqs/query_api.py +1 -1
  99. localstack/services/sqs/utils.py +121 -2
  100. localstack/services/stepfunctions/asl/jsonata/jsonata.py +1 -1
  101. localstack/testing/aws/cloudformation_utils.py +1 -1
  102. localstack/testing/pytest/cloudformation/fixtures.py +3 -3
  103. localstack/testing/pytest/container.py +4 -5
  104. localstack/testing/pytest/fixtures.py +20 -19
  105. localstack/testing/pytest/in_memory_localstack.py +0 -4
  106. localstack/testing/pytest/marking.py +13 -4
  107. localstack/testing/pytest/stepfunctions/utils.py +4 -3
  108. localstack/testing/pytest/util.py +1 -1
  109. localstack/testing/pytest/validation_tracking.py +1 -2
  110. localstack/testing/snapshots/transformer_utility.py +5 -0
  111. localstack/utils/analytics/events.py +2 -2
  112. localstack/utils/analytics/metadata.py +1 -2
  113. localstack/utils/analytics/metrics/counter.py +6 -8
  114. localstack/utils/analytics/publisher.py +1 -2
  115. localstack/utils/analytics/service_request_aggregator.py +2 -2
  116. localstack/utils/archives.py +11 -11
  117. localstack/utils/aws/arns.py +17 -9
  118. localstack/utils/aws/aws_responses.py +7 -7
  119. localstack/utils/aws/aws_stack.py +2 -3
  120. localstack/utils/aws/message_forwarding.py +1 -2
  121. localstack/utils/aws/request_context.py +4 -5
  122. localstack/utils/batch_policy.py +3 -3
  123. localstack/utils/bootstrap.py +7 -7
  124. localstack/utils/catalog/catalog.py +139 -0
  125. localstack/utils/catalog/catalog_loader.py +11 -0
  126. localstack/utils/catalog/common.py +58 -0
  127. localstack/utils/catalog/plugins.py +28 -0
  128. localstack/utils/cloudwatch/cloudwatch_util.py +5 -5
  129. localstack/utils/collections.py +7 -8
  130. localstack/utils/config_listener.py +1 -1
  131. localstack/utils/container_networking.py +2 -3
  132. localstack/utils/container_utils/container_client.py +115 -131
  133. localstack/utils/container_utils/docker_cmd_client.py +42 -42
  134. localstack/utils/container_utils/docker_sdk_client.py +63 -62
  135. localstack/utils/diagnose.py +2 -3
  136. localstack/utils/docker_utils.py +3 -4
  137. localstack/utils/files.py +31 -7
  138. localstack/utils/functions.py +3 -2
  139. localstack/utils/http.py +4 -5
  140. localstack/utils/json.py +19 -5
  141. localstack/utils/kinesis/kinesis_connector.py +2 -1
  142. localstack/utils/net.py +6 -6
  143. localstack/utils/no_exit_argument_parser.py +2 -2
  144. localstack/utils/numbers.py +9 -2
  145. localstack/utils/objects.py +6 -5
  146. localstack/utils/patch.py +2 -1
  147. localstack/utils/run.py +10 -9
  148. localstack/utils/scheduler.py +11 -11
  149. localstack/utils/server/tcp_proxy.py +2 -2
  150. localstack/utils/serving.py +2 -3
  151. localstack/utils/strings.py +10 -11
  152. localstack/utils/sync.py +126 -1
  153. localstack/utils/tagging.py +1 -4
  154. localstack/utils/testutil.py +5 -4
  155. localstack/utils/threads.py +2 -2
  156. localstack/utils/time.py +11 -3
  157. localstack/utils/urls.py +1 -3
  158. localstack/version.py +2 -2
  159. {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev7.dist-info}/METADATA +17 -12
  160. {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev7.dist-info}/RECORD +168 -164
  161. {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev7.dist-info}/entry_points.txt +4 -2
  162. localstack_core-4.10.1.dev7.dist-info/plux.json +1 -0
  163. localstack/packages/terraform.py +0 -46
  164. localstack/services/cloudformation/deploy.html +0 -144
  165. localstack/services/cloudformation/deploy_ui.py +0 -47
  166. localstack/services/cloudformation/plugins.py +0 -12
  167. localstack_core-4.7.1.dev139.dist-info/plux.json +0 -1
  168. {localstack_core-4.7.1.dev139.data → localstack_core-4.10.1.dev7.data}/scripts/localstack +0 -0
  169. {localstack_core-4.7.1.dev139.data → localstack_core-4.10.1.dev7.data}/scripts/localstack-supervisor +0 -0
  170. {localstack_core-4.7.1.dev139.data → localstack_core-4.10.1.dev7.data}/scripts/localstack.bat +0 -0
  171. {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev7.dist-info}/WHEEL +0 -0
  172. {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev7.dist-info}/licenses/LICENSE.txt +0 -0
  173. {localstack_core-4.7.1.dev139.dist-info → localstack_core-4.10.1.dev7.dist-info}/top_level.txt +0 -0
@@ -9,9 +9,9 @@ import shlex
9
9
  import signal
10
10
  import threading
11
11
  import time
12
- from collections.abc import Iterable
12
+ from collections.abc import Callable, Iterable
13
13
  from functools import wraps
14
- from typing import Any, Callable, Optional, Union
14
+ from typing import Any
15
15
 
16
16
  from localstack import config, constants
17
17
  from localstack.config import (
@@ -175,7 +175,7 @@ def get_docker_image_details(image_name: str = None) -> dict[str, str]:
175
175
  return result
176
176
 
177
177
 
178
- def get_image_environment_variable(env_name: str) -> Optional[str]:
178
+ def get_image_environment_variable(env_name: str) -> str | None:
179
179
  image_name = get_docker_image_to_start()
180
180
  image_info = DOCKER_CLIENT.inspect_image(image_name)
181
181
  image_envs = image_info["Config"]["Env"]
@@ -544,7 +544,7 @@ class ContainerConfigurators:
544
544
 
545
545
  @staticmethod
546
546
  def gateway_listen(
547
- port: Union[int, Iterable[int], HostAndPort, Iterable[HostAndPort]],
547
+ port: int | Iterable[int] | HostAndPort | Iterable[HostAndPort],
548
548
  ):
549
549
  """
550
550
  Uses the given ports to configure GATEWAY_LISTEN. For instance, ``gateway_listen([4566, 443])`` would
@@ -1000,7 +1000,7 @@ class RunningContainer:
1000
1000
  return
1001
1001
  raise
1002
1002
 
1003
- def inspect(self) -> dict[str, Union[dict, str]]:
1003
+ def inspect(self) -> dict[str, dict | str]:
1004
1004
  return self.container_client.inspect_container(container_name_or_id=self.id)
1005
1005
 
1006
1006
  def attach(self):
@@ -1028,7 +1028,7 @@ class ContainerLogPrinter:
1028
1028
  self.callback = callback
1029
1029
 
1030
1030
  self._closed = threading.Event()
1031
- self._stream: Optional[CancellableStream] = None
1031
+ self._stream: CancellableStream | None = None
1032
1032
 
1033
1033
  def _can_start_streaming(self):
1034
1034
  if self._closed.is_set():
@@ -1338,7 +1338,7 @@ def start_infra_in_docker_detached(console, cli_params: dict[str, Any] = None):
1338
1338
  console.log("detaching")
1339
1339
 
1340
1340
 
1341
- def wait_container_is_ready(timeout: Optional[float] = None):
1341
+ def wait_container_is_ready(timeout: float | None = None):
1342
1342
  """Blocks until the localstack main container is running and the ready marker has been printed."""
1343
1343
  container_name = config.MAIN_CONTAINER_NAME
1344
1344
  started = time.time()
@@ -0,0 +1,139 @@
1
+ import logging
2
+ from abc import abstractmethod
3
+
4
+ from plux import Plugin
5
+
6
+ from localstack.services.cloudformation.resource_provider import (
7
+ plugin_manager as cfn_plugin_manager,
8
+ )
9
+ from localstack.utils.catalog.catalog_loader import RemoteCatalogLoader
10
+ from localstack.utils.catalog.common import (
11
+ AwsServiceOperationsSupportInLatest,
12
+ AwsServicesSupportInLatest,
13
+ AwsServiceSupportAtRuntime,
14
+ CloudFormationResourcesSupportAtRuntime,
15
+ CloudFormationResourcesSupportInLatest,
16
+ LocalstackEmulatorType,
17
+ )
18
+
19
+ ServiceName = str
20
+ ServiceOperations = set[str]
21
+ ProviderName = str
22
+ CfnResourceName = str
23
+ CfnResourceMethodName = str
24
+ AwsServicesSupportStatus = (
25
+ AwsServiceSupportAtRuntime | AwsServicesSupportInLatest | AwsServiceOperationsSupportInLatest
26
+ )
27
+ CfnResourceSupportStatus = (
28
+ CloudFormationResourcesSupportInLatest | CloudFormationResourcesSupportAtRuntime
29
+ )
30
+ CfnResourceCatalog = dict[LocalstackEmulatorType, dict[CfnResourceName, set[CfnResourceMethodName]]]
31
+
32
+ LOG = logging.getLogger(__name__)
33
+
34
+
35
+ class CatalogPlugin(Plugin):
36
+ namespace = "localstack.utils.catalog"
37
+
38
+ @staticmethod
39
+ def _get_cfn_resources_catalog(cloudformation_resources: dict) -> CfnResourceCatalog:
40
+ cfn_resources_catalog = {}
41
+ for emulator_type, resources in cloudformation_resources.items():
42
+ cfn_resources_catalog[emulator_type] = {}
43
+ for resource_name, resource in resources.items():
44
+ cfn_resources_catalog[emulator_type][resource_name] = set(resource.methods)
45
+ return cfn_resources_catalog
46
+
47
+ @staticmethod
48
+ def _get_services_at_runtime() -> set[ServiceName]:
49
+ from localstack.services.plugins import SERVICE_PLUGINS
50
+
51
+ return set(SERVICE_PLUGINS.list_available())
52
+
53
+ @staticmethod
54
+ def _get_cfn_resources_available_at_runtime() -> set[CfnResourceName]:
55
+ return set(cfn_plugin_manager.list_names())
56
+
57
+ @abstractmethod
58
+ def get_aws_service_status(
59
+ self, service_name: str, operation_name: str | None = None
60
+ ) -> AwsServicesSupportStatus | None:
61
+ pass
62
+
63
+ @abstractmethod
64
+ def get_cloudformation_resource_status(
65
+ self, resource_name: str, service_name: str, is_pro_resource: bool = False
66
+ ) -> CfnResourceSupportStatus | AwsServicesSupportInLatest | None:
67
+ pass
68
+
69
+
70
+ class AwsCatalogRuntimePlugin(CatalogPlugin):
71
+ name = "aws-catalog-runtime-only"
72
+
73
+ def get_aws_service_status(
74
+ self, service_name: str, operation_name: str | None = None
75
+ ) -> AwsServicesSupportStatus | None:
76
+ return None
77
+
78
+ def get_cloudformation_resource_status(
79
+ self, resource_name: str, service_name: str, is_pro_resource: bool = False
80
+ ) -> CfnResourceSupportStatus | AwsServicesSupportInLatest | None:
81
+ return None
82
+
83
+
84
+ class AwsCatalogRemoteStatePlugin(CatalogPlugin):
85
+ name = "aws-catalog-remote-state"
86
+ current_emulator_type: LocalstackEmulatorType = LocalstackEmulatorType.COMMUNITY
87
+ services_in_latest: dict[ServiceName, dict[LocalstackEmulatorType, ServiceOperations]] = {}
88
+ services_at_runtime: set[ServiceName] = set()
89
+ cfn_resources_in_latest: CfnResourceCatalog = {}
90
+ cfn_resources_at_runtime: set[CfnResourceName] = set()
91
+
92
+ def __init__(self, remote_catalog_loader: RemoteCatalogLoader | None = None) -> None:
93
+ catalog_loader = remote_catalog_loader or RemoteCatalogLoader()
94
+ remote_catalog = catalog_loader.get_remote_catalog()
95
+ for service_name, emulators in remote_catalog.services.items():
96
+ for emulator_type, service_provider in emulators.items():
97
+ self.services_in_latest.setdefault(service_name, {})[emulator_type] = set(
98
+ service_provider.operations
99
+ )
100
+
101
+ self.cfn_resources_in_latest = self._get_cfn_resources_catalog(
102
+ remote_catalog.cloudformation_resources
103
+ )
104
+ self.cfn_resources_at_runtime = self._get_cfn_resources_available_at_runtime()
105
+ self.services_at_runtime = self._get_services_at_runtime()
106
+
107
+ def get_aws_service_status(
108
+ self, service_name: str, operation_name: str | None = None
109
+ ) -> AwsServicesSupportStatus | None:
110
+ if not self.services_in_latest:
111
+ return None
112
+ if service_name not in self.services_in_latest:
113
+ return AwsServicesSupportInLatest.NOT_SUPPORTED
114
+ if self.current_emulator_type not in self.services_in_latest[service_name]:
115
+ return AwsServicesSupportInLatest.SUPPORTED_WITH_LICENSE_UPGRADE
116
+ if not operation_name:
117
+ return AwsServicesSupportInLatest.SUPPORTED
118
+ if operation_name in self.services_in_latest[service_name][self.current_emulator_type]:
119
+ return AwsServiceOperationsSupportInLatest.SUPPORTED
120
+ for emulator_type in self.services_in_latest[service_name]:
121
+ if emulator_type is self.current_emulator_type:
122
+ continue
123
+ if operation_name in self.services_in_latest[service_name][emulator_type]:
124
+ return AwsServiceOperationsSupportInLatest.SUPPORTED_WITH_LICENSE_UPGRADE
125
+ return AwsServiceOperationsSupportInLatest.NOT_SUPPORTED
126
+
127
+ def get_cloudformation_resource_status(
128
+ self, resource_name: str, service_name: str, is_pro_resource: bool = False
129
+ ) -> CfnResourceSupportStatus | AwsServicesSupportInLatest | None:
130
+ if resource_name in self.cfn_resources_at_runtime:
131
+ return CloudFormationResourcesSupportAtRuntime.AVAILABLE
132
+ if service_name in self.services_at_runtime:
133
+ if resource_name in self.cfn_resources_in_latest[self.current_emulator_type]:
134
+ return CloudFormationResourcesSupportInLatest.SUPPORTED
135
+ else:
136
+ return CloudFormationResourcesSupportInLatest.NOT_SUPPORTED
137
+ if service_name in self.services_in_latest:
138
+ return self.get_aws_service_status(service_name, operation_name=None)
139
+ return AwsServicesSupportInLatest.NOT_SUPPORTED
@@ -0,0 +1,11 @@
1
+ import json
2
+
3
+ from localstack.utils.catalog.common import AwsRemoteCatalog
4
+
5
+ LICENSE_CATALOG_PATH = ""
6
+
7
+
8
+ class RemoteCatalogLoader:
9
+ def get_remote_catalog(self) -> AwsRemoteCatalog:
10
+ with open(LICENSE_CATALOG_PATH) as f:
11
+ return AwsRemoteCatalog(**json.load(f))
@@ -0,0 +1,58 @@
1
+ from enum import StrEnum
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class CloudFormationResource(BaseModel):
7
+ methods: list[str]
8
+
9
+
10
+ class AwsServiceCatalog(BaseModel):
11
+ provider: str
12
+ operations: list[str]
13
+ plans: list[str]
14
+
15
+
16
+ class LocalStackMetadata(BaseModel):
17
+ version: str
18
+
19
+
20
+ class AwsRemoteCatalog(BaseModel):
21
+ schema_version: str
22
+ localstack: LocalStackMetadata
23
+ services: dict[str, dict[str, AwsServiceCatalog]]
24
+ cloudformation_resources: dict[str, dict[str, CloudFormationResource]]
25
+
26
+
27
+ class LocalstackEmulatorType(StrEnum):
28
+ COMMUNITY = "community"
29
+ PRO = "pro"
30
+
31
+
32
+ class AwsServiceSupportAtRuntime(StrEnum):
33
+ AVAILABLE = "AVAILABLE"
34
+ AVAILABLE_WITH_LICENSE_UPGRADE = "AVAILABLE_WITH_LICENSE_UPGRADE"
35
+ NOT_IMPLEMENTED = "NOT_IMPLEMENTED"
36
+
37
+
38
+ class AwsServicesSupportInLatest(StrEnum):
39
+ SUPPORTED = "SUPPORTED"
40
+ SUPPORTED_WITH_LICENSE_UPGRADE = "SUPPORTED_WITH_LICENSE_UPGRADE"
41
+ NOT_SUPPORTED = "NOT_SUPPORTED"
42
+ NON_DEFAULT_PROVIDER = "NON_DEFAULT_PROVIDER"
43
+
44
+
45
+ class AwsServiceOperationsSupportInLatest(StrEnum):
46
+ SUPPORTED = "SUPPORTED"
47
+ SUPPORTED_WITH_LICENSE_UPGRADE = "SUPPORTED_WITH_LICENSE_UPGRADE"
48
+ NOT_SUPPORTED = "NOT_SUPPORTED"
49
+
50
+
51
+ class CloudFormationResourcesSupportInLatest(StrEnum):
52
+ SUPPORTED = "SUPPORTED"
53
+ NOT_SUPPORTED = "NOT_SUPPORTED"
54
+
55
+
56
+ class CloudFormationResourcesSupportAtRuntime(StrEnum):
57
+ AVAILABLE = "AVAILABLE"
58
+ NOT_IMPLEMENTED = "NOT_IMPLEMENTED"
@@ -0,0 +1,28 @@
1
+ import logging
2
+
3
+ from plux import PluginManager
4
+
5
+ from localstack.utils.catalog.catalog import CatalogPlugin
6
+ from localstack.utils.objects import singleton_factory
7
+
8
+ LOG = logging.getLogger(__name__)
9
+
10
+
11
+ @singleton_factory
12
+ def get_aws_catalog() -> CatalogPlugin:
13
+ plugin_manager = PluginManager(CatalogPlugin.namespace)
14
+ try:
15
+ plugin_name = "aws-catalog-remote-state-with-license"
16
+ if not plugin_manager.exists(plugin_name):
17
+ plugin_name = "aws-catalog-remote-state"
18
+ return plugin_manager.load(plugin_name)
19
+ except Exception as e:
20
+ LOG.debug(
21
+ "Failed to load catalog plugin with the latest LocalStack services support data, falling back to catalog without remote state: %s",
22
+ e,
23
+ )
24
+ # Try to load runtime catalog from pro version first
25
+ fallback_plugin_name = "aws-catalog-runtime-only-with-license"
26
+ if not plugin_manager.exists(fallback_plugin_name):
27
+ fallback_plugin_name = "aws-catalog-runtime-only"
28
+ return plugin_manager.load(fallback_plugin_name)
@@ -2,7 +2,7 @@ import logging
2
2
  import time
3
3
  from datetime import datetime, timezone
4
4
  from itertools import islice
5
- from typing import Optional, TypedDict
5
+ from typing import TypedDict
6
6
 
7
7
  from werkzeug import Response as WerkzeugResponse
8
8
 
@@ -20,8 +20,8 @@ LOG = logging.getLogger(__name__)
20
20
  class SqsMetricBatchData(TypedDict, total=False):
21
21
  MetricName: str
22
22
  QueueName: str
23
- Value: Optional[int]
24
- Unit: Optional[str]
23
+ Value: int | None
24
+ Unit: str | None
25
25
 
26
26
 
27
27
  def dimension_lambda(kwargs):
@@ -30,7 +30,7 @@ def dimension_lambda(kwargs):
30
30
 
31
31
 
32
32
  def publish_lambda_metric(
33
- metric, value, kwargs, account_id: Optional[str] = None, region_name: Optional[str] = None
33
+ metric, value, kwargs, account_id: str | None = None, region_name: str | None = None
34
34
  ):
35
35
  # publish metric only if CloudWatch service is available
36
36
  if not is_api_enabled("cloudwatch"):
@@ -155,7 +155,7 @@ def store_cloudwatch_logs(
155
155
  log_stream_name,
156
156
  log_output,
157
157
  start_time=None,
158
- auto_create_group: Optional[bool] = True,
158
+ auto_create_group: bool | None = True,
159
159
  ):
160
160
  if not is_api_enabled("logs"):
161
161
  return
@@ -5,10 +5,9 @@ and manipulate python collection (dicts, list, sets).
5
5
 
6
6
  import logging
7
7
  import re
8
- from collections.abc import Iterable, Iterator, Mapping, Sized
8
+ from collections.abc import Callable, Iterable, Iterator, Mapping, Sized
9
9
  from typing import (
10
10
  Any,
11
- Callable,
12
11
  Optional,
13
12
  TypedDict,
14
13
  TypeVar,
@@ -116,7 +115,7 @@ class PaginatedList(list[_ListType]):
116
115
  next_token: str = None,
117
116
  page_size: int = None,
118
117
  filter_function: Callable[[_ListType], bool] = None,
119
- ) -> tuple[list[_ListType], Optional[str]]:
118
+ ) -> tuple[list[_ListType], str | None]:
120
119
  if filter_function is not None:
121
120
  result_list = list(filter(filter_function, self))
122
121
  else:
@@ -148,7 +147,7 @@ class PaginatedList(list[_ListType]):
148
147
  class CustomExpiryTTLCache(cachetools.TTLCache):
149
148
  """TTLCache that allows to set custom expiry times for individual keys."""
150
149
 
151
- def set_expiry(self, key: Any, ttl: Union[float, int]) -> float:
150
+ def set_expiry(self, key: Any, ttl: float | int) -> float:
152
151
  """Set the expiry of the given key in a TTLCache to (<current_time> + <ttl>)"""
153
152
  with self.timer as time:
154
153
  # note: need to access the internal dunder API here
@@ -315,7 +314,7 @@ def is_list_or_tuple(obj) -> bool:
315
314
  return isinstance(obj, (list, tuple))
316
315
 
317
316
 
318
- def ensure_list(obj: Any, wrap_none=False) -> Optional[list]:
317
+ def ensure_list(obj: Any, wrap_none=False) -> list | None:
319
318
  """Wrap the given object in a list, or return the object itself if it already is a list."""
320
319
  if obj is None and not wrap_none:
321
320
  return obj
@@ -414,7 +413,7 @@ def items_equivalent(list1, list2, comparator):
414
413
  return True
415
414
 
416
415
 
417
- def is_none_or_empty(obj: Union[Optional[str], Optional[list]]) -> bool:
416
+ def is_none_or_empty(obj: str | None | list | None) -> bool:
418
417
  return (
419
418
  obj is None
420
419
  or (isinstance(obj, str) and obj.strip() == "")
@@ -475,7 +474,7 @@ def convert_to_typed_dict(typed_dict: type[T], obj: dict, strict: bool = False)
475
474
  return result
476
475
 
477
476
 
478
- def dict_multi_values(elements: Union[list, dict]) -> dict[str, list[Any]]:
477
+ def dict_multi_values(elements: list | dict) -> dict[str, list[Any]]:
479
478
  """
480
479
  Return a dictionary with the original keys from the list of dictionary and the
481
480
  values are the list of values of the original dictionary.
@@ -516,7 +515,7 @@ def split_list_by(
516
515
  return truthy, falsy
517
516
 
518
517
 
519
- def is_comma_delimited_list(string: str, item_regex: Optional[str] = None) -> bool:
518
+ def is_comma_delimited_list(string: str, item_regex: str | None = None) -> bool:
520
519
  """
521
520
  Checks if the given string is a comma-delimited list of items.
522
521
  The optional `item_regex` parameter specifies the regex pattern for each item in the list.
@@ -1,7 +1,7 @@
1
1
  import json
2
2
  import logging
3
3
  import re
4
- from typing import Callable
4
+ from collections.abc import Callable
5
5
 
6
6
  from requests.models import Response
7
7
 
@@ -2,7 +2,6 @@ import logging
2
2
  import os
3
3
  import re
4
4
  from functools import lru_cache
5
- from typing import Optional
6
5
 
7
6
  from localstack import config, constants
8
7
  from localstack.utils.container_utils.container_client import ContainerException
@@ -13,7 +12,7 @@ LOG = logging.getLogger(__name__)
13
12
 
14
13
 
15
14
  @lru_cache
16
- def get_main_container_network() -> Optional[str]:
15
+ def get_main_container_network() -> str | None:
17
16
  """
18
17
  Gets the main network of the LocalStack container (if we run in one, bridge otherwise)
19
18
  If there are multiple networks connected to the LocalStack container, we choose the first as "main" network
@@ -50,7 +49,7 @@ def get_main_container_network() -> Optional[str]:
50
49
 
51
50
 
52
51
  @lru_cache
53
- def get_endpoint_for_network(network: Optional[str] = None) -> str:
52
+ def get_endpoint_for_network(network: str | None = None) -> str:
54
53
  """
55
54
  Get the LocalStack endpoint (= IP address) on the given network.
56
55
  If a network is given, it will return the IP address/hostname of LocalStack on that network