Skip to content

Commit 6c0bb17

Browse files
committed
refactor(idempotency): add from __future__ import annotations
and update code according to ruff rules TCH, UP006, UP007, UP037 and FA100.
1 parent 2d59b7a commit 6c0bb17

File tree

14 files changed

+145
-113
lines changed

14 files changed

+145
-113
lines changed

aws_lambda_powertools/utilities/idempotency/base.py

+26-22
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1+
from __future__ import annotations
2+
13
import datetime
24
import logging
35
from copy import deepcopy
4-
from typing import Any, Callable, Dict, Optional, Tuple
6+
from typing import TYPE_CHECKING, Any, Callable
57

6-
from aws_lambda_powertools.utilities.idempotency.config import (
7-
IdempotencyConfig,
8-
)
98
from aws_lambda_powertools.utilities.idempotency.exceptions import (
109
IdempotencyAlreadyInProgressError,
1110
IdempotencyInconsistentStateError,
@@ -15,20 +14,25 @@
1514
IdempotencyPersistenceLayerError,
1615
IdempotencyValidationError,
1716
)
18-
from aws_lambda_powertools.utilities.idempotency.persistence.base import (
19-
BasePersistenceLayer,
20-
)
2117
from aws_lambda_powertools.utilities.idempotency.persistence.datarecord import (
2218
STATUS_CONSTANTS,
2319
DataRecord,
2420
)
25-
from aws_lambda_powertools.utilities.idempotency.serialization.base import (
26-
BaseIdempotencySerializer,
27-
)
2821
from aws_lambda_powertools.utilities.idempotency.serialization.no_op import (
2922
NoOpSerializer,
3023
)
3124

25+
if TYPE_CHECKING:
26+
from aws_lambda_powertools.utilities.idempotency.config import (
27+
IdempotencyConfig,
28+
)
29+
from aws_lambda_powertools.utilities.idempotency.persistence.base import (
30+
BasePersistenceLayer,
31+
)
32+
from aws_lambda_powertools.utilities.idempotency.serialization.base import (
33+
BaseIdempotencySerializer,
34+
)
35+
3236
MAX_RETRIES = 2
3337
logger = logging.getLogger(__name__)
3438

@@ -69,9 +73,9 @@ def __init__(
6973
function_payload: Any,
7074
config: IdempotencyConfig,
7175
persistence_store: BasePersistenceLayer,
72-
output_serializer: Optional[BaseIdempotencySerializer] = None,
73-
function_args: Optional[Tuple] = None,
74-
function_kwargs: Optional[Dict] = None,
76+
output_serializer: BaseIdempotencySerializer | None = None,
77+
function_args: tuple | None = None,
78+
function_kwargs: dict | None = None,
7579
):
7680
"""
7781
Initialize the IdempotencyHandler
@@ -84,12 +88,12 @@ def __init__(
8488
Idempotency Configuration
8589
persistence_store : BasePersistenceLayer
8690
Instance of persistence layer to store idempotency records
87-
output_serializer: Optional[BaseIdempotencySerializer]
91+
output_serializer: BaseIdempotencySerializer | None
8892
Serializer to transform the data to and from a dictionary.
8993
If not supplied, no serialization is done via the NoOpSerializer
90-
function_args: Optional[Tuple]
94+
function_args: tuple | None
9195
Function arguments
92-
function_kwargs: Optional[Dict]
96+
function_kwargs: dict | None
9397
Function keyword arguments
9498
"""
9599
self.function = function
@@ -150,7 +154,7 @@ def _process_idempotency(self):
150154

151155
return self._get_function_response()
152156

153-
def _get_remaining_time_in_millis(self) -> Optional[int]:
157+
def _get_remaining_time_in_millis(self) -> int | None:
154158
"""
155159
Tries to determine the remaining time available for the current lambda invocation.
156160
@@ -160,7 +164,7 @@ def _get_remaining_time_in_millis(self) -> Optional[int]:
160164
161165
Returns
162166
-------
163-
Optional[int]
167+
int | None
164168
Remaining time in millis, or None if the remaining time cannot be determined.
165169
"""
166170

@@ -169,7 +173,7 @@ def _get_remaining_time_in_millis(self) -> Optional[int]:
169173

170174
return None
171175

172-
def _get_idempotency_record(self) -> Optional[DataRecord]:
176+
def _get_idempotency_record(self) -> DataRecord | None:
173177
"""
174178
Retrieve the idempotency record from the persistence layer.
175179
@@ -198,7 +202,7 @@ def _get_idempotency_record(self) -> Optional[DataRecord]:
198202

199203
return data_record
200204

201-
def _handle_for_status(self, data_record: DataRecord) -> Optional[Any]:
205+
def _handle_for_status(self, data_record: DataRecord) -> Any | None:
202206
"""
203207
Take appropriate action based on data_record's status
204208
@@ -208,7 +212,7 @@ def _handle_for_status(self, data_record: DataRecord) -> Optional[Any]:
208212
209213
Returns
210214
-------
211-
Optional[Any]
215+
Any | None
212216
Function's response previously used for this idempotency key, if it has successfully executed already.
213217
In case an output serializer is configured, the response is deserialized.
214218
@@ -235,7 +239,7 @@ def _handle_for_status(self, data_record: DataRecord) -> Optional[Any]:
235239
f"Execution already in progress with idempotency key: "
236240
f"{self.persistence_store.event_key_jmespath}={data_record.idempotency_key}",
237241
)
238-
response_dict: Optional[dict] = data_record.response_json_as_dict()
242+
response_dict: dict | None = data_record.response_json_as_dict()
239243
if response_dict is not None:
240244
serialized_response = self.output_serializer.from_dict(response_dict)
241245
if self.config.response_hook is not None:

aws_lambda_powertools/utilities/idempotency/config.py

+11-8
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
1-
from typing import Dict, Optional
1+
from __future__ import annotations
22

3-
from aws_lambda_powertools.utilities.idempotency import IdempotentHookFunction
4-
from aws_lambda_powertools.utilities.typing import LambdaContext
3+
from typing import TYPE_CHECKING
4+
5+
if TYPE_CHECKING:
6+
from aws_lambda_powertools.utilities.idempotency import IdempotentHookFunction
7+
from aws_lambda_powertools.utilities.typing import LambdaContext
58

69

710
class IdempotencyConfig:
811
def __init__(
912
self,
1013
event_key_jmespath: str = "",
1114
payload_validation_jmespath: str = "",
12-
jmespath_options: Optional[Dict] = None,
15+
jmespath_options: dict | None = None,
1316
raise_on_no_idempotency_key: bool = False,
1417
expires_after_seconds: int = 60 * 60, # 1 hour default
1518
use_local_cache: bool = False,
1619
local_cache_max_items: int = 256,
1720
hash_function: str = "md5",
18-
lambda_context: Optional[LambdaContext] = None,
19-
response_hook: Optional[IdempotentHookFunction] = None,
21+
lambda_context: LambdaContext | None = None,
22+
response_hook: IdempotentHookFunction | None = None,
2023
):
2124
"""
2225
Initialize the base persistence layer
@@ -50,8 +53,8 @@ def __init__(
5053
self.use_local_cache = use_local_cache
5154
self.local_cache_max_items = local_cache_max_items
5255
self.hash_function = hash_function
53-
self.lambda_context: Optional[LambdaContext] = lambda_context
54-
self.response_hook: Optional[IdempotentHookFunction] = response_hook
56+
self.lambda_context: LambdaContext | None = lambda_context
57+
self.response_hook: IdempotentHookFunction | None = response_hook
5558

5659
def register_lambda_context(self, lambda_context: LambdaContext):
5760
"""Captures the Lambda context, to calculate the remaining time before the invocation times out"""

aws_lambda_powertools/utilities/idempotency/exceptions.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
Idempotency errors
33
"""
44

5-
from typing import Optional, Union
5+
from __future__ import annotations
66

7-
from aws_lambda_powertools.utilities.idempotency.persistence.datarecord import DataRecord
7+
from typing import TYPE_CHECKING
8+
9+
if TYPE_CHECKING:
10+
from aws_lambda_powertools.utilities.idempotency.persistence.datarecord import DataRecord
811

912

1013
class BaseError(Exception):
@@ -13,7 +16,7 @@ class BaseError(Exception):
1316
See https://github.com/aws-powertools/powertools-lambda-python/issues/1772
1417
"""
1518

16-
def __init__(self, *args: Optional[Union[str, Exception]]):
19+
def __init__(self, *args: str | Exception | None):
1720
self.message = str(args[0]) if args else ""
1821
self.details = "".join(str(arg) for arg in args[1:]) if args[1:] else None
1922

@@ -31,7 +34,7 @@ class IdempotencyItemAlreadyExistsError(BaseError):
3134
Item attempting to be inserted into persistence store already exists and is not expired
3235
"""
3336

34-
def __init__(self, *args: Optional[Union[str, Exception]], old_data_record: Optional[DataRecord] = None):
37+
def __init__(self, *args: str | Exception | None, old_data_record: DataRecord | None = None):
3538
self.old_data_record = old_data_record
3639
super().__init__(*args)
3740

aws_lambda_powertools/utilities/idempotency/hook.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
from typing import Any, Protocol
1+
from __future__ import annotations
22

3-
from aws_lambda_powertools.utilities.idempotency.persistence.datarecord import DataRecord
3+
from typing import TYPE_CHECKING, Any, Protocol
4+
5+
if TYPE_CHECKING:
6+
from aws_lambda_powertools.utilities.idempotency.persistence.datarecord import DataRecord
47

58

69
class IdempotentHookFunction(Protocol):

aws_lambda_powertools/utilities/idempotency/idempotency.py

+17-13
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,40 @@
22
Primary interface for idempotent Lambda functions utility
33
"""
44

5+
from __future__ import annotations
6+
57
import functools
68
import logging
79
import os
810
from inspect import isclass
9-
from typing import Any, Callable, Dict, Optional, Type, Union, cast
11+
from typing import TYPE_CHECKING, Any, Callable, cast
1012

1113
from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
1214
from aws_lambda_powertools.shared import constants
1315
from aws_lambda_powertools.shared.types import AnyCallableT
1416
from aws_lambda_powertools.utilities.idempotency.base import IdempotencyHandler
1517
from aws_lambda_powertools.utilities.idempotency.config import IdempotencyConfig
16-
from aws_lambda_powertools.utilities.idempotency.persistence.base import (
17-
BasePersistenceLayer,
18-
)
1918
from aws_lambda_powertools.utilities.idempotency.serialization.base import (
2019
BaseIdempotencyModelSerializer,
2120
BaseIdempotencySerializer,
2221
)
23-
from aws_lambda_powertools.utilities.typing import LambdaContext
22+
23+
if TYPE_CHECKING:
24+
from aws_lambda_powertools.utilities.idempotency.persistence.base import (
25+
BasePersistenceLayer,
26+
)
27+
from aws_lambda_powertools.utilities.typing import LambdaContext
2428

2529
logger = logging.getLogger(__name__)
2630

2731

2832
@lambda_handler_decorator
2933
def idempotent(
3034
handler: Callable[[Any, LambdaContext], Any],
31-
event: Dict[str, Any],
35+
event: dict[str, Any],
3236
context: LambdaContext,
3337
persistence_store: BasePersistenceLayer,
34-
config: Optional[IdempotencyConfig] = None,
38+
config: IdempotencyConfig | None = None,
3539
**kwargs,
3640
) -> Any:
3741
"""
@@ -41,9 +45,9 @@ def idempotent(
4145
----------
4246
handler: Callable
4347
Lambda's handler
44-
event: Dict
48+
event: dict
4549
Lambda's Event
46-
context: Dict
50+
context: dict
4751
Lambda's Context
4852
persistence_store: BasePersistenceLayer
4953
Instance of BasePersistenceLayer to store data
@@ -86,12 +90,12 @@ def idempotent(
8690

8791

8892
def idempotent_function(
89-
function: Optional[AnyCallableT] = None,
93+
function: AnyCallableT | None = None,
9094
*,
9195
data_keyword_argument: str,
9296
persistence_store: BasePersistenceLayer,
93-
config: Optional[IdempotencyConfig] = None,
94-
output_serializer: Optional[Union[BaseIdempotencySerializer, Type[BaseIdempotencyModelSerializer]]] = None,
97+
config: IdempotencyConfig | None = None,
98+
output_serializer: BaseIdempotencySerializer | type[BaseIdempotencyModelSerializer] | None = None,
9599
**kwargs: Any,
96100
) -> Any:
97101
"""
@@ -107,7 +111,7 @@ def idempotent_function(
107111
Instance of BasePersistenceLayer to store data
108112
config: IdempotencyConfig
109113
Configuration
110-
output_serializer: Optional[Union[BaseIdempotencySerializer, Type[BaseIdempotencyModelSerializer]]]
114+
output_serializer: BaseIdempotencySerializer | type[BaseIdempotencyModelSerializer] | None
111115
Serializer to transform the data to and from a dictionary.
112116
If not supplied, no serialization is done via the NoOpSerializer.
113117
In case a serializer of type inheriting BaseIdempotencyModelSerializer is given,

0 commit comments

Comments
 (0)