py_trees.decorators module

Decorate your children. They make great furniture pieces.

Decorators are behaviours that manage a single child and provide common modifications to their underlying child behaviour (e.g. inverting the result). That is, they provide a means for behaviours to wear different ‘hats’ and this combinatorially expands the capabilities of your behaviour library.

images/many-hats.png

An example:

Decorators (Hats)

Decorators with specific functionality:

And the X is Y family:

Decorators for Blocking Behaviours

It is worth making a note of the effect of decorators on blocking behaviours, i.e. those that return RUNNING before eventually returning SUCCESS or FAILURE.

A decorator, such as py_trees.decorators.RunningIsSuccess() on a blocking behaviour will immediately terminate the underlying child and re-intialise on it’s next tick. This is often surprising (to the user) but is necessary to ensure the underlying child isn’t left in a dangling state (i.e. RUNNING) as subsequent ticks move on to other parts of the tree.

A better approach in this case is to build a non-blocking variant or a combination of non-blocking behaviors that handle construction, monitoring and destruction of the activity represented by the original blocking behaviour.

class py_trees.decorators.Condition(name: str, child: Behaviour, status: Status)

Bases: Decorator

A blocking conditional decorator.

Encapsulates a behaviour and wait for it’s status to flip to the desired state. This behaviour will tick with RUNNING while waiting and SUCCESS when the flip occurs.

update() Status

Check if the condtion has triggered, block otherwise.

SUCCESS if the decorated child has returned the specified status, otherwise RUNNING. This decorator will never return FAILURE

Returns:

the behaviour’s new status Status

class py_trees.decorators.Count(name: str, child: Behaviour)

Bases: Decorator

Count the number of times it’s child has been ticked.

This increments counters tracking the total number of times it’s child has been ticked as well as the number of times it has landed in each respective state.

It will always re-zero counters on setup().

Attributes:

total_tick_count: number of ticks in total running_count: number of ticks resulting in this state success_count: number of ticks resulting in this state failure_count: number of ticks resulting in this state interrupt_count: number of times a higher priority has interrupted

setup(**kwargs: int) None

Reset the counters.

terminate(new_status: Status) None

Increment the completion / interruption counters.

update() Status

Increment the counter.

Returns:

the behaviour’s new status Status

class py_trees.decorators.Decorator(name: str, child: Behaviour)

Bases: Behaviour

Parent class for decorating a child/subtree with some additional logic.

Args:

child: the child to be decorated name: the decorator name

Raises:

TypeError: if the child is not an instance of Behaviour

stop(new_status: Status) None

Check if the child is running (dangling) and stop it if that is the case.

Args:

new_status (Status): the behaviour is transitioning to this new status

tick() Iterator[Behaviour]

Manage the decorated child through the tick.

Yields:

a reference to itself or one of its children

tip() Behaviour | None

Retrieve the tip of this behaviour’s subtree (if it has one).

This corresponds to the the deepest node that was running before the subtree traversal reversed direction and headed back to this node.

Returns:

child behaviour, or None if its status is INVALID

class py_trees.decorators.EternalGuard(name: str, child: Behaviour, condition: Any, blackboard_keys: List[str] | Set[str] | None = None)

Bases: Decorator

Continuously guard (with a condition) the execution of a child/subtree.

The eternal guard checks a condition prior to every tick of the child/subtree. If at any time the condition fails, the child/subtree is invalidated.

Note

This is stronger than a conventional guard which is only checked once before any and all ticking of what follows the guard.

Args:

child: the child behaviour or subtree condition: a functional check that determines execution or not of the subtree blackboard_keys: provide read access for the conditional function to these keys name: the decorator name

Examples:

Simple conditional function returning True/False:

def check():
     return True

foo = py_trees.behaviours.Foo()
eternal_guard = py_trees.decorators.EternalGuard(
    name="Eternal Guard",
    condition=check,
    child=foo
)

Simple conditional function returning SUCCESS/FAILURE:

def check():
     return py_trees.common.Status.SUCCESS

foo = py_trees.behaviours.Foo()
eternal_guard = py_trees.decorators.EternalGuard(
    name="Eternal Guard",
    condition=check,
    child=foo
)

Conditional function that makes checks against data on the blackboard (the blackboard client with pre-configured access is provided by the EternalGuard instance):

def check(blackboard):
     return blackboard.velocity > 3.0

foo = py_trees.behaviours.Foo()
eternal_guard = py_trees.decorators.EternalGuard(
    name="Eternal Guard",
    condition=check,
    blackboard_keys={"velocity"},
    child=foo
)

See also

py-trees-demo-eternal-guard for an alternative means of implementing the eternal guard concept using sequences without memory.

tick() Iterator[Behaviour]

Conditionally manage the child.

Yields:

a reference to itself or one of its children

update() Status

Reflect the decorated child’s status.

The update method is only ever triggered in the child’s post-tick, which implies that the condition has already been checked and passed (refer to the tick() method).

Returns:

the behaviour’s new status Status

class py_trees.decorators.FailureIsRunning(name: str, child: Behaviour)

Bases: Decorator

Dont stop running.

update() Status

Reflect FAILURE as RUNNING.

Returns:

the behaviour’s new status Status

class py_trees.decorators.FailureIsSuccess(name: str, child: Behaviour)

Bases: Decorator

Be positive, always succeed.

update() Status

Reflect FAILURE as SUCCESS.

Returns:

the behaviour’s new status Status

class py_trees.decorators.Inverter(name: str, child: Behaviour)

Bases: Decorator

A decorator that inverts the result of a class’s update function.

update() Status

Flip SUCCESS and FAILURE.

Returns:

the behaviour’s new status Status

class py_trees.decorators.OneShot(name: str, child: Behaviour, policy: OneShotPolicy)

Bases: Decorator

A decorator that implements the oneshot pattern.

This decorator ensures that the underlying child is ticked through to completion just once and while doing so, will return with the same status as it’s child. Thereafter it will return with the final status of the underlying child.

Completion status is determined by the policy given on construction.

terminate(new_status: Status) None

Prevent further entry if finishing with SUCCESS.

This uses a flag to register that the behaviour has gone through to completion. In future ticks, it will block entry to the child and just return the original status result.

tick() Iterator[Behaviour]

Tick the child or bounce back with the original status if already completed.

Yields:

a reference to itself or a behaviour in it’s child subtree

update() Status

Bounce if the child has already successfully completed.

Returns:

the behaviour’s new status Status

class py_trees.decorators.PassThrough(name: str, child: Behaviour)

Bases: Decorator

This decorator simply reflects the child’s current status.

This behaviour is useful for debugging or visualisation purposes.

update() Status

Just reflect the child status.

Returns:

the behaviour’s new status Status

class py_trees.decorators.Repeat(name: str, child: Behaviour, num_success: int)

Bases: Decorator

Repeat.

SUCCESS is RUNNING up to a specified number at which point this decorator returns SUCCESS.

FAILURE is always FAILURE.

Args:

child: the child behaviour or subtree num_success: repeat this many times (-1 to repeat indefinitely) name: the decorator name

initialise() None

Reset the currently registered number of successes.

update() Status

Repeat until the nth consecutive success.

Returns:

SUCCESS on nth success, RUNNING on running, or pre-nth success FAILURE failure.

class py_trees.decorators.Retry(name: str, child: Behaviour, num_failures: int)

Bases: Decorator

Keep trying, pastafarianism is within reach.

FAILURE is RUNNING up to a specified number of attempts.

Args:

child: the child behaviour or subtree num_failures: maximum number of permitted failures name: the decorator name

initialise() None

Reset the currently registered number of attempts.

update() Status

Retry until failure count is reached.

Returns:

SUCCESS on success, RUNNING on running, or pre-nth failure FAILURE only on the nth failure.

class py_trees.decorators.RunningIsFailure(name: str, child: Behaviour)

Bases: Decorator

Got to be snappy! We want results…yesterday.

update() Status

Reflect RUNNING as FAILURE.

Returns:

the behaviour’s new status Status

class py_trees.decorators.RunningIsSuccess(name: str, child: Behaviour)

Bases: Decorator

Don’t hang around…

update() Status

Reflect RUNNING as SUCCESS.

Returns:

the behaviour’s new status Status

class py_trees.decorators.StatusToBlackboard(name: str, child: Behaviour, variable_name: str)

Bases: Decorator

Reflect the status of the decorator’s child to the blackboard.

Args:

child: the child behaviour or subtree variable_name: name of the blackboard variable, may be nested, e.g. foo.status name: the decorator name

update() Status

Reflect the decorated child’s status to the blackboard.

Returns: the decorated child’s status

class py_trees.decorators.SuccessIsFailure(name: str, child: Behaviour)

Bases: Decorator

Be depressed, always fail.

update() Status

Reflect SUCCESS as FAILURE.

Returns:

the behaviour’s new status Status

class py_trees.decorators.SuccessIsRunning(name: str, child: Behaviour)

Bases: Decorator

The tickling never ends…

update() Status

Reflect SUCCESS as RUNNING.

Returns:

the behaviour’s new status Status

class py_trees.decorators.Timeout(name: str, child: Behaviour, duration: float = 5.0)

Bases: Decorator

Executes a child/subtree with a timeout.

A decorator that applies a timeout pattern to an existing behaviour. If the timeout is reached, the encapsulated behaviour’s stop() method is called with status FAILURE otherwise it will simply directly tick and return with the same status as that of it’s encapsulated behaviour.

initialise() None

Reset the feedback message and finish time on behaviour entry.

update() Status

Fail on timeout, or block / reflect the child’s result accordingly.

Terminate the child and return FAILURE if the timeout is exceeded.

Returns:

the behaviour’s new status Status