import sys from collections.abc import Iterable from hashlib import sha256 from typing import List from service.tasks.precondition.utils import only_keys class Trigger: def __init__(self, context, **kw): self.params = kw self._condition = self.set_condition(context, **kw) def __repr__(self): return f"{self.__class__.__name__}({self.params})" def set_condition(self, context, **kw): raise NotImplementedError def check_condition(self, context): if not context.setdefault(self._condition, False): context[self._condition] = True return True else: return False def __call__(self, context, **kw): if self.check_condition(context): return self.execute(context, **self.params) def execute(self, context, **kw): """Implement to make stuff happen""" raise NotImplementedError class Consequence: description = "Generic consequence, please write better description" visible = True params_to_keep: List[str] = [] def __init__(self, **kw): if self.params_to_keep: self.params = only_keys(kw, *self.params_to_keep) else: self.params = kw self._resolve_set_key = self.get_resolve_set_key() def __repr__(self): return f"{self.__class__.__name__}({self.params})" def __str__(self): h = sha256(self.__class__.__name__.encode()) h.update(str(self.params).encode()) return h.hexdigest() def __hash__(self): return int.from_bytes( sha256(f"{self.__class__.__name__}{str(self.params)}".encode()).digest(), sys.byteorder, ) def __len__(self): return 1 @classmethod def get_resolve_set_key(cls): return f"{cls.__name__}_resolved_ids" def add_resolved_id(self, context, rid): if self._resolve_set_key in context: rset = context[self._resolve_set_key] else: rset = set() context[self._resolve_set_key] = rset rset.add(rid) def is_resolved_id(self, context, rid): return ( self._resolve_set_key in context and rid in context[self._resolve_set_key] ) def is_accepted(self, hash_list): return not self.visible or ( isinstance(hash_list, Iterable) and str(self) in hash_list ) def pre_resolve(self, context, hash_list) -> List[Trigger]: if self.is_accepted(hash_list): return self.pre_execute(context, **self.params) else: raise RuntimeError( f"{self.__class__.__name__}({str(self)}) Not on the accepted consequences list!" ) def do_resolve(self, context, hash_list) -> List[Trigger]: if self.is_accepted(hash_list): return self.execute(context, **self.params) else: raise RuntimeError( f"{self.__class__.__name__}({str(self)}) Not on the accepted consequences list!" ) def pre_execute(self, context, **kw) -> List[Trigger]: """Implement to do something immediately before execution""" return [] def execute(self, context, **kw) -> List[Trigger]: """Implement to make the consequence happen""" return []