Skip to content

Commit da54341

Browse files
committed
Use Protocol for type checking
1 parent 07479b6 commit da54341

File tree

4 files changed

+19
-20
lines changed

4 files changed

+19
-20
lines changed

aws_lambda_powertools/utilities/idempotency/idempotency.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
from aws_lambda_powertools.utilities.idempotency.persistence.base import (
2929
BasePersistenceLayer,
3030
)
31-
from aws_lambda_powertools.utilities.typing import DurableContext, LambdaContext
31+
from aws_lambda_powertools.utilities.typing import DurableContextProtocol, LambdaContext
3232

3333
from aws_lambda_powertools.warnings import PowertoolsUserWarning
3434

@@ -37,9 +37,9 @@
3737

3838
@lambda_handler_decorator
3939
def idempotent(
40-
handler: Callable[[Any, LambdaContext | DurableContext], Any],
40+
handler: Callable[[Any, LambdaContext | DurableContextProtocol], Any],
4141
event: dict[str, Any],
42-
context: LambdaContext | DurableContext,
42+
context: LambdaContext | DurableContextProtocol,
4343
persistence_store: BasePersistenceLayer,
4444
config: IdempotencyConfig | None = None,
4545
key_prefix: str | None = None,
@@ -92,9 +92,9 @@ def handler(event, context):
9292

9393
config = config or IdempotencyConfig()
9494

95-
if hasattr(context, "state"):
95+
if hasattr(context, "state") and hasattr(context, "lambda_context"):
9696
# Extract lambda_context from DurableContext
97-
durable_context = cast("DurableContext", context)
97+
durable_context = cast("DurableContextProtocol", context)
9898
config.register_lambda_context(durable_context.lambda_context)
9999
# Note: state.operations is accessed via duck typing at runtime
100100
is_replay = len(durable_context.state.operations) > 1 # type: ignore[attr-defined]

aws_lambda_powertools/utilities/typing/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
[`Typing`](../utilities/typing.md)
55
"""
66

7-
from .lambda_context import DurableContext, LambdaContext
7+
from .lambda_context import DurableContextProtocol, LambdaContext
88

9-
__all__ = ["DurableContext", "LambdaContext"]
9+
__all__ = ["DurableContextProtocol", "LambdaContext"]

aws_lambda_powertools/utilities/typing/lambda_context.py

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

3-
from typing import TYPE_CHECKING
3+
from typing import TYPE_CHECKING, Protocol, runtime_checkable
44

55
if TYPE_CHECKING:
66
from aws_lambda_powertools.utilities.typing.lambda_client_context import (
@@ -95,14 +95,13 @@ def get_remaining_time_in_millis() -> int:
9595
return 0
9696

9797

98-
class DurableContext:
98+
@runtime_checkable
99+
class DurableContextProtocol(Protocol):
99100
_lambda_context: LambdaContext
100101
_state: object
101102

102103
@property
103-
def lambda_context(self) -> LambdaContext:
104-
return self._lambda_context
104+
def lambda_context(self) -> LambdaContext: ...
105105

106106
@property
107-
def state(self) -> object:
108-
return self._state
107+
def state(self) -> object: ...

tests/functional/idempotency/_boto3/test_idempotency.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
from aws_lambda_powertools.utilities.idempotency.serialization.dataclass import (
4747
DataclassSerializer,
4848
)
49-
from aws_lambda_powertools.utilities.typing import DurableContext
49+
from aws_lambda_powertools.utilities.typing import DurableContextProtocol
5050
from aws_lambda_powertools.utilities.validation import envelopes, validator
5151
from aws_lambda_powertools.warnings import PowertoolsUserWarning
5252
from tests.functional.idempotency.utils import (
@@ -2145,18 +2145,18 @@ def lambda_handler(record, context):
21452145
@pytest.fixture
21462146
def durable_context_single_operation(lambda_context):
21472147
"""DurableContext with single operation (execution mode, is_replay=False)"""
2148-
durable_ctx = DurableContext()
2149-
durable_ctx._lambda_context = lambda_context
2150-
durable_ctx._state = Mock(operations=[{"id": "op1"}])
2148+
durable_ctx = Mock(spec=DurableContextProtocol)
2149+
durable_ctx.lambda_context = lambda_context
2150+
durable_ctx.state = Mock(operations=[{"id": "op1"}])
21512151
return durable_ctx
21522152

21532153

21542154
@pytest.fixture
21552155
def durable_context_multiple_operations(lambda_context):
21562156
"""DurableContext with multiple operations (replay mode, is_replay=True)"""
2157-
durable_ctx = DurableContext()
2158-
durable_ctx._lambda_context = lambda_context
2159-
durable_ctx._state = Mock(operations=[{"id": "op1"}, {"id": "op2"}])
2157+
durable_ctx = Mock(spec=DurableContextProtocol)
2158+
durable_ctx.lambda_context = lambda_context
2159+
durable_ctx.state = Mock(operations=[{"id": "op1"}, {"id": "op2"}])
21602160
return durable_ctx
21612161

21622162

0 commit comments

Comments
 (0)