Source code for doot.workflow.structs.task_name

  1#!/usr/bin/env python3
  2"""
  3
  4"""
  5
  6# Imports:
  7from __future__ import annotations
  8
  9# ##-- stdlib imports
 10import datetime
 11import enum
 12import functools as ftz
 13import importlib
 14import itertools as itz
 15import logging as logmod
 16import pathlib as pl
 17import re
 18import time
 19import weakref
 20from uuid import UUID, uuid1
 21
 22# ##-- end stdlib imports
 23
 24# ##-- 3rd party imports
 25from pydantic import field_validator, model_validator
 26from jgdv import Maybe, Proto
 27from jgdv.structs.strang import Strang
 28from jgdv.structs.strang import _interface as StrangAPI  # noqa: N812
 29from jgdv.structs.strang.processor import StrangBasicProcessor
 30
 31# ##-- end 3rd party imports
 32
 33# ##-- 1st party imports
 34import doot
 35import doot.errors
 36
 37# ##-- end 1st party imports
 38
 39from .. import _interface as API # noqa: N812
 40
 41# ##-- types
 42# isort: off
 43import abc
 44import collections.abc
 45from typing import TYPE_CHECKING, cast, assert_type, assert_never
 46from typing import Generic, NewType, Never
 47# Protocols:
 48from typing import Protocol, runtime_checkable
 49# Typing Decorators:
 50from typing import no_type_check, final, override, overload
 51
 52if TYPE_CHECKING:
 53    from jgdv._abstract.pre_processable import PreProcessResult, PostInstanceData, InstanceData
 54    from jgdv import Maybe, VerStr
 55    from jgdv.structs.strang import Strang_p
 56    from typing import Final
 57    from typing import ClassVar, Any, LiteralString
 58    from typing import Self, Literal
 59    from typing import TypeGuard
 60    from collections.abc import Iterable, Iterator, Callable, Generator
 61    from collections.abc import Sequence, Mapping, MutableMapping, Hashable
 62
 63    from .._interface import TaskName_p
 64##--|
 65
 66# isort: on
 67# ##-- end types
 68
 69##-- logging
 70logging = logmod.getLogger(__name__)
 71##-- end logging
 72DEFAULT_SEP   : Final[str] = doot.constants.patterns.TASK_SEP # type: ignore[attr-defined]
 73TASKS_PREFIX  : Final[str] = "tasks."
 74
 75##--|
 76
[docs] 77class TaskNameHeadMarks_e(StrangAPI.StrangMarkAbstract_e): 78 """ Markers used in a Strang's head """ 79 basic = "$basic$"
80
[docs] 81class TaskNameBodyMarks_e(StrangAPI.StrangMarkAbstract_e): 82 """ Markers Used in a base Strang's body """ 83 84 head = "$head$" 85 cleanup = "$cleanup$" 86 partial = "$partial$" 87 data = "$data$" 88 empty = "" 89 hide = "_" 90 extend = "+" 91 customised = "$+$" 92
[docs] 93 @override 94 @classmethod 95 def default(cls) -> Maybe[str]: 96 """ The mark used if no mark is found""" 97 return None
98
[docs] 99 @override 100 @classmethod 101 def implicit(cls) -> set[str]: 102 """ Marks that arent in the form $mark$ """ 103 return {cls.hide, cls.empty}
104
[docs] 105 @override 106 @classmethod 107 def skip(cls) -> Maybe[str]: 108 """ The mark placed in empty words """ 109 return cls.empty
110
[docs] 111 @override 112 @classmethod 113 def idempotent(cls) -> set[str]: 114 """ marks you can't have more than one of """ 115 return {cls.head, cls.hide}
116 117
[docs] 118 @classmethod 119 def generated(cls) -> set[str]: 120 return { cls.cleanup, cls.head }
121##--| 122TASKSECTIONS : Final[StrangAPI.Sections_d] = StrangAPI.Sections_d( 123 StrangAPI.Sec_d("group", ".", "::", str, TaskNameHeadMarks_e, True), # noqa: FBT003 124 StrangAPI.Sec_d("body", ".", None, str, TaskNameBodyMarks_e, True), # noqa: FBT003 125) 126##--| 127
[docs] 128class TaskNameProcessor[T:API.TaskName_p](StrangBasicProcessor): 129
[docs] 130 @override 131 def pre_process(self, cls:type[T], input:Any, *args:Any, strict:bool=False, **kwargs:Any) -> PreProcessResult: 132 """ Remove 'tasks' as a prefix, and strip quotes """ 133 match input: 134 case Strang(): 135 cleaned = str(input).removeprefix(TASKS_PREFIX).replace('"', "") 136 case str(): 137 cleaned = input.removeprefix(TASKS_PREFIX).replace('"', "") 138 case x if not strict: 139 cleaned = str(x) 140 case x: 141 raise TypeError(type(x)) 142 143 return super().pre_process(cls, cleaned, *args, strict=strict, **kwargs)
144
[docs] 145 @override 146 def _implicit_mark(self, val:str, *, sec:StrangAPI.Sec_d, data:dict, index:int, maxcount:int) -> Maybe[StrangAPI.StrangMarkAbstract_e]: 147 """ Builds certain marks that are not in the form $mark$. 148 149 In particular, pass marks that are empty words between two case chars: group::a.b..c 150 And meta marks for tasks like job and hide: group::+._.a.b.c 151 """ 152 match sec.marks: 153 case None: 154 return None 155 case x: 156 marks = x 157 match marks.skip(): 158 case None: 159 pass 160 case x if val == x.value: 161 return x 162 163 if val not in marks: 164 return None 165 return marks(val)
166
[docs] 167@Proto(API.TaskName_p, StrangAPI.Strang_p) 168class TaskName(Strang): 169 """ 170 A Task Name. 171 """ 172 __slots__ = () 173 Marks : ClassVar = TaskNameBodyMarks_e 174 _processor : ClassVar = TaskNameProcessor() 175 _sections : ClassVar = TASKSECTIONS 176
[docs] 177 def with_cleanup(self) -> Self: 178 """ 179 Generate a $cleanup$ task name. the UUID of the source is carried with it 180 """ 181 if self.is_cleanup(): 182 return self 183 # if not self.uuid(): 184 # raise ValueError("adding $cleanup$ to a task name requires a uuid in the base", self[:]) 185 186 return self.push(TaskNameBodyMarks_e.cleanup, uuid=self.uuid())
187
[docs] 188 def with_head(self) -> Self: 189 """ generate a $head$ task name, carrying the uuid along with it """ 190 if self.is_head(): 191 return self 192 # if not self.uuid(): 193 # raise ValueError("Adding $head$ to a task name requires a uuid in the base", self[:]) 194 195 return self.push(TaskNameBodyMarks_e.head, uuid=self.uuid())
196
[docs] 197 def is_cleanup(self) -> bool: 198 return TaskNameBodyMarks_e.cleanup in self
199
[docs] 200 def is_head(self) -> bool: 201 return TaskNameBodyMarks_e.head in self
202
[docs] 203 def pop_generated(self) -> Self: 204 if not (self.is_head() or self.is_cleanup()): 205 return self 206 207 assert(self.uuid()) 208 base = self.pop(top=False) 209 return type(self)(f"{base}[<uuid>]", uuid=self.uuid())