@@ -277,6 +277,23 @@ def test_step_details_minimal():
277277 assert details .error is None
278278
279279
280+ def test_step_details_from_existing ():
281+ """Test StepDetails.from_existing factory method."""
282+ original = StepDetails (
283+ attempt = 2 ,
284+ next_attempt_timestamp = datetime .datetime (2023 , 1 , 1 , tzinfo = datetime .UTC ),
285+ result = "original_result" ,
286+ error = ErrorObject .from_message ("original_error" ),
287+ )
288+
289+ # Test clearing next_attempt_timestamp
290+ updated = StepDetails .from_existing (original , next_attempt_timestamp = None )
291+ assert updated .attempt == 2
292+ assert updated .next_attempt_timestamp is None
293+ assert updated .result == "original_result"
294+ assert updated .error .message == "original_error"
295+
296+
280297def test_wait_details_from_dict ():
281298 """Test WaitDetails.from_dict method."""
282299 timestamp = datetime .datetime (2023 , 1 , 1 , 12 , 0 , 0 , tzinfo = datetime .UTC )
@@ -330,6 +347,36 @@ def test_callback_details_minimal():
330347 assert details .error is None
331348
332349
350+ def test_callback_details_from_existing_with_result ():
351+ """Test CallbackDetails.from_existing factory method with result update."""
352+ original = CallbackDetails (
353+ callback_id = "cb123" ,
354+ result = "original_result" ,
355+ error = ErrorObject .from_message ("original_error" ),
356+ )
357+
358+ # Test updating result
359+ updated = CallbackDetails .from_existing (original , result = "new_result" )
360+ assert updated .callback_id == "cb123"
361+ assert updated .result == "new_result"
362+ assert updated .error .message == "original_error"
363+
364+
365+ def test_callback_details_from_existing_with_error ():
366+ """Test CallbackDetails.from_existing factory method with error update."""
367+ original = CallbackDetails (
368+ callback_id = "cb123" ,
369+ result = "original_result" ,
370+ error = None ,
371+ )
372+
373+ new_error = ErrorObject .from_message ("new_error" )
374+ updated = CallbackDetails .from_existing (original , error = new_error )
375+ assert updated .callback_id == "cb123"
376+ assert updated .result == "original_result"
377+ assert updated .error .message == "new_error"
378+
379+
333380def test_invoke_details_from_dict ():
334381 """Test ChainedInvokeDetails.from_dict method."""
335382 error_data = {"ErrorMessage" : "Invoke error" }
@@ -1119,6 +1166,27 @@ def test_operation_from_dict_no_options():
11191166 assert operation .operation_id == "test-id"
11201167
11211168
1169+ def test_operation_from_existing_with_callback_details ():
1170+ """Test Operation.from_existing factory method with callback_details update."""
1171+ original = Operation (
1172+ operation_id = "op1" ,
1173+ operation_type = OperationType .CALLBACK ,
1174+ status = OperationStatus .STARTED ,
1175+ callback_details = CallbackDetails (callback_id = "cb123" , result = None ),
1176+ )
1177+
1178+ new_callback_details = CallbackDetails (callback_id = "cb123" , result = "success_result" )
1179+ updated = Operation .from_existing (
1180+ original ,
1181+ status = OperationStatus .SUCCEEDED ,
1182+ callback_details = new_callback_details ,
1183+ )
1184+
1185+ assert updated .status == OperationStatus .SUCCEEDED
1186+ assert updated .callback_details .callback_id == "cb123"
1187+ assert updated .callback_details .result == "success_result"
1188+
1189+
11221190def test_operation_from_dict_individual_options ():
11231191 """Test Operation.from_dict with each option type individually."""
11241192 # Test with just ContextOptions
@@ -1510,6 +1578,60 @@ def test_operation_to_dict_all_optional_fields():
15101578 assert result ["SubType" ] == "Step"
15111579
15121580
1581+ def test_operation_from_existing ():
1582+ """Test Operation.from_existing factory method."""
1583+ original = Operation (
1584+ operation_id = "op1" ,
1585+ operation_type = OperationType .STEP ,
1586+ status = OperationStatus .STARTED ,
1587+ parent_id = "parent1" ,
1588+ name = "original_step" ,
1589+ start_timestamp = datetime .datetime (2023 , 1 , 1 , tzinfo = datetime .UTC ),
1590+ step_details = StepDetails (attempt = 1 , result = "original_result" ),
1591+ )
1592+
1593+ # Test updating status and end_timestamp
1594+ updated = Operation .from_existing (
1595+ original ,
1596+ status = OperationStatus .SUCCEEDED ,
1597+ end_timestamp = datetime .datetime (2023 , 1 , 2 , tzinfo = datetime .UTC ),
1598+ )
1599+
1600+ assert updated .operation_id == "op1"
1601+ assert updated .operation_type == OperationType .STEP
1602+ assert updated .status == OperationStatus .SUCCEEDED
1603+ assert updated .parent_id == "parent1"
1604+ assert updated .name == "original_step"
1605+ assert updated .start_timestamp == datetime .datetime (2023 , 1 , 1 , tzinfo = datetime .UTC )
1606+ assert updated .end_timestamp == datetime .datetime (2023 , 1 , 2 , tzinfo = datetime .UTC )
1607+ assert updated .step_details .attempt == 1
1608+ assert updated .step_details .result == "original_result"
1609+
1610+
1611+ def test_operation_from_existing_with_step_details ():
1612+ """Test Operation.from_existing factory method with step_details update."""
1613+ original = Operation (
1614+ operation_id = "op1" ,
1615+ operation_type = OperationType .STEP ,
1616+ status = OperationStatus .PENDING ,
1617+ step_details = StepDetails (
1618+ attempt = 1 ,
1619+ next_attempt_timestamp = datetime .datetime (2023 , 1 , 1 , tzinfo = datetime .UTC ),
1620+ ),
1621+ )
1622+
1623+ new_step_details = StepDetails (attempt = 1 , next_attempt_timestamp = None )
1624+ updated = Operation .from_existing (
1625+ original ,
1626+ status = OperationStatus .READY ,
1627+ step_details = new_step_details ,
1628+ )
1629+
1630+ assert updated .status == OperationStatus .READY
1631+ assert updated .step_details .attempt == 1
1632+ assert updated .step_details .next_attempt_timestamp is None
1633+
1634+
15131635# =============================================================================
15141636# Tests for Checkpoint Classes
15151637# =============================================================================
0 commit comments