Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c865449

Browse files
ericbnleandrodamascena
andauthoredAug 19, 2024··
refactor(data_classes): add from __future__ import annotations (#4939)
* refactor(data_classes): add from __future__ import annotations and update code according to ruff rules TCH, UP006, UP007, UP037 and FA100. * Fix subclassing Dict in Python 3.8 --------- Co-authored-by: Leandro Damascena <[email protected]>
1 parent 4688495 commit c865449

30 files changed

+442
-387
lines changed
 

‎aws_lambda_powertools/utilities/data_classes/active_mq_event.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from __future__ import annotations
2+
13
from functools import cached_property
2-
from typing import Any, Dict, Iterator, Optional
4+
from typing import Any, Iterator
35

46
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
57
from aws_lambda_powertools.utilities.data_classes.shared_functions import base64_decode
@@ -62,32 +64,32 @@ def destination_physicalname(self) -> str:
6264
return self["destination"]["physicalName"]
6365

6466
@property
65-
def delivery_mode(self) -> Optional[int]:
67+
def delivery_mode(self) -> int | None:
6668
"""persistent or non-persistent delivery"""
6769
return self.get("deliveryMode")
6870

6971
@property
70-
def correlation_id(self) -> Optional[str]:
72+
def correlation_id(self) -> str | None:
7173
"""User defined correlation id"""
7274
return self.get("correlationID")
7375

7476
@property
75-
def reply_to(self) -> Optional[str]:
77+
def reply_to(self) -> str | None:
7678
"""User defined reply to"""
7779
return self.get("replyTo")
7880

7981
@property
80-
def get_type(self) -> Optional[str]:
82+
def get_type(self) -> str | None:
8183
"""User defined message type"""
8284
return self.get("type")
8385

8486
@property
85-
def expiration(self) -> Optional[int]:
87+
def expiration(self) -> int | None:
8688
"""Expiration attribute whose value is given in milliseconds"""
8789
return self.get("expiration")
8890

8991
@property
90-
def priority(self) -> Optional[int]:
92+
def priority(self) -> int | None:
9193
"""
9294
JMS defines a ten-level priority value, with 0 as the lowest priority and 9
9395
as the highest. In addition, clients should consider priorities 0-4 as
@@ -110,9 +112,9 @@ class ActiveMQEvent(DictWrapper):
110112
- https://aws.amazon.com/blogs/compute/using-amazon-mq-as-an-event-source-for-aws-lambda/
111113
"""
112114

113-
def __init__(self, data: Dict[str, Any]):
115+
def __init__(self, data: dict[str, Any]):
114116
super().__init__(data)
115-
self._messages: Optional[Iterator[ActiveMQMessage]] = None
117+
self._messages: Iterator[ActiveMQMessage] | None = None
116118

117119
@property
118120
def event_source(self) -> str:

‎aws_lambda_powertools/utilities/data_classes/alb_event.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from typing import Any, Dict, List
1+
from __future__ import annotations
2+
3+
from typing import Any
24

35
from aws_lambda_powertools.shared.headers_serializer import (
46
BaseHeadersSerializer,
@@ -33,19 +35,19 @@ def request_context(self) -> ALBEventRequestContext:
3335
return ALBEventRequestContext(self._data)
3436

3537
@property
36-
def multi_value_query_string_parameters(self) -> Dict[str, List[str]]:
38+
def multi_value_query_string_parameters(self) -> dict[str, list[str]]:
3739
return self.get("multiValueQueryStringParameters") or {}
3840

3941
@property
40-
def resolved_query_string_parameters(self) -> Dict[str, List[str]]:
42+
def resolved_query_string_parameters(self) -> dict[str, list[str]]:
4143
return self.multi_value_query_string_parameters or super().resolved_query_string_parameters
4244

4345
@property
44-
def multi_value_headers(self) -> Dict[str, List[str]]:
46+
def multi_value_headers(self) -> dict[str, list[str]]:
4547
return CaseInsensitiveDict(self.get("multiValueHeaders"))
4648

4749
@property
48-
def resolved_headers_field(self) -> Dict[str, Any]:
50+
def resolved_headers_field(self) -> dict[str, Any]:
4951
return self.multi_value_headers or self.headers
5052

5153
def header_serializer(self) -> BaseHeadersSerializer:

‎aws_lambda_powertools/utilities/data_classes/api_gateway_authorizer_event.py

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
from __future__ import annotations
2+
13
import enum
24
import re
3-
from typing import Any, Dict, List, Optional
5+
from typing import Any
46

57
from aws_lambda_powertools.utilities.data_classes.common import (
68
BaseRequestContext,
@@ -141,19 +143,19 @@ def http_method(self) -> str:
141143
return self["httpMethod"]
142144

143145
@property
144-
def headers(self) -> Dict[str, str]:
146+
def headers(self) -> dict[str, str]:
145147
return CaseInsensitiveDict(self["headers"])
146148

147149
@property
148-
def query_string_parameters(self) -> Dict[str, str]:
150+
def query_string_parameters(self) -> dict[str, str]:
149151
return self["queryStringParameters"]
150152

151153
@property
152-
def path_parameters(self) -> Dict[str, str]:
154+
def path_parameters(self) -> dict[str, str]:
153155
return self["pathParameters"]
154156

155157
@property
156-
def stage_variables(self) -> Dict[str, str]:
158+
def stage_variables(self) -> dict[str, str]:
157159
return self["stageVariables"]
158160

159161
@property
@@ -193,7 +195,7 @@ def parsed_arn(self) -> APIGatewayRouteArn:
193195
return parse_api_gateway_arn(self.route_arn)
194196

195197
@property
196-
def identity_source(self) -> List[str]:
198+
def identity_source(self) -> list[str]:
197199
"""The identity source for which authorization is requested.
198200
199201
For a REQUEST authorizer, this is optional. The value is a set of one or more mapping expressions of the
@@ -217,29 +219,29 @@ def raw_query_string(self) -> str:
217219
return self["rawQueryString"]
218220

219221
@property
220-
def cookies(self) -> List[str]:
222+
def cookies(self) -> list[str]:
221223
"""Cookies"""
222224
return self["cookies"]
223225

224226
@property
225-
def headers(self) -> Dict[str, str]:
227+
def headers(self) -> dict[str, str]:
226228
"""Http headers"""
227229
return CaseInsensitiveDict(self["headers"])
228230

229231
@property
230-
def query_string_parameters(self) -> Dict[str, str]:
232+
def query_string_parameters(self) -> dict[str, str]:
231233
return self["queryStringParameters"]
232234

233235
@property
234236
def request_context(self) -> BaseRequestContextV2:
235237
return BaseRequestContextV2(self._data)
236238

237239
@property
238-
def path_parameters(self) -> Dict[str, str]:
240+
def path_parameters(self) -> dict[str, str]:
239241
return self.get("pathParameters") or {}
240242

241243
@property
242-
def stage_variables(self) -> Dict[str, str]:
244+
def stage_variables(self) -> dict[str, str]:
243245
return self.get("stageVariables") or {}
244246

245247

@@ -253,7 +255,7 @@ class APIGatewayAuthorizerResponseV2:
253255
is authorized to make calls to the GraphQL API. If this value is
254256
true, execution of the GraphQL API continues. If this value is false,
255257
an UnauthorizedException is raised
256-
context: Dict[str, Any], optional
258+
context: dict[str, Any], optional
257259
A JSON object visible as `event.requestContext.authorizer` lambda event
258260
259261
The context object only supports key-value pairs. Nested keys are not supported.
@@ -264,14 +266,14 @@ class APIGatewayAuthorizerResponseV2:
264266
def __init__(
265267
self,
266268
authorize: bool = False,
267-
context: Optional[Dict[str, Any]] = None,
269+
context: dict[str, Any] | None = None,
268270
):
269271
self.authorize = authorize
270272
self.context = context
271273

272274
def asdict(self) -> dict:
273275
"""Return the response as a dict"""
274-
response: Dict = {"isAuthorized": self.authorize}
276+
response: dict = {"isAuthorized": self.authorize}
275277

276278
if self.context:
277279
response["context"] = self.context
@@ -329,8 +331,8 @@ def __init__(
329331
aws_account_id: str,
330332
api_id: str,
331333
stage: str,
332-
context: Optional[Dict] = None,
333-
usage_identifier_key: Optional[str] = None,
334+
context: dict | None = None,
335+
usage_identifier_key: str | None = None,
334336
partition: str = "aws",
335337
):
336338
"""
@@ -357,7 +359,7 @@ def __init__(
357359
greedily expand over '/' or other separators.
358360
See https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_resource.html for more
359361
details.
360-
context : Dict, optional
362+
context : dict, optional
361363
Optional, context.
362364
Note: only names of type string and values of type int, string or boolean are supported
363365
usage_identifier_key: str, optional
@@ -375,18 +377,18 @@ def __init__(
375377
self.stage = stage
376378
self.context = context
377379
self.usage_identifier_key = usage_identifier_key
378-
self._allow_routes: List[Dict] = []
379-
self._deny_routes: List[Dict] = []
380+
self._allow_routes: list[dict] = []
381+
self._deny_routes: list[dict] = []
380382
self._resource_pattern = re.compile(self.path_regex)
381383
self.partition = partition
382384

383385
@staticmethod
384386
def from_route_arn(
385387
arn: str,
386388
principal_id: str,
387-
context: Optional[Dict] = None,
388-
usage_identifier_key: Optional[str] = None,
389-
) -> "APIGatewayAuthorizerResponse":
389+
context: dict | None = None,
390+
usage_identifier_key: str | None = None,
391+
) -> APIGatewayAuthorizerResponse:
390392
parsed_arn = parse_api_gateway_arn(arn)
391393
return APIGatewayAuthorizerResponse(
392394
principal_id,
@@ -398,7 +400,7 @@ def from_route_arn(
398400
usage_identifier_key,
399401
)
400402

401-
def _add_route(self, effect: str, http_method: str, resource: str, conditions: Optional[List[Dict]] = None):
403+
def _add_route(self, effect: str, http_method: str, resource: str, conditions: list[dict] | None = None):
402404
"""Adds a route to the internal lists of allowed or denied routes. Each object in
403405
the internal list contains a resource ARN and a condition statement. The condition
404406
statement can be null."""
@@ -427,17 +429,17 @@ def _add_route(self, effect: str, http_method: str, resource: str, conditions: O
427429
self._deny_routes.append(route)
428430

429431
@staticmethod
430-
def _get_empty_statement(effect: str) -> Dict[str, Any]:
432+
def _get_empty_statement(effect: str) -> dict[str, Any]:
431433
"""Returns an empty statement object prepopulated with the correct action and the desired effect."""
432434
return {"Action": "execute-api:Invoke", "Effect": effect.capitalize(), "Resource": []}
433435

434-
def _get_statement_for_effect(self, effect: str, routes: List[Dict]) -> List[Dict]:
436+
def _get_statement_for_effect(self, effect: str, routes: list[dict]) -> list[dict]:
435437
"""This function loops over an array of objects containing a `resourceArn` and
436438
`conditions` statement and generates the array of statements for the policy."""
437439
if not routes:
438440
return []
439441

440-
statements: List[Dict] = []
442+
statements: list[dict] = []
441443
statement = self._get_empty_statement(effect)
442444

443445
for route in routes:
@@ -476,31 +478,31 @@ def deny_all_routes(self, http_method: str = HttpVerb.ALL.value):
476478

477479
self._add_route(effect="Deny", http_method=http_method, resource="*")
478480

479-
def allow_route(self, http_method: str, resource: str, conditions: Optional[List[Dict]] = None):
481+
def allow_route(self, http_method: str, resource: str, conditions: list[dict] | None = None):
480482
"""Adds an API Gateway method (Http verb + Resource path) to the list of allowed
481483
methods for the policy.
482484
483485
Optionally includes a condition for the policy statement. More on AWS policy
484486
conditions here: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html#Condition"""
485487
self._add_route(effect="Allow", http_method=http_method, resource=resource, conditions=conditions)
486488

487-
def deny_route(self, http_method: str, resource: str, conditions: Optional[List[Dict]] = None):
489+
def deny_route(self, http_method: str, resource: str, conditions: list[dict] | None = None):
488490
"""Adds an API Gateway method (Http verb + Resource path) to the list of denied
489491
methods for the policy.
490492
491493
Optionally includes a condition for the policy statement. More on AWS policy
492494
conditions here: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html#Condition"""
493495
self._add_route(effect="Deny", http_method=http_method, resource=resource, conditions=conditions)
494496

495-
def asdict(self) -> Dict[str, Any]:
497+
def asdict(self) -> dict[str, Any]:
496498
"""Generates the policy document based on the internal lists of allowed and denied
497499
conditions. This will generate a policy with two main statements for the effect:
498500
one statement for Allow and one statement for Deny.
499501
Methods that includes conditions will have their own statement in the policy."""
500502
if len(self._allow_routes) == 0 and len(self._deny_routes) == 0:
501503
raise ValueError("No statements defined for the policy")
502504

503-
response: Dict[str, Any] = {
505+
response: dict[str, Any] = {
504506
"principalId": self.principal_id,
505507
"policyDocument": {"Version": "2012-10-17", "Statement": []},
506508
}

‎aws_lambda_powertools/utilities/data_classes/api_gateway_proxy_event.py

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from __future__ import annotations
2+
13
from functools import cached_property
2-
from typing import Any, Dict, List, Optional
4+
from typing import Any
35

46
from aws_lambda_powertools.shared.headers_serializer import (
57
BaseHeadersSerializer,
@@ -17,11 +19,11 @@
1719

1820
class APIGatewayEventAuthorizer(DictWrapper):
1921
@property
20-
def claims(self) -> Dict[str, Any]:
22+
def claims(self) -> dict[str, Any]:
2123
return self.get("claims") or {} # key might exist but can be `null`
2224

2325
@property
24-
def scopes(self) -> List[str]:
26+
def scopes(self) -> list[str]:
2527
return self.get("scopes") or [] # key might exist but can be `null`
2628

2729
@property
@@ -31,11 +33,11 @@ def principal_id(self) -> str:
3133
return self.get("principalId") or "" # key might exist but can be `null`
3234

3335
@property
34-
def integration_latency(self) -> Optional[int]:
36+
def integration_latency(self) -> int | None:
3537
"""The authorizer latency in ms."""
3638
return self.get("integrationLatency")
3739

38-
def get_context(self) -> Dict[str, Any]:
40+
def get_context(self) -> dict[str, Any]:
3941
"""Retrieve the authorization context details injected by a Lambda Authorizer.
4042
4143
Example
@@ -49,45 +51,45 @@ def get_context(self) -> Dict[str, Any]:
4951
5052
Returns:
5153
--------
52-
Dict[str, Any]
54+
dict[str, Any]
5355
A dictionary containing Lambda authorization context details.
5456
"""
5557
return self._data
5658

5759

5860
class APIGatewayEventRequestContext(BaseRequestContext):
5961
@property
60-
def connected_at(self) -> Optional[int]:
62+
def connected_at(self) -> int | None:
6163
"""The Epoch-formatted connection time. (WebSocket API)"""
6264
return self["requestContext"].get("connectedAt")
6365

6466
@property
65-
def connection_id(self) -> Optional[str]:
67+
def connection_id(self) -> str | None:
6668
"""A unique ID for the connection that can be used to make a callback to the client. (WebSocket API)"""
6769
return self["requestContext"].get("connectionId")
6870

6971
@property
70-
def event_type(self) -> Optional[str]:
72+
def event_type(self) -> str | None:
7173
"""The event type: `CONNECT`, `MESSAGE`, or `DISCONNECT`. (WebSocket API)"""
7274
return self["requestContext"].get("eventType")
7375

7476
@property
75-
def message_direction(self) -> Optional[str]:
77+
def message_direction(self) -> str | None:
7678
"""Message direction (WebSocket API)"""
7779
return self["requestContext"].get("messageDirection")
7880

7981
@property
80-
def message_id(self) -> Optional[str]:
82+
def message_id(self) -> str | None:
8183
"""A unique server-side ID for a message. Available only when the `eventType` is `MESSAGE`."""
8284
return self["requestContext"].get("messageId")
8385

8486
@property
85-
def operation_name(self) -> Optional[str]:
87+
def operation_name(self) -> str | None:
8688
"""The name of the operation being performed"""
8789
return self["requestContext"].get("operationName")
8890

8991
@property
90-
def route_key(self) -> Optional[str]:
92+
def route_key(self) -> str | None:
9193
"""The selected route key."""
9294
return self["requestContext"].get("routeKey")
9395

@@ -114,34 +116,34 @@ def resource(self) -> str:
114116
return self["resource"]
115117

116118
@property
117-
def multi_value_headers(self) -> Dict[str, List[str]]:
119+
def multi_value_headers(self) -> dict[str, list[str]]:
118120
return CaseInsensitiveDict(self.get("multiValueHeaders"))
119121

120122
@property
121-
def multi_value_query_string_parameters(self) -> Dict[str, List[str]]:
123+
def multi_value_query_string_parameters(self) -> dict[str, list[str]]:
122124
return self.get("multiValueQueryStringParameters") or {} # key might exist but can be `null`
123125

124126
@property
125-
def resolved_query_string_parameters(self) -> Dict[str, List[str]]:
127+
def resolved_query_string_parameters(self) -> dict[str, list[str]]:
126128
if self.multi_value_query_string_parameters:
127129
return self.multi_value_query_string_parameters
128130

129131
return super().resolved_query_string_parameters
130132

131133
@property
132-
def resolved_headers_field(self) -> Dict[str, Any]:
134+
def resolved_headers_field(self) -> dict[str, Any]:
133135
return self.multi_value_headers or self.headers
134136

135137
@property
136138
def request_context(self) -> APIGatewayEventRequestContext:
137139
return APIGatewayEventRequestContext(self._data)
138140

139141
@property
140-
def path_parameters(self) -> Dict[str, str]:
142+
def path_parameters(self) -> dict[str, str]:
141143
return self.get("pathParameters") or {}
142144

143145
@property
144-
def stage_variables(self) -> Dict[str, str]:
146+
def stage_variables(self) -> dict[str, str]:
145147
return self.get("stageVariables") or {}
146148

147149
def header_serializer(self) -> BaseHeadersSerializer:
@@ -164,11 +166,11 @@ def caller_id(self) -> str:
164166
"""The principal identifier of the caller making the request."""
165167
return self.get("callerId") or "" # key might exist but can be `null`
166168

167-
def _cognito_identity(self) -> Dict:
169+
def _cognito_identity(self) -> dict:
168170
return self.get("cognitoIdentity") or {} # not available in FunctionURL; key might exist but can be `null`
169171

170172
@property
171-
def cognito_amr(self) -> List[str]:
173+
def cognito_amr(self) -> list[str]:
172174
"""This represents how the user was authenticated.
173175
AMR stands for Authentication Methods References as per the openid spec"""
174176
return self._cognito_identity().get("amr", [])
@@ -203,21 +205,21 @@ def user_id(self) -> str:
203205

204206
class RequestContextV2Authorizer(DictWrapper):
205207
@property
206-
def jwt_claim(self) -> Dict[str, Any]:
208+
def jwt_claim(self) -> dict[str, Any]:
207209
jwt = self.get("jwt") or {} # not available in FunctionURL; key might exist but can be `null`
208210
return jwt.get("claims") or {} # key might exist but can be `null`
209211

210212
@property
211-
def jwt_scopes(self) -> List[str]:
213+
def jwt_scopes(self) -> list[str]:
212214
jwt = self.get("jwt") or {} # not available in FunctionURL; key might exist but can be `null`
213215
return jwt.get("scopes", [])
214216

215217
@property
216-
def get_lambda(self) -> Dict[str, Any]:
218+
def get_lambda(self) -> dict[str, Any]:
217219
"""Lambda authorization context details"""
218220
return self.get("lambda") or {} # key might exist but can be `null`
219221

220-
def get_context(self) -> Dict[str, Any]:
222+
def get_context(self) -> dict[str, Any]:
221223
"""Retrieve the authorization context details injected by a Lambda Authorizer.
222224
223225
Example
@@ -231,7 +233,7 @@ def get_context(self) -> Dict[str, Any]:
231233
232234
Returns:
233235
--------
234-
Dict[str, Any]
236+
dict[str, Any]
235237
A dictionary containing Lambda authorization context details.
236238
"""
237239
return self.get_lambda
@@ -284,19 +286,19 @@ def raw_query_string(self) -> str:
284286
return self["rawQueryString"]
285287

286288
@property
287-
def cookies(self) -> List[str]:
289+
def cookies(self) -> list[str]:
288290
return self.get("cookies") or []
289291

290292
@property
291293
def request_context(self) -> RequestContextV2:
292294
return RequestContextV2(self._data)
293295

294296
@property
295-
def path_parameters(self) -> Dict[str, str]:
297+
def path_parameters(self) -> dict[str, str]:
296298
return self.get("pathParameters") or {}
297299

298300
@property
299-
def stage_variables(self) -> Dict[str, str]:
301+
def stage_variables(self) -> dict[str, str]:
300302
return self.get("stageVariables") or {}
301303

302304
@property
@@ -315,5 +317,5 @@ def header_serializer(self):
315317
return HttpApiHeadersSerializer()
316318

317319
@cached_property
318-
def resolved_headers_field(self) -> Dict[str, Any]:
320+
def resolved_headers_field(self) -> dict[str, Any]:
319321
return CaseInsensitiveDict((k, v.split(",") if "," in v else v) for k, v in self.headers.items())

‎aws_lambda_powertools/utilities/data_classes/appsync_authorizer_event.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from typing import Any, Dict, List, Optional
1+
from __future__ import annotations
2+
3+
from typing import Any
24

35
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
46

@@ -27,12 +29,12 @@ def query_string(self) -> str:
2729
return self["requestContext"]["queryString"]
2830

2931
@property
30-
def operation_name(self) -> Optional[str]:
32+
def operation_name(self) -> str | None:
3133
"""GraphQL operation name, optional"""
3234
return self["requestContext"].get("operationName")
3335

3436
@property
35-
def variables(self) -> Dict:
37+
def variables(self) -> dict:
3638
"""GraphQL variables"""
3739
return self["requestContext"]["variables"]
3840

@@ -73,13 +75,13 @@ class AppSyncAuthorizerResponse:
7375
cached for. If no value is returned, the value from the API (if configured)
7476
or the default of 300 seconds (five minutes) is used. If this is 0, the response
7577
is not cached.
76-
resolver_context: Dict[str, Any], optional
78+
resolver_context: dict[str, Any], optional
7779
A JSON object visible as `$ctx.identity.resolverContext` in resolver templates
7880
7981
The resolverContext object only supports key-value pairs. Nested keys are not supported.
8082
8183
Warning: The total size of this JSON object must not exceed 5MB.
82-
deny_fields: List[str], optional
84+
deny_fields: list[str], optional
8385
A list of fields that will be set to `null` regardless of the resolver's return.
8486
8587
A field is either `TypeName.FieldName`, or an ARN such as
@@ -91,9 +93,9 @@ class AppSyncAuthorizerResponse:
9193
def __init__(
9294
self,
9395
authorize: bool = False,
94-
max_age: Optional[int] = None,
95-
resolver_context: Optional[Dict[str, Any]] = None,
96-
deny_fields: Optional[List[str]] = None,
96+
max_age: int | None = None,
97+
resolver_context: dict[str, Any] | None = None,
98+
deny_fields: list[str] | None = None,
9799
):
98100
self.authorize = authorize
99101
self.max_age = max_age
@@ -102,7 +104,7 @@ def __init__(
102104

103105
def asdict(self) -> dict:
104106
"""Return the response as a dict"""
105-
response: Dict = {"isAuthorized": self.authorize}
107+
response: dict = {"isAuthorized": self.authorize}
106108

107109
if self.max_age is not None:
108110
response["ttlOverride"] = self.max_age

‎aws_lambda_powertools/utilities/data_classes/appsync_resolver_event.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
from typing import Any, Dict, List, Optional, Union
1+
from __future__ import annotations
2+
3+
from typing import Any
24

35
from aws_lambda_powertools.utilities.data_classes.common import CaseInsensitiveDict, DictWrapper
46

57

6-
def get_identity_object(identity: Optional[dict]) -> Any:
8+
def get_identity_object(identity: dict | None) -> Any:
79
"""Get the identity object based on the best detected type"""
810
# API_KEY authorization
911
if identity is None:
@@ -21,7 +23,7 @@ class AppSyncIdentityIAM(DictWrapper):
2123
"""AWS_IAM authorization"""
2224

2325
@property
24-
def source_ip(self) -> List[str]:
26+
def source_ip(self) -> list[str]:
2527
"""The source IP address of the caller received by AWS AppSync."""
2628
return self["sourceIp"]
2729

@@ -66,7 +68,7 @@ class AppSyncIdentityCognito(DictWrapper):
6668
"""AMAZON_COGNITO_USER_POOLS authorization"""
6769

6870
@property
69-
def source_ip(self) -> List[str]:
71+
def source_ip(self) -> list[str]:
7072
"""The source IP address of the caller received by AWS AppSync."""
7173
return self["sourceIp"]
7274

@@ -81,7 +83,7 @@ def sub(self) -> str:
8183
return self["sub"]
8284

8385
@property
84-
def claims(self) -> Dict[str, str]:
86+
def claims(self) -> dict[str, str]:
8587
"""The claims that the user has."""
8688
return self["claims"]
8789

@@ -91,7 +93,7 @@ def default_auth_strategy(self) -> str:
9193
return self["defaultAuthStrategy"]
9294

9395
@property
94-
def groups(self) -> List[str]:
96+
def groups(self) -> list[str]:
9597
"""List of OIDC groups"""
9698
return self["groups"]
9799

@@ -115,18 +117,18 @@ def parent_type_name(self) -> str:
115117
return self["parentTypeName"]
116118

117119
@property
118-
def variables(self) -> Dict[str, str]:
120+
def variables(self) -> dict[str, str]:
119121
"""A map which holds all variables that are passed into the GraphQL request."""
120122
return self.get("variables") or {}
121123

122124
@property
123-
def selection_set_list(self) -> List[str]:
125+
def selection_set_list(self) -> list[str]:
124126
"""A list representation of the fields in the GraphQL selection set. Fields that are aliased will
125127
only be referenced by the alias name, not the field name."""
126128
return self.get("selectionSetList") or []
127129

128130
@property
129-
def selection_set_graphql(self) -> Optional[str]:
131+
def selection_set_graphql(self) -> str | None:
130132
"""A string representation of the selection set, formatted as GraphQL schema definition language (SDL).
131133
Although fragments are not be merged into the selection set, inline fragments are preserved."""
132134
return self.get("selectionSetGraphQL")
@@ -147,7 +149,7 @@ class AppSyncResolverEvent(DictWrapper):
147149
def __init__(self, data: dict):
148150
super().__init__(data)
149151

150-
info: Optional[dict] = data.get("info")
152+
info: dict | None = data.get("info")
151153
if not info:
152154
info = {"fieldName": self.get("fieldName"), "parentTypeName": self.get("typeName")}
153155

@@ -164,12 +166,12 @@ def field_name(self) -> str:
164166
return self.info.field_name
165167

166168
@property
167-
def arguments(self) -> Dict[str, Any]:
169+
def arguments(self) -> dict[str, Any]:
168170
"""A map that contains all GraphQL arguments for this field."""
169171
return self["arguments"]
170172

171173
@property
172-
def identity(self) -> Union[None, AppSyncIdentityIAM, AppSyncIdentityCognito]:
174+
def identity(self) -> AppSyncIdentityIAM | AppSyncIdentityCognito | None:
173175
"""An object that contains information about the caller.
174176
175177
Depending on the type of identify found:
@@ -181,17 +183,17 @@ def identity(self) -> Union[None, AppSyncIdentityIAM, AppSyncIdentityCognito]:
181183
return get_identity_object(self.get("identity"))
182184

183185
@property
184-
def source(self) -> Dict[str, Any]:
186+
def source(self) -> dict[str, Any]:
185187
"""A map that contains the resolution of the parent field."""
186188
return self.get("source") or {}
187189

188190
@property
189-
def request_headers(self) -> Dict[str, str]:
191+
def request_headers(self) -> dict[str, str]:
190192
"""Request headers"""
191193
return CaseInsensitiveDict(self["request"]["headers"])
192194

193195
@property
194-
def prev_result(self) -> Optional[Dict[str, Any]]:
196+
def prev_result(self) -> dict[str, Any] | None:
195197
"""It represents the result of whatever previous operation was executed in a pipeline resolver."""
196198
prev = self.get("prev")
197199
if not prev:

‎aws_lambda_powertools/utilities/data_classes/aws_config_rule_event.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from __future__ import annotations
22

3-
from typing import Any, Dict, List, Optional
3+
from typing import Any
44

55
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
66

@@ -36,7 +36,7 @@ def get_invoke_event(
3636

3737
class AWSConfigConfigurationChanged(DictWrapper):
3838
@property
39-
def configuration_item_diff(self) -> Dict:
39+
def configuration_item_diff(self) -> dict:
4040
"""The configuration item diff of the ConfigurationItemChangeNotification event."""
4141
return self["configurationItemDiff"]
4242

@@ -46,7 +46,7 @@ def configuration_item(self) -> AWSConfigConfigurationItemChanged:
4646
return AWSConfigConfigurationItemChanged(self["configurationItem"])
4747

4848
@property
49-
def raw_configuration_item(self) -> Dict:
49+
def raw_configuration_item(self) -> dict:
5050
"""The raw configuration item of the ConfigurationItemChangeNotification event."""
5151
return self["configurationItem"]
5252

@@ -68,27 +68,27 @@ def notification_creation_time(self) -> str:
6868

6969
class AWSConfigConfigurationItemChanged(DictWrapper):
7070
@property
71-
def related_events(self) -> List:
71+
def related_events(self) -> list:
7272
"""The related events of the ConfigurationItemChangeNotification event."""
7373
return self["relatedEvents"]
7474

7575
@property
76-
def relationships(self) -> List:
76+
def relationships(self) -> list:
7777
"""The relationships of the ConfigurationItemChangeNotification event."""
7878
return self["relationships"]
7979

8080
@property
81-
def configuration(self) -> Dict:
81+
def configuration(self) -> dict:
8282
"""The configuration of the ConfigurationItemChangeNotification event."""
8383
return self["configuration"]
8484

8585
@property
86-
def supplementary_configuration(self) -> Dict:
86+
def supplementary_configuration(self) -> dict:
8787
"""The supplementary configuration of the ConfigurationItemChangeNotification event."""
8888
return self["supplementaryConfiguration"]
8989

9090
@property
91-
def tags(self) -> Dict:
91+
def tags(self) -> dict:
9292
"""The tags of the ConfigurationItemChangeNotification event."""
9393
return self["tags"]
9494

@@ -286,10 +286,10 @@ class AWSConfigRuleEvent(DictWrapper):
286286
- https://docs.aws.amazon.com/config/latest/developerguide/evaluate-config_develop-rules_lambda-functions.html
287287
"""
288288

289-
def __init__(self, data: Dict[str, Any]):
289+
def __init__(self, data: dict[str, Any]):
290290
super().__init__(data)
291-
self._invoking_event: Optional[Any] = None
292-
self._rule_parameters: Optional[Any] = None
291+
self._invoking_event: Any | None = None
292+
self._rule_parameters: Any | None = None
293293

294294
@property
295295
def version(self) -> str:
@@ -312,7 +312,7 @@ def raw_invoking_event(self) -> str:
312312
return self["invokingEvent"]
313313

314314
@property
315-
def rule_parameters(self) -> Dict:
315+
def rule_parameters(self) -> dict:
316316
"""The parameters of the event."""
317317
if self._rule_parameters is None:
318318
self._rule_parameters = self._json_deserializer(self["ruleParameters"])
@@ -355,6 +355,6 @@ def accountid(self) -> str:
355355
return self["accountId"]
356356

357357
@property
358-
def evalution_mode(self) -> Optional[str]:
358+
def evalution_mode(self) -> str | None:
359359
"""The evalution mode of the event."""
360360
return self.get("evaluationMode")

‎aws_lambda_powertools/utilities/data_classes/bedrock_agent_event.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from __future__ import annotations
2+
13
from functools import cached_property
2-
from typing import Any, Dict, List, Optional
4+
from typing import Any
35

46
from aws_lambda_powertools.utilities.data_classes.common import BaseProxyEvent, DictWrapper
57

@@ -38,13 +40,13 @@ def value(self) -> str:
3840

3941
class BedrockAgentRequestMedia(DictWrapper):
4042
@property
41-
def properties(self) -> List[BedrockAgentProperty]:
43+
def properties(self) -> list[BedrockAgentProperty]:
4244
return [BedrockAgentProperty(x) for x in self["properties"]]
4345

4446

4547
class BedrockAgentRequestBody(DictWrapper):
4648
@property
47-
def content(self) -> Dict[str, BedrockAgentRequestMedia]:
49+
def content(self) -> dict[str, BedrockAgentRequestMedia]:
4850
return {k: BedrockAgentRequestMedia(v) for k, v in self["content"].items()}
4951

5052

@@ -80,24 +82,24 @@ def http_method(self) -> str:
8082
return self["httpMethod"]
8183

8284
@property
83-
def parameters(self) -> List[BedrockAgentProperty]:
85+
def parameters(self) -> list[BedrockAgentProperty]:
8486
parameters = self.get("parameters") or []
8587
return [BedrockAgentProperty(x) for x in parameters]
8688

8789
@property
88-
def request_body(self) -> Optional[BedrockAgentRequestBody]:
90+
def request_body(self) -> BedrockAgentRequestBody | None:
8991
return BedrockAgentRequestBody(self["requestBody"]) if self.get("requestBody") else None
9092

9193
@property
9294
def agent(self) -> BedrockAgentInfo:
9395
return BedrockAgentInfo(self["agent"])
9496

9597
@property
96-
def session_attributes(self) -> Dict[str, str]:
98+
def session_attributes(self) -> dict[str, str]:
9799
return self["sessionAttributes"]
98100

99101
@property
100-
def prompt_session_attributes(self) -> Dict[str, str]:
102+
def prompt_session_attributes(self) -> dict[str, str]:
101103
return self["promptSessionAttributes"]
102104

103105
# The following methods add compatibility with BaseProxyEvent
@@ -106,14 +108,14 @@ def path(self) -> str:
106108
return self["apiPath"]
107109

108110
@cached_property
109-
def query_string_parameters(self) -> Dict[str, str]:
111+
def query_string_parameters(self) -> dict[str, str]:
110112
# In Bedrock Agent events, query string parameters are passed as undifferentiated parameters,
111113
# together with the other parameters. So we just return all parameters here.
112114
parameters = self.get("parameters") or []
113115
return {x["name"]: x["value"] for x in parameters}
114116

115117
@property
116-
def resolved_headers_field(self) -> Dict[str, Any]:
118+
def resolved_headers_field(self) -> dict[str, Any]:
117119
return {}
118120

119121
@cached_property

‎aws_lambda_powertools/utilities/data_classes/cloud_watch_alarm_event.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
from functools import cached_property
4-
from typing import Any, List, Literal, Optional
4+
from typing import Any, Literal
55

66
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
77

@@ -30,23 +30,23 @@ def reason_data(self) -> str:
3030
return self["reasonData"]
3131

3232
@cached_property
33-
def reason_data_decoded(self) -> Optional[Any]:
33+
def reason_data_decoded(self) -> Any | None:
3434
"""
3535
Deserialized version of reason_data.
3636
"""
3737

3838
return self._json_deserializer(self.reason_data) if self.reason_data else None
3939

4040
@property
41-
def actions_suppressed_by(self) -> Optional[Literal["Alarm", "ExtensionPeriod", "WaitPeriod"]]:
41+
def actions_suppressed_by(self) -> Literal["Alarm", "ExtensionPeriod", "WaitPeriod"] | None:
4242
"""
4343
Describes why the actions when the value is `ALARM` are suppressed in a composite
4444
alarm.
4545
"""
4646
return self.get("actionsSuppressedBy", None)
4747

4848
@property
49-
def actions_suppressed_reason(self) -> Optional[str]:
49+
def actions_suppressed_reason(self) -> str | None:
5050
"""
5151
Captures the reason for action suppression.
5252
"""
@@ -69,14 +69,14 @@ def metric_id(self) -> str:
6969
return self["id"]
7070

7171
@property
72-
def expression(self) -> Optional[str]:
72+
def expression(self) -> str | None:
7373
"""
7474
Optional expression of the alarm metric.
7575
"""
7676
return self.get("expression", None)
7777

7878
@property
79-
def label(self) -> Optional[str]:
79+
def label(self) -> str | None:
8080
"""
8181
Optional label of the alarm metric.
8282
"""
@@ -96,21 +96,21 @@ def metric_stat(self) -> CloudWatchAlarmMetricStat:
9696

9797
class CloudWatchAlarmMetricStat(DictWrapper):
9898
@property
99-
def period(self) -> Optional[int]:
99+
def period(self) -> int | None:
100100
"""
101101
Metric evaluation period, in seconds.
102102
"""
103103
return self.get("period", None)
104104

105105
@property
106-
def stat(self) -> Optional[str]:
106+
def stat(self) -> str | None:
107107
"""
108108
Statistical aggregation of metric points, e.g. Average, SampleCount, etc.
109109
"""
110110
return self.get("stat", None)
111111

112112
@property
113-
def unit(self) -> Optional[str]:
113+
def unit(self) -> str | None:
114114
"""
115115
Unit for metric.
116116
"""
@@ -156,42 +156,42 @@ def configuration(self) -> CloudWatchAlarmConfiguration:
156156

157157
class CloudWatchAlarmConfiguration(DictWrapper):
158158
@property
159-
def description(self) -> Optional[str]:
159+
def description(self) -> str | None:
160160
"""
161161
Optional description for the Alarm.
162162
"""
163163
return self.get("description", None)
164164

165165
@property
166-
def alarm_rule(self) -> Optional[str]:
166+
def alarm_rule(self) -> str | None:
167167
"""
168168
Optional description for the Alarm rule in case of composite alarm.
169169
"""
170170
return self.get("alarmRule", None)
171171

172172
@property
173-
def alarm_actions_suppressor(self) -> Optional[str]:
173+
def alarm_actions_suppressor(self) -> str | None:
174174
"""
175175
Optional action suppression for the Alarm rule in case of composite alarm.
176176
"""
177177
return self.get("actionsSuppressor", None)
178178

179179
@property
180-
def alarm_actions_suppressor_wait_period(self) -> Optional[str]:
180+
def alarm_actions_suppressor_wait_period(self) -> str | None:
181181
"""
182182
Optional action suppression wait period for the Alarm rule in case of composite alarm.
183183
"""
184184
return self.get("actionsSuppressorWaitPeriod", None)
185185

186186
@property
187-
def alarm_actions_suppressor_extension_period(self) -> Optional[str]:
187+
def alarm_actions_suppressor_extension_period(self) -> str | None:
188188
"""
189189
Optional action suppression extension period for the Alarm rule in case of composite alarm.
190190
"""
191191
return self.get("actionsSuppressorExtensionPeriod", None)
192192

193193
@property
194-
def metrics(self) -> List[CloudWatchAlarmMetric]:
194+
def metrics(self) -> list[CloudWatchAlarmMetric]:
195195
"""
196196
The metrics evaluated for the Alarm.
197197
"""

‎aws_lambda_powertools/utilities/data_classes/cloud_watch_custom_widget_event.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from typing import Any, Dict, Optional
1+
from __future__ import annotations
2+
3+
from typing import Any
24

35
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
46

@@ -37,17 +39,17 @@ def end(self) -> int:
3739
return self["end"]
3840

3941
@property
40-
def relative_start(self) -> Optional[int]:
42+
def relative_start(self) -> int | None:
4143
"""The relative start time within the time range"""
4244
return self.get("relativeStart")
4345

4446
@property
45-
def zoom_start(self) -> Optional[int]:
47+
def zoom_start(self) -> int | None:
4648
"""The start time within the zoomed time range"""
4749
return (self.get("zoom") or {}).get("start")
4850

4951
@property
50-
def zoom_end(self) -> Optional[int]:
52+
def zoom_end(self) -> int | None:
5153
"""The end time within the zoomed time range"""
5254
return (self.get("zoom") or {}).get("end")
5355

@@ -114,12 +116,12 @@ def title(self) -> str:
114116
return self["title"]
115117

116118
@property
117-
def params(self) -> Dict[str, Any]:
119+
def params(self) -> dict[str, Any]:
118120
"""Get widget parameters"""
119121
return self["params"]
120122

121123
@property
122-
def forms(self) -> Dict[str, Any]:
124+
def forms(self) -> dict[str, Any]:
123125
"""Get widget form data"""
124126
return self["forms"]["all"]
125127

@@ -150,7 +152,7 @@ def describe(self) -> bool:
150152
return bool(self.get("describe", False))
151153

152154
@property
153-
def widget_context(self) -> Optional[CloudWatchWidgetContext]:
155+
def widget_context(self) -> CloudWatchWidgetContext | None:
154156
"""The widget context"""
155157
if self.get("widgetContext"):
156158
return CloudWatchWidgetContext(self["widgetContext"])

‎aws_lambda_powertools/utilities/data_classes/cloud_watch_logs_event.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
from __future__ import annotations
2+
13
import base64
24
import zlib
3-
from typing import Dict, List, Optional
45

56
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
67

@@ -23,7 +24,7 @@ def message(self) -> str:
2324
return self["message"]
2425

2526
@property
26-
def extracted_fields(self) -> Dict[str, str]:
27+
def extracted_fields(self) -> dict[str, str]:
2728
"""Get the `extractedFields` property"""
2829
return self.get("extractedFields") or {}
2930

@@ -45,7 +46,7 @@ def log_stream(self) -> str:
4546
return self["logStream"]
4647

4748
@property
48-
def subscription_filters(self) -> List[str]:
49+
def subscription_filters(self) -> list[str]:
4950
"""The list of subscription filter names that matched with the originating log data."""
5051
return self["subscriptionFilters"]
5152

@@ -59,12 +60,12 @@ def message_type(self) -> str:
5960
return self["messageType"]
6061

6162
@property
62-
def policy_level(self) -> Optional[str]:
63+
def policy_level(self) -> str | None:
6364
"""The level at which the policy was enforced."""
6465
return self.get("policyLevel")
6566

6667
@property
67-
def log_events(self) -> List[CloudWatchLogsLogEvent]:
68+
def log_events(self) -> list[CloudWatchLogsLogEvent]:
6869
"""The actual log data, represented as an array of log event records.
6970
7071
The ID property is a unique identifier for every log event.

‎aws_lambda_powertools/utilities/data_classes/cloudformation_custom_resource_event.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from typing import Any, Dict, Literal
1+
from __future__ import annotations
2+
3+
from typing import Any, Literal
24

35
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
46

@@ -37,9 +39,9 @@ def resource_type(self) -> str:
3739
return self["ResourceType"]
3840

3941
@property
40-
def resource_properties(self) -> Dict[str, Any]:
42+
def resource_properties(self) -> dict[str, Any]:
4143
return self.get("ResourceProperties") or {}
4244

4345
@property
44-
def old_resource_properties(self) -> Dict[str, Any]:
46+
def old_resource_properties(self) -> dict[str, Any]:
4547
return self.get("OldResourceProperties") or {}

‎aws_lambda_powertools/utilities/data_classes/code_pipeline_job_event.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
from __future__ import annotations
2+
13
import tempfile
24
import zipfile
35
from functools import cached_property
4-
from typing import Any, Dict, List, Optional
6+
from typing import Any
57
from urllib.parse import unquote_plus
68

79
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
@@ -14,12 +16,12 @@ def function_name(self) -> str:
1416
return self["FunctionName"]
1517

1618
@property
17-
def user_parameters(self) -> Optional[str]:
19+
def user_parameters(self) -> str | None:
1820
"""User parameters"""
1921
return self.get("UserParameters", None)
2022

2123
@cached_property
22-
def decoded_user_parameters(self) -> Dict[str, Any]:
24+
def decoded_user_parameters(self) -> dict[str, Any]:
2325
"""Json Decoded user parameters"""
2426
if self.user_parameters is not None:
2527
return self._json_deserializer(self.user_parameters)
@@ -69,7 +71,7 @@ def name(self) -> str:
6971
return self["name"]
7072

7173
@property
72-
def revision(self) -> Optional[str]:
74+
def revision(self) -> str | None:
7375
return self.get("revision")
7476

7577
@property
@@ -93,7 +95,7 @@ def session_token(self) -> str:
9395
return self["sessionToken"]
9496

9597
@property
96-
def expiration_time(self) -> Optional[int]:
98+
def expiration_time(self) -> int | None:
9799
return self.get("expirationTime")
98100

99101

@@ -116,12 +118,12 @@ def action_configuration(self) -> CodePipelineActionConfiguration:
116118
return CodePipelineActionConfiguration(self["actionConfiguration"])
117119

118120
@property
119-
def input_artifacts(self) -> List[CodePipelineArtifact]:
121+
def input_artifacts(self) -> list[CodePipelineArtifact]:
120122
"""Represents a CodePipeline input artifact"""
121123
return [CodePipelineArtifact(item) for item in self["inputArtifacts"]]
122124

123125
@property
124-
def output_artifacts(self) -> List[CodePipelineArtifact]:
126+
def output_artifacts(self) -> list[CodePipelineArtifact]:
125127
"""Represents a CodePipeline output artifact"""
126128
return [CodePipelineArtifact(item) for item in self["outputArtifacts"]]
127129

@@ -131,12 +133,12 @@ def artifact_credentials(self) -> CodePipelineArtifactCredentials:
131133
return CodePipelineArtifactCredentials(self["artifactCredentials"])
132134

133135
@property
134-
def continuation_token(self) -> Optional[str]:
136+
def continuation_token(self) -> str | None:
135137
"""A continuation token if continuing job"""
136138
return self.get("continuationToken")
137139

138140
@property
139-
def encryption_key(self) -> Optional[CodePipelineEncryptionKey]:
141+
def encryption_key(self) -> CodePipelineEncryptionKey | None:
140142
"""Represents a CodePipeline encryption key"""
141143
key_data = self.get("encryptionKey")
142144
return CodePipelineEncryptionKey(key_data) if key_data is not None else None
@@ -151,7 +153,7 @@ class CodePipelineJobEvent(DictWrapper):
151153
- https://docs.aws.amazon.com/lambda/latest/dg/services-codepipeline.html
152154
"""
153155

154-
def __init__(self, data: Dict[str, Any]):
156+
def __init__(self, data: dict[str, Any]):
155157
super().__init__(data)
156158
self._job = self["CodePipeline.job"]
157159

@@ -171,12 +173,12 @@ def data(self) -> CodePipelineData:
171173
return CodePipelineData(self._job["data"])
172174

173175
@property
174-
def user_parameters(self) -> Optional[str]:
176+
def user_parameters(self) -> str | None:
175177
"""Action configuration user parameters"""
176178
return self.data.action_configuration.configuration.user_parameters
177179

178180
@property
179-
def decoded_user_parameters(self) -> Dict[str, Any]:
181+
def decoded_user_parameters(self) -> dict[str, Any]:
180182
"""Json Decoded action configuration user parameters"""
181183
return self.data.action_configuration.configuration.decoded_user_parameters
182184

@@ -216,7 +218,7 @@ def setup_s3_client(self):
216218
user_agent.register_feature_to_client(client=s3, feature="data_classes")
217219
return s3
218220

219-
def find_input_artifact(self, artifact_name: str) -> Optional[CodePipelineArtifact]:
221+
def find_input_artifact(self, artifact_name: str) -> CodePipelineArtifact | None:
220222
"""Find an input artifact by artifact name
221223
222224
Parameters
@@ -234,7 +236,7 @@ def find_input_artifact(self, artifact_name: str) -> Optional[CodePipelineArtifa
234236
return artifact
235237
return None
236238

237-
def get_artifact(self, artifact_name: str, filename: str) -> Optional[str]:
239+
def get_artifact(self, artifact_name: str, filename: str) -> str | None:
238240
"""Get a file within an artifact zip on s3
239241
240242
Parameters

‎aws_lambda_powertools/utilities/data_classes/cognito_user_pool_event.py

Lines changed: 54 additions & 52 deletions
Large diffs are not rendered by default.

‎aws_lambda_powertools/utilities/data_classes/common.py

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
from __future__ import annotations
2+
13
import base64
24
import json
35
from functools import cached_property
4-
from typing import Any, Callable, Dict, Iterator, List, Mapping, Optional
6+
from typing import TYPE_CHECKING, Any, Callable, Iterator, Mapping
57

6-
from aws_lambda_powertools.shared.headers_serializer import BaseHeadersSerializer
8+
if TYPE_CHECKING:
9+
from aws_lambda_powertools.shared.headers_serializer import BaseHeadersSerializer
710

811

912
class CaseInsensitiveDict(dict):
@@ -52,11 +55,11 @@ def __setitem__(self, k, v):
5255
class DictWrapper(Mapping):
5356
"""Provides a single read only access to a wrapper dict"""
5457

55-
def __init__(self, data: Dict[str, Any], json_deserializer: Optional[Callable] = None):
58+
def __init__(self, data: dict[str, Any], json_deserializer: Callable | None = None):
5659
"""
5760
Parameters
5861
----------
59-
data : Dict[str, Any]
62+
data : dict[str, Any]
6063
Lambda Event Source Event payload
6164
json_deserializer : Callable, optional
6265
function to deserialize `str`, `bytes`, `bytearray` containing a JSON document to a Python `obj`,
@@ -83,7 +86,7 @@ def __len__(self) -> int:
8386
def __str__(self) -> str:
8487
return str(self._str_helper())
8588

86-
def _str_helper(self) -> Dict[str, Any]:
89+
def _str_helper(self) -> dict[str, Any]:
8790
"""
8891
Recursively get a Dictionary of DictWrapper properties primarily
8992
for use by __str__ for debugging purposes.
@@ -98,7 +101,7 @@ def _str_helper(self) -> Dict[str, Any]:
98101
if hasattr(self, "_sensitive_properties"):
99102
sensitive_properties.extend(self._sensitive_properties) # pyright: ignore
100103

101-
result: Dict[str, Any] = {}
104+
result: dict[str, Any] = {}
102105
for property_key in properties:
103106
if property_key in sensitive_properties:
104107
result[property_key] = "[SENSITIVE]"
@@ -120,33 +123,33 @@ def _str_helper(self) -> Dict[str, Any]:
120123

121124
return result
122125

123-
def _properties(self) -> List[str]:
126+
def _properties(self) -> list[str]:
124127
return [p for p in dir(self.__class__) if isinstance(getattr(self.__class__, p), property)]
125128

126-
def get(self, key: str, default: Optional[Any] = None) -> Optional[Any]:
129+
def get(self, key: str, default: Any | None = None) -> Any | None:
127130
return self._data.get(key, default)
128131

129132
@property
130-
def raw_event(self) -> Dict[str, Any]:
133+
def raw_event(self) -> dict[str, Any]:
131134
"""The original raw event dict"""
132135
return self._data
133136

134137

135138
class BaseProxyEvent(DictWrapper):
136139
@property
137-
def headers(self) -> Dict[str, str]:
140+
def headers(self) -> dict[str, str]:
138141
return CaseInsensitiveDict(self.get("headers"))
139142

140143
@property
141-
def query_string_parameters(self) -> Dict[str, str]:
144+
def query_string_parameters(self) -> dict[str, str]:
142145
return self.get("queryStringParameters") or {}
143146

144147
@property
145-
def multi_value_query_string_parameters(self) -> Dict[str, List[str]]:
148+
def multi_value_query_string_parameters(self) -> dict[str, list[str]]:
146149
return self.get("multiValueQueryStringParameters") or {}
147150

148151
@cached_property
149-
def resolved_query_string_parameters(self) -> Dict[str, List[str]]:
152+
def resolved_query_string_parameters(self) -> dict[str, list[str]]:
150153
"""
151154
This property determines the appropriate query string parameter to be used
152155
as a trusted source for validating OpenAPI.
@@ -157,7 +160,7 @@ def resolved_query_string_parameters(self) -> Dict[str, List[str]]:
157160
return {k: v.split(",") for k, v in self.query_string_parameters.items()}
158161

159162
@property
160-
def resolved_headers_field(self) -> Dict[str, str]:
163+
def resolved_headers_field(self) -> dict[str, str]:
161164
"""
162165
This property determines the appropriate header to be used
163166
as a trusted source for validating OpenAPI.
@@ -172,11 +175,11 @@ def resolved_headers_field(self) -> Dict[str, str]:
172175
return self.headers
173176

174177
@property
175-
def is_base64_encoded(self) -> Optional[bool]:
178+
def is_base64_encoded(self) -> bool | None:
176179
return self.get("isBase64Encoded")
177180

178181
@property
179-
def body(self) -> Optional[str]:
182+
def body(self) -> str | None:
180183
"""Submitted body of the request as a string"""
181184
return self.get("body")
182185

@@ -189,9 +192,9 @@ def json_body(self) -> Any:
189192
return None
190193

191194
@cached_property
192-
def decoded_body(self) -> Optional[str]:
195+
def decoded_body(self) -> str | None:
193196
"""Decode the body from base64 if encoded, otherwise return it as is."""
194-
body: Optional[str] = self.body
197+
body: str | None = self.body
195198
if self.is_base64_encoded and body:
196199
return base64.b64decode(body.encode()).decode()
197200
return body
@@ -247,56 +250,56 @@ def validity_not_before(self) -> str:
247250

248251
class APIGatewayEventIdentity(DictWrapper):
249252
@property
250-
def access_key(self) -> Optional[str]:
253+
def access_key(self) -> str | None:
251254
return self["requestContext"]["identity"].get("accessKey")
252255

253256
@property
254-
def account_id(self) -> Optional[str]:
257+
def account_id(self) -> str | None:
255258
"""The AWS account ID associated with the request."""
256259
return self["requestContext"]["identity"].get("accountId")
257260

258261
@property
259-
def api_key(self) -> Optional[str]:
262+
def api_key(self) -> str | None:
260263
"""For API methods that require an API key, this variable is the API key associated with the method request.
261264
For methods that don't require an API key, this variable is null."""
262265
return self["requestContext"]["identity"].get("apiKey")
263266

264267
@property
265-
def api_key_id(self) -> Optional[str]:
268+
def api_key_id(self) -> str | None:
266269
"""The API key ID associated with an API request that requires an API key."""
267270
return self["requestContext"]["identity"].get("apiKeyId")
268271

269272
@property
270-
def caller(self) -> Optional[str]:
273+
def caller(self) -> str | None:
271274
"""The principal identifier of the caller making the request."""
272275
return self["requestContext"]["identity"].get("caller")
273276

274277
@property
275-
def cognito_authentication_provider(self) -> Optional[str]:
278+
def cognito_authentication_provider(self) -> str | None:
276279
"""A comma-separated list of the Amazon Cognito authentication providers used by the caller
277280
making the request. Available only if the request was signed with Amazon Cognito credentials."""
278281
return self["requestContext"]["identity"].get("cognitoAuthenticationProvider")
279282

280283
@property
281-
def cognito_authentication_type(self) -> Optional[str]:
284+
def cognito_authentication_type(self) -> str | None:
282285
"""The Amazon Cognito authentication type of the caller making the request.
283286
Available only if the request was signed with Amazon Cognito credentials."""
284287
return self["requestContext"]["identity"].get("cognitoAuthenticationType")
285288

286289
@property
287-
def cognito_identity_id(self) -> Optional[str]:
290+
def cognito_identity_id(self) -> str | None:
288291
"""The Amazon Cognito identity ID of the caller making the request.
289292
Available only if the request was signed with Amazon Cognito credentials."""
290293
return self["requestContext"]["identity"].get("cognitoIdentityId")
291294

292295
@property
293-
def cognito_identity_pool_id(self) -> Optional[str]:
296+
def cognito_identity_pool_id(self) -> str | None:
294297
"""The Amazon Cognito identity pool ID of the caller making the request.
295298
Available only if the request was signed with Amazon Cognito credentials."""
296299
return self["requestContext"]["identity"].get("cognitoIdentityPoolId")
297300

298301
@property
299-
def principal_org_id(self) -> Optional[str]:
302+
def principal_org_id(self) -> str | None:
300303
"""The AWS organization ID."""
301304
return self["requestContext"]["identity"].get("principalOrgId")
302305

@@ -306,22 +309,22 @@ def source_ip(self) -> str:
306309
return self["requestContext"]["identity"]["sourceIp"]
307310

308311
@property
309-
def user(self) -> Optional[str]:
312+
def user(self) -> str | None:
310313
"""The principal identifier of the user making the request."""
311314
return self["requestContext"]["identity"].get("user")
312315

313316
@property
314-
def user_agent(self) -> Optional[str]:
317+
def user_agent(self) -> str | None:
315318
"""The User Agent of the API caller."""
316319
return self["requestContext"]["identity"].get("userAgent")
317320

318321
@property
319-
def user_arn(self) -> Optional[str]:
322+
def user_arn(self) -> str | None:
320323
"""The Amazon Resource Name (ARN) of the effective user identified after authentication."""
321324
return self["requestContext"]["identity"].get("userArn")
322325

323326
@property
324-
def client_cert(self) -> Optional[RequestContextClientCert]:
327+
def client_cert(self) -> RequestContextClientCert | None:
325328
client_cert = self["requestContext"]["identity"].get("clientCert")
326329
return None if client_cert is None else RequestContextClientCert(client_cert)
327330

@@ -338,16 +341,16 @@ def api_id(self) -> str:
338341
return self["requestContext"]["apiId"]
339342

340343
@property
341-
def domain_name(self) -> Optional[str]:
344+
def domain_name(self) -> str | None:
342345
"""A domain name"""
343346
return self["requestContext"].get("domainName")
344347

345348
@property
346-
def domain_prefix(self) -> Optional[str]:
349+
def domain_prefix(self) -> str | None:
347350
return self["requestContext"].get("domainPrefix")
348351

349352
@property
350-
def extended_request_id(self) -> Optional[str]:
353+
def extended_request_id(self) -> str | None:
351354
"""An automatically generated ID for the API call, which contains more useful information
352355
for debugging/troubleshooting."""
353356
return self["requestContext"].get("extendedRequestId")
@@ -381,7 +384,7 @@ def request_id(self) -> str:
381384
return self["requestContext"]["requestId"]
382385

383386
@property
384-
def request_time(self) -> Optional[str]:
387+
def request_time(self) -> str | None:
385388
"""The CLF-formatted request time (dd/MMM/yyyy:HH:mm:ss +-hhmm)"""
386389
return self["requestContext"].get("requestTime")
387390

@@ -474,7 +477,7 @@ def time_epoch(self) -> int:
474477
return self["requestContext"]["timeEpoch"]
475478

476479
@property
477-
def authentication(self) -> Optional[RequestContextClientCert]:
480+
def authentication(self) -> RequestContextClientCert | None:
478481
"""Optional when using mutual TLS authentication"""
479482
# FunctionURL might have NONE as AuthZ
480483
authentication = self["requestContext"].get("authentication") or {}

‎aws_lambda_powertools/utilities/data_classes/connect_contact_flow_event.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
from __future__ import annotations
2+
13
from enum import Enum, auto
2-
from typing import Dict, Optional
34

45
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
56

@@ -47,19 +48,19 @@ def name(self) -> str:
4748

4849
class ConnectContactFlowMediaStreamAudio(DictWrapper):
4950
@property
50-
def start_fragment_number(self) -> Optional[str]:
51+
def start_fragment_number(self) -> str | None:
5152
"""The number that identifies the Kinesis Video Streams fragment, in the stream used for Live media streaming,
5253
in which the customer audio stream started.
5354
"""
5455
return self["StartFragmentNumber"]
5556

5657
@property
57-
def start_timestamp(self) -> Optional[str]:
58+
def start_timestamp(self) -> str | None:
5859
"""When the customer audio stream started."""
5960
return self["StartTimestamp"]
6061

6162
@property
62-
def stream_arn(self) -> Optional[str]:
63+
def stream_arn(self) -> str | None:
6364
"""The ARN of the Kinesis Video stream used for Live media streaming that includes the customer data to
6465
reference.
6566
"""
@@ -80,7 +81,7 @@ def customer(self) -> ConnectContactFlowMediaStreamCustomer:
8081

8182
class ConnectContactFlowData(DictWrapper):
8283
@property
83-
def attributes(self) -> Dict[str, str]:
84+
def attributes(self) -> dict[str, str]:
8485
"""These are attributes that have been previously associated with a contact,
8586
such as when using a Set contact attributes block in a contact flow.
8687
This map may be empty if there aren't any saved attributes.
@@ -98,7 +99,7 @@ def contact_id(self) -> str:
9899
return self["ContactId"]
99100

100101
@property
101-
def customer_endpoint(self) -> Optional[ConnectContactFlowEndpoint]:
102+
def customer_endpoint(self) -> ConnectContactFlowEndpoint | None:
102103
"""Contains the customer’s address (number) and type of address."""
103104
if self["CustomerEndpoint"] is not None:
104105
return ConnectContactFlowEndpoint(self["CustomerEndpoint"])
@@ -129,14 +130,14 @@ def previous_contact_id(self) -> str:
129130
return self["PreviousContactId"]
130131

131132
@property
132-
def queue(self) -> Optional[ConnectContactFlowQueue]:
133+
def queue(self) -> ConnectContactFlowQueue | None:
133134
"""The current queue."""
134135
if self["Queue"] is not None:
135136
return ConnectContactFlowQueue(self["Queue"])
136137
return None
137138

138139
@property
139-
def system_endpoint(self) -> Optional[ConnectContactFlowEndpoint]:
140+
def system_endpoint(self) -> ConnectContactFlowEndpoint | None:
140141
"""Contains the address (number) the customer dialed to call your contact center and type of address."""
141142
if self["SystemEndpoint"] is not None:
142143
return ConnectContactFlowEndpoint(self["SystemEndpoint"])
@@ -161,6 +162,6 @@ def contact_data(self) -> ConnectContactFlowData:
161162
return ConnectContactFlowData(self["Details"]["ContactData"])
162163

163164
@property
164-
def parameters(self) -> Dict[str, str]:
165+
def parameters(self) -> dict[str, str]:
165166
"""These are parameters specific to this call that were defined when you created the Lambda function."""
166167
return self["Details"]["Parameters"]

‎aws_lambda_powertools/utilities/data_classes/dynamo_db_stream_event.py

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
from __future__ import annotations
2+
13
from enum import Enum
24
from functools import cached_property
3-
from typing import Any, Dict, Iterator, Optional
5+
from typing import Any, Iterator
46

57
from aws_lambda_powertools.shared.dynamodb_deserializer import TypeDeserializer
68
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
@@ -18,17 +20,17 @@ class StreamViewType(Enum):
1820
class StreamRecord(DictWrapper):
1921
_deserializer = TypeDeserializer()
2022

21-
def __init__(self, data: Dict[str, Any]):
23+
def __init__(self, data: dict[str, Any]):
2224
"""StreamRecord constructor
2325
Parameters
2426
----------
25-
data: Dict[str, Any]
27+
data: dict[str, Any]
2628
Represents the dynamodb dict inside DynamoDBStreamEvent's records
2729
"""
2830
super().__init__(data)
2931
self._deserializer = TypeDeserializer()
3032

31-
def _deserialize_dynamodb_dict(self, key: str) -> Dict[str, Any]:
33+
def _deserialize_dynamodb_dict(self, key: str) -> dict[str, Any]:
3234
"""Deserialize DynamoDB records available in `Keys`, `NewImage`, and `OldImage`
3335
3436
Parameters
@@ -38,46 +40,46 @@ def _deserialize_dynamodb_dict(self, key: str) -> Dict[str, Any]:
3840
3941
Returns
4042
-------
41-
Dict[str, Any]
43+
dict[str, Any]
4244
Deserialized records in Python native types
4345
"""
4446
dynamodb_dict = self._data.get(key) or {}
4547
return {k: self._deserializer.deserialize(v) for k, v in dynamodb_dict.items()}
4648

4749
@property
48-
def approximate_creation_date_time(self) -> Optional[int]:
50+
def approximate_creation_date_time(self) -> int | None:
4951
"""The approximate date and time when the stream record was created, in UNIX epoch time format."""
5052
item = self.get("ApproximateCreationDateTime")
5153
return None if item is None else int(item)
5254

5355
@cached_property
54-
def keys(self) -> Dict[str, Any]: # type: ignore[override]
56+
def keys(self) -> dict[str, Any]: # type: ignore[override]
5557
"""The primary key attribute(s) for the DynamoDB item that was modified."""
5658
return self._deserialize_dynamodb_dict("Keys")
5759

5860
@cached_property
59-
def new_image(self) -> Dict[str, Any]:
61+
def new_image(self) -> dict[str, Any]:
6062
"""The item in the DynamoDB table as it appeared after it was modified."""
6163
return self._deserialize_dynamodb_dict("NewImage")
6264

6365
@cached_property
64-
def old_image(self) -> Dict[str, Any]:
66+
def old_image(self) -> dict[str, Any]:
6567
"""The item in the DynamoDB table as it appeared before it was modified."""
6668
return self._deserialize_dynamodb_dict("OldImage")
6769

6870
@property
69-
def sequence_number(self) -> Optional[str]:
71+
def sequence_number(self) -> str | None:
7072
"""The sequence number of the stream record."""
7173
return self.get("SequenceNumber")
7274

7375
@property
74-
def size_bytes(self) -> Optional[int]:
76+
def size_bytes(self) -> int | None:
7577
"""The size of the stream record, in bytes."""
7678
item = self.get("SizeBytes")
7779
return None if item is None else int(item)
7880

7981
@property
80-
def stream_view_type(self) -> Optional[StreamViewType]:
82+
def stream_view_type(self) -> StreamViewType | None:
8183
"""The type of data from the modified DynamoDB item that was captured in this stream record"""
8284
item = self.get("StreamViewType")
8385
return None if item is None else StreamViewType[str(item)]
@@ -93,39 +95,39 @@ class DynamoDBRecord(DictWrapper):
9395
"""A description of a unique event within a stream"""
9496

9597
@property
96-
def aws_region(self) -> Optional[str]:
98+
def aws_region(self) -> str | None:
9799
"""The region in which the GetRecords request was received"""
98100
return self.get("awsRegion")
99101

100102
@property
101-
def dynamodb(self) -> Optional[StreamRecord]:
103+
def dynamodb(self) -> StreamRecord | None:
102104
"""The main body of the stream record, containing all the DynamoDB-specific dicts."""
103105
stream_record = self.get("dynamodb")
104106
return None if stream_record is None else StreamRecord(stream_record)
105107

106108
@property
107-
def event_id(self) -> Optional[str]:
109+
def event_id(self) -> str | None:
108110
"""A globally unique identifier for the event that was recorded in this stream record."""
109111
return self.get("eventID")
110112

111113
@property
112-
def event_name(self) -> Optional[DynamoDBRecordEventName]:
114+
def event_name(self) -> DynamoDBRecordEventName | None:
113115
"""The type of data modification that was performed on the DynamoDB table"""
114116
item = self.get("eventName")
115117
return None if item is None else DynamoDBRecordEventName[item]
116118

117119
@property
118-
def event_source(self) -> Optional[str]:
120+
def event_source(self) -> str | None:
119121
"""The AWS service from which the stream record originated. For DynamoDB Streams, this is aws:dynamodb."""
120122
return self.get("eventSource")
121123

122124
@property
123-
def event_source_arn(self) -> Optional[str]:
125+
def event_source_arn(self) -> str | None:
124126
"""The Amazon Resource Name (ARN) of the event source"""
125127
return self.get("eventSourceARN")
126128

127129
@property
128-
def event_version(self) -> Optional[str]:
130+
def event_version(self) -> str | None:
129131
"""The version number of the stream record format."""
130132
return self.get("eventVersion")
131133

‎aws_lambda_powertools/utilities/data_classes/event_bridge_event.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from typing import Any, Dict, List, Optional
1+
from __future__ import annotations
2+
3+
from typing import Any
24

35
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
46

@@ -43,7 +45,7 @@ def region(self) -> str:
4345
return self["region"]
4446

4547
@property
46-
def resources(self) -> List[str]:
48+
def resources(self) -> list[str]:
4749
"""This JSON array contains ARNs that identify resources that are involved in the event.
4850
Inclusion of these ARNs is at the discretion of the service."""
4951
return self["resources"]
@@ -59,11 +61,11 @@ def detail_type(self) -> str:
5961
return self["detail-type"]
6062

6163
@property
62-
def detail(self) -> Dict[str, Any]:
64+
def detail(self) -> dict[str, Any]:
6365
"""A JSON object, whose content is at the discretion of the service originating the event."""
6466
return self["detail"]
6567

6668
@property
67-
def replay_name(self) -> Optional[str]:
69+
def replay_name(self) -> str | None:
6870
"""Identifies whether the event is being replayed and what is the name of the replay."""
6971
return self["replay-name"]

‎aws_lambda_powertools/utilities/data_classes/event_source.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,32 @@
1-
from typing import Any, Callable, Dict, Type
1+
from __future__ import annotations
2+
3+
from typing import TYPE_CHECKING, Any, Callable
24

35
from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
4-
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
5-
from aws_lambda_powertools.utilities.typing import LambdaContext
6+
7+
if TYPE_CHECKING:
8+
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
9+
from aws_lambda_powertools.utilities.typing import LambdaContext
610

711

812
@lambda_handler_decorator
913
def event_source(
1014
handler: Callable[[Any, LambdaContext], Any],
11-
event: Dict[str, Any],
15+
event: dict[str, Any],
1216
context: LambdaContext,
13-
data_class: Type[DictWrapper],
17+
data_class: type[DictWrapper],
1418
):
1519
"""Middleware to create an instance of the passed in event source data class
1620
1721
Parameters
1822
----------
1923
handler: Callable
2024
Lambda's handler
21-
event: Dict
25+
event: dict[str, Any]
2226
Lambda's Event
23-
context: Dict
27+
context: LambdaContext
2428
Lambda's Context
25-
data_class: Type[DictWrapper]
29+
data_class: type[DictWrapper]
2630
Data class type to instantiate
2731
2832
Example

‎aws_lambda_powertools/utilities/data_classes/kafka_event.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
from __future__ import annotations
2+
13
import base64
24
from functools import cached_property
3-
from typing import Any, Dict, Iterator, List, Optional
5+
from typing import Any, Iterator
46

57
from aws_lambda_powertools.utilities.data_classes.common import CaseInsensitiveDict, DictWrapper
68

@@ -57,12 +59,12 @@ def json_value(self) -> Any:
5759
return self._json_deserializer(self.decoded_value.decode("utf-8"))
5860

5961
@property
60-
def headers(self) -> List[Dict[str, List[int]]]:
62+
def headers(self) -> list[dict[str, list[int]]]:
6163
"""The raw Kafka record headers."""
6264
return self["headers"]
6365

6466
@cached_property
65-
def decoded_headers(self) -> Dict[str, bytes]:
67+
def decoded_headers(self) -> dict[str, bytes]:
6668
"""Decodes the headers as a single dictionary."""
6769
return CaseInsensitiveDict((k, bytes(v)) for chunk in self.headers for k, v in chunk.items())
6870

@@ -75,17 +77,17 @@ class KafkaEvent(DictWrapper):
7577
- https://docs.aws.amazon.com/lambda/latest/dg/with-msk.html
7678
"""
7779

78-
def __init__(self, data: Dict[str, Any]):
80+
def __init__(self, data: dict[str, Any]):
7981
super().__init__(data)
80-
self._records: Optional[Iterator[KafkaEventRecord]] = None
82+
self._records: Iterator[KafkaEventRecord] | None = None
8183

8284
@property
8385
def event_source(self) -> str:
8486
"""The AWS service from which the Kafka event record originated."""
8587
return self["eventSource"]
8688

8789
@property
88-
def event_source_arn(self) -> Optional[str]:
90+
def event_source_arn(self) -> str | None:
8991
"""The AWS service ARN from which the Kafka event record originated, mandatory for AWS MSK."""
9092
return self.get("eventSourceArn")
9193

@@ -95,7 +97,7 @@ def bootstrap_servers(self) -> str:
9597
return self["bootstrapServers"]
9698

9799
@property
98-
def decoded_bootstrap_servers(self) -> List[str]:
100+
def decoded_bootstrap_servers(self) -> list[str]:
99101
"""The decoded Kafka bootstrap URL."""
100102
return self.bootstrap_servers.split(",")
101103

‎aws_lambda_powertools/utilities/data_classes/kinesis_firehose_event.py

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
from __future__ import annotations
2+
13
import base64
24
import json
35
import warnings
46
from dataclasses import dataclass, field
57
from functools import cached_property
6-
from typing import Any, Callable, ClassVar, Dict, Iterator, List, Optional, Tuple
8+
from typing import Any, Callable, ClassVar, Iterator
79

810
from typing_extensions import Literal
911

@@ -17,17 +19,17 @@ class KinesisFirehoseDataTransformationRecordMetadata:
1719
1820
Parameters
1921
----------
20-
partition_keys: Dict[str, str]
22+
partition_keys: dict[str, str]
2123
A dict of partition keys/value in string format, e.g. `{"year":"2023","month":"09"}`
2224
2325
Documentation:
2426
--------------
2527
- https://docs.aws.amazon.com/firehose/latest/dev/dynamic-partitioning.html
2628
"""
2729

28-
partition_keys: Dict[str, str] = field(default_factory=lambda: {})
30+
partition_keys: dict[str, str] = field(default_factory=lambda: {})
2931

30-
def asdict(self) -> Dict:
32+
def asdict(self) -> dict:
3133
if self.partition_keys is not None:
3234
return {"partitionKeys": self.partition_keys}
3335
return {}
@@ -48,7 +50,7 @@ class KinesisFirehoseDataTransformationRecord:
4850
4951
Use `data_from_text` or `data_from_json` methods to convert data if needed.
5052
51-
metadata: Optional[KinesisFirehoseDataTransformationRecordMetadata]
53+
metadata: KinesisFirehoseDataTransformationRecordMetadata | None
5254
Metadata associated with this record; can contain partition keys.
5355
5456
See: https://docs.aws.amazon.com/firehose/latest/dev/dynamic-partitioning.html
@@ -63,23 +65,23 @@ class KinesisFirehoseDataTransformationRecord:
6365
- https://docs.aws.amazon.com/firehose/latest/dev/data-transformation.html
6466
"""
6567

66-
_valid_result_types: ClassVar[Tuple[str, str, str]] = ("Ok", "Dropped", "ProcessingFailed")
68+
_valid_result_types: ClassVar[tuple[str, str, str]] = ("Ok", "Dropped", "ProcessingFailed")
6769

6870
record_id: str
6971
result: Literal["Ok", "Dropped", "ProcessingFailed"] = "Ok"
7072
data: str = ""
71-
metadata: Optional[KinesisFirehoseDataTransformationRecordMetadata] = None
73+
metadata: KinesisFirehoseDataTransformationRecordMetadata | None = None
7274
json_serializer: Callable = json.dumps
7375
json_deserializer: Callable = json.loads
7476

75-
def asdict(self) -> Dict:
77+
def asdict(self) -> dict:
7678
if self.result not in self._valid_result_types:
7779
warnings.warn(
7880
stacklevel=1,
7981
message=f'The result "{self.result}" is not valid, Choose from "Ok", "Dropped", "ProcessingFailed"',
8082
)
8183

82-
record: Dict[str, Any] = {
84+
record: dict[str, Any] = {
8385
"recordId": self.record_id,
8486
"result": self.result,
8587
"data": self.data,
@@ -103,7 +105,7 @@ def data_as_text(self) -> str:
103105
return self.data_as_bytes.decode("utf-8")
104106

105107
@cached_property
106-
def data_as_json(self) -> Dict:
108+
def data_as_json(self) -> dict:
107109
"""Decoded base64-encoded data loaded to json"""
108110
if not self.data:
109111
return {}
@@ -121,7 +123,7 @@ class KinesisFirehoseDataTransformationResponse:
121123
122124
Parameters
123125
----------
124-
records : List[KinesisFirehoseResponseRecord]
126+
records : list[KinesisFirehoseResponseRecord]
125127
records of Kinesis Data Firehose response object,
126128
optional parameter at start. can be added later using `add_record` function.
127129
@@ -161,12 +163,12 @@ def lambda_handler(event: dict, context: LambdaContext):
161163
```
162164
"""
163165

164-
records: List[KinesisFirehoseDataTransformationRecord] = field(default_factory=list)
166+
records: list[KinesisFirehoseDataTransformationRecord] = field(default_factory=list)
165167

166168
def add_record(self, record: KinesisFirehoseDataTransformationRecord):
167169
self.records.append(record)
168170

169-
def asdict(self) -> Dict:
171+
def asdict(self) -> dict:
170172
if not self.records:
171173
raise ValueError("Amazon Kinesis Data Firehose doesn't accept empty response")
172174

@@ -225,7 +227,7 @@ def data(self) -> str:
225227
return self["data"]
226228

227229
@property
228-
def metadata(self) -> Optional[KinesisFirehoseRecordMetadata]:
230+
def metadata(self) -> KinesisFirehoseRecordMetadata | None:
229231
"""Optional: metadata associated with this record; present only when Kinesis Stream is source"""
230232
return KinesisFirehoseRecordMetadata(self._data) if self.get("kinesisRecordMetadata") else None
231233

@@ -248,7 +250,7 @@ def build_data_transformation_response(
248250
self,
249251
result: Literal["Ok", "Dropped", "ProcessingFailed"] = "Ok",
250252
data: str = "",
251-
metadata: Optional[KinesisFirehoseDataTransformationRecordMetadata] = None,
253+
metadata: KinesisFirehoseDataTransformationRecordMetadata | None = None,
252254
) -> KinesisFirehoseDataTransformationRecord:
253255
"""Create a KinesisFirehoseResponseRecord directly using the record_id and given values
254256
@@ -290,7 +292,7 @@ def delivery_stream_arn(self) -> str:
290292
return self["deliveryStreamArn"]
291293

292294
@property
293-
def source_kinesis_stream_arn(self) -> Optional[str]:
295+
def source_kinesis_stream_arn(self) -> str | None:
294296
"""ARN of the Kinesis Stream; present only when Kinesis Stream is source"""
295297
return self.get("sourceKinesisStreamArn")
296298

‎aws_lambda_powertools/utilities/data_classes/kinesis_stream_event.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
from __future__ import annotations
2+
13
import base64
24
import json
35
import zlib
4-
from typing import Iterator, List
6+
from typing import Iterator
57

68
from aws_lambda_powertools.utilities.data_classes.cloud_watch_logs_event import (
79
CloudWatchLogsDecodedData,
@@ -109,7 +111,7 @@ def records(self) -> Iterator[KinesisStreamRecord]:
109111
yield KinesisStreamRecord(record)
110112

111113

112-
def extract_cloudwatch_logs_from_event(event: KinesisStreamEvent) -> List[CloudWatchLogsDecodedData]:
114+
def extract_cloudwatch_logs_from_event(event: KinesisStreamEvent) -> list[CloudWatchLogsDecodedData]:
113115
return [CloudWatchLogsDecodedData(record.kinesis.data_zlib_compressed_as_json()) for record in event.records]
114116

115117

‎aws_lambda_powertools/utilities/data_classes/rabbit_mq_event.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from __future__ import annotations
2+
13
from functools import cached_property
2-
from typing import Any, Dict, List
4+
from typing import Any
35

46
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
57
from aws_lambda_powertools.utilities.data_classes.shared_functions import base64_decode
@@ -15,7 +17,7 @@ def content_encoding(self) -> str:
1517
return self["contentEncoding"]
1618

1719
@property
18-
def headers(self) -> Dict[str, Any]:
20+
def headers(self) -> dict[str, Any]:
1921
return self["headers"]
2022

2123
@property
@@ -100,7 +102,7 @@ class RabbitMQEvent(DictWrapper):
100102
- https://aws.amazon.com/blogs/compute/using-amazon-mq-for-rabbitmq-as-an-event-source-for-lambda/
101103
"""
102104

103-
def __init__(self, data: Dict[str, Any]):
105+
def __init__(self, data: dict[str, Any]):
104106
super().__init__(data)
105107
self._rmq_messages_by_queue = {
106108
key: [RabbitMessage(message) for message in messages]
@@ -117,5 +119,5 @@ def event_source_arn(self) -> str:
117119
return self["eventSourceArn"]
118120

119121
@property
120-
def rmq_messages_by_queue(self) -> Dict[str, List[RabbitMessage]]:
122+
def rmq_messages_by_queue(self) -> dict[str, list[RabbitMessage]]:
121123
return self._rmq_messages_by_queue

‎aws_lambda_powertools/utilities/data_classes/s3_batch_operation_event.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
1+
from __future__ import annotations
2+
13
import warnings
24
from dataclasses import dataclass, field
3-
from typing import Any, Dict, Iterator, List, Literal, Optional, Tuple
5+
from typing import Any, Iterator, Literal
46
from urllib.parse import unquote_plus
57

68
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
79

810
# list of valid result code. Used both in S3BatchOperationResponse and S3BatchOperationResponseRecord
9-
VALID_RESULT_CODES: Tuple[str, str, str] = ("Succeeded", "TemporaryFailure", "PermanentFailure")
11+
VALID_RESULT_CODES: tuple[str, str, str] = ("Succeeded", "TemporaryFailure", "PermanentFailure")
1012
RESULT_CODE_TYPE = Literal["Succeeded", "TemporaryFailure", "PermanentFailure"]
1113

1214

1315
@dataclass(repr=False, order=False)
1416
class S3BatchOperationResponseRecord:
1517
task_id: str
1618
result_code: RESULT_CODE_TYPE
17-
result_string: Optional[str] = None
19+
result_string: str | None = None
1820

19-
def asdict(self) -> Dict[str, Any]:
21+
def asdict(self) -> dict[str, Any]:
2022
if self.result_code not in VALID_RESULT_CODES:
2123
warnings.warn(
2224
stacklevel=2,
@@ -53,7 +55,7 @@ class S3BatchOperationResponse:
5355
treat_missing_keys_as : Literal["Succeeded", "TemporaryFailure", "PermanentFailure"]
5456
Undocumented parameter, defaults to "Succeeded"
5557
56-
results : List[S3BatchOperationResult]
58+
results : list[S3BatchOperationResult]
5759
Results of each S3 Batch Operations task,
5860
optional parameter at start. Can be added later using `add_result` function.
5961
@@ -112,7 +114,7 @@ def lambda_handler(event: S3BatchOperationEvent, context: LambdaContext):
112114
invocation_schema_version: str
113115
invocation_id: str
114116
treat_missing_keys_as: RESULT_CODE_TYPE = "Succeeded"
115-
results: List[S3BatchOperationResponseRecord] = field(default_factory=list)
117+
results: list[S3BatchOperationResponseRecord] = field(default_factory=list)
116118

117119
def __post_init__(self):
118120
if self.treat_missing_keys_as not in VALID_RESULT_CODES:
@@ -125,7 +127,7 @@ def __post_init__(self):
125127
def add_result(self, result: S3BatchOperationResponseRecord):
126128
self.results.append(result)
127129

128-
def asdict(self) -> Dict:
130+
def asdict(self) -> dict:
129131
result_count = len(self.results)
130132

131133
if result_count != 1:
@@ -146,7 +148,7 @@ def get_id(self) -> str:
146148
return self["id"]
147149

148150
@property
149-
def user_arguments(self) -> Dict[str, str]:
151+
def user_arguments(self) -> dict[str, str]:
150152
"""Get user arguments provided for this job (only for invocation schema 2.0)"""
151153
return self.get("userArguments") or {}
152154

@@ -163,12 +165,12 @@ def s3_key(self) -> str:
163165
return unquote_plus(self["s3Key"])
164166

165167
@property
166-
def s3_version_id(self) -> Optional[str]:
168+
def s3_version_id(self) -> str | None:
167169
"""Object version if bucket is versioning-enabled, otherwise null"""
168170
return self.get("s3VersionId")
169171

170172
@property
171-
def s3_bucket_arn(self) -> Optional[str]:
173+
def s3_bucket_arn(self) -> str | None:
172174
"""Get the s3 bucket arn (present only for invocationSchemaVersion '1.0')"""
173175
return self.get("s3BucketArn")
174176

‎aws_lambda_powertools/utilities/data_classes/s3_event.py

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from typing import Dict, Iterator, Optional
1+
from __future__ import annotations
2+
3+
from typing import Iterator
24
from urllib.parse import unquote_plus
35

46
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
@@ -32,7 +34,7 @@ def key(self) -> str:
3234
return unquote_plus(self["key"])
3335

3436
@property
35-
def size(self) -> Optional[int]:
37+
def size(self) -> int | None:
3638
"""Object size. Object deletion event doesn't contain size."""
3739
return self.get("size")
3840

@@ -79,12 +81,12 @@ def requester(self) -> str:
7981
return self["requester"]
8082

8183
@property
82-
def source_ip_address(self) -> Optional[str]:
84+
def source_ip_address(self) -> str | None:
8385
"""Get the source IP address of S3 request. Only present for events triggered by an S3 request."""
8486
return self.get("source-ip-address")
8587

8688
@property
87-
def reason(self) -> Optional[str]:
89+
def reason(self) -> str | None:
8890
"""Get the reason for the S3 notification.
8991
9092
For 'Object Created events', the S3 API used to create the object: `PutObject`, `POST Object`, `CopyObject`, or
@@ -94,7 +96,7 @@ def reason(self) -> Optional[str]:
9496
return self.get("reason")
9597

9698
@property
97-
def deletion_type(self) -> Optional[str]:
99+
def deletion_type(self) -> str | None:
98100
"""Get the deletion type for the S3 object in this notification.
99101
100102
For 'Object Deleted' events, when an unversioned object is deleted, or a versioned object is permanently deleted
@@ -104,15 +106,15 @@ def deletion_type(self) -> Optional[str]:
104106
return self.get("deletion-type")
105107

106108
@property
107-
def restore_expiry_time(self) -> Optional[str]:
109+
def restore_expiry_time(self) -> str | None:
108110
"""Get the restore expiry time for the S3 object in this notification.
109111
110112
For 'Object Restore Completed' events, the time when the temporary copy of the object will be deleted from S3.
111113
"""
112114
return self.get("restore-expiry-time")
113115

114116
@property
115-
def source_storage_class(self) -> Optional[str]:
117+
def source_storage_class(self) -> str | None:
116118
"""Get the source storage class of the S3 object in this notification.
117119
118120
For 'Object Restore Initiated' and 'Object Restore Completed' events, the storage class of the object being
@@ -121,15 +123,15 @@ def source_storage_class(self) -> Optional[str]:
121123
return self.get("source-storage-class")
122124

123125
@property
124-
def destination_storage_class(self) -> Optional[str]:
126+
def destination_storage_class(self) -> str | None:
125127
"""Get the destination storage class of the S3 object in this notification.
126128
127129
For 'Object Storage Class Changed' events, the new storage class of the object.
128130
"""
129131
return self.get("destination-storage-class")
130132

131133
@property
132-
def destination_access_tier(self) -> Optional[str]:
134+
def destination_access_tier(self) -> str | None:
133135
"""Get the destination access tier of the S3 object in this notification.
134136
135137
For 'Object Access Tier Changed' events, the new access tier of the object.
@@ -182,7 +184,7 @@ def etag(self) -> str:
182184
return self["s3"]["object"].get("eTag", "")
183185

184186
@property
185-
def version_id(self) -> Optional[str]:
187+
def version_id(self) -> str | None:
186188
"""Object version if bucket is versioning-enabled, otherwise null"""
187189
return self["s3"]["object"].get("versionId")
188190

@@ -273,7 +275,7 @@ def request_parameters(self) -> S3RequestParameters:
273275
return S3RequestParameters(self._data)
274276

275277
@property
276-
def response_elements(self) -> Dict[str, str]:
278+
def response_elements(self) -> dict[str, str]:
277279
"""The responseElements key value is useful if you want to trace a request by following up with AWS Support.
278280
279281
Both x-amz-request-id and x-amz-id-2 help Amazon S3 trace an individual request. These values are the same
@@ -287,7 +289,7 @@ def s3(self) -> S3Message:
287289
return S3Message(self._data)
288290

289291
@property
290-
def glacier_event_data(self) -> Optional[S3EventRecordGlacierEventData]:
292+
def glacier_event_data(self) -> S3EventRecordGlacierEventData | None:
291293
"""The glacierEventData key is only visible for s3:ObjectRestore:Completed events."""
292294
item = self.get("glacierEventData")
293295
return None if item is None else S3EventRecordGlacierEventData(item)

‎aws_lambda_powertools/utilities/data_classes/s3_object_event.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from typing import Dict, Optional
1+
from __future__ import annotations
22

33
from aws_lambda_powertools.utilities.data_classes.common import CaseInsensitiveDict, DictWrapper
44

@@ -62,7 +62,7 @@ def url(self) -> str:
6262
return self["url"]
6363

6464
@property
65-
def headers(self) -> Dict[str, str]:
65+
def headers(self) -> dict[str, str]:
6666
"""A map of string to strings containing the HTTP headers and their values from the original call,
6767
excluding any authorization-related headers.
6868
@@ -194,7 +194,7 @@ def arn(self) -> str:
194194
return self["arn"]
195195

196196
@property
197-
def session_context(self) -> Optional[S3ObjectSessionContext]:
197+
def session_context(self) -> S3ObjectSessionContext | None:
198198
"""If the request was made with temporary security credentials,
199199
this element provides information about the session that was created for those credentials."""
200200
session_context = self.get("sessionContext")

‎aws_lambda_powertools/utilities/data_classes/ses_event.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from typing import Iterator, List, Optional
1+
from __future__ import annotations
2+
3+
from typing import Iterator
24

35
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
46

@@ -20,7 +22,7 @@ def return_path(self) -> str:
2022
return self["returnPath"]
2123

2224
@property
23-
def get_from(self) -> List[str]:
25+
def get_from(self) -> list[str]:
2426
"""The values in the From header of the email."""
2527
# Note: this name conflicts with existing python builtins
2628
return self["from"]
@@ -31,7 +33,7 @@ def date(self) -> str:
3133
return self["date"]
3234

3335
@property
34-
def to(self) -> List[str]:
36+
def to(self) -> list[str]:
3537
"""The values in the To header of the email."""
3638
return self["to"]
3739

@@ -46,22 +48,22 @@ def subject(self) -> str:
4648
return str(self["subject"])
4749

4850
@property
49-
def cc(self) -> List[str]:
51+
def cc(self) -> list[str]:
5052
"""The values in the CC header of the email."""
5153
return self.get("cc") or []
5254

5355
@property
54-
def bcc(self) -> List[str]:
56+
def bcc(self) -> list[str]:
5557
"""The values in the BCC header of the email."""
5658
return self.get("bcc") or []
5759

5860
@property
59-
def sender(self) -> List[str]:
61+
def sender(self) -> list[str]:
6062
"""The values in the Sender header of the email."""
6163
return self.get("sender") or []
6264

6365
@property
64-
def reply_to(self) -> List[str]:
66+
def reply_to(self) -> list[str]:
6567
"""The values in the replyTo header of the email."""
6668
return self.get("replyTo") or []
6769

@@ -87,7 +89,7 @@ def message_id(self) -> str:
8789
return self["messageId"]
8890

8991
@property
90-
def destination(self) -> List[str]:
92+
def destination(self) -> list[str]:
9193
"""A complete list of all recipient addresses (including To: and CC: recipients)
9294
from the MIME headers of the incoming email."""
9395
return self["destination"]
@@ -131,7 +133,7 @@ def get_type(self) -> str:
131133
return self["type"]
132134

133135
@property
134-
def topic_arn(self) -> Optional[str]:
136+
def topic_arn(self) -> str | None:
135137
"""String that contains the Amazon Resource Name (ARN) of the Amazon SNS topic to which the
136138
notification was published."""
137139
return self.get("topicArn")
@@ -162,7 +164,7 @@ def processing_time_millis(self) -> int:
162164
return int(self["processingTimeMillis"])
163165

164166
@property
165-
def recipients(self) -> List[str]:
167+
def recipients(self) -> list[str]:
166168
"""A list of recipients (specifically, the envelope RCPT TO addresses) that were matched by the
167169
active receipt rule. The addresses listed here may differ from those listed by the destination
168170
field in the mail object."""
@@ -195,7 +197,7 @@ def dmarc_verdict(self) -> SESReceiptStatus:
195197
return SESReceiptStatus(self["dmarcVerdict"])
196198

197199
@property
198-
def dmarc_policy(self) -> Optional[str]:
200+
def dmarc_policy(self) -> str | None:
199201
"""Indicates the Domain-based Message Authentication, Reporting & Conformance (DMARC) settings for
200202
the sending domain. This field only appears if the message fails DMARC authentication.
201203
Possible values for this field are: none, quarantine, reject"""

‎aws_lambda_powertools/utilities/data_classes/sns_event.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from typing import Dict, Iterator
1+
from __future__ import annotations
2+
3+
from typing import Iterator
24

35
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
46

@@ -50,7 +52,7 @@ def message(self) -> str:
5052
return self["Message"]
5153

5254
@property
53-
def message_attributes(self) -> Dict[str, SNSMessageAttribute]:
55+
def message_attributes(self) -> dict[str, SNSMessageAttribute]:
5456
return {k: SNSMessageAttribute(v) for (k, v) in self["MessageAttributes"].items()}
5557

5658
@property

‎aws_lambda_powertools/utilities/data_classes/sqs_event.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from __future__ import annotations
2+
13
from functools import cached_property
2-
from typing import Any, Dict, ItemsView, Iterator, Optional, Type, TypeVar
4+
from typing import Any, Dict, ItemsView, Iterator, TypeVar
35

46
from aws_lambda_powertools.utilities.data_classes import S3Event
57
from aws_lambda_powertools.utilities.data_classes.common import DictWrapper
@@ -8,7 +10,7 @@
810

911
class SQSRecordAttributes(DictWrapper):
1012
@property
11-
def aws_trace_header(self) -> Optional[str]:
13+
def aws_trace_header(self) -> str | None:
1214
"""Returns the AWS X-Ray trace header string."""
1315
return self.get("AWSTraceHeader")
1416

@@ -33,12 +35,12 @@ def approximate_first_receive_timestamp(self) -> str:
3335
return self["ApproximateFirstReceiveTimestamp"]
3436

3537
@property
36-
def sequence_number(self) -> Optional[str]:
38+
def sequence_number(self) -> str | None:
3739
"""The large, non-consecutive number that Amazon SQS assigns to each message."""
3840
return self.get("SequenceNumber")
3941

4042
@property
41-
def message_group_id(self) -> Optional[str]:
43+
def message_group_id(self) -> str | None:
4244
"""The tag that specifies that a message belongs to a specific message group.
4345
4446
Messages that belong to the same message group are always processed one by one, in a
@@ -47,7 +49,7 @@ def message_group_id(self) -> Optional[str]:
4749
return self.get("MessageGroupId")
4850

4951
@property
50-
def message_deduplication_id(self) -> Optional[str]:
52+
def message_deduplication_id(self) -> str | None:
5153
"""The token used for deduplication of sent messages.
5254
5355
If a message with a particular message deduplication ID is sent successfully, any messages sent
@@ -56,7 +58,7 @@ def message_deduplication_id(self) -> Optional[str]:
5658
return self.get("MessageDeduplicationId")
5759

5860
@property
59-
def dead_letter_queue_source_arn(self) -> Optional[str]:
61+
def dead_letter_queue_source_arn(self) -> str | None:
6062
"""The SQS queue ARN that sent the record to this DLQ.
6163
Only present when a Lambda function is using a DLQ as an event source.
6264
"""
@@ -67,12 +69,12 @@ class SQSMessageAttribute(DictWrapper):
6769
"""The user-specified message attribute value."""
6870

6971
@property
70-
def string_value(self) -> Optional[str]:
72+
def string_value(self) -> str | None:
7173
"""Strings are Unicode with UTF-8 binary encoding."""
7274
return self["stringValue"]
7375

7476
@property
75-
def binary_value(self) -> Optional[str]:
77+
def binary_value(self) -> str | None:
7678
"""Binary type attributes can store any binary data, such as compressed data, encrypted data, or images.
7779
7880
Base64-encoded binary data object"""
@@ -85,7 +87,7 @@ def data_type(self) -> str:
8587

8688

8789
class SQSMessageAttributes(Dict[str, SQSMessageAttribute]):
88-
def __getitem__(self, key: str) -> Optional[SQSMessageAttribute]: # type: ignore
90+
def __getitem__(self, key: str) -> SQSMessageAttribute | None: # type: ignore
8991
item = super().get(key)
9092
return None if item is None else SQSMessageAttribute(item) # type: ignore
9193

@@ -230,7 +232,7 @@ def decoded_nested_sns_event(self) -> SNSMessage:
230232
"""
231233
return self._decode_nested_event(SNSMessage)
232234

233-
def _decode_nested_event(self, nested_event_class: Type[NestedEvent]) -> NestedEvent:
235+
def _decode_nested_event(self, nested_event_class: type[NestedEvent]) -> NestedEvent:
234236
"""Returns the nested event source data object.
235237
236238
This is useful for handling events that are sent in the body of a SQS message.

‎aws_lambda_powertools/utilities/data_classes/vpc_lattice.py

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
from __future__ import annotations
2+
13
from functools import cached_property
2-
from typing import Any, Dict, Optional
4+
from typing import Any
35

46
from aws_lambda_powertools.shared.headers_serializer import (
57
BaseHeadersSerializer,
@@ -25,7 +27,7 @@ def json_body(self) -> Any:
2527
return self._json_deserializer(self.decoded_body)
2628

2729
@property
28-
def headers(self) -> Dict[str, str]:
30+
def headers(self) -> dict[str, str]:
2931
"""The VPC Lattice event headers."""
3032
return CaseInsensitiveDict(self["headers"])
3133

@@ -70,63 +72,63 @@ def path(self) -> str:
7072
return self["raw_path"]
7173

7274
@property
73-
def query_string_parameters(self) -> Dict[str, str]:
75+
def query_string_parameters(self) -> dict[str, str]:
7476
"""The request query string parameters."""
7577
return self["query_string_parameters"]
7678

7779
@cached_property
78-
def resolved_headers_field(self) -> Dict[str, Any]:
80+
def resolved_headers_field(self) -> dict[str, Any]:
7981
return CaseInsensitiveDict((k, v.split(",") if "," in v else v) for k, v in self.headers.items())
8082

8183

8284
class vpcLatticeEventV2Identity(DictWrapper):
8385
@property
84-
def source_vpc_arn(self) -> Optional[str]:
86+
def source_vpc_arn(self) -> str | None:
8587
"""The VPC Lattice v2 Event requestContext Identity sourceVpcArn"""
8688
return self.get("sourceVpcArn")
8789

8890
@property
89-
def get_type(self) -> Optional[str]:
91+
def get_type(self) -> str | None:
9092
"""The VPC Lattice v2 Event requestContext Identity type"""
9193
return self.get("type")
9294

9395
@property
94-
def principal(self) -> Optional[str]:
96+
def principal(self) -> str | None:
9597
"""The VPC Lattice v2 Event requestContext principal"""
9698
return self.get("principal")
9799

98100
@property
99-
def principal_org_id(self) -> Optional[str]:
101+
def principal_org_id(self) -> str | None:
100102
"""The VPC Lattice v2 Event requestContext principalOrgID"""
101103
return self.get("principalOrgID")
102104

103105
@property
104-
def session_name(self) -> Optional[str]:
106+
def session_name(self) -> str | None:
105107
"""The VPC Lattice v2 Event requestContext sessionName"""
106108
return self.get("sessionName")
107109

108110
@property
109-
def x509_subject_cn(self) -> Optional[str]:
111+
def x509_subject_cn(self) -> str | None:
110112
"""The VPC Lattice v2 Event requestContext X509SubjectCn"""
111113
return self.get("X509SubjectCn")
112114

113115
@property
114-
def x509_issuer_ou(self) -> Optional[str]:
116+
def x509_issuer_ou(self) -> str | None:
115117
"""The VPC Lattice v2 Event requestContext X509IssuerOu"""
116118
return self.get("X509IssuerOu")
117119

118120
@property
119-
def x509_san_dns(self) -> Optional[str]:
121+
def x509_san_dns(self) -> str | None:
120122
"""The VPC Lattice v2 Event requestContext X509SanDns"""
121123
return self.get("x509SanDns")
122124

123125
@property
124-
def x509_san_uri(self) -> Optional[str]:
126+
def x509_san_uri(self) -> str | None:
125127
"""The VPC Lattice v2 Event requestContext X509SanUri"""
126128
return self.get("X509SanUri")
127129

128130
@property
129-
def x509_san_name_cn(self) -> Optional[str]:
131+
def x509_san_name_cn(self) -> str | None:
130132
"""The VPC Lattice v2 Event requestContext X509SanNameCn"""
131133
return self.get("X509SanNameCn")
132134

@@ -170,7 +172,7 @@ def version(self) -> str:
170172
return self["version"]
171173

172174
@property
173-
def is_base64_encoded(self) -> Optional[bool]:
175+
def is_base64_encoded(self) -> bool | None:
174176
"""A boolean flag to indicate if the applicable request payload is Base64-encode"""
175177
return self.get("isBase64Encoded")
176178

@@ -185,10 +187,10 @@ def request_context(self) -> vpcLatticeEventV2RequestContext:
185187
return vpcLatticeEventV2RequestContext(self["requestContext"])
186188

187189
@cached_property
188-
def query_string_parameters(self) -> Dict[str, str]:
190+
def query_string_parameters(self) -> dict[str, str]:
189191
"""The request query string parameters.
190192
191-
For VPC Lattice V2, the queryStringParameters will contain a Dict[str, List[str]]
193+
For VPC Lattice V2, the queryStringParameters will contain a dict[str, list[str]]
192194
so to keep compatibility with existing utilities, we merge all the values with a comma.
193195
"""
194196
params = self.get("queryStringParameters") or {}

0 commit comments

Comments
 (0)
Please sign in to comment.