Source code for pyniryo_nate.models.programs

import re
from dataclasses import dataclass
from datetime import datetime
from typing import Optional
from uuid import UUID

from strenum import StrEnum

from .._internal import transport_models
from . import ExecutorStatus


[docs] class ProgramType(StrEnum): """ Enumeration of supported program types and Python versions. """ PYTHON39 = 'python3.9' PYTHON310 = 'python3.10' PYTHON311 = 'python3.11' PYTHON312 = 'python3.12' GOLANG = 'golang' def _key(self) -> tuple[str, tuple[int, ...]]: pattern = r'^([a-z]+)([\d\.?]+)$' match = re.match(pattern, self) if not match: raise ValueError(f"Invalid ProgramType format: {self}") return match.group(1), tuple(int(v) for v in match.group(2).split('.'))
[docs] @classmethod def python(cls) -> 'ProgramType': """ Get the latest supported Python version. :return: The latest supported Python version. """ return max((e for e in cls if e.value.startswith('python')), key=lambda e: e._key())
[docs] @classmethod def from_transport_model(cls, model: transport_models.s.ProgramType) -> 'ProgramType': return cls(model.value)
[docs] def to_transport_model(self) -> transport_models.s.ProgramType: return transport_models.s.ProgramType(str(self))
[docs] @dataclass class Program: """ Represents a program stored on the robot. :param id: The unique identifier of the program. :param name: The name of the program. :param type: The type/version of the program. """ id: str name: str type: ProgramType
[docs] @classmethod def from_transport_model(cls, model: transport_models.s.Program) -> 'Program': return cls( id=str(model.id), name=model.name, type=ProgramType.from_transport_model(model.type), )
[docs] def to_transport_model(self) -> transport_models.s.Program: return transport_models.s.Program( id=UUID(self.id), name=self.name, type=transport_models.s.ProgramType(self.type.value), )
[docs] @dataclass class ProgramExecutionContext: """ Represents the execution context for a program. :param environment: Environment variables to set for the program execution. :param arguments: Command-line arguments to pass to the program. """ environment: dict[str, str] arguments: list[str]
[docs] @classmethod def from_transport_model(cls, model: transport_models.s.ProgramExecutionContext) -> 'ProgramExecutionContext': return cls( environment=model.environment or {}, arguments=model.arguments or [], )
[docs] def to_transport_model(self) -> transport_models.s.ProgramExecutionContext: return transport_models.s.ProgramExecutionContext(environment=self.environment, arguments=self.arguments)
[docs] @dataclass class ExecutionOutput: """ Represents output from a program execution. :param output: The output text from the program. :param eof: Whether this is the end of the output stream. """ output: str eof: bool
[docs] @classmethod def from_transport_model(cls, model: transport_models.a.ProgramExecutionOutput) -> 'ExecutionOutput': return cls(output=model.output, eof=model.eof)
[docs] def to_transport_model(self) -> transport_models.a.ProgramExecutionOutput: return transport_models.a.ProgramExecutionOutput(output=self.output, eof=self.eof)
ExecutionStatusStatus = ExecutorStatus
[docs] @dataclass class ProgramExecution: """ Represents a program execution instance. :param id: The unique identifier of the execution. :param program_id: The ID of the program being executed. :param program_name: The name of the program being executed, when the robot reports it. :param context: The execution context (environment variables and arguments). :param started_at: When the execution started. :param finished_at: When the execution finished. :param exit_code: The exit code of the program execution. """ id: str program_id: str context: ProgramExecutionContext started_at: datetime | None finished_at: datetime | None exit_code: int | None status: ExecutionStatusStatus program_name: str | None = None
[docs] @classmethod def from_transport_model(cls, model: transport_models.s.ProgramExecution) -> 'ProgramExecution': return cls(id=str(model.id), program_id=str(model.programId), program_name=model.programName, context=ProgramExecutionContext.from_transport_model(model.context), started_at=model.startedAt, finished_at=model.finishedAt, exit_code=model.exitCode, status=ExecutionStatusStatus(model.status.value))
[docs] def to_transport_model(self) -> transport_models.s.ProgramExecution: return transport_models.s.ProgramExecution(id=UUID(self.id), programId=UUID(self.program_id), programName=self.program_name, context=self.context.to_transport_model(), startedAt=self.started_at, finishedAt=self.finished_at, exitCode=self.exit_code, status=transport_models.s.ExecutorStatus(self.status))
[docs] @dataclass class ProgramExecutorStatus: """ Represents the current status of the program executor. :param execution: The current execution (None if no execution). :param status: The current execution status. """ execution: Optional[ProgramExecution] status: ExecutorStatus
[docs] @classmethod def from_transport_model(cls, model: transport_models.s.ProgramsExecutorStatus) -> 'ProgramExecutorStatus': return cls(status=ExecutionStatusStatus.from_transport_model(model.status), execution=ProgramExecution.from_transport_model(model.execution) if model.execution else None)
[docs] @classmethod def from_a_transport_model(cls, model: transport_models.a.ProgramsExecutorStatus) -> 'ProgramExecutorStatus': return cls( status=ExecutionStatusStatus.from_transport_model(transport_models.s.ExecutorStatus(model.status.value)), execution=ProgramExecution.from_transport_model( transport_models.s.ProgramExecution.model_validate(model.execution)) if model.execution else None, )
[docs] def to_transport_model(self) -> transport_models.s.ProgramsExecutorStatus: return transport_models.s.ProgramsExecutorStatus( status=self.status.to_transport_model(), execution=self.execution.to_transport_model() if self.execution else None)