Skip to content

Commit 5fb8f30

Browse files
author
Rares Polenciuc
committed
refactor: replace dataclasses.replace with instance factories
1 parent fea8882 commit 5fb8f30

File tree

3 files changed

+40
-88
lines changed

3 files changed

+40
-88
lines changed

examples/src/wait_for_callback/wait_for_callback.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ def external_system_call(_callback_id: str) -> None:
1010
"""Simulate calling an external system with callback ID."""
1111
# In real usage, this would make an API call to an external system
1212
# passing the callback_id for the system to call back when done
13+
print(_callback_id)
1314

1415

1516
@durable_execution

src/aws_durable_execution_sdk_python_testing/execution.py

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

33
import json
4-
from dataclasses import replace
4+
55
from datetime import UTC, datetime
66
from enum import Enum
77
from threading import Lock
@@ -13,12 +13,14 @@
1313
InvocationStatus,
1414
)
1515
from aws_durable_execution_sdk_python.lambda_service import (
16+
CallbackDetails,
1617
ErrorObject,
1718
ExecutionDetails,
1819
Operation,
1920
OperationStatus,
2021
OperationType,
2122
OperationUpdate,
23+
StepDetails,
2224
)
2325

2426
from aws_durable_execution_sdk_python_testing.exceptions import (
@@ -289,10 +291,8 @@ def complete_wait(self, operation_id: str) -> Operation:
289291
with self._state_lock:
290292
self._token_sequence += 1
291293
# Build and assign updated operation
292-
self.operations[index] = replace(
293-
operation,
294-
status=OperationStatus.SUCCEEDED,
295-
end_timestamp=datetime.now(UTC),
294+
self.operations[index] = operation.create_succeeded(
295+
end_timestamp=datetime.now(UTC)
296296
)
297297
return self.operations[index]
298298

@@ -313,17 +313,7 @@ def complete_retry(self, operation_id: str) -> Operation:
313313
# Thread-safe increment sequence and operation update
314314
with self._state_lock:
315315
self._token_sequence += 1
316-
# Build updated step_details with cleared next_attempt_timestamp
317-
new_step_details = None
318-
if operation.step_details:
319-
new_step_details = replace(
320-
operation.step_details, next_attempt_timestamp=None
321-
)
322-
323-
# Build updated operation
324-
updated_operation = replace(
325-
operation, status=OperationStatus.READY, step_details=new_step_details
326-
)
316+
updated_operation = operation.create_completed_retry()
327317

328318
# Assign
329319
self.operations[index] = updated_operation
@@ -340,18 +330,9 @@ def complete_callback_success(
340330

341331
with self._state_lock:
342332
self._token_sequence += 1
343-
updated_callback_details = None
344-
if operation.callback_details:
345-
updated_callback_details = replace(
346-
operation.callback_details,
347-
result=result.decode() if result else None,
348-
)
349-
350-
self.operations[index] = replace(
351-
operation,
352-
status=OperationStatus.SUCCEEDED,
333+
self.operations[index] = operation.create_callback_result(
334+
result=result.decode() if result else result,
353335
end_timestamp=datetime.now(UTC),
354-
callback_details=updated_callback_details,
355336
)
356337
return self.operations[index]
357338

@@ -367,17 +348,9 @@ def complete_callback_failure(
367348

368349
with self._state_lock:
369350
self._token_sequence += 1
370-
updated_callback_details = None
371-
if operation.callback_details:
372-
updated_callback_details = replace(
373-
operation.callback_details, error=error
374-
)
375-
376-
self.operations[index] = replace(
377-
operation,
378-
status=OperationStatus.FAILED,
351+
self.operations[index] = operation.create_callback_failure(
352+
error=error,
379353
end_timestamp=datetime.now(UTC),
380-
callback_details=updated_callback_details,
381354
)
382355
return self.operations[index]
383356

@@ -386,8 +359,7 @@ def _end_execution(self, status: OperationStatus) -> None:
386359
execution_op: Operation = self.get_operation_execution_started()
387360
if execution_op.operation_type == OperationType.EXECUTION:
388361
with self._state_lock:
389-
self.operations[0] = replace(
390-
execution_op,
362+
self.operations[0] = execution_op.create_execution_end(
391363
status=status,
392364
end_timestamp=datetime.now(UTC),
393365
)

src/aws_durable_execution_sdk_python_testing/model.py

Lines changed: 28 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from __future__ import annotations
44

55
import datetime
6-
from dataclasses import dataclass, replace
6+
from dataclasses import dataclass
77
from enum import Enum
88
from typing import Any
99

@@ -2547,26 +2547,13 @@ def events_to_operations(events: list[Event]) -> list[Operation]:
25472547
# Merge with previous operation if it exists
25482548
# Most fields are immutable, so they get preserved from previous events
25492549
if previous_operation:
2550-
operation = replace(
2551-
operation,
2552-
name=operation.name or previous_operation.name,
2553-
parent_id=operation.parent_id or previous_operation.parent_id,
2554-
sub_type=operation.sub_type or previous_operation.sub_type,
2555-
start_timestamp=previous_operation.start_timestamp,
2556-
end_timestamp=previous_operation.end_timestamp,
2557-
execution_details=previous_operation.execution_details,
2558-
context_details=previous_operation.context_details,
2559-
step_details=previous_operation.step_details,
2560-
wait_details=previous_operation.wait_details,
2561-
callback_details=previous_operation.callback_details,
2562-
chained_invoke_details=previous_operation.chained_invoke_details,
2563-
)
2550+
operation = operation.create_merged_from_previous(previous_operation)
25642551

25652552
# Set timestamps based on event configuration
25662553
if event_config.is_start_event:
2567-
operation = replace(operation, start_timestamp=event.event_timestamp)
2554+
operation = operation.create_with_start_timestamp(event.event_timestamp)
25682555
if event_config.is_end_event:
2569-
operation = replace(operation, end_timestamp=event.event_timestamp)
2556+
operation = operation.create_with_end_timestamp(event.event_timestamp)
25702557

25712558
# Add operation-specific details incrementally
25722559
# Each event type contributes only the fields it has
@@ -2577,11 +2564,10 @@ def events_to_operations(events: list[Event]) -> list[Operation]:
25772564
and event.execution_started_details
25782565
and event.execution_started_details.input
25792566
):
2580-
operation = replace(
2581-
operation,
2582-
execution_details=ExecutionDetails(
2567+
operation = operation.create_with_execution_details(
2568+
ExecutionDetails(
25832569
input_payload=event.execution_started_details.input.payload
2584-
),
2570+
)
25852571
)
25862572

25872573
# CALLBACK details - merge callback_id, result, and error from different events
@@ -2613,13 +2599,12 @@ def events_to_operations(events: list[Event]) -> list[Operation]:
26132599
):
26142600
error = event.callback_timed_out_details.error.payload
26152601

2616-
operation = replace(
2617-
operation,
2618-
callback_details=CallbackDetails(
2602+
operation = operation.create_with_callback_details(
2603+
CallbackDetails(
26192604
callback_id=callback_id,
26202605
result=result,
26212606
error=error,
2622-
),
2607+
)
26232608
)
26242609

26252610
# STEP details - only update if this event type has result data
@@ -2655,23 +2640,21 @@ def events_to_operations(events: list[Event]) -> list[Operation]:
26552640
seconds=event.step_failed_details.retry_details.next_attempt_delay_seconds
26562641
)
26572642

2658-
operation = replace(
2659-
operation,
2660-
step_details=StepDetails(
2643+
operation = operation.create_with_step_details(
2644+
StepDetails(
26612645
result=result_val,
26622646
error=error_val,
26632647
attempt=attempt,
26642648
next_attempt_timestamp=next_attempt_ts,
2665-
),
2649+
)
26662650
)
26672651

26682652
# WAIT details
26692653
if operation_type == OperationType.WAIT and event.wait_started_details:
2670-
operation = replace(
2671-
operation,
2672-
wait_details=WaitDetails(
2654+
operation = operation.create_with_wait_details(
2655+
WaitDetails(
26732656
scheduled_end_timestamp=event.wait_started_details.scheduled_end_timestamp
2674-
),
2657+
)
26752658
)
26762659

26772660
# CONTEXT details - only update if this event type has result data (matching TypeScript hasResult)
@@ -2680,20 +2663,18 @@ def events_to_operations(events: list[Event]) -> list[Operation]:
26802663
event.context_succeeded_details
26812664
and event.context_succeeded_details.result
26822665
):
2683-
operation = replace(
2684-
operation,
2685-
context_details=ContextDetails(
2666+
operation = operation.create_with_context_details(
2667+
ContextDetails(
26862668
result=event.context_succeeded_details.result.payload,
26872669
error=None,
2688-
),
2670+
)
26892671
)
26902672
elif event.context_failed_details and event.context_failed_details.error:
2691-
operation = replace(
2692-
operation,
2693-
context_details=ContextDetails(
2673+
operation = operation.create_with_context_details(
2674+
ContextDetails(
26942675
result=None,
26952676
error=event.context_failed_details.error.payload,
2696-
),
2677+
)
26972678
)
26982679

26992680
# CHAINED_INVOKE details - only update if this event type has result data (matching TypeScript hasResult)
@@ -2702,23 +2683,21 @@ def events_to_operations(events: list[Event]) -> list[Operation]:
27022683
event.chained_invoke_succeeded_details
27032684
and event.chained_invoke_succeeded_details.result
27042685
):
2705-
operation = replace(
2706-
operation,
2707-
chained_invoke_details=ChainedInvokeDetails(
2686+
operation = operation.create_with_chained_invoke_details(
2687+
ChainedInvokeDetails(
27082688
result=event.chained_invoke_succeeded_details.result.payload,
27092689
error=None,
2710-
),
2690+
)
27112691
)
27122692
elif (
27132693
event.chained_invoke_failed_details
27142694
and event.chained_invoke_failed_details.error
27152695
):
2716-
operation = replace(
2717-
operation,
2718-
chained_invoke_details=ChainedInvokeDetails(
2696+
operation = operation.create_with_chained_invoke_details(
2697+
ChainedInvokeDetails(
27192698
result=None,
27202699
error=event.chained_invoke_failed_details.error.payload,
2721-
),
2700+
)
27222701
)
27232702

27242703
# Store in map

0 commit comments

Comments
 (0)