localstack-core 4.13.2.dev78__py3-none-any.whl → 4.13.2.dev79__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.
@@ -26,7 +26,7 @@ class LambdaStore(BaseStore):
26
26
  capacity_providers: dict[str, CapacityProvider] = LocalAttribute(default=dict)
27
27
 
28
28
  # maps resource ARNs for EventSourceMappings and CodeSigningConfiguration to tags
29
- TAGS = LocalAttribute(default=TaggingService)
29
+ TAGS: TaggingService = LocalAttribute(default=TaggingService)
30
30
 
31
31
 
32
32
  lambda_stores = AccountRegionBundle("lambda", LambdaStore)
@@ -1624,9 +1624,12 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1624
1624
  "$LATEST version cannot be deleted without deleting the function.", Type="User"
1625
1625
  )
1626
1626
 
1627
+ unqualified_function_arn = api_utils.unqualified_lambda_arn(
1628
+ function_name=function_name, region=region, account=account_id
1629
+ )
1627
1630
  if function_name not in store.functions:
1628
1631
  e = ResourceNotFoundException(
1629
- f"Function not found: {api_utils.unqualified_lambda_arn(function_name=function_name, region=region, account=account_id)}",
1632
+ f"Function not found: {unqualified_function_arn}",
1630
1633
  Type="User",
1631
1634
  )
1632
1635
  raise e
@@ -1643,6 +1646,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
1643
1646
  destroy_code_if_not_used(code=version.config.code, function=function)
1644
1647
  else:
1645
1648
  # delete the whole function
1649
+ self._remove_all_tags(unqualified_function_arn)
1646
1650
  # TODO: introduce locking for safe deletion: We could create a new version at the API layer before
1647
1651
  # the old version gets cleaned up in the internal lambda service.
1648
1652
  function = store.functions.pop(function_name)
@@ -2468,6 +2472,10 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
2468
2472
  raise ResourceNotFoundException(
2469
2473
  "The resource you requested does not exist.", Type="User"
2470
2474
  )
2475
+ # the full deletion of the ESM is happening asynchronously, but we delete the Tags instantly
2476
+ # this behavior is similar to ``get_event_source_mapping`` which will raise right after deletion, but it is not
2477
+ # always the case in AWS. Add more testing and align behavior with ``get_event_source_mapping``.
2478
+ self._remove_all_tags(event_source_mapping["EventSourceMappingArn"])
2471
2479
  esm_worker.delete()
2472
2480
  return {**esm, "State": EsmState.DELETING}
2473
2481
 
@@ -4380,27 +4388,67 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
4380
4388
  # =======================================
4381
4389
  # =============== TAGS ===============
4382
4390
  # =======================================
4383
- # only Function, Event Source Mapping, and Code Signing Config (not currently supported by LocalStack) ARNs an are available for tagging in AWS
4391
+ # only Function, Event Source Mapping, and Code Signing Config (not currently supported by LocalStack) ARNs
4392
+ # are available for tagging in AWS
4384
4393
 
4385
- def _get_tags(self, resource: TaggableResource) -> dict[str, str]:
4386
- state = self.fetch_lambda_store_for_tagging(resource)
4387
- lambda_adapted_tags = {
4388
- tag["Key"]: tag["Value"]
4389
- for tag in state.TAGS.list_tags_for_resource(resource).get("Tags")
4390
- }
4391
- return lambda_adapted_tags
4394
+ def _update_resource_tags(
4395
+ self, resource_arn: str, account_id: str, region: str, tags: dict[str, str]
4396
+ ) -> None:
4397
+ tagger_service = lambda_stores[account_id][region].TAGS
4398
+ tag_svc_adapted_tags = [{"Key": key, "Value": value} for key, value in tags.items()]
4399
+ tagger_service.tag_resource(resource_arn, tag_svc_adapted_tags)
4400
+
4401
+ def _list_resource_tags(
4402
+ self, resource_arn: str, account_id: str, region: str
4403
+ ) -> dict[str, str]:
4404
+ tagger_service = lambda_stores[account_id][region].TAGS
4405
+ return tagger_service.tags.get(resource_arn, {})
4406
+
4407
+ def _remove_resource_tags(
4408
+ self, resource_arn: str, account_id: str, region: str, keys: TagKeyList
4409
+ ) -> None:
4410
+ tagger_service = lambda_stores[account_id][region].TAGS
4411
+ tagger_service.untag_resource(resource_arn, keys)
4392
4412
 
4393
- def _store_tags(self, resource: TaggableResource, tags: dict[str, str]):
4394
- state = self.fetch_lambda_store_for_tagging(resource)
4395
- if len(state.TAGS.tags.get(resource, {}) | tags) > LAMBDA_TAG_LIMIT_PER_RESOURCE:
4413
+ def _remove_all_resource_tags(self, resource_arn: str, account_id: str, region: str) -> None:
4414
+ tagger_service = lambda_stores[account_id][region].TAGS
4415
+ return tagger_service.tags.pop(resource_arn, None)
4416
+
4417
+ def _get_tags(self, resource: TaggableResource) -> dict[str, str]:
4418
+ account_id, region = self._get_account_id_and_region_for_taggable_resource(resource)
4419
+ tags = self._list_resource_tags(resource_arn=resource, account_id=account_id, region=region)
4420
+ return tags
4421
+
4422
+ def _store_tags(self, resource: TaggableResource, tags: dict[str, str]) -> None:
4423
+ account_id, region = self._get_account_id_and_region_for_taggable_resource(resource)
4424
+ existing_tags = self._list_resource_tags(
4425
+ resource_arn=resource, account_id=account_id, region=region
4426
+ )
4427
+ if len({**existing_tags, **tags}) > LAMBDA_TAG_LIMIT_PER_RESOURCE:
4428
+ # note: we cannot use | on `ImmutableDict` and regular `dict`
4396
4429
  raise InvalidParameterValueException(
4397
4430
  "Number of tags exceeds resource tag limit.", Type="User"
4398
4431
  )
4432
+ self._update_resource_tags(
4433
+ resource_arn=resource,
4434
+ account_id=account_id,
4435
+ region=region,
4436
+ tags=tags,
4437
+ )
4399
4438
 
4400
- tag_svc_adapted_tags = [{"Key": key, "Value": value} for key, value in tags.items()]
4401
- state.TAGS.tag_resource(resource, tag_svc_adapted_tags)
4439
+ def _remove_tags(self, resource: TaggableResource, keys: TagKeyList) -> None:
4440
+ account_id, region = self._get_account_id_and_region_for_taggable_resource(resource)
4441
+ self._remove_resource_tags(
4442
+ resource_arn=resource, account_id=account_id, region=region, keys=keys
4443
+ )
4444
+
4445
+ def _remove_all_tags(self, resource: TaggableResource) -> None:
4446
+ account_id, region = self._get_account_id_and_region_for_taggable_resource(resource)
4447
+ self._remove_all_resource_tags(resource_arn=resource, account_id=account_id, region=region)
4402
4448
 
4403
- def fetch_lambda_store_for_tagging(self, resource: TaggableResource) -> LambdaStore:
4449
+ def _get_account_id_and_region_for_taggable_resource(
4450
+ self, resource: TaggableResource
4451
+ ) -> tuple[str, str]:
4404
4452
  """
4405
4453
  Takes a resource ARN for a TaggableResource (Lambda Function, Event Source Mapping, Code Signing Config, or Capacity Provider) and returns a corresponding
4406
4454
  LambdaStore for its region and account.
@@ -4461,7 +4509,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
4461
4509
  _raise_validation_exception()
4462
4510
 
4463
4511
  # If no exceptions are raised, assume ARN and referenced resource is valid for tag operations
4464
- return lambda_stores[account_id][region]
4512
+ return account_id, region
4465
4513
 
4466
4514
  def tag_resource(
4467
4515
  self, context: RequestContext, resource: TaggableResource, tags: Tags, **kwargs
@@ -4498,8 +4546,7 @@ class LambdaProvider(LambdaApi, ServiceLifecycleHook):
4498
4546
  "1 validation error detected: Value null at 'tagKeys' failed to satisfy constraint: Member must not be null"
4499
4547
  ) # should probably be generalized a bit
4500
4548
 
4501
- state = self.fetch_lambda_store_for_tagging(resource)
4502
- state.TAGS.untag_resource(resource, tag_keys)
4549
+ self._remove_tags(resource, tag_keys)
4503
4550
 
4504
4551
  if (resource_id := extract_resource_from_arn(resource)) and resource_id.startswith(
4505
4552
  "function"
localstack/version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '4.13.2.dev78'
32
- __version_tuple__ = version_tuple = (4, 13, 2, 'dev78')
31
+ __version__ = version = '4.13.2.dev79'
32
+ __version_tuple__ = version_tuple = (4, 13, 2, 'dev79')
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: localstack-core
3
- Version: 4.13.2.dev78
3
+ Version: 4.13.2.dev79
4
4
  Summary: The core library and runtime of LocalStack
5
5
  Author-email: LocalStack Contributors <info@localstack.cloud>
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ localstack/deprecations.py,sha256=-3IYgCd6LEC3PjO7hbr3Dg-p0PIS6phjmv1qZnj1uo0,15
4
4
  localstack/openapi.yaml,sha256=jFUzv-NKkJttxb8HRrmKiNYOmJD-zVfPxG3DDMrRwfg,30865
5
5
  localstack/plugins.py,sha256=BIJC9dlo0WbP7lLKkCiGtd_2q5oeqiHZohvoRTcejXM,2457
6
6
  localstack/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- localstack/version.py,sha256=4F3b4oTPGdcwXYqCECPfPyPgNIPqH79AoCRWohk-iMU,721
7
+ localstack/version.py,sha256=a6KrbLgLbP6GRt_axBHHz-6HpRow3Ze3L01TImlrJYE,721
8
8
  localstack/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  localstack/aws/accounts.py,sha256=102zpGowOxo0S6UGMpfjw14QW7WCLVAGsnFK5xFMLoo,3043
10
10
  localstack/aws/app.py,sha256=n9bJCfJRuMz_gLGAH430c3bIQXgUXeWO5NPfcdL2MV8,5145
@@ -548,7 +548,7 @@ localstack/services/lambda_/ldm.py,sha256=a5EJ5BFQbImAOgCcLBY20R-wQPL0UuLqG5mNhn
548
548
  localstack/services/lambda_/networking.py,sha256=H9fq1aYThqXZkOi0fCoJrHI9rm19qgUVxFe3vYloN08,938
549
549
  localstack/services/lambda_/packages.py,sha256=z81Gm3FdyH6ml_iRmJLRKCxj9jFWR11BAI6rvoIXMrY,3976
550
550
  localstack/services/lambda_/plugins.py,sha256=eZsdzZqgEG9EZpd3W8TUdoydTpPXl6JBzJgDx_qeFUU,1275
551
- localstack/services/lambda_/provider.py,sha256=AfnsOUK41KYxS1D6wyC2NsqT75WD1BMVhug9ALdIljc,203684
551
+ localstack/services/lambda_/provider.py,sha256=reDMdVrV-nbMgpCihmdtXxdeRKmYjyRMsCD0xRQ3MPA,206016
552
552
  localstack/services/lambda_/provider_utils.py,sha256=T0f16GVXgB1LvUrR6Sy-hq3r3n1b-pPvGNfpim3nOVw,3176
553
553
  localstack/services/lambda_/runtimes.py,sha256=05pz5fPQyn3JyQOtMMhd-Z5SCO65TzqJI7UhDySInsA,9253
554
554
  localstack/services/lambda_/urlrouter.py,sha256=LNIXNbAKbGdkbfZsKCVrbdtkc0uZzqdYjLpF1jAoCIA,8960
@@ -585,7 +585,7 @@ localstack/services/lambda_/invocation/lambda_models.py,sha256=Bbks7_AGK3Y4keCG3
585
585
  localstack/services/lambda_/invocation/lambda_service.py,sha256=sRG-JV84SPIf4QLia3sETZO9eAdrIAWb1w-WpbYmKw8,34073
586
586
  localstack/services/lambda_/invocation/logs.py,sha256=TD2oSyKAizn5_KHbnav1Rh_hITKxLV8RSrHR7lYgOUM,3798
587
587
  localstack/services/lambda_/invocation/metrics.py,sha256=IOzQguI3v8xl47FP6jMZYL3g9k-NIZEkvldAImdXljQ,1134
588
- localstack/services/lambda_/invocation/models.py,sha256=dxQKlaAAXvbX3-gTAotTRiTSmSI0aHoA5tbWB1q9j1U,1273
588
+ localstack/services/lambda_/invocation/models.py,sha256=Z-WcatCB5Scxsp30-h-9Rj4fAY3kPM0iGqmT_ZFMxpQ,1289
589
589
  localstack/services/lambda_/invocation/plugins.py,sha256=axAnRqpDyPvqh95s21FX7CcYZ5Or6QPJ3LykXu4tpyc,402
590
590
  localstack/services/lambda_/invocation/runtime_executor.py,sha256=C6zQeEq7Z8W3RYW07nZb2KMnTW65SlIy-kkSC-pIOG8,4191
591
591
  localstack/services/lambda_/invocation/version_manager.py,sha256=kyNMcedZ0IniBjDyhnOuBatWRl6mK5V_HT39WRDvVlM,14935
@@ -1311,10 +1311,10 @@ localstack/utils/server/tcp_proxy.py,sha256=y2NJAmvftTiAYsLU_8qe4W5LGqwUw21i90Pu
1311
1311
  localstack/utils/xray/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1312
1312
  localstack/utils/xray/trace_header.py,sha256=ahXk9eonq7LpeENwlqUEPj3jDOCiVRixhntQuxNor-Q,6209
1313
1313
  localstack/utils/xray/traceid.py,sha256=GKO-R2sMMjlrH2UaLPXlQlZ6flbE7ZKb6IZMtMu_M5U,1110
1314
- localstack_core-4.13.2.dev78.data/scripts/localstack-supervisor,sha256=nm1Il2d6ASyOB6Vo4CRHd90w7TK9FdRl9VPp0NN6hUk,6378
1315
- localstack_core-4.13.2.dev78.dist-info/licenses/LICENSE.txt,sha256=3PC-9Z69UsNARuQ980gNR_JsLx8uvMjdG6C7cc4LBYs,606
1316
- localstack_core-4.13.2.dev78.dist-info/METADATA,sha256=GLVAxUqY2yBoaXW8gmQX5mdqxKk3c1ehIghy56D68JU,5867
1317
- localstack_core-4.13.2.dev78.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
1318
- localstack_core-4.13.2.dev78.dist-info/entry_points.txt,sha256=59aAnn8KVHWAHkMg2dOgmgYtRZ-xTX9T4UiIchWgK6k,20975
1319
- localstack_core-4.13.2.dev78.dist-info/top_level.txt,sha256=3sqmK2lGac8nCy8nwsbS5SpIY_izmtWtgaTFKHYVHbI,11
1320
- localstack_core-4.13.2.dev78.dist-info/RECORD,,
1314
+ localstack_core-4.13.2.dev79.data/scripts/localstack-supervisor,sha256=nm1Il2d6ASyOB6Vo4CRHd90w7TK9FdRl9VPp0NN6hUk,6378
1315
+ localstack_core-4.13.2.dev79.dist-info/licenses/LICENSE.txt,sha256=3PC-9Z69UsNARuQ980gNR_JsLx8uvMjdG6C7cc4LBYs,606
1316
+ localstack_core-4.13.2.dev79.dist-info/METADATA,sha256=rvkvbqx71QziMwPZ0N6cvaldmcSCtpyYsfvfDEkNXXM,5867
1317
+ localstack_core-4.13.2.dev79.dist-info/WHEEL,sha256=YCfwYGOYMi5Jhw2fU4yNgwErybb2IX5PEwBKV4ZbdBo,91
1318
+ localstack_core-4.13.2.dev79.dist-info/entry_points.txt,sha256=59aAnn8KVHWAHkMg2dOgmgYtRZ-xTX9T4UiIchWgK6k,20975
1319
+ localstack_core-4.13.2.dev79.dist-info/top_level.txt,sha256=3sqmK2lGac8nCy8nwsbS5SpIY_izmtWtgaTFKHYVHbI,11
1320
+ localstack_core-4.13.2.dev79.dist-info/RECORD,,