diff --git a/src/primaite/simulator/core.py b/src/primaite/simulator/core.py index 69edd8db..1456d41c 100644 --- a/src/primaite/simulator/core.py +++ b/src/primaite/simulator/core.py @@ -1,3 +1,4 @@ +# flake8: noqa """Core of the PrimAITE Simulator.""" from abc import ABC, abstractmethod from typing import Callable, Dict, List, Optional, Union @@ -10,7 +11,7 @@ from primaite import getLogger _LOGGER = getLogger(__name__) -class ActionPermissionValidator(ABC): +class ActionPermissionValidator(BaseModel): """ Base class for action validators. @@ -33,7 +34,7 @@ class AllowAllValidator(ActionPermissionValidator): return True -class Action: +class Action(BaseModel): """ This object stores data related to a single action. @@ -41,34 +42,22 @@ class Action: the action can be performed or not. """ - def __init__( - self, func: Callable[[List[str], Dict], None], validator: ActionPermissionValidator = AllowAllValidator() - ) -> None: - """ - Save the functions that are for this action. - - Here's a description for the intended use of both of these. - - ``func`` is a function that accepts a request and a context dict. Typically this would be a lambda function - that invokes a class method of your SimComponent. For example if the component is a node and the action is for - turning it off, then the SimComponent should have a turn_off(self) method that does not need to accept any args. - Then, this Action will be given something like ``func = lambda request, context: self.turn_off()``. - - ``validator`` is an instance of a subclass of `ActionPermissionValidator`. This is essentially a callable that - accepts `request` and `context` and returns a boolean to represent whether the permission is granted to perform - the action. - - :param func: Function that performs the request. - :type func: Callable[[List[str], Dict], None] - :param validator: Function that checks if the request is authenticated given the context. By default, if no - validator is provided, an 'allow all' validator is added which permits all requests. - :type validator: ActionPermissionValidator - """ - self.func: Callable[[List[str], Dict], None] = func - self.validator: ActionPermissionValidator = validator + func: Callable[[List[str], Dict], None] + """ + ``func`` is a function that accepts a request and a context dict. Typically this would be a lambda function + that invokes a class method of your SimComponent. For example if the component is a node and the action is for + turning it off, then the SimComponent should have a turn_off(self) method that does not need to accept any args. + Then, this Action will be given something like ``func = lambda request, context: self.turn_off()``. + """ + validator: ActionPermissionValidator = AllowAllValidator() + """ + ``validator`` is an instance of `ActionPermissionValidator`. This is essentially a callable that + accepts `request` and `context` and returns a boolean to represent whether the permission is granted to perform + the action. The default validator will allow + """ -class ActionManager: +class ActionManager(BaseModel): """ ActionManager is used by `SimComponent` instances to keep track of actions. @@ -76,9 +65,8 @@ class ActionManager: class is responsible for providing a consistent API for processing actions as well as helpful error messages. """ - def __init__(self) -> None: - """Initialise ActionManager with an empty action lookup.""" - self.actions: Dict[str, Action] = {} + actions: Dict[str, Action] = {} + """maps action verb to an action object.""" def process_request(self, request: List[str], context: Dict) -> None: """Process an action request. @@ -125,6 +113,11 @@ class ActionManager: self.actions[name] = action + def list_actions(self) -> List[List[str]]: + actions = [] + for act_name, act in self.actions.items(): + pass # TODO: + class SimComponent(BaseModel): """Extension of pydantic BaseModel with additional methods that must be defined by all classes in the simulator.""" @@ -178,6 +171,14 @@ class SimComponent(BaseModel): } return state + def possible_actions(self) -> List[List[str]]: + """Enumerate all actions that this component can accept. + + :return: List of all action strings that can be passed to this component. + :rtype: List[Dict[str]] + """ + action_list = ActionManager # TODO: extract possible actions? how to do this neatly? + def apply_action(self, action: List[str], context: Dict = {}) -> None: """ Apply an action to a simulation component. Action data is passed in as a 'namespaced' list of strings. @@ -230,7 +231,3 @@ class SimComponent(BaseModel): _LOGGER.warn(msg) raise RuntimeWarning(msg) self._parent = new_parent - - @parent.deleter - def parent(self) -> None: - self._parent = None