|
@@ -6,32 +6,21 @@ import logging
|
|
|
import os
|
|
import os
|
|
|
|
|
|
|
|
from contextlib import contextmanager
|
|
from contextlib import contextmanager
|
|
|
-from enum import Enum, auto
|
|
|
|
|
-from functools import reduce
|
|
|
|
|
|
|
+from functools import reduce, wraps
|
|
|
from types import SimpleNamespace, NoneType
|
|
from types import SimpleNamespace, NoneType
|
|
|
from typing import Annotated, Any, Callable, Iterator, Literal, Self, final, overload
|
|
from typing import Annotated, Any, Callable, Iterator, Literal, Self, final, overload
|
|
|
|
|
|
|
|
from pydantic import BaseModel, Field
|
|
from pydantic import BaseModel, Field
|
|
|
from pydantic_core import PydanticUndefined
|
|
from pydantic_core import PydanticUndefined
|
|
|
|
|
|
|
|
|
|
+from cipy.status import Status
|
|
|
|
|
+from cipy.predicate import Predicate, Success, _SENTINEL
|
|
|
|
|
+
|
|
|
type Scalar = bool | int | float | str
|
|
type Scalar = bool | int | float | str
|
|
|
type Computed = Ref | Factory
|
|
type Computed = Ref | Factory
|
|
|
type Value = Scalar | Computed
|
|
type Value = Scalar | Computed
|
|
|
|
|
|
|
|
|
|
|
|
|
-class Status(Enum):
|
|
|
|
|
- """Result status of a runner, higher numbers take priority"""
|
|
|
|
|
-
|
|
|
|
|
- NOT_RUN = auto()
|
|
|
|
|
- SKIPPED = auto()
|
|
|
|
|
- SUCCESS = auto()
|
|
|
|
|
- FAILURE = auto()
|
|
|
|
|
- CANCELLED = auto()
|
|
|
|
|
-
|
|
|
|
|
- def __ior__(self, other: Status) -> Status:
|
|
|
|
|
- return self if self.value > other.value else other
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
class Inputs(BaseModel):
|
|
class Inputs(BaseModel):
|
|
|
"""Stub class describing input arguments"""
|
|
"""Stub class describing input arguments"""
|
|
|
|
|
|
|
@@ -164,6 +153,7 @@ class Action(BaseModel, abc.ABC):
|
|
|
|
|
|
|
|
name: str
|
|
name: str
|
|
|
id: str = Field(default="", exclude_if=lambda v: not v)
|
|
id: str = Field(default="", exclude_if=lambda v: not v)
|
|
|
|
|
+ enabled: Predicate = Success()
|
|
|
inputs: Inputs = Inputs()
|
|
inputs: Inputs = Inputs()
|
|
|
outputs: Outputs = Outputs()
|
|
outputs: Outputs = Outputs()
|
|
|
|
|
|
|
@@ -172,10 +162,12 @@ class Action(BaseModel, abc.ABC):
|
|
|
"""Get this class's logger"""
|
|
"""Get this class's logger"""
|
|
|
return logging.getLogger(self.__class__.__name__)
|
|
return logging.getLogger(self.__class__.__name__)
|
|
|
|
|
|
|
|
- # pylint: disable=unused-argument
|
|
|
|
|
- def enabled(self, status: Status, context: Context) -> bool:
|
|
|
|
|
- """Should this action even be run?"""
|
|
|
|
|
- return status.value <= Status.SUCCESS.value
|
|
|
|
|
|
|
+ def is_enabled(self, status: Status, context: Context) -> bool:
|
|
|
|
|
+ """Proxy function to test if this Action is permitted to run"""
|
|
|
|
|
+ with context.extend(
|
|
|
|
|
+ inputs=self.inputs, status=status, logger=self.logger
|
|
|
|
|
+ ) as ctx:
|
|
|
|
|
+ return self.enabled(ctx) and (hasattr(ctx, _SENTINEL) or Success()(ctx))
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
@abc.abstractmethod
|
|
|
def run(self, context: Context) -> Status:
|
|
def run(self, context: Context) -> Status:
|