diff --git a/beams/behavior_tree/ActionNode.py b/beams/behavior_tree/ActionNode.py index f47ffca..2300dfd 100644 --- a/beams/behavior_tree/ActionNode.py +++ b/beams/behavior_tree/ActionNode.py @@ -1,15 +1,16 @@ -import time import atexit import logging import os +import time from multiprocessing import Event, Queue, Value from typing import Callable import py_trees -from beams.typing_helper import Evaluatable, ActionNodeWorkFunction, ActionNodeWorkLoop from beams.behavior_tree.ActionWorker import ActionWorker from beams.behavior_tree.VolatileStatus import VolatileStatus +from beams.typing_helper import (ActionNodeWorkFunction, ActionNodeWorkLoop, + Evaluatable) logger = logging.getLogger(__name__) @@ -37,7 +38,7 @@ def work_wrapper( logger.debug(f"WAITING FOR INIT from node: {name}") work_gate.wait() work_gate.clear() - + # Set to running volatile_status.set_value(py_trees.common.Status.RUNNING) while not completion_condition(): diff --git a/beams/behavior_tree/ActionWorker.py b/beams/behavior_tree/ActionWorker.py index 8ce3bea..da41f8f 100644 --- a/beams/behavior_tree/ActionWorker.py +++ b/beams/behavior_tree/ActionWorker.py @@ -1,18 +1,19 @@ """ A worker specialized to execute ActionNode work functions -The primary utility of this "wrapper" class is to maintain the extensibility of the base Worker class. -This is done by using this class to enumerate the "add_args" required by an ActioNode work function +The primary utility of this "wrapper" class is to maintain the extensibility of the base Worker class. +This is done by using this class to enumerate the "add_args" required by an ActioNode work function not required by work functions in general. The add_args are as follows: * proc_name: names spawned process *and* generated BT node * work_gate: IPC signalling mechanism to spawned work that py_trees initialise() has been called by parent * volatile_status: IPC signalling mechanism that contains multiproccesing safe BT status * comp_cond: the Evaluatable function that determines success or failure of BT node -* LOGGER_QUEUE: instance of the logging queue +* LOGGER_QUEUE: instance of the logging queue * worker_logging_configurer: utility functuon to register log queue with handler """ -from typing import Any, Callable, Optional from multiprocessing import Event +from typing import Any, Callable, Optional + from epics.multiproc import CAProcess from beams.behavior_tree.VolatileStatus import VolatileStatus @@ -37,9 +38,9 @@ def __init__( proc_type=CAProcess, add_args=(proc_name, work_gate, - volatile_status, + volatile_status, comp_cond, - LOGGER_QUEUE, + LOGGER_QUEUE, worker_logging_configurer) ) diff --git a/beams/sequencer/helpers/Worker.py b/beams/sequencer/helpers/Worker.py index b81ffc2..25e221a 100644 --- a/beams/sequencer/helpers/Worker.py +++ b/beams/sequencer/helpers/Worker.py @@ -30,7 +30,7 @@ def __init__( else: self.work_func = work_func # Critical Note: This makes assumptions of the work_func signature in that it takes a Value argument in position 0 - self.work_proc = proc_type(target=self.work_func, + self.work_proc = proc_type(target=self.work_func, name=self.proc_name, args=(self.do_work, *self.add_args,)) self.stop_func = stop_func @@ -58,7 +58,7 @@ def stop_work(self): logger.debug(f"Ending work, calling join on {self.proc_name}") self.work_proc.join() - logger.debug(f"Worker process joined from {self.proc_name}" ) + logger.debug(f"Worker process joined from {self.proc_name}") def work_func(self): """ diff --git a/beams/tests/artifacts/im2l0_test.json b/beams/tests/artifacts/im2l0_test.json index c0b2c42..bb8d1cd 100644 --- a/beams/tests/artifacts/im2l0_test.json +++ b/beams/tests/artifacts/im2l0_test.json @@ -89,4 +89,4 @@ ] } } -} \ No newline at end of file +} diff --git a/beams/tests/mock_iocs/IM2L0.py b/beams/tests/mock_iocs/IM2L0.py index 37cdadb..3c27141 100644 --- a/beams/tests/mock_iocs/IM2L0.py +++ b/beams/tests/mock_iocs/IM2L0.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from enum import Enum from textwrap import dedent + from caproto.server import PVGroup, ioc_arg_parser, pvproperty, run diff --git a/beams/tests/test_tree_generator.py b/beams/tests/test_tree_generator.py index 60c6923..09e7b99 100644 --- a/beams/tests/test_tree_generator.py +++ b/beams/tests/test_tree_generator.py @@ -95,7 +95,7 @@ def test_stop_hitting_yourself(request): ct = 0 while ( - ct == 0 # simulate a constantly monitoring tree + ct == 0 # simulate a constantly monitoring tree or tree.root.status not in (py_trees.common.Status.SUCCESS, py_trees.common.Status.FAILURE) diff --git a/beams/tree_config.py b/beams/tree_config.py index 21cd8d9..5a3f59c 100644 --- a/beams/tree_config.py +++ b/beams/tree_config.py @@ -17,11 +17,11 @@ from py_trees.common import ComparisonExpression, ParallelPolicy, Status from py_trees.composites import Parallel, Selector, Sequence -from beams.typing_helper import Evaluatable from beams.behavior_tree.ActionNode import ActionNode, wrapped_action_work from beams.behavior_tree.CheckAndDo import CheckAndDo from beams.behavior_tree.ConditionNode import ConditionNode from beams.serialization import as_tagged_union +from beams.typing_helper import Evaluatable logger = logging.getLogger(__name__) @@ -146,7 +146,7 @@ def get_condition_function(self) -> Evaluatable: op = getattr(operator, self.operator.value) def cond_func(): - # Note: this bakes EPICS into how Conditions work. + # Note: this bakes EPICS into how Conditions work. # Further implictly now relies of type of "value" to determine whether to get as_string val = caget(self.pv, as_string=isinstance(self.value, str)) if val is None: diff --git a/beams/typing_helper.py b/beams/typing_helper.py index bfaf1c0..53c4c22 100644 --- a/beams/typing_helper.py +++ b/beams/typing_helper.py @@ -5,40 +5,39 @@ """ +from multiprocessing import Event, Queue, Value from typing import Callable -from multiprocessing import Queue, Event, Value import py_trees from beams.behavior_tree.VolatileStatus import VolatileStatus - ''' -Evaluatable: function handle that returns a boolean , accpeting arbitrary arugments +Evaluatable: function handle that returns a boolean , accpeting arbitrary arugments ''' Evaluatable = Callable[..., bool] ''' Defines signature for an ActionNode work loop function handle. This is neccisated by how beams.behavior_tree.ActionWoker expects to spawn the work process via base class beams.sequencer.helpers.Worker -Parameter Types: +Parameter Types: Value: volatile indicating work remains to be performed (tree is still ticking, program still running) str: name of process Event: work gate reflecting py_trees state of node with respect to tree VolatileStatus: mechanism to signal from this process to other processes what the py_trees.common.Status of this node is Evaluatable: this is a completion condition that allows exit of the while loop within the work loop which will wait for a py_trees "initialise" call to reset the Event (work gate) such that meaningful work can resume on this process - Queue: logging queue + Queue: logging queue Callable: mechanism to get logger -Return Types: +Return Types: None ''' ActionNodeWorkLoop = Callable[[Value, str, Event, VolatileStatus, Evaluatable, Queue, Callable], None] ''' -Work function handle of function to be called during the RUNNING state of an ActionNode +Work function handle of function to be called during the RUNNING state of an ActionNode Parameter Types: - Evaluatable: determines what py_trees.common.Status to return + Evaluatable: determines what py_trees.common.Status to return Return Types: py_trees.common.Status: reflects return type from this node with respect to tree logic '''