|
38 | 38 | * :class:`py_trees.decorators.EternalGuard`
|
39 | 39 | * :class:`py_trees.decorators.Inverter`
|
40 | 40 | * :class:`py_trees.decorators.OneShot`
|
| 41 | +* :class:`py_trees.decorators.OnTerminate` |
41 | 42 | * :class:`py_trees.decorators.Repeat`
|
42 | 43 | * :class:`py_trees.decorators.Retry`
|
43 | 44 | * :class:`py_trees.decorators.StatusToBlackboard`
|
@@ -920,3 +921,64 @@ def update(self) -> common.Status:
|
920 | 921 | the behaviour's new status :class:`~py_trees.common.Status`
|
921 | 922 | """
|
922 | 923 | return self.decorated.status
|
| 924 | + |
| 925 | + |
| 926 | +class OnTerminate(Decorator): |
| 927 | + """ |
| 928 | + Trigger the child for a single tick on :meth:`terminate`. |
| 929 | +
|
| 930 | + Always return :data:`~py_trees.common.Status.RUNNING` and on |
| 931 | + on :meth:`terminate`, call the child's |
| 932 | + :meth:`~py_trees.behaviour.Behaviour.update` method, once. |
| 933 | +
|
| 934 | + This is useful to cleanup, restore a context switch or to |
| 935 | + implement a finally-like behaviour. |
| 936 | +
|
| 937 | + .. seealso:: :meth:`py_trees.idioms.eventually` |
| 938 | + """ |
| 939 | + |
| 940 | + def __init__(self, name: str, child: behaviour.Behaviour): |
| 941 | + """ |
| 942 | + Initialise with the standard decorator arguments. |
| 943 | +
|
| 944 | + Args: |
| 945 | + name: the decorator name |
| 946 | + child: the child to be decorated |
| 947 | + """ |
| 948 | + super(OnTerminate, self).__init__(name=name, child=child) |
| 949 | + |
| 950 | + def tick(self) -> typing.Iterator[behaviour.Behaviour]: |
| 951 | + """ |
| 952 | + Bypass the child when ticking. |
| 953 | +
|
| 954 | + Yields: |
| 955 | + a reference to itself |
| 956 | + """ |
| 957 | + self.logger.debug(f"{self.__class__.__name__}.tick()") |
| 958 | + self.status = self.update() |
| 959 | + yield self |
| 960 | + |
| 961 | + def update(self) -> common.Status: |
| 962 | + """ |
| 963 | + Return with :data:`~py_trees.common.Status.RUNNING`. |
| 964 | +
|
| 965 | + Returns: |
| 966 | + the behaviour's new status :class:`~py_trees.common.Status` |
| 967 | + """ |
| 968 | + return common.Status.RUNNING |
| 969 | + |
| 970 | + def terminate(self, new_status: common.Status) -> None: |
| 971 | + """Tick the child behaviour once.""" |
| 972 | + self.logger.debug( |
| 973 | + "{}.terminate({})".format( |
| 974 | + self.__class__.__name__, |
| 975 | + "{}->{}".format(self.status, new_status) |
| 976 | + if self.status != new_status |
| 977 | + else f"{new_status}", |
| 978 | + ) |
| 979 | + ) |
| 980 | + if new_status == common.Status.INVALID: |
| 981 | + self.decorated.tick_once() |
| 982 | + # Do not need to stop the child here - this method |
| 983 | + # is only called by Decorator.stop() which will handle |
| 984 | + # that responsibility immediately after this method returns. |
0 commit comments