diff --git a/temporalio/client.py b/temporalio/client.py index 770a51392..593cef4a4 100644 --- a/temporalio/client.py +++ b/temporalio/client.py @@ -3147,6 +3147,17 @@ class WorkflowExecutionStatus(IntEnum): temporalio.api.enums.v1.WorkflowExecutionStatus.WORKFLOW_EXECUTION_STATUS_TIMED_OUT ) + @property + def to_pascal_case(self) -> str: + """Convert WorkflowExecutionStatus enum name to Temporal search attribute format. + + Returns: + Formatted string for ExecutionStatus search attribute + """ + # Convert "TIMED_OUT" -> "TimedOut", "CONTINUED_AS_NEW" -> "ContinuedAsNew", etc. + return "".join(word.capitalize() for word in self.name.split("_")) + + @dataclass class WorkflowExecutionCount: diff --git a/tests/test_client.py b/tests/test_client.py index 63dec2810..d2fa0a689 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -410,6 +410,26 @@ async def test_query_rejected(client: Client, worker: ExternalWorker): assert err.value.status == WorkflowExecutionStatus.COMPLETED +def test_workflow_execution_status_search_attribute_value(): + """Test that WorkflowExecutionStatus.to_pascal_case converts to PascalCase correctly.""" + test_cases = [ + (WorkflowExecutionStatus.RUNNING, "Running"), + (WorkflowExecutionStatus.COMPLETED, "Completed"), + (WorkflowExecutionStatus.FAILED, "Failed"), + (WorkflowExecutionStatus.CANCELED, "Canceled"), + (WorkflowExecutionStatus.TERMINATED, "Terminated"), + (WorkflowExecutionStatus.TIMED_OUT, "TimedOut"), + (WorkflowExecutionStatus.CONTINUED_AS_NEW, "ContinuedAsNew"), + ] + + for status, expected in test_cases: + actual = status.to_pascal_case + assert actual == expected, ( + f"WorkflowExecutionStatus.{status.name}.to_pascal_case " + f"returned '{actual}', expected '{expected}'" + ) + + async def test_signal(client: Client, worker: ExternalWorker): handle = await client.start_workflow( "kitchen_sink",