from abc import ABC, abstractmethod from enum import Enum from typing import List, Any, Optional from radiuma_api.io_port import InPort from radiuma_api.io_port import OutPort from radiuma_api.execution_context import ExecutionContext # Write Codes Here: class Status(Enum): PENDING = "pending" READY = "ready" RUNNING = "running" PAUSED = "paused" STOPPED = "stopped" COMPLETED = "completed" FAILED = "failed" class TaskEvent(Enum): BEFORE_RUN = "before_run" AFTER_RUN = "after_run" ON_ERROR = "on_error" STATUS_CHANGED = "status_changed" class TaskEventListener: def handle(self, event: TaskEvent, task: "Task", payload: Optional[Any] = None): pass class Task(ABC): def __init__(self, name: str): self.name = name self.status = Status.PENDING self.inputs: List[InPort] = [] self.outputs: List[OutPort] = [] self._listeners: List[TaskEventListener] = [] # Events def add_listener(self, listener: TaskEventListener): self._listeners.append(listener) def _emit(self, event: TaskEvent, payload: Optional[Any] = None): for listener in self._listeners: listener.handle(event, self, payload) def _set_status(self, new_status: Status): old_status = self.status self.status = new_status if old_status != new_status: self._emit(TaskEvent.STATUS_CHANGED, {"from": old_status, "to": new_status}) # Lifecycle def pause(self): if self.status == Status.RUNNING: self._set_status(Status.PAUSED) def resume(self): if self.status == Status.PAUSED: self._set_status(Status.READY) def stop(self): if self.status in (Status.RUNNING, Status.PAUSED, Status.READY): self._set_status(Status.STOPPED) # Ports def _add_input_port(self, port: InPort): port.parent_task = self self.inputs.append(port) def _add_output_port(self, port: OutPort): port.parent_task = self self.outputs.append(port) def check_inputs_ready(self, context: ExecutionContext) -> bool: """Check if all required inputs have data in ExecutionContext.""" for in_port in self.inputs: if in_port.required and not context.has_data(in_port): return False return True # Runnable @abstractmethod def run(self, context: ExecutionContext): pass