.. _doot.workflow._interface: ======================== doot.workflow._interface ======================== .. py:module:: doot.workflow._interface .. autoapi-nested-parse:: Tasks are the main abstractions managed by Doot - JOBS create tasks - TASKS have actions - ACTIONS are individual atomic steps of a task, given the detailed information necessary to perform the step. Jobs, as they can control refication order, can add setup and teardown tasks. This can allow interleaving, or grouping. Communication paths: Job -> Task : by creation Task -> Action : by creation Action -> Task : by return value, updating task state dict Task -> Job : by reference to the job Task -> Task = Postboxes Action -> Action = Action -> Task State -> Action Type Aliases ------------ .. autoapisummary:: doot.workflow._interface.ActionReturn Enums ----- .. autoapisummary:: doot.workflow._interface.QueueMeta_e doot.workflow._interface.RelationMeta_e doot.workflow._interface.TaskMeta_e doot.workflow._interface.TaskStatus_e doot.workflow._interface.ArtifactStatus_e doot.workflow._interface.ActionResponse_e Protocols --------- .. autoapisummary:: doot.workflow._interface.Status_ep doot.workflow._interface.ActionSpec_i doot.workflow._interface.InjectSpec_i doot.workflow._interface.RelationSpec_i doot.workflow._interface.TaskSpec_i doot.workflow._interface.Action_p doot.workflow._interface.Artifact_i doot.workflow._interface.TaskName_p doot.workflow._interface.TaskFactory_p doot.workflow._interface.SubTaskFactory_p doot.workflow._interface.Task_p doot.workflow._interface.Job_p doot.workflow._interface.Task_i Classes ------- .. autoapisummary:: doot.workflow._interface.DelayedSpec Module Contents =============== .. py:data:: ActionReturn :type: TypeAlias :value: Maybe[dict | bool | ActionResponse_e] .. _doot.workflow._interface.QueueMeta_e: .. py:class:: QueueMeta_e(*args, **kwds) Bases: :py:obj:`enum.Enum` available ways a task can be activated for running onRegister/auto : activates automatically when added to the task network reactive : activates if an adjacent node completes default : activates only if uses queues the task, or its a dependencyOf .. py:attribute:: default .. py:attribute:: onRegister .. py:attribute:: reactive .. py:attribute:: reactiveFail .. py:attribute:: auto .. _doot.workflow._interface.RelationMeta_e: .. py:class:: RelationMeta_e(*args, **kwds) Bases: :py:obj:`enum.Enum` What types+synonyms of task relation there can be, in the form Obj {rel} Y, eg: cake dependsOn baking. or: baking requirementFor cake. or: eatingCake conflictsWith givingCake .. py:attribute:: needs .. py:attribute:: blocks .. py:method:: default() -> RelationMeta_e :classmethod: .. _doot.workflow._interface.TaskMeta_e: .. py:class:: TaskMeta_e Bases: :py:obj:`enum.StrEnum` Flags describing properties of a task, stored in the Task_p instance itself. .. py:attribute:: TASK .. py:attribute:: JOB .. py:attribute:: TRANSFORMER .. py:attribute:: INTERNAL .. py:attribute:: JOB_HEAD .. py:attribute:: CONCRETE .. py:attribute:: DISABLED .. py:attribute:: EPHEMERAL .. py:attribute:: IDEMPOTENT .. py:attribute:: REQ_TEARDOWN .. py:attribute:: REQ_SETUP .. py:attribute:: IS_TEARDOWN .. py:attribute:: IS_SETUP .. py:attribute:: THREAD_SAFE .. py:attribute:: STATEFUL .. py:attribute:: STATELESS .. py:attribute:: VERSIONED .. py:method:: default() -> jgdv.Maybe :classmethod: .. _doot.workflow._interface.TaskStatus_e: .. py:class:: TaskStatus_e(*args, **kwds) Bases: :py:obj:`enum.Enum` Enumeration of the different states a task/artifact can be in. The state is stored in the task object itself. Before a task object hsa been created, the tracker provides the status according to what specs exist for the task name. .. py:attribute:: NAMED .. py:attribute:: DECLARED .. py:attribute:: DEFINED .. py:attribute:: DISABLED .. py:attribute:: INIT .. py:attribute:: WAIT .. py:attribute:: READY .. py:attribute:: RUNNING .. py:attribute:: SKIPPED .. py:attribute:: HALTED .. py:attribute:: FAILED .. py:attribute:: SUCCESS .. py:attribute:: TEARDOWN .. py:attribute:: DEAD .. py:method:: default() -> TaskStatus_e :classmethod: .. py:method:: pre_set() -> set :classmethod: .. py:method:: success_set() -> set :classmethod: .. py:method:: fail_set() -> set :classmethod: .. _doot.workflow._interface.ArtifactStatus_e: .. py:class:: ArtifactStatus_e(*args, **kwds) Bases: :py:obj:`enum.Enum` States an artifact can be in .. py:attribute:: DECLARED .. py:attribute:: STALE .. py:attribute:: TOCLEAN .. py:attribute:: EXISTS .. _doot.workflow._interface.ActionResponse_e: .. py:class:: ActionResponse_e(*args, **kwds) Bases: :py:obj:`enum.Enum` Description of how a Action went. .. py:attribute:: SUCCEED .. py:attribute:: FAIL .. py:attribute:: SKIP .. py:attribute:: SKIP_GROUP .. py:attribute:: SKIP_TASK .. py:attribute:: SUCCESS .. _doot.workflow._interface.Status_ep: .. py:class:: Status_ep Bases: :py:obj:`Protocol` Base class for protocol classes. Protocol classes are defined as:: class Proto(Protocol): def meth(self) -> int: ... Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing). For example:: class C: def meth(self) -> int: return 0 def func(x: Proto) -> int: return x.meth() func(C()) # Passes static type check See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as:: class GenProto[T](Protocol): def meth(self) -> T: ... .. py:method:: default() -> Any :classmethod: .. py:method:: pre_set() -> set :classmethod: .. py:method:: success_set() -> set :classmethod: .. py:method:: fail_set() -> set :classmethod: .. _doot.workflow._interface.ActionSpec_i: .. py:class:: ActionSpec_i Bases: :py:obj:`jgdv._abstract.protocols.general.Buildable_p`, :py:obj:`Protocol` For things that need building, but don't have a separate factory TODO add type parameter .. py:attribute:: do :type: jgdv.Maybe[jgdv.structs.strang.CodeReference] .. py:attribute:: args :type: list[Any] .. py:attribute:: kwargs :type: jgdv.structs.chainguard.ChainGuard .. py:attribute:: fun :type: jgdv.Maybe[jgdv.Func] .. _doot.workflow._interface.InjectSpec_i: .. py:class:: InjectSpec_i Bases: :py:obj:`jgdv._abstract.protocols.general.Buildable_p`, :py:obj:`Protocol` For things that need building, but don't have a separate factory TODO add type parameter .. py:attribute:: from_spec :type: dict .. py:attribute:: from_state :type: dict .. py:attribute:: from_target :type: dict .. py:attribute:: literal :type: dict .. py:attribute:: with_suffix :type: jgdv.Maybe[str] .. py:method:: apply_from_spec(parent: dict | TaskSpec_i | Task_p) -> dict .. py:method:: apply_from_state(parent: dict | Task_p) -> dict .. py:method:: apply_literal(val: Any) -> dict .. py:method:: validate(control: Task_p | TaskSpec_i, target: Task_p | TaskSpec_i, *, only_spec: bool = False) -> bool .. py:method:: validate_details(control: Task_p | TaskSpec_i, target: Task_p | TaskSpec_i, *, only_spec: bool = False) -> dict .. _doot.workflow._interface.RelationSpec_i: .. py:class:: RelationSpec_i Bases: :py:obj:`Protocol` Base class for protocol classes. Protocol classes are defined as:: class Proto(Protocol): def meth(self) -> int: ... Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing). For example:: class C: def meth(self) -> int: return 0 def func(x: Proto) -> int: return x.meth() func(C()) # Passes static type check See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as:: class GenProto[T](Protocol): def meth(self) -> T: ... .. py:attribute:: Marks :type: ClassVar[type[enum.Enum]] .. py:attribute:: target :type: TaskName_p | Artifact_i .. py:attribute:: relation :type: RelationMeta_e .. py:attribute:: object :type: jgdv.Maybe[TaskName_p | Artifact_i] .. py:attribute:: constraints :type: dict[str, str] .. py:attribute:: inject :type: jgdv.Maybe[InjectSpec_i] .. py:method:: to_ordered_pair(obj: RelationTarget, *, target: jgdv.Maybe[TaskName_p] = None) -> tuple[jgdv.Maybe[RelationTarget], jgdv.Maybe[RelationTarget]] .. py:method:: instantiate(*, obj: jgdv.Maybe[RelationTarget] = None, target: jgdv.Maybe[RelationTarget] = None) -> RelationSpec_i .. py:method:: forward_dir_p() -> bool .. py:method:: accepts(control: Task_i | TaskSpec_i, target: Task_i | TaskSpec_i) -> bool .. _doot.workflow._interface.TaskSpec_i: .. py:class:: TaskSpec_i Bases: :py:obj:`Protocol` The data spec of a task. is created from TOML data .. py:attribute:: _default_ctor :type: ClassVar[str] .. py:attribute:: _blocking_groups :type: ClassVar[tuple[str, Ellipsis]] .. py:attribute:: Marks :type: ClassVar[enum.Enum] .. py:attribute:: name :type: TaskName_p .. py:attribute:: doc :type: jgdv.Maybe[list[str]] .. py:attribute:: sources :type: list[jgdv.Maybe[TaskName_p | pathlib.Path]] .. py:attribute:: actions :type: list[ActionSpec_i] .. py:attribute:: required_for :type: list[ActionSpec_i | RelationSpec_i] .. py:attribute:: depends_on :type: list[ActionSpec_i | RelationSpec_i] .. py:attribute:: setup :type: list[ActionSpec_i | RelationSpec_i] .. py:attribute:: cleanup :type: list[ActionSpec_i | RelationSpec_i] .. py:attribute:: on_fail :type: list[ActionSpec_i | RelationSpec_i] .. py:attribute:: version :type: str .. py:attribute:: priority :type: int .. py:attribute:: ctor :type: jgdv.structs.strang.CodeReference .. py:attribute:: queue_behaviour :type: QueueMeta_e .. py:attribute:: meta :type: set[TaskMeta_e] .. py:property:: extra :type: jgdv.structs.chainguard.ChainGuard .. py:method:: param_specs() -> list .. _doot.workflow._interface.Action_p: .. py:class:: Action_p Bases: :py:obj:`Protocol` holds individual action information and state, and executes it .. _doot.workflow._interface.Artifact_i: .. py:class:: Artifact_i Bases: :py:obj:`jgdv.structs.locator._interface.Location_p`, :py:obj:`Protocol` Something which describes a file system location, with a possible identifier, and metadata .. py:attribute:: priority :type: int .. py:method:: get_status() -> ArtifactStatus_e .. py:method:: reify(other: pathlib.Path | jgdv.structs.locator._interface.Location_p) -> jgdv.Maybe[Artifact_i] .. _doot.workflow._interface.TaskName_p: .. py:class:: TaskName_p Bases: :py:obj:`jgdv.structs.strang._interface.Strang_p`, :py:obj:`Protocol` The Main protocol describing a Strang. .. py:method:: with_head() -> Self .. py:method:: is_head() -> bool .. py:method:: with_cleanup() -> Self .. py:method:: is_cleanup() -> bool .. py:method:: pop_generated() -> Self .. _doot.workflow._interface.TaskFactory_p: .. py:class:: TaskFactory_p(*, spec_ctor: jgdv.Maybe[type] = None, task_ctor: jgdv.Maybe[type] = None, job_ctor: jgdv.Maybe[type] = None) Bases: :py:obj:`Protocol` Base class for protocol classes. Protocol classes are defined as:: class Proto(Protocol): def meth(self) -> int: ... Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing). For example:: class C: def meth(self) -> int: return 0 def func(x: Proto) -> int: return x.meth() func(C()) # Passes static type check See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as:: class GenProto[T](Protocol): def meth(self) -> T: ... .. py:method:: build(data: jgdv.structs.chainguard.ChainGuard | dict | TaskName_p | str) -> TaskSpec_i .. py:method:: instantiate(obj: TaskSpec_i, *, extra: jgdv.Maybe[collections.abc.Mapping | bool] = None) -> TaskSpec_i .. py:method:: merge(*, bot: dict | TaskSpec_i, top: dict | TaskSpec_i, suffix: jgdv.Maybe[str | Literal[False]] = None) -> TaskSpec_i .. py:method:: make(obj: TaskSpec_i, *, ensure: jgdv.Maybe = None, inject: jgdv.Maybe[tuple[InjectSpec_i, Task_i]] = None, parent: jgdv.Maybe[Task_i] = None) -> Task_i .. py:method:: action_group_elements(obj: TaskSpec_i) -> collections.abc.Iterable[ActionSpec_i | RelationSpec_i] .. _doot.workflow._interface.SubTaskFactory_p: .. py:class:: SubTaskFactory_p Bases: :py:obj:`Protocol` Base class for protocol classes. Protocol classes are defined as:: class Proto(Protocol): def meth(self) -> int: ... Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing). For example:: class C: def meth(self) -> int: return 0 def func(x: Proto) -> int: return x.meth() func(C()) # Passes static type check See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as:: class GenProto[T](Protocol): def meth(self) -> T: ... .. py:method:: generate_names(obj: TaskSpec_i) -> list[TaskName_p] .. py:method:: generate_specs(obj: TaskSpec_i | Artifact_i | DelayedSpec) -> list[dict] .. _doot.workflow._interface.Task_p: .. py:class:: Task_p(spec: TaskSpec_i) Bases: :py:obj:`Protocol` Base class for protocol classes. Protocol classes are defined as:: class Proto(Protocol): def meth(self) -> int: ... Such classes are primarily used with static type checkers that recognize structural subtyping (static duck-typing). For example:: class C: def meth(self) -> int: return 0 def func(x: Proto) -> int: return x.meth() func(C()) # Passes static type check See PEP 544 for details. Protocol classes decorated with @typing.runtime_checkable act as simple-minded runtime protocols that check only the presence of given attributes, ignoring their type signatures. Protocol classes can be generic, they are defined as:: class GenProto[T](Protocol): def meth(self) -> T: ... .. py:property:: name :type: TaskName_p .. py:property:: spec :type: TaskSpec_i .. py:property:: status :type: TaskStatus_e .. py:property:: priority :type: int .. py:property:: internal_state :type: dict .. py:method:: log(msg: str, level: int = logmod.DEBUG, prefix: jgdv.Maybe[str] = None) -> None .. py:method:: prepare_actions() -> None .. py:method:: get_action_group(group_name: str) -> list[ActionSpec_i] .. _doot.workflow._interface.Job_p: .. py:class:: Job_p(spec: TaskSpec_i) Bases: :py:obj:`Task_p`, :py:obj:`Protocol` builds tasks .. py:method:: expand_job() -> list .. _doot.workflow._interface.Task_i: .. py:class:: Task_i(spec: TaskSpec_i) Bases: :py:obj:`Task_p`, :py:obj:`Protocol` Meta information for a task .. py:attribute:: _default_flags :type: ClassVar[set[TaskMeta_e]] .. py:attribute:: _version :type: str .. py:attribute:: _help :type: tuple[str, Ellipsis] .. py:attribute:: doc :type: tuple[str, Ellipsis] .. _doot.workflow._interface.DelayedSpec: .. py:class:: DelayedSpec(**kwargs: Any) .. py:attribute:: base :type: TaskName_p .. py:attribute:: target :type: TaskName_p .. py:attribute:: inject :type: list[InjectSpec_i] .. py:attribute:: applied :type: dict .. py:attribute:: overrides :type: dict