GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix(idempotency): return stored falsy responses on replay (#8701) · exg/powertools-lambda-python@d7b3024

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • aws_lambda_powertools/utilities/idempotency
    • base.py
  • tests/functional/idempotency/_boto3
    • test_idempotency.py
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎aws_lambda_powertools/utilities/idempotency/base.py‎

Copy file name to clipboardExpand all lines: aws_lambda_powertools/utilities/idempotency/base.py
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ def _handle_for_status(self, data_record: DataRecord) -> Any | None:
271271
raise IdempotencyAlreadyInProgressError(inprogress_error_message)
272272

273273
response_dict = data_record.response_json_as_dict()
274-
serialized_response = self.output_serializer.from_dict(response_dict) if response_dict else None
274+
serialized_response = self.output_serializer.from_dict(response_dict) if response_dict is not None else None
275275

276276
if self.config.response_hook:
277277
logger.debug("Response hook configured, invoking function")
Collapse file

‎tests/functional/idempotency/_boto3/test_idempotency.py‎

Copy file name to clipboardExpand all lines: tests/functional/idempotency/_boto3/test_idempotency.py
+30Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,6 +1398,36 @@ def record_handler(record):
13981398
assert from_dict_called is False, "in case response is None, from_dict should not be called"
13991399

14001400

1401+
@pytest.mark.parametrize(
1402+
"expected_result",
1403+
[0, False, "", [], {}],
1404+
ids=["zero", "false", "empty_str", "empty_list", "empty_dict"],
1405+
)
1406+
def test_idempotent_function_falsy_response_replay(expected_result):
1407+
# GIVEN a function returning a falsy value
1408+
config = IdempotencyConfig(use_local_cache=True)
1409+
mock_event = {"customer_id": "fake", "transaction_id": "fake-id"}
1410+
idempotency_key = f"{TESTS_MODULE_PREFIX}.test_idempotent_function_falsy_response_replay.<locals>.record_handler#{hash_idempotency_key(mock_event)}" # noqa E501
1411+
persistence_layer = MockPersistenceLayer(expected_idempotency_key=idempotency_key)
1412+
calls = 0
1413+
1414+
@idempotent_function(persistence_store=persistence_layer, data_keyword_argument="record", config=config)
1415+
def record_handler(record):
1416+
nonlocal calls
1417+
calls += 1
1418+
return expected_result
1419+
1420+
# WHEN calling the function twice with the same payload
1421+
first_result = record_handler(record=mock_event)
1422+
second_result = record_handler(record=mock_event)
1423+
1424+
# THEN the second call returns the stored falsy value instead of None
1425+
assert first_result == expected_result
1426+
assert second_result == expected_result
1427+
assert type(second_result) is type(expected_result)
1428+
assert calls == 1
1429+
1430+
14011431
@pytest.mark.parametrize("output_serializer_type", ["explicit", "deduced"])
14021432
def test_idempotent_function_serialization_dataclass(output_serializer_type: str):
14031433
# GIVEN

0 commit comments

Comments
0 (0)
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.