Skip to content

Commit 91726c1

Browse files
committed
chore: test dataclasses/pydantic with jmespath
1 parent 4f69010 commit 91726c1

File tree

2 files changed

+76
-15
lines changed

2 files changed

+76
-15
lines changed

aws_lambda_powertools/utilities/idempotency/base.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323

2424
def _prepare_data(data: Any) -> Any:
2525
"""Prepare data for json serialization.
26-
This will convert dataclasses, pydantic models or event source data classes to a dict."""
26+
27+
We will convert Python dataclasses, pydantic models or event source data classes to a dict,
28+
otherwise return data as-is.
29+
"""
2730
if hasattr(data, "__dataclass_fields__"):
2831
import dataclasses
2932

tests/functional/idempotency/test_idempotency.py

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@
3030
TABLE_NAME = "TEST_TABLE"
3131

3232

33+
def get_dataclasses_lib():
34+
"""Python 3.6 doesn't support dataclasses natively"""
35+
import dataclasses
36+
37+
return dataclasses
38+
39+
3340
# Using parametrize to run test twice, with two separate instances of persistence store. One instance with caching
3441
# enabled, and one without.
3542
@pytest.mark.parametrize("idempotency_config", [{"use_local_cache": False}, {"use_local_cache": True}], indirect=True)
@@ -1073,23 +1080,20 @@ def test_invalid_dynamodb_persistence_layer():
10731080
assert str(ve.value) == "key_attr [id] and sort_key_attr [id] cannot be the same!"
10741081

10751082

1083+
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher for dataclasses")
10761084
def test_idempotent_function_dataclasses():
1077-
try:
1078-
# Scenario _prepare_data should convert a python dataclasses to a dict
1079-
from dataclasses import asdict, dataclass
1085+
# Scenario _prepare_data should convert a python dataclasses to a dict
1086+
dataclasses = get_dataclasses_lib()
10801087

1081-
@dataclass
1082-
class Foo:
1083-
name: str
1084-
1085-
expected_result = {"name": "Bar"}
1086-
data = Foo(name="Bar")
1087-
as_dict = _prepare_data(data)
1088-
assert as_dict == asdict(data)
1089-
assert as_dict == expected_result
1088+
@dataclasses.dataclass
1089+
class Foo:
1090+
name: str
10901091

1091-
except ModuleNotFoundError:
1092-
pass # Python 3.6
1092+
expected_result = {"name": "Bar"}
1093+
data = Foo(name="Bar")
1094+
as_dict = _prepare_data(data)
1095+
assert as_dict == dataclasses.asdict(data)
1096+
assert as_dict == expected_result
10931097

10941098

10951099
def test_idempotent_function_pydantic():
@@ -1108,3 +1112,57 @@ class Foo(BaseModel):
11081112
def test_idempotent_function_other(data):
11091113
# All other data types should be left as is
11101114
assert _prepare_data(data) == data
1115+
1116+
1117+
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher for dataclasses")
1118+
def test_idempotent_function_dataclass_with_jmespath():
1119+
# GIVEN
1120+
dataclasses = get_dataclasses_lib()
1121+
config = IdempotencyConfig(event_key_jmespath="transaction_id", use_local_cache=True)
1122+
mock_event = {"customer_id": "fake", "transaction_id": "fake-id"}
1123+
persistence_layer = MockPersistenceLayer(
1124+
expected_idempotency_key="test-func.collect_payment#"
1125+
+ hashlib.md5(serialize(mock_event["transaction_id"]).encode()).hexdigest()
1126+
)
1127+
1128+
@dataclasses.dataclass
1129+
class Payment:
1130+
customer_id: str
1131+
transaction_id: str
1132+
1133+
@idempotent_function(data_keyword_argument="payment", persistence_store=persistence_layer, config=config)
1134+
def collect_payment(payment: Payment):
1135+
return payment.transaction_id
1136+
1137+
# WHEN
1138+
payment = Payment(**mock_event)
1139+
result = collect_payment(payment=payment)
1140+
1141+
# THEN idempotency key assertion happens at MockPersistenceLayer
1142+
assert result == payment.transaction_id
1143+
1144+
1145+
@pytest.mark.skipif(sys.version_info < (3, 7), reason="requires python3.7 or higher for dataclasses")
1146+
def test_idempotent_function_pydantic_with_jmespath():
1147+
# GIVEN
1148+
config = IdempotencyConfig(event_key_jmespath="transaction_id", use_local_cache=True)
1149+
mock_event = {"customer_id": "fake", "transaction_id": "fake-id"}
1150+
persistence_layer = MockPersistenceLayer(
1151+
expected_idempotency_key="test-func.collect_payment#"
1152+
+ hashlib.md5(serialize(mock_event["transaction_id"]).encode()).hexdigest()
1153+
)
1154+
1155+
class Payment(BaseModel):
1156+
customer_id: str
1157+
transaction_id: str
1158+
1159+
@idempotent_function(data_keyword_argument="payment", persistence_store=persistence_layer, config=config)
1160+
def collect_payment(payment: Payment):
1161+
return payment.transaction_id
1162+
1163+
# WHEN
1164+
payment = Payment(**mock_event)
1165+
result = collect_payment(payment=payment)
1166+
1167+
# THEN idempotency key assertion happens at MockPersistenceLayer
1168+
assert result == payment.transaction_id

0 commit comments

Comments
 (0)