Source code for gcip2.tasks_core.task_builder

  1import dataclasses
  2import os
  3import typing
  4from collections.abc import Iterable
  5from enum import Enum
  6
  7import injector
  8import pydantic
  9
 10from gcip2 import ProjectConfig
 11from gcip2.tasks_core.models.actions import ActionBuilderImpl
 12from gcip2.tasks_core.models.params import Param, Params
 13
 14
[docs] 15class Task(pydantic.BaseModel): 16 basename: typing.Optional[str] = None 17 18 name: typing.Optional[str] = None 19 20 doc: str = "" 21 22 actions: typing.Optional[list[type["ActionBuilderImpl"]]] = None 23 24 parsed_params: dict[str, typing.Any] = {} 25 26 params: list[Param] = pydantic.Field(default_factory=lambda: []) 27
[docs] 28 def parse_task_params(self, args: list[str], di: injector.Injector): 29 _config = di.get(ProjectConfig) 30 31 if _config.extra.model_extra: 32 for key, val in _config.extra.model_extra.items(): 33 self.parsed_params[f"extra__{key}"] = val 34 35 args_iter = iter(args) 36 37 for arg in args_iter: 38 if arg.startswith("--"): 39 key = arg.removeprefix("--") 40 param = next( 41 (p for p in self.params if key in [p.long, p.inverse]), 42 None, 43 ) 44 elif arg.startswith("-"): 45 key = arg.removeprefix("-") 46 param = next( 47 (p for p in self.params if key in [p.short, p.inverse]), 48 None, 49 ) 50 else: 51 continue 52 53 if not param: 54 raise ValueError(f"Unknown parameter: --{key}") 55 56 if param.type is bool: 57 self.parsed_params[param.name] = True if key == param.long or key == param.short else False 58 continue 59 60 try: 61 value = next(args_iter) 62 except StopIteration as err: 63 raise StopIteration from err 64 65 self.parsed_params[param.name] = param.type(value)
66
[docs] 67 def exec_task(self, inj: injector.Injector): 68 if not self.actions: 69 raise RuntimeError("not found actions to execute.") 70 for action_cls in self.actions: 71 action = inj.create_object(action_cls) 72 action.execute(**self.parsed_params)
73 74
[docs] 75class TaskBulder:
[docs] 76 def build(self) -> Task: 77 raise NotImplementedError
78 79
[docs] 80@injector.inject 81@dataclasses.dataclass 82class TaskBuilderImpl(TaskBulder): 83 _basename: typing.ClassVar[str | Enum | None] = None 84 85 _params: Params 86 _config: ProjectConfig 87 88 model: Task = dataclasses.field(init=False, default_factory=Task) 89 90 def __post_init__(self): 91 "extension point for childs" 92
[docs] 93 def apply(self): 94 return self
95
[docs] 96 def build(self) -> Task: 97 if not self._basename: 98 raise ValueError("task name not set.") 99 100 if not self.model.doc: 101 self.model.doc = ".".join( 102 [ 103 self.__class__.__module__, 104 self.__class__.__name__, 105 ] 106 ) 107 108 if isinstance(self._basename, str): 109 self.model.basename = self._basename 110 else: 111 self.model.basename = self._basename.value 112 113 return self.model.model_copy(deep=True)
114
[docs] 115 def with_actions(self, actions: Iterable[type[ActionBuilderImpl]]): 116 self.model.actions = list(actions) 117 return self
118
[docs] 119 def with_params(self: typing.Self, params: Iterable[Param]) -> typing.Self: 120 self.model.params = list(params) 121 122 params_dict = {} 123 for param in params: 124 params_dict[param.name] = os.getenv(param.env_var, param.default) if param.env_var else param.default 125 self.model.parsed_params = params_dict 126 127 return self
128
[docs] 129 def replace_param(self, param_name: str, param: str, default: str): 130 self.model.parsed_params[param_name] = param or default
131
[docs] 132 def with_name(self, name: str): 133 self.model.name = name 134 return self
135
[docs] 136 def with_doc(self, doc: str): 137 self.model.doc = doc 138 return self