Skip to content

Commit badc0bc

Browse files
authored
Publish current action (#106)
2 parents 77db53f + 45b1932 commit badc0bc

8 files changed

+73
-31
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,5 @@ ENV/
196196
**/docs/_out
197197
**/docs/cppapi
198198
**/docs/pyapi
199+
200+
.ruff_cache/

.pre-commit-config.yaml

+1-4
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ repos:
66
args:
77
- "--fix"
88
- "--exit-non-zero-on-fix"
9-
- repo: https://github.com/psf/black
10-
rev: 23.10.0 # keep this version for Ubuntu support
11-
hooks:
12-
- id: black
9+
- id: ruff-format
1310
- repo: https://github.com/pocc/pre-commit-hooks
1411
rev: v1.3.5
1512
hooks:

dynamic_stack_decider/dynamic_stack_decider/abstract_action_element.py

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
from abc import ABCMeta
2+
from typing import TYPE_CHECKING
23

34
from dynamic_stack_decider.abstract_stack_element import AbstractStackElement
45

6+
if TYPE_CHECKING:
7+
from dynamic_stack_decider.dsd import DSD
8+
59

610
class AbstractActionElement(AbstractStackElement, metaclass=ABCMeta):
711
"""
@@ -14,19 +18,16 @@ class AbstractActionElement(AbstractStackElement, metaclass=ABCMeta):
1418
If the action is complete, it can remove itself from the stack by performing a pop command.
1519
"""
1620

17-
def __init__(self, blackboard, dsd, parameters=None):
21+
def __init__(self, blackboard, dsd: "DSD", parameters: dict[str, bool | int | float | str]):
1822
"""
1923
Constructor of the action element
2024
:param blackboard: Shared blackboard for data exchange between elements
2125
:param dsd: The stack decider which has this element on its stack.
22-
:param parameters: Optional parameters which serve as arguments to this element
26+
:param parameters: Parameters which serve as arguments to this element
2327
"""
2428
super().__init__(blackboard, dsd, parameters)
2529
# Reevaluation can be disabled by setting 'r' or 'reevaluate' to False
26-
if parameters is not None:
27-
self.never_reevaluate = not parameters.get("r", True) or not parameters.get("reevaluate", True)
28-
else:
29-
self.never_reevaluate = False
30+
self.never_reevaluate = not parameters.get("r", True) or not parameters.get("reevaluate", True)
3031

3132
def do_not_reevaluate(self):
3233
"""
@@ -41,6 +42,6 @@ def repr_dict(self) -> dict:
4142
"""
4243
return {
4344
"type": "action",
44-
"name": self.__class__.__name__,
45+
"name": self.name,
4546
"debug_data": self._debug_data,
4647
}

dynamic_stack_decider/dynamic_stack_decider/abstract_decision_element.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def repr_dict(self) -> dict:
2626
"""
2727
return {
2828
"type": "decision",
29-
"name": self.__class__.__name__,
29+
"name": self.name,
3030
"debug_data": self._debug_data,
3131
}
3232

dynamic_stack_decider/dynamic_stack_decider/abstract_stack_element.py

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
from abc import ABCMeta, abstractmethod
2-
from typing import Union
2+
from typing import TYPE_CHECKING, Union
33

44
from dynamic_stack_decider.logger import get_logger
55

6+
if TYPE_CHECKING:
7+
from dynamic_stack_decider.dsd import DSD
8+
69

710
class AbstractStackElement(metaclass=ABCMeta):
811
"""
@@ -12,14 +15,14 @@ class AbstractStackElement(metaclass=ABCMeta):
1215
Each element which inherits from the AbstractStackElement can be used as a root element on the stack.
1316
"""
1417

15-
_dsd = None
16-
_init_data = None
18+
_dsd: "DSD"
19+
parameters: dict[str, bool | int | float | str]
1720

18-
def __init__(self, blackboard, dsd, parameters=None):
21+
def __init__(self, blackboard, dsd: "DSD", parameters: dict[str, bool | int | float | str]):
1922
"""
2023
:param blackboard: Shared blackboard for data exchange between elements
2124
:param dsd: The stack decider which has this element on its stack.
22-
:param parameters: Optional parameters which serve as arguments to this element
25+
:param parameters: Parameters which serve as arguments to this element
2326
"""
2427
self._debug_data = {}
2528
"""
@@ -28,8 +31,16 @@ def __init__(self, blackboard, dsd, parameters=None):
2831
"""
2932

3033
self._dsd = dsd
34+
self.parameters = parameters
3135
self.blackboard = blackboard
3236

37+
@property
38+
def name(self) -> str:
39+
"""
40+
Returns the name of the action
41+
"""
42+
return self.__class__.__name__
43+
3344
def pop(self):
3445
"""
3546
Help method which pops the element of the stack.
@@ -90,6 +101,6 @@ def repr_dict(self) -> dict:
90101
"""Represent this stack element as dictionary which is JSON encodable"""
91102
return {
92103
"type": "abstract",
93-
"name": self.__class__.__name__,
104+
"name": self.name,
94105
"debug_data": self._debug_data,
95106
}

dynamic_stack_decider/dynamic_stack_decider/dsd.py

+33-2
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ class DSD:
108108
stack_reevaluate = False
109109
do_not_reevaluate = False
110110
old_representation = ""
111+
debug_active_action_cache: Optional[str] = None
111112

112113
def __init__(self, blackboard, debug_topic: str = None, node: Optional[Node] = None):
113114
"""
@@ -142,6 +143,10 @@ def __init__(self, blackboard, debug_topic: str = None, node: Optional[Node] = N
142143
debug_stack_topic = f"{debug_topic}/dsd_stack"
143144
self.debug_stack_publisher = node.create_publisher(String, debug_stack_topic, 10)
144145
get_logger().debug(f"Debugging stack on '{debug_stack_topic}'")
146+
# Publish the currently active action
147+
debug_current_action_topic = f"{debug_topic}/dsd_current_action"
148+
self.debug_current_action_publisher = node.create_publisher(String, debug_current_action_topic, 10)
149+
get_logger().debug(f"Debugging current action on '{debug_current_action_topic}'")
145150

146151
def register_actions(self, module_path):
147152
"""
@@ -196,7 +201,7 @@ def _bind_modules(self, element):
196201
else:
197202
raise ValueError(f'Unknown parser tree element type "{type(element)}" for element "{element}"!')
198203

199-
def _init_element(self, element):
204+
def _init_element(self, element: AbstractTreeElement):
200205
"""Initializes the module belonging to the given element."""
201206
if isinstance(element, SequenceTreeElement):
202207
initialized_actions = list()
@@ -206,7 +211,7 @@ def _init_element(self, element):
206211
else:
207212
return element.module(self.blackboard, self, element.parameters)
208213

209-
def set_start_element(self, start_element):
214+
def set_start_element(self, start_element: AbstractTreeElement):
210215
"""
211216
This method defines the start element on the stack, which stays always on the bottom of the stack.
212217
It should be called in __init__.
@@ -236,6 +241,7 @@ def update(self, reevaluate: bool = True):
236241
"""
237242
try:
238243
self.debug_publish_stack()
244+
self.debug_publish_current_action()
239245

240246
if reevaluate and not self.do_not_reevaluate:
241247
self.stack_exec_index = 0
@@ -362,3 +368,28 @@ def debug_publish_tree(self):
362368
data = self.tree.repr_dict()
363369
msg = String(data=json.dumps(data))
364370
self.debug_tree_publisher.publish(msg)
371+
372+
def debug_publish_current_action(self):
373+
"""
374+
Publishes the name of the currently active action
375+
"""
376+
# Check if debugging is active and if there is something on the stack
377+
if not self.debug_active or len(self.stack) == 0:
378+
return
379+
380+
# Get the top element
381+
stack_top = self.stack[-1][1]
382+
# Check if it is an action or a sequence element and retrieve the current action
383+
if isinstance(stack_top, AbstractActionElement):
384+
current_action = stack_top
385+
elif isinstance(stack_top, SequenceElement):
386+
current_action = stack_top.current_action
387+
else:
388+
return
389+
390+
# Only publish if the action changed
391+
if current_action.name != self.debug_active_action_cache:
392+
# Publish the name of the current action
393+
self.debug_current_action_publisher.publish(String(data=current_action.name))
394+
# Cache the current action name
395+
self.debug_active_action_cache = current_action.name

dynamic_stack_decider/dynamic_stack_decider/sequence_element.py

+11-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
from typing import TYPE_CHECKING
2+
3+
from dynamic_stack_decider.abstract_action_element import AbstractActionElement
14
from dynamic_stack_decider.abstract_stack_element import AbstractStackElement
25

6+
if TYPE_CHECKING:
7+
from dynamic_stack_decider.dsd import DSD
8+
39

410
class SequenceElement(AbstractStackElement):
511
"""
@@ -10,11 +16,11 @@ class SequenceElement(AbstractStackElement):
1016
This is not an abstract class to inherit from.
1117
"""
1218

13-
def __init__(self, blackboard, dsd, actions=()):
19+
def __init__(self, blackboard, dsd: "DSD", actions: list[AbstractActionElement]):
1420
"""
1521
:param actions: list of initialized action elements
1622
"""
17-
super().__init__(blackboard, dsd)
23+
super().__init__(blackboard, dsd, dict())
1824
self.actions = actions
1925
self.current_action_index = 0
2026

@@ -40,21 +46,17 @@ def in_last_element(self):
4046
return self.current_action_index == len(self.actions) - 1
4147

4248
@property
43-
def current_action(self):
49+
def current_action(self) -> AbstractActionElement:
4450
"""
4551
Returns the currently executed action of the sequence element
46-
47-
:rtype: AbstractActionElement
4852
"""
4953
return self.actions[self.current_action_index]
5054

51-
def repr_dict(self):
55+
def repr_dict(self) -> dict:
5256
"""
5357
Represent this stack element as dictionary which is JSON encodable
54-
55-
:rtype: dict
5658
"""
57-
self.publish_debug_data("Active Element", self.current_action.__class__.__name__)
59+
self.publish_debug_data("Active Element", self.current_action.name)
5860
if self.current_action._debug_data:
5961
self.publish_debug_data("Corresponding debug data", self.current_action._debug_data)
6062
data = {

dynamic_stack_decider/dynamic_stack_decider/tree.py

-2
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ def __init__(self, name, parent, parameters=None, unset_parameters=None):
8686
:param parent: the parent element, None for the root element
8787
:param parameters: A dictionary of parameters
8888
:param unset_parameters: A dictionary of parameters that must be set later
89-
:type parent: DecisionTreeElement
9089
"""
9190
# Call the constructor of the superclass
9291
super().__init__(name, parent, parameters, unset_parameters)
@@ -185,7 +184,6 @@ def __init__(self, name, parent, parameters=None, unset_parameters=None):
185184
Create a new ActionTreeElement
186185
:param name: the class name of the corresponding AbstractActionElement
187186
:param parent: the parent element
188-
:type parent: DecisionTreeElement
189187
:param parameters: A dictionary of parameters
190188
:param unset_parameters: A dictionary of parameters that must be set later
191189
"""

0 commit comments

Comments
 (0)