Module API
py_trees
This is the top-level namespace of the py_trees package.
py_trees.behaviour
The core behaviour template for all py_tree behaviours.
- class py_trees.behaviour.Behaviour(name: str)[source]
Bases:
ABC
A parent class for all user definable tree behaviours.
- Parameters
name (str) – the behaviour name, defaults to auto-generating from the class name
- Raises
TypeError – if the provided name is not a string
- Variables
~py_trees.behaviours.Behaviour.id (
uuid.UUID
) – automagically generated unique identifier for the behaviour~py_trees.behaviours.Behaviour.name (
str
) – the behaviour name~py_trees.behaviours.Behaviour.blackboards (List[py_trees.blackboard.Client]) – collection of attached blackboard clients
~py_trees.behaviours.Behaviour.status (
Status
) – the behaviour status (INVALID
,RUNNING
,FAILURE
,SUCCESS
)~py_trees.behaviours.Behaviour.parent (
Behaviour
) – aComposite
instance if nested in a tree, otherwise None~py_trees.behaviours.Behaviour.children ([
Behaviour
]) – empty for regular behaviours, populated for composites~py_trees.behaviours.Behaviour.logger (
logging.Logger
) – a simple logging mechanism~py_trees.behaviours.Behaviour.feedback_message (
str
) – improve debugging with a simple message~py_trees.behaviours.Behaviour.blackbox_level (
BlackBoxLevel
) – a helper variable for dot graphs and runtime gui’s to collapse/explode entire subtrees dependent upon the blackbox level.
- attach_blackboard_client(name: Optional[str] = None, namespace: Optional[str] = None) Client [source]
Create and attach a blackboard to this behaviour.
- has_parent_with_instance_type(instance_type: Type[Behaviour]) bool [source]
Search this behaviour’s ancestors for one of the specified type.
- has_parent_with_name(name: str) bool [source]
Search this behaviour’s ancestors for one with the specified name.
- initialise() None [source]
Execute user specified instructions prior to commencement of a new round of activity.
Users should override this method to perform any necessary initialising/clearing/resetting of variables prior to a new round of activity for the behaviour.
This method is automatically called via the
py_trees.behaviour.Behaviour.tick()
method whenever the behaviour is notRUNNING
.… note:: This method can be called more than once in the lifetime of a tree!
- Return type
None
- iterate(direct_descendants: bool = False) Iterator[Behaviour] [source]
Iterate over this child and it’s children.
This utilises python generators for looping. To traverse the entire tree:
for node in my_behaviour.iterate(): print("Name: {0}".format(node.name))
- setup(**kwargs: Any) None [source]
Set up and verify infrastructure (middleware connections, etc) is available.
Users should override this method for any configuration and/or validation that is necessary prior to ticking the tree. Such construction is best done here rather than in __init__ since there is no guarantee at __init__ that the infrastructure is ready or even available (e.g. you may be just rendering dot graphs of the trees, no robot around).
Examples
establishing a middleware connection to a sensor or driver
ensuring a sensor or driver is in a ‘ready’ state
This method will typically be called before a tree’s first tick as this gives the application time to check and verify that everything is in a ready state before executing. This is especially important given that a tree does not always tick every behaviour and if not checked up-front, it may be some time before discovering a behaviour was in a broken state.
Tip
When to use
__init__()
,setup()
and when to useinitialise()
?Use
__init__()
for configuration of non-runtime dependencies (e.g. no middleware).Use
setup()
for one-offs or to get early signal that everything (e.g. middleware) is ready to go.Use
initialise()
for just-in-time configurations and/or checks.There are times when it makes sense to do all three. For example, pythonic variable configuration in
__init__()
, middleware service client creation / server existence checks insetup()
and a just-in-time check to ensure the server is still available ininitialise()
.Tip
Faults are notified to the user of the behaviour via exceptions. Choice of exception to use is left to the user.
Warning
The kwargs argument is for distributing objects at runtime to behaviours before ticking. For example, a simulator instance with which behaviours can interact with the simulator’s python api, a ros2 node for setting up communications. Use sparingly, as this is not proof against keyword conflicts amongst disparate libraries of behaviours.
- setup_with_descendants() None [source]
Call setup on this child, it’s children (it’s children’s children, ).
- Return type
None
- shutdown() None [source]
Destroy setup infrastructure (the antithesis of setup).
Users should override this method for any custom destruction of infrastructure usually brought into being in
setup()
.- Raises
Exception – of whatever flavour the child raises when errors occur on destruction
- Return type
None
See also
- stop(new_status: Status) None [source]
Stop the behaviour with the specified status.
- Parameters
new_status (Status) – the behaviour is transitioning to this new status
- Return type
None
This is called to bring the current round of activity for the behaviour to completion, typically resulting in a final status of
SUCCESS
,FAILURE
orINVALID
.Warning
Users should not override this method to provide custom termination behaviour. The
terminate()
method has been provided for that purpose.
- terminate(new_status: Status) None [source]
Execute user specified instructions when the behaviour is stopped.
Users should override this method to clean up. It will be triggered when a behaviour either finishes execution (switching from
RUNNING
toFAILURE
||SUCCESS
) or it got interrupted by a higher priority branch (switching toINVALID
). Remember that theinitialise()
method will handle resetting of variables before re-entry, so this method is about disabling resources until this behaviour’s next tick. This could be a indeterminably long time. e.g.cancel an external action that got started
shut down any temporary communication handles
- Parameters
new_status (
Status
) – the behaviour is transitioning to this new status- Return type
None
Warning
Do not set self.status = new_status here, that is automatically handled by the
stop()
method. Use the argument purely for introspection purposes (e.g. comparing the current state in self.status with the state it will transition to in new_status.See also
- tick() Iterator[Behaviour] [source]
Tick the behaviour.
This function is a generator that can be used by an iterator on an entire behaviour tree. It handles the logic for deciding when to call the user’s
initialise()
andterminate()
methods as well as making the actual call to the user’supdate()
method that determines the behaviour’s new status once the tick has finished. Once done, it will then yield itself (generator mechanism) so that it can be used as part of an iterator for the entire tree.for node in my_behaviour.tick(): print("Do something")
Note
This is a generator function, you must use this with yield. If you need a direct call, prefer
tick_once()
instead.Warning
Users should not override this method to provide custom tick behaviour. The
update()
method has been provided for that purpose.
- tick_once() None [source]
Tick the object without iterating step-by-step over the children (i.e. without generators).
- Return type
None
- tip() Optional[Behaviour] [source]
Get 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.
- abstract update() Status [source]
Execute user specified instructions when the behaviour is ticked.
Users should override this method to perform any logic required to arrive at a decision on the behaviour’s new status. It is the primary worker function called by the
tick()
mechanism.Tip
This method should be almost instantaneous and non-blocking
See also
py_trees.behaviours
A library of fundamental behaviours for use.
- class py_trees.behaviours.BlackboardToStatus(name: str, variable_name: str)[source]
Bases:
Behaviour
Reflects a
Status
stored in a blackboard variable.This behaviour reverse engineers the
StatusToBlackboard
decorator. Used in conjuction with that decorator, this behaviour can be used to reflect the status of a decision elsewhere in the tree.Note
A word of caution. The consequences of a behaviour’s status should be discernable upon inspection of the tree graph. If using StatusToBlackboard and BlackboardToStatus to reflect a behaviour’s status across a tree, this is no longer true. The graph of the tree communicates the local consequences, but not the reflected consequences at the point BlackboardToStatus is used. A recommendation, use this class only where other options are infeasible or impractical.
- Parameters
- Raises
- class py_trees.behaviours.CheckBlackboardVariableExists(name: str, variable_name: str)[source]
Bases:
Behaviour
A non-blocking check for the existence of a blackboard variable.
Check the blackboard to verify if a specific variable (key-value pair) exists. This is non-blocking, so will always tick with status
FAILURE
SUCCESS
.See also
WaitForBlackboardVariable
for the blocking counterpart to this behaviour.- Parameters
- class py_trees.behaviours.CheckBlackboardVariableValue(name: str, check: ComparisonExpression)[source]
Bases:
Behaviour
Non-blocking check to determine if a blackboard variable matches a given value/expression.
Inspect a blackboard variable and if it exists, check that it meets the specified criteria (given by operation type and expected value). This is non-blocking, so it will always tick with
SUCCESS
orFAILURE
.- Parameters
name (str) – name of the behaviour
check (ComparisonExpression) – a comparison expression to check against
Note
If the variable does not yet exist on the blackboard, the behaviour will return with status
FAILURE
.Tip
The python operator module includes many useful comparison operations.
- class py_trees.behaviours.CheckBlackboardVariableValues(name: str, checks: List[ComparisonExpression], operator: Callable[[bool, bool], bool], namespace: Optional[str] = None)[source]
Bases:
Behaviour
Apply a logical operation across a set of blackboard variable checks.
This is non-blocking, so will always tick with status
FAILURE
orSUCCESS
.- Parameters
checks (List[ComparisonExpression]) – a list of comparison checks to apply to blackboard variables
logical_operator – a logical check to apply across the results of the blackboard variable checks
name (str) – name of the behaviour
namespace (Optional[str]) – optionally store results of the checks (boolean) under this namespace
Tip
The python operator module includes many useful logical operators, e.g. operator.xor.
- Raises
ValueError if less than two variable checks are specified (insufficient for logical operations) –
- Parameters
- class py_trees.behaviours.Dummy(name: str = 'Dummy')
Bases:
Behaviour
Crash test dummy used for anything dangerous.
- Parameters
name (str) –
- terminate(new_status: Status) None
Execute user specified instructions when the behaviour is stopped.
Users should override this method to clean up. It will be triggered when a behaviour either finishes execution (switching from
RUNNING
toFAILURE
||SUCCESS
) or it got interrupted by a higher priority branch (switching toINVALID
). Remember that theinitialise()
method will handle resetting of variables before re-entry, so this method is about disabling resources until this behaviour’s next tick. This could be a indeterminably long time. e.g.cancel an external action that got started
shut down any temporary communication handles
- Parameters
- Return type
None
Warning
Do not set self.status = new_status here, that is automatically handled by the
stop()
method. Use the argument purely for introspection purposes (e.g. comparing the current state in self.status with the state it will transition to in new_status.See also
- class py_trees.behaviours.Failure(name: str = 'Failure')
Bases:
Behaviour
Do nothing but tick over with
FAILURE
.- Parameters
name (str) –
- terminate(new_status: Status) None
Execute user specified instructions when the behaviour is stopped.
Users should override this method to clean up. It will be triggered when a behaviour either finishes execution (switching from
RUNNING
toFAILURE
||SUCCESS
) or it got interrupted by a higher priority branch (switching toINVALID
). Remember that theinitialise()
method will handle resetting of variables before re-entry, so this method is about disabling resources until this behaviour’s next tick. This could be a indeterminably long time. e.g.cancel an external action that got started
shut down any temporary communication handles
- Parameters
- Return type
None
Warning
Do not set self.status = new_status here, that is automatically handled by the
stop()
method. Use the argument purely for introspection purposes (e.g. comparing the current state in self.status with the state it will transition to in new_status.See also
- class py_trees.behaviours.Periodic(name: str, n: int)[source]
Bases:
Behaviour
Simply periodically rotates it’s status over all each status.
That is,
RUNNING
for N ticks,SUCCESS
for N ticks,FAILURE
for N ticks…Note
It does not reset the count when initialising.
- class py_trees.behaviours.ProbabilisticBehaviour(name: str, weights: Optional[List[float]] = None)[source]
Bases:
Behaviour
Return a status based on a probability distribution. If unspecified - a uniform distribution will be used.
- Parameters
Note
Probability distribution does not need to be normalised, it will be normalised internally.
- Raises
ValueError if only some probabilities are specified –
- Parameters
- class py_trees.behaviours.Running(name: str = 'Running')
Bases:
Behaviour
Do nothing but tick over with
RUNNING
.- Parameters
name (str) –
- terminate(new_status: Status) None
Execute user specified instructions when the behaviour is stopped.
Users should override this method to clean up. It will be triggered when a behaviour either finishes execution (switching from
RUNNING
toFAILURE
||SUCCESS
) or it got interrupted by a higher priority branch (switching toINVALID
). Remember that theinitialise()
method will handle resetting of variables before re-entry, so this method is about disabling resources until this behaviour’s next tick. This could be a indeterminably long time. e.g.cancel an external action that got started
shut down any temporary communication handles
- Parameters
- Return type
None
Warning
Do not set self.status = new_status here, that is automatically handled by the
stop()
method. Use the argument purely for introspection purposes (e.g. comparing the current state in self.status with the state it will transition to in new_status.See also
- class py_trees.behaviours.SetBlackboardVariable(name: str, variable_name: str, variable_value: Union[Any, Callable[[], Any]], overwrite: bool)[source]
Bases:
Behaviour
Set the specified variable on the blackboard.
- Parameters
- class py_trees.behaviours.StatusQueue(name: str, queue: List[Status], eventually: Optional[Status])[source]
Bases:
Behaviour
Cycle through a specified queue of states.
Note
This does not reset when the behaviour initialises.
- Parameters
- class py_trees.behaviours.Success(name: str = 'Success')
Bases:
Behaviour
Do nothing but tick over with
SUCCESS
.- Parameters
name (str) –
- terminate(new_status: Status) None
Execute user specified instructions when the behaviour is stopped.
Users should override this method to clean up. It will be triggered when a behaviour either finishes execution (switching from
RUNNING
toFAILURE
||SUCCESS
) or it got interrupted by a higher priority branch (switching toINVALID
). Remember that theinitialise()
method will handle resetting of variables before re-entry, so this method is about disabling resources until this behaviour’s next tick. This could be a indeterminably long time. e.g.cancel an external action that got started
shut down any temporary communication handles
- Parameters
- Return type
None
Warning
Do not set self.status = new_status here, that is automatically handled by the
stop()
method. Use the argument purely for introspection purposes (e.g. comparing the current state in self.status with the state it will transition to in new_status.See also
- class py_trees.behaviours.SuccessEveryN(name: str, n: int)[source]
Bases:
Behaviour
Non-blocking, periodic success.
This behaviour updates it’s status with
SUCCESS
once every N ticks,FAILURE
otherwise.Tip
Use with decorators to change the status value as desired, e.g.
py_trees.decorators.FailureIsRunning()
- class py_trees.behaviours.TickCounter(name: str, duration: int, completion_status: Status)[source]
Bases:
Behaviour
Block for a specified tick count.
A useful utility behaviour for demos and tests. Simply ticks with
RUNNING
for the specified number of ticks before returning the requested completion status (SUCCESS
orFAILURE
).This behaviour will reset the tick counter when initialising.
- Parameters
- class py_trees.behaviours.UnsetBlackboardVariable(name: str, key: str)[source]
Bases:
Behaviour
Unset the specified variable (key-value pair) from the blackboard.
This always returns
SUCCESS
regardless of whether the variable was already present or not.
- class py_trees.behaviours.WaitForBlackboardVariable(name: str, variable_name: str)[source]
Bases:
CheckBlackboardVariableExists
Block until a blackboard variable comes into existence.
This is blocking, so it will tick with status
SUCCESS
if the variable is found, andRUNNING
otherwise.See also
CheckBlackboardVariableExists
for the non-blocking counterpart to this behaviour.- Parameters
- class py_trees.behaviours.WaitForBlackboardVariableValue(name: str, check: ComparisonExpression)[source]
Bases:
CheckBlackboardVariableValue
Block until a blackboard variable matches a given value/expression.
Inspect a blackboard variable and if it exists, check that it meets the specified criteria (given by operation type and expected value). This is blocking, so it will always tick with
SUCCESS
orRUNNING
.See also
CheckBlackboardVariableValue
for the non-blocking counterpart to this behaviour.Note
If the variable does not yet exist on the blackboard, the behaviour will return with status
RUNNING
.- Parameters
check (ComparisonExpression) – a comparison expression to check against
name (str) – name of the behaviour
- py_trees.behaviours.dummy(self: Behaviour) Status [source]
Define a functor for a crash test dummy behaviour.
- py_trees.behaviours.failure(self: Behaviour) Status [source]
Define a functor for an always failing behaviour.
py_trees.blackboard
Blackboards, for behaviours to write and read from.
Blackboards are not a necessary component of behaviour tree implementations, but are nonetheless, a fairly common mechanism for sharing data between behaviours in the tree. See, for example, the design notes for blackboards in Unreal Engine.

Implementations vary widely depending on the needs of the framework using them. The simplest implementations take the form of a key-value store with global access, while more rigorous implementations scope access or form a secondary graph overlaying the tree connecting data ports between behaviours.
The ‘Zen of PyTrees’ is to enable rapid development, yet be rich enough so that all of the magic is exposed for debugging purposes. The first implementation of a blackboard was merely a global key-value store with an api that lent itself to ease of use, but did not expose the data sharing between behaviours which meant any tooling used to introspect or visualise the tree, only told half the story.
The current implementation adopts a strategy similar to that of a filesystem. Each client (subsequently behaviour) registers itself for read/write access to keys on the blackboard. This is less to do with permissions and more to do with tracking users of keys on the blackboard - extremely helpful with debugging.
The alternative approach of layering a secondary data graph with parameter and input-output ports on each behaviour was discarded as being too heavy for the zen requirements of py_trees. This is in part due to the wiring costs, but also due to complexity arising from a tree’s partial graph execution (a feature which makes trees different from most computational graph frameworks) and not to regress on py_trees’ capability to dynamically insert and prune subtrees on the fly.
A high-level list of existing / planned features:
[+] Centralised key-value store
[+] Client connections with namespaced read/write access to the store
[+] Integration with behaviours for key-behaviour associations (debugging)
[+] Activity stream that logs read/write operations by clients
[+] Exclusive locks for writing
[+] Framework for key remappings
- class py_trees.blackboard.ActivityItem(key: str, client_name: str, client_id: UUID, activity_type: str, previous_value: Optional[Any] = None, current_value: Optional[Any] = None)[source]
Bases:
object
Holds data pertaining to activity on the blackboard.
- Parameters
key (str) – name of the variable on the blackboard
client_name (str) – convenient name of the client performing the operation
client_id (UUID) – unique id of the client performing the operation
activity_type (str) – type of activity
previous_value (Optional[Any]) – of the given key (None if this field is not relevant)
current_value (Optional[Any]) – current value for the given key (None if this field is not relevant)
- __init__(key: str, client_name: str, client_id: UUID, activity_type: str, previous_value: Optional[Any] = None, current_value: Optional[Any] = None)[source]
- __weakref__
list of weak references to the object (if defined)
- class py_trees.blackboard.ActivityStream(maximum_size: int = 500)[source]
Bases:
object
Stores the stream of events recording blackboard activity.
What got registered, unregistered, written, accessed? What operations failed due to incorrect permissions? What did the written variable change from? What did it change to? The activity stream captures all of these and more. It is a very useful mechanisms for debugging your tree from tick to tick.
- Variables
(typing.List[ActivityItem] (data) – list of activity items, earliest first
maximum_size (int) – pop items if this size is exceeded
- Parameters
maximum_size (int) –
- __init__(maximum_size: int = 500)[source]
Initialise the stream with a maximum storage limit.
- Parameters
maximum_size (int) – pop items from the stream if this size is exceeded
- __weakref__
list of weak references to the object (if defined)
- push(activity_item: ActivityItem) None [source]
Push the next activity item to the stream.
- Parameters
activity_item (ActivityItem) – new item to append to the stream
- Return type
None
- class py_trees.blackboard.ActivityType(value)[source]
Bases:
Enum
An enumerator representing the operation on a blackboard variable.
- ACCESSED = 'ACCESSED'
Key accessed, either for reading, or modification of the value’s internal attributes (e.g. foo.bar).
- ACCESS_DENIED = 'ACCESS_DENIED'
Client did not have access to read/write a key.
- INITIALISED = 'INITIALISED'
Initialised a key-value pair on the blackboard
- NO_KEY = 'NO_KEY'
Tried to access a key that does not yet exist on the blackboard.
- NO_OVERWRITE = 'NO_OVERWRITE'
Tried to write but variable already exists and a no-overwrite request was respected.
- READ = 'READ'
Read from the blackboard
- UNSET = 'UNSET'
Key was removed from the blackboard
- WRITE = 'WRITE'
Wrote to the blackboard.
- class py_trees.blackboard.Blackboard[source]
Bases:
object
Centralised key-value store for sharing data between behaviours.
This class is a coat-hanger for the centralised data store, metadata for it’s administration and static methods for interacting with it.
This api is intended for authors of debugging and introspection tools on the blackboard. Users should make use of the
Client
.- Variables
Blackboard.clients (Dict[uuid.UUID, str]) – client uuid-name registry
Blackboard.metadata (Dict[str, KeyMetaData]) – key associated metadata
Blackboard.activity_stream (ActivityStream) – logged activity
Blackboard.separator (char) – namespace separator character
- __weakref__
list of weak references to the object (if defined)
- static absolute_name(namespace: str, key: str) str [source]
Generate the fully qualified key name from namespace and name arguments.
Examples
'/' + 'foo' = '/foo' '/' + '/foo' = '/foo' '/foo' + 'bar' = '/foo/bar' '/foo/' + 'bar' = '/foo/bar' '/foo' + '/foo/bar' = '/foo/bar' '/foo' + '/bar' = '/bar' '/foo' + 'foo/bar' = '/foo/foo/bar'
- Parameters
- Returns
the absolute name
- Return type
Warning
To expedite the method call (it’s used with high frequency in blackboard key lookups), no checks are made to ensure the namespace argument leads with a “/”. Nor does it check that a name in absolute form is actually embedded in the specified namespace, it just returns the given (absolute) name directly.
- static clear() None [source]
Completely clear all key, value and client information from the blackboard.
This also deletes the activity stream, if it exists.
- Return type
None
- static disable_activity_stream() None [source]
Disable logging into the activity stream.
- Return type
None
- static enable_activity_stream(maximum_size: int = 500) None [source]
Enable logging into the activity stream.
- Parameters
maximum_size (int) – pop items from the stream if this size is exceeded
- Raises
RuntimeError if the activity stream is already enabled –
- Return type
None
- static exists(name: str) bool [source]
Check if the specified variable exists on the blackboard.
- Parameters
name (str) – name of the variable, can be nested, e.g. battery.percentage
- Raises
AttributeError – if the client does not have read access to the variable
- Return type
- static get(variable_name: str) Any [source]
Get a variable from the blackboard.
Extract the value associated with the given a variable name, can be nested, e.g. battery.percentage. This differs from the client get method in that it doesn’t pass through the client access checks. Use for debugging / introspection tooling (e.g. display methods) only (prefer the clients for rigorous programmatic access).
- static key(variable_name: str) str [source]
Extract the key portion of an abitrary blackboard variable name.
Given a variable name that potentially also includes a reference to internal attributes of the variable stored on the blackboard, return the part that represents the blackboard key only.
Example: ‘/foo/bar.woohoo -> /foo/bar’.
- static key_with_attributes(variable_name: str) Tuple[str, str] [source]
Separate key and attribrutes from a variable name.
Given a variable name that potentially also includes a reference to internal attributes of the variable stored on the blackboard, separate and return in tuple form.
Example: ‘/foo/bar.woohoo -> (/foo/bar’, ‘woohoo’)
- static keys_filtered_by_clients(client_ids: Union[Set[UUID], List[UUID]]) Set[str] [source]
Get the set of blackboard keys filtered by client unique identifiers.
- static keys_filtered_by_regex(regex: str) Set[str] [source]
Get the set of blackboard keys filtered by regex.
- static relative_name(namespace: str, key: str) str [source]
Generate the abbreviated name for a key relative to the specified namespace.
Examples
'/' + 'foo' = 'foo' '/' + '/foo' = 'foo' '/foo' + 'bar' = 'bar' '/foo/' + 'bar' = 'bar' '/foo' + '/foo/bar' = 'bar' '/foo/' + '/foo/bar' = 'bar' '/foo' + 'foo/bar' = 'foo/bar' '/foo' + '/food/bar' => KeyError('/food/bar' is prefixed with a namespace conflicting with '/foo/')
- Parameters
- Returns
the absolute name
- Raises
KeyError if the key is prefixed with a conflicting namespace –
- Return type
Warning
To expedite the method call (it’s used with high frequency in blackboard key lookups), no checks are made to ensure the namespace argument leads with a “/”. Be sure to lead with a “/”!
- static set(variable_name: str, value: Any) None [source]
Set a variable on the blackboard.
Set the value associated with the given variable name. The name can be nested, e.g. battery.percentage. This differs from the client get method in that it doesn’t pass through the client access checks. Use for debugging / introspection tooling (e.g. display methods) only (prefer the clients for rigorous programmatic access).
- Parameters
- Raises
AttributeError – if it is attempting to set a nested attribute tha does not exist.
- Return type
None
- class py_trees.blackboard.Client(*, name: Optional[str] = None, namespace: Optional[str] = None)[source]
Bases:
object
Client to the key-value store for sharing data between behaviours.
Examples
Blackboard clients will accept a user-friendly name or create one for you if none is provided. Regardless of what name is chosen, clients are always uniquely identified via a uuid generated on construction.
provided = py_trees.blackboard.Client(name="Provided") print(provided) generated = py_trees.blackboard.Client() print(generated)
Client Instantiation
Register read/write access for keys on the blackboard. Note, registration is not initialisation.
blackboard = py_trees.blackboard.Client(name="Client") blackboard.register_key(key="foo", access=py_trees.common.Access.WRITE) blackboard.register_key(key="bar", access=py_trees.common.Access.READ) blackboard.foo = "foo" print(blackboard)
Variable Read/Write Registration
Keys and clients can make use of namespaces, designed by the ‘/’ char. Most methods permit a flexible expression of either relative or absolute names.
blackboard = py_trees.blackboard.Client(name="Global") parameters = py_trees.blackboard.Client(name="Parameters", namespace="parameters") blackboard.register_key(key="foo", access=py_trees.common.Access.WRITE) blackboard.register_key(key="/bar", access=py_trees.common.Access.WRITE) blackboard.register_key(key="/parameters/default_speed", access=py_trees.common.Access.WRITE) parameters.register_key(key="aggressive_speed", access=py_trees.common.Access.WRITE) blackboard.foo = "foo" blackboard.bar = "bar" blackboard.parameters.default_speed = 20.0 parameters.aggressive_speed = 60.0 miss_daisy = blackboard.parameters.default_speed van_diesel = parameters.aggressive_speed print(blackboard) print(parameters)
Namespaces and Namespaced Clients
Disconnected instances will discover the centralised key-value store.
def check_foo(): blackboard = py_trees.blackboard.Client(name="Reader") blackboard.register_key(key="foo", access=py_trees.common.Access.READ) print("Foo: {}".format(blackboard.foo)) blackboard = py_trees.blackboard.Client(name="Writer") blackboard.register_key(key="foo", access=py_trees.common.Access.WRITE) blackboard.foo = "bar" check_foo()
To respect an already initialised key on the blackboard:
blackboard = Client(name="Writer") blackboard.register_key(key="foo", access=py_trees.common.Access.READ) result = blackboard.set("foo", "bar", overwrite=False)
Store complex objects on the blackboard:
class Nested(object): def __init__(self): self.foo = None self.bar = None def __str__(self): return str(self.__dict__) writer = py_trees.blackboard.Client(name="Writer") writer.register_key(key="nested", access=py_trees.common.Access.WRITE) reader = py_trees.blackboard.Client(name="Reader") reader.register_key(key="nested", access=py_trees.common.Access.READ) writer.nested = Nested() writer.nested.foo = "I am foo" writer.nested.bar = "I am bar" foo = reader.nested.foo print(writer) print(reader)
Log and display the activity stream:
py_trees.blackboard.Blackboard.enable_activity_stream(maximum_size=100) reader = py_trees.blackboard.Client(name="Reader") reader.register_key(key="foo", access=py_trees.common.Access.READ) writer = py_trees.blackboard.Client(name="Writer") writer.register_key(key="foo", access=py_trees.common.Access.WRITE) writer.foo = "bar" writer.foo = "foobar" unused_result = reader.foo print(py_trees.display.unicode_blackboard_activity_stream()) py_trees.blackboard.Blackboard.activity_stream.clear()
Display the blackboard on the console, or part thereof:
writer = py_trees.blackboard.Client(name="Writer") for key in {"foo", "bar", "dude", "dudette"}: writer.register_key(key=key, access=py_trees.common.Access.WRITE) reader = py_trees.blackboard.Client(name="Reader") for key in {"foo", "bar"}: reader.register_key(key="key", access=py_trees.common.Access.READ) writer.foo = "foo" writer.bar = "bar" writer.dude = "bob" # all key-value pairs print(py_trees.display.unicode_blackboard()) # various filtered views print(py_trees.display.unicode_blackboard(key_filter={"foo"})) print(py_trees.display.unicode_blackboard(regex_filter="dud*")) print(py_trees.display.unicode_blackboard(client_filter={reader.unique_identifier})) # list the clients associated with each key print(py_trees.display.unicode_blackboard(display_only_key_metadata=True))
Behaviours are not automagically connected to the blackboard but you may manually attach one or more clients so that associations between behaviours and variables can be tracked - this is very useful for introspection and debugging.
Creating a custom behaviour with blackboard variables:
class Foo(py_trees.behaviour.Behaviour): def __init__(self, name): super().__init__(name=name) self.blackboard = self.attach_blackboard_client(name="Foo Global") self.parameters = self.attach_blackboard_client(name="Foo Params", namespace="foo_parameters_") self.state = self.attach_blackboard_client(name="Foo State", namespace="foo_state_") # create a key 'foo_parameters_init' on the blackboard self.parameters.register_key("init", access=py_trees.common.Access.READ) # create a key 'foo_state_number_of_noodles' on the blackboard self.state.register_key("number_of_noodles", access=py_trees.common.Access.WRITE) def initialise(self): self.state.number_of_noodles = self.parameters.init def update(self): self.state.number_of_noodles += 1 self.feedback_message = self.state.number_of_noodles if self.state.number_of_noodles > 5: return py_trees.common.Status.SUCCESS else: return py_trees.common.Status.RUNNING # could equivalently do directly via the Blackboard static methods if # not interested in tracking / visualising the application configuration configuration = py_trees.blackboard.Client(name="App Config") configuration.register_key("foo_parameters_init", access=py_trees.common.Access.WRITE) configuration.foo_parameters_init = 3 foo = Foo(name="The Foo") for i in range(1, 8): foo.tick_once() print("Number of Noodles: {}".format(foo.feedback_message))
Rendering a dot graph for a behaviour tree, complete with blackboard variables:
# in code py_trees.display.render_dot_tree(py_trees.demos.blackboard.create_root()) # command line tools py-trees-render --with-blackboard-variables py_trees.demos.blackboard.create_root
Tree with Blackboard Variables
And to demonstrate that it doesn’t become a tangled nightmare at scale, an example of a more complex tree:
A more complex tree
Debug deeper with judicious application of the tree, blackboard and activity stream display methods around the tree tick (refer to
py_trees.visitors.DisplaySnapshotVisitor
for examplar code):Tree level debugging
See also
- Variables
name (str) – client’s convenient, but not necessarily unique identifier
namespace (str) – apply this as a prefix to any key/variable name operations
unique_identifier (uuid.UUID) – client’s unique identifier
read (Set[str]) – set of absolute key names with read access
write (Set[str]) – set of absolute key names with write access
exclusive (Set[str]) – set of absolute key names with exclusive write access
required (Set[str]) – set of absolute key names required to have data present
str] (remappings (Dict[str,) – client key names with blackboard remappings
(typing.Set[str] (namespaces) – a cached list of namespaces this client accesses
- Parameters
- __getattr__(name: str) Any [source]
Access variables via a convenient attribute accessor.
This is also responsible for checking permissions prior to returning the variable.
- Raises
AttributeError – if the client does not have read access to the variable
KeyError – if the variable does not yet exist on the blackboard
- Parameters
name (str) –
- Return type
- __init__(*, name: Optional[str] = None, namespace: Optional[str] = None)[source]
Initialise with a unique name and optionally, a namespace to operate within.
- Parameters
name (Optional[str]) – client’s convenient identifier (stringifies the uuid if None)
namespace (Optional[str]) – prefix to apply to key/variable name operations
read – list of keys for which this client has read access
write – list of keys for which this client has write access
exclusive – list of keys for which this client has exclusive write access
- Raises
TypeError – if the provided name is not of type str
ValueError – if the unique identifier has already been registered
- __setattr__(name: str, value: Any) None [source]
Set variables via a convenient attribute setter.
This is also responsible for checking permissions prior to writing.
- Raises
AttributeError – if the client does not have write access to the variable
- Parameters
- Return type
None
- __str__() str [source]
Generate a string representation for the behaviour.
- Returns
the string representation
- Return type
- __weakref__
list of weak references to the object (if defined)
- absolute_name(key: str) str [source]
Generate the fully qualified key name for this key.
blackboard = Client(name="FooBar", namespace="foo") blackboard.register_key(key="bar", access=py_trees.common.Access.READ) print("{}".format(blackboard.absolute_name("bar"))) # "/foo/bar"
- exists(name: str) bool [source]
Check if the specified variable exists on the blackboard.
- Parameters
name (str) – name of the variable to get, can be nested, e.g. battery.percentage
- Raises
AttributeError – if the client does not have read access to the variable
- Return type
- get(name: str) Any [source]
Access via method a key on the blackboard.
This is the more cumbersome method (as opposed to simply using ‘.<name>’), but useful when the name is programatically generated.
- Parameters
name (str) – name of the variable to get, can be nested, e.g. battery.percentage
- Raises
AttributeError – if the client does not have read access to the variable
KeyError – if the variable or it’s nested attributes do not yet exist on the blackboard
- Return type
- id() UUID [source]
Access the unique identifier for this client.
- Returns
The uuid.UUID object
- Return type
- is_registered(key: str, access: Union[None, Access] = None) bool [source]
Check to see if the specified key is registered.
- register_key(key: str, access: Access, required: bool = False, remap_to: Optional[str] = None) None [source]
Register a key on the blackboard to associate with this client.
- Parameters
- Return type
None
Note the remap simply changes the storage location. From the perspective of the client, access via the specified ‘key’ remains the same.
- set(name: str, value: Any, overwrite: bool = True) bool [source]
Set, conditionally depending on whether the variable already exists or otherwise.
This is most useful when initialising variables and multiple elements seek to do so. A good policy to adopt for your applications in these situations is a first come, first served policy. Ensure global configuration has the first opportunity followed by higher priority behaviours in the tree and so forth. Lower priority behaviours would use this to respect the pre-configured setting and at most, just validate that it is acceptable to the functionality of it’s own behaviour.
- Parameters
- Returns
success or failure (overwrite is False and variable already set)
- Raises
AttributeError – if the client does not have write access to the variable
KeyError – if the variable does not yet exist on the blackboard
- Return type
- unregister(clear: bool = True) None [source]
Unregister this blackboard client.
If requested, clear key-value pairs if this client is the last user of those variables.
- Parameters
clear (bool) – remove key-values pairs from the blackboard
- Return type
None
- unregister_all_keys(clear: bool = True) None [source]
Unregister all keys currently registered by this blackboard client.
If requested, clear key-value pairs if this client is the last user of those variables.
- Parameters
clear (bool) – remove key-values pairs from the blackboard
- Return type
None
- unregister_key(key: str, clear: bool = True, update_namespace_cache: bool = True) None [source]
Unegister a key associated with this client.
- Parameters
- Return type
None
A method that batches calls to this method is
unregister_all_keys()
.
- class py_trees.blackboard.IntermediateVariableFetcher(blackboard: Client, namespace: str)[source]
Bases:
object
Convenient attribute accessor constrained to (possibly nested) namespaces.
- __weakref__
list of weak references to the object (if defined)
py_trees.common
Common definitions, methods and variables used by the py_trees library.
- class py_trees.common.Access(value)[source]
Bases:
Enum
Use to distinguish types of access to, e.g. variables on a blackboard.
- EXCLUSIVE_WRITE = 'EXCLUSIVE_WRITE'
Exclusive lock for writing, i.e. no other writer permitted.
- READ = 'READ'
Read access.
- WRITE = 'WRITE'
Write access, implicitly also grants read access.
- class py_trees.common.BlackBoxLevel(value)[source]
Bases:
IntEnum
A hint used for visualisation.
Whether a behaviour is a blackbox entity that may be considered collapsible (i.e. everything in its subtree will not be visualised) by visualisation tools. DETAIL.
- BIG_PICTURE = 3
A blackbox that represents a big picture part of the entire tree view.
- COMPONENT = 2
A blackbox that encapsulates a subgroup of functionalities as a single group.
- DETAIL = 1
A blackbox that encapsulates detailed activity.
- NOT_A_BLACKBOX = 4
Not a blackbox, do not ever collapse.
- class py_trees.common.ClearingPolicy(value)[source]
Bases:
IntEnum
Policy rules for behaviours to dictate when data should be cleared/reset.
- NEVER = 3
Never clear the data
- ON_INITIALISE = 1
Clear when entering the
initialise()
method.
- class py_trees.common.Duration(value)[source]
Bases:
Enum
Naming conventions.
- UNTIL_THE_BATTLE_OF_ALFREDO = 1.7976931348623157e+308
UNTIL_THE_BATTLE_OF_ALFREDO
is an alias forINFINITE
.
- class py_trees.common.Name(value)[source]
Bases:
Enum
Naming conventions.
- AUTO_GENERATED = 'AUTO_GENERATED'
Automagically generate (hopefully) something sensible..
- class py_trees.common.ParallelPolicy[source]
Configurable policies for
Parallel
behaviours.- class SuccessOnAll(synchronise: bool = True)[source]
Success depends on all children succeeding.
Return
SUCCESS
only when each and every child returnsSUCCESS
. If synchronisation is requested, any children that tick withSUCCESS
will be skipped on subsequent ticks until the policy criteria is met, or one of the children returns statusFAILURE
.- Parameters
synchronise (bool) –
- class SuccessOnOne[source]
Success depends on just one child (can be any child).
Return
SUCCESS
so long as at least one child hasSUCCESS
and the remainder areRUNNING
- class SuccessOnSelected(children: List[Any], synchronise: bool = True)[source]
Success depends on an explicitly selected set of children behaviours.
Return
SUCCESS
so long as each child in a specified list returnsSUCCESS
. If synchronisation is requested, any children that tick withSUCCESS
will be skipped on subsequent ticks until the policy criteria is met, or one of the children returns statusFAILURE
.
- class py_trees.common.Status(value)[source]
Bases:
Enum
An enumerator representing the status of a behaviour.
- FAILURE = 'FAILURE'
Behaviour check has failed, or execution of its action finished with a failed result.
- INVALID = 'INVALID'
Behaviour is uninitialised and/or in an inactive state, i.e. not currently being ticked.
- RUNNING = 'RUNNING'
Behaviour is in the middle of executing some action, result still pending.
- SUCCESS = 'SUCCESS'
Behaviour check has passed, or execution of its action has finished with a successful result.
- class py_trees.common.VisibilityLevel(value)[source]
Bases:
IntEnum
Flag used by visualisation tools to configure visibility..
Closely associated with the
BlackBoxLevel
for a behaviour.This sets the visibility level to be used for visualisations. Visibility levels correspond to reducing levels of visibility in a visualisation.
- ALL = 0
Do not collapse any behaviour.
- BIG_PICTURE = 3
Collapse any blackbox that isn’t marked with
BIG_PICTURE
.
- common.string_to_visibility_level() VisibilityLevel
Will convert a string to a visibility level.
Note that it will quietly return ALL if the string is not matched to any visibility level string identifier.
- Parameters
level (str) – visibility level as a string
- Returns
visibility level enum
- Return type
py_trees.composites
Composites (multi-child) types for behaviour trees.
Composites are responsible for directing the path traced through the tree on a given tick (execution). They are the factories (Sequences and Parallels) and decision makers (Selectors) of a behaviour tree.
![digraph selector {
graph [fontname="times-roman"];
node [fontname="times-roman"];
edge [fontname="times-roman"];
Sequence [fontcolor=black, shape=box, fontsize=11, style=filled, fillcolor=orange];
Selector [fontcolor=black, shape=octagon, fontsize=11, style=filled, fillcolor=cyan];
Parallel [fontcolor=black, shape=parallelogram, fontsize=11, style=filled, fillcolor=gold];
}](_images/graphviz-2dfd3fd9b3550ff638d7a986cf1f7d1d81e498f9.png)
PyTree Composites
Composite behaviours typically manage children and apply some logic to the way they execute and return a result, but generally don’t do anything themselves. Perform the checks or actions you need to do in the non-composite behaviours.
Most any desired functionality can be authored with a combination of these three composites. In fact, it is precisely this feature that makes behaviour trees attractive - it breaks down complex decision making logic to just three primitive elements. It is possible and often desirable to extend this set with custom composites of your own, but think carefully before you do - in almost every case, a combination of the existing composites will serve and as a result, you will merely compound the complexity inherent in your tree logic. This this makes it confoundingly difficult to design, introspect and debug. As an example, design sessions often revolve around a sketched graph on a whiteboard. When these graphs are composed of just five elements (Selectors, Sequences, Parallels, Decorators and Behaviours), it is very easy to understand the logic at a glance. Double the number of fundamental elements and you may as well be back at the terminal parsing code.
Tip
You should never need to subclass or create new composites.
The basic operational modes of the three composites in this library are as follows:
Selector
: execute a child based on cascading prioritiesSequence
: execute children sequentiallyParallel
: execute children concurrently
This library does provide some flexibility in how each composite is implemented without breaking the fundamental nature of each (as described above). Selectors and Sequences can be configured with or without memory (resumes or resets if children are RUNNING) and the results of a parallel can be configured to wait upon all children completing, succeed on one, all or a subset thereof.
Tip
Follow the links in each composite’s documentation to the relevant demo programs.
- class py_trees.composites.Composite(name: str, children: Optional[Sequence[Behaviour]] = None)[source]
-
The parent class to all composite behaviours.
- Parameters
- add_child(child: Behaviour) UUID [source]
Add a child.
- Parameters
child (Behaviour) – child to add
- Raises
RuntimeError – if the child already has a parent
- Returns
unique id of the child
- Return type
- add_children(children: List[Behaviour]) Behaviour [source]
Append a list of children to the current list.
- insert_child(child: Behaviour, index: int) UUID [source]
Insert child at the specified index.
This simply directly calls the python list’s
insert
method using the child and index arguments.
- remove_all_children() None [source]
Remove all children. Makes sure to stop each child if necessary.
- Return type
None
- remove_child(child: Behaviour) int [source]
Remove the child behaviour from this composite.
- Parameters
child (Behaviour) – child to delete
- Returns
index of the child that was removed
- Return type
Todo
Error handling for when child is not in this list
- remove_child_by_id(child_id: UUID) None [source]
Remove the child with the specified id.
- Parameters
child_id (UUID) – unique id of the child
- Raises
IndexError – if the child was not found
- Return type
None
- replace_child(child: Behaviour, replacement: Behaviour) None [source]
Replace the child behaviour with another.
- stop(new_status: Status = Status.INVALID) None [source]
Provide common stop-level functionality for all composites.
The latter situation can arise for some composites, but more importantly, will always occur when high higher priority behaviour interrupts this one.
- Parameters
new_status (Status) – behaviour will transition to this new status
- Return type
None
- abstract tick() Iterator[Behaviour] [source]
Tick the composite.
All composite subclasses require a re-implementation of the tick method to provide the logic for managing multiple children (
tick()
merely provides default logic for when there are no children).
- tip() Optional[Behaviour] [source]
Recursive function to extract the last running node of the tree.
- update() Status [source]
Unused update method.
Composites should direct the flow, whilst behaviours do the real work.
Such flows are a consequence of how the composite interacts with it’s children. The success of behaviour trees depends on this logic being simple, well defined and limited to a few well established patterns - this is what ensures that visualising a tree enables a user to quickly grasp the decision making captured therein.
For the standard patterns, this logic is limited to the ordering of execution and logical inferences on the resulting status of the composite’s children.
This is a good guideline to adhere to (i.e. don’t reach inside children to inference on custom variables, nor reach out to the system your tree is attached to).
Implementation wise, this renders the
update()
method redundant as all customisation to create a simple, well defined composite happens in thetick()
method.Bottom line, composites do not make use of this method. Implementing it for subclasses of the core composites will not do anything.
- Return type
- class py_trees.composites.Parallel(name: str, policy: Base, children: Optional[Sequence[Behaviour]] = None)[source]
Bases:
Composite
Parallels enable a kind of spooky at-a-distance concurrency.
A parallel ticks every child every time the parallel is itself ticked. The parallelism however, is merely conceptual. The children have actually been sequentially ticked, but from both the tree and the parallel’s purview, all children have been ticked at once.
The parallelism too, is not true in the sense that it kicks off multiple threads or processes to do work. Some behaviours may kick off threads or processes in the background, or connect to existing threads/processes. The behaviour itself however, merely monitors these and is itself encosced in a py_tree which only ever ticks in a single-threaded operation.
Parallels with policy
SuccessOnAll
only returnsSUCCESS
if all children returnSUCCESS
Parallels with policy
SuccessOnOne
returnSUCCESS
if at least one child returnsSUCCESS
and others areRUNNING
Parallels with policy
SuccessOnSelected
only returnsSUCCESS
if a specified subset of children returnSUCCESS
Policies
SuccessOnAll
andSuccessOnSelected
may be configured to be synchronised in which case children that tick withSUCCESS
will be skipped on subsequent ticks until the policy criteria is met, or one of the children returns statusFAILURE
.Parallels with policy
SuccessOnSelected
will check in both thesetup()
andtick()
methods to to verify the selected set of children is actually a subset of the children of this parallel.See also
- __init__(name: str, policy: Base, children: Optional[Sequence[Behaviour]] = None)[source]
Initialise the behaviour with name, policy and a list of children.
- setup(**kwargs: int) None [source]
Detect before ticking whether the policy configuration is invalid.
- Parameters
**kwargs (
dict
) – distribute arguments to this behaviour and in turn, all of it’s children- Raises
RuntimeError – if the parallel’s policy configuration is invalid
Exception – be ready to catch if any of the children raise an exception
- Return type
None
- stop(new_status: Status = Status.INVALID) None [source]
Ensure that any running children are stopped.
- Parameters
new_status (Status) – the composite is transitioning to this new status
- Return type
None
- tick() Iterator[Behaviour] [source]
Tick over the children.
- Yields
Behaviour
– a reference to itself or one of its children- Raises
RuntimeError – if the policy configuration was invalid
- Return type
- validate_policy_configuration() None [source]
Validate the currently stored policy.
Policy configuration can be invalid if: * Policy is SuccessOnSelected and no behaviours have been specified * Policy is SuccessOnSelected and behaviours that are not children exist
- Raises
RuntimeError – if policy configuration was invalid
- Return type
None
- class py_trees.composites.Selector(name: str, memory: bool, children: Optional[Sequence[Behaviour]] = None)[source]
Bases:
Composite
Selectors are the decision makers.
A selector executes each of its child behaviours in turn until one of them succeeds (at which point it itself returns
RUNNING
orSUCCESS
, or it runs out of children at which point it itself returnsFAILURE
. We usually refer to selecting children as a means of choosing between priorities. Each child and its subtree represent a decreasingly lower priority path.Note
Switching from a low -> high priority branch causes a stop(INVALID) signal to be sent to the previously executing low priority branch. This signal will percolate down that child’s own subtree. Behaviours should make sure that they catch this and destruct appropriately.
Note
If configured with memory, higher priority checks will be skipped when a child returned with running on the previous tick. i.e. once a priority is locked in, it will run to completion and can only be interrupted if the selector is interrupted by higher priorities elsewhere in the tree.
See also
The py-trees-demo-selector program demos higher priority switching under a selector.
- Parameters
- stop(new_status: Status = Status.INVALID) None [source]
Ensure that children are appropriately stopped and update status.
- Parameters
new_status (Status) – the composite is transitioning to this new status
- Return type
None
- class py_trees.composites.Sequence(name: str, memory: bool, children: Optional[Sequence[Behaviour]] = None)[source]
Bases:
Composite
Sequences are the factory lines of behaviour trees.
A sequence will progressively tick over each of its children so long as each child returns
SUCCESS
. If any child returnsFAILURE
orRUNNING
the sequence will halt and the parent will adopt the result of this child. If it reaches the last child, it returns with that result regardless.Note
The sequence halts once it engages with a child is RUNNING, remaining behaviours are not ticked.
Note
If configured with memory and a child returned with running on the previous tick, it will proceed directly to the running behaviour, skipping any and all preceding behaviours. With memory is useful for moving through a long running series of tasks. Without memory is useful if you want conditional guards in place preceding the work that you always want checked off.
See also
The py-trees-demo-sequence program demos a simple sequence in action.
- Parameters
py_trees.console
Simple colour definitions and syntax highlighting for the console.
Colour Definitions
The current list of colour definitions include:
Regular
: black, red, green, yellow, blue, magenta, cyan, white,
Bold
: bold, bold_black, bold_red, bold_green, bold_yellow, bold_blue, bold_magenta, bold_cyan, bold_white
These colour definitions can be used in the following way:
import py_trees.console as console
print(console.cyan + " Name" + console.reset + ": " + console.yellow + "Dude" + console.reset)
- py_trees.console.banner(msg: str) None [source]
Print a banner with centred text to stdout.
- Parameters
msg (str) – text to centre in the banner
- Return type
None
- py_trees.console.colours = ['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']
List of all available colours.
- py_trees.console.console_has_colours() bool [source]
Detect if the console (stdout) has colourising capability.
- Return type
- py_trees.console.debug(msg: str) None [source]
Print a debug message.
- Parameters
str – message to print
msg (str) –
- Return type
None
- py_trees.console.define_symbol_or_fallback(original: str, fallback: str, encoding: str = 'utf-8') str [source]
Go unicode, or fallback to ascii.
Return the correct encoding according to the specified encoding. Used to make sure we get an appropriate symbol, even if the shell is merely ascii as is often the case on, e.g. Jenkins CI.
- py_trees.console.error(msg: str) None [source]
Print an error message.
- Parameters
str – message to print
msg (str) –
- Return type
None
- py_trees.console.has_colours = False
Whether the loading program has access to colours or not.
- py_trees.console.has_unicode(encoding: str = 'utf-8') bool [source]
Define whether the specified encoding has unicode symbols.
This is usually used to check if stdout is capable of unicode or otherwise (e.g. Jenkins CI is often be configured with unicode disabled).
- py_trees.console.info(msg: str) None [source]
Print an info message.
- Parameters
str – message to print
msg (str) –
- Return type
None
- py_trees.console.logdebug(message: str) None [source]
Prefixes
[DEBUG]
and colours the message green.- Parameters
message (str) – message to log.
- Return type
None
- py_trees.console.logerror(message: str) None [source]
Prefixes
[ERROR]
and colours the message red.- Parameters
message (str) – message to log.
- Return type
None
- py_trees.console.logfatal(message: str) None [source]
Prefixes
[FATAL]
and colours the message bold red.- Parameters
message (str) – message to log.
- Return type
None
- py_trees.console.loginfo(message: str) None [source]
Prefixes
[ INFO]
to the message.- Parameters
message (str) – message to log.
- Return type
None
- py_trees.console.logwarn(message: str) None [source]
Prefixes
[ WARN]
and colours the message yellow.- Parameters
message (str) – message to log.
- Return type
None
- py_trees.console.pretty_print(msg: str, colour: str = '') None [source]
Pretty print a coloured message.
- py_trees.console.pretty_println(msg: str, colour: str = '') None [source]
Pretty print a coloured message with a newline.
- py_trees.console.read_single_keypress() str [source]
Wait for a single keypress on stdin.
This is a silly function to call if you need to do it a lot because it has to store stdin’s current setup, setup stdin for reading single keystrokes then read the single keystroke then revert stdin back after reading the keystroke.
- Returns
the character of the key that was pressed
- Raises
KeyboardInterrupt – if CTRL-C was pressed (keycode 0x03)
- Return type
py_trees.decorators
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.

An example:
![digraph life {
graph [fontname="times-roman"];
node [fontname="times-roman"];
edge [fontname="times-roman"];
Life [fillcolor=orange, fontcolor=black, fontsize=11, shape=box, style=filled];
Inverter [fillcolor=ghostwhite, fontcolor=black, fontsize=11, shape=ellipse, style=filled];
Life -> Inverter;
"Busy?" [fillcolor=gray, fontcolor=black, fontsize=11, shape=ellipse, style=filled];
Inverter -> "Busy?";
Timeout [fillcolor=ghostwhite, fontcolor=black, fontsize=11, shape=ellipse, style=filled];
Life -> Timeout;
"Have a Beer!" [fillcolor=gray, fontcolor=black, fontsize=11, shape=ellipse, style=filled];
Timeout -> "Have a Beer!";
}](_images/graphviz-48aa7f2f538fca61152ca1c401fe49093f74cd0d.png)
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3"""Example demonstrating the use of some simple decorator nodes."""
4
5import py_trees.decorators
6import py_trees.display
7
8if __name__ == "__main__":
9 root = py_trees.composites.Sequence(name="Life", memory=False)
10 timeout = py_trees.decorators.Timeout(
11 name="Timeout", child=py_trees.behaviours.Success(name="Have a Beer!")
12 )
13 failure_is_success = py_trees.decorators.Inverter(
14 name="Inverter", child=py_trees.behaviours.Success(name="Busy?")
15 )
16 root.add_children([failure_is_success, timeout])
17 py_trees.display.render_dot_tree(root)
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)[source]
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 andSUCCESS
when the flip occurs.
- class py_trees.decorators.Count(name: str, child: Behaviour)[source]
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()
.- Variables
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
- Parameters
- class py_trees.decorators.Decorator(name: str, child: Behaviour)[source]
Bases:
Behaviour
Parent class for decorating a child/subtree with some additional logic.
- Parameters
- Raises
- stop(new_status: Status) None [source]
Check if the child is running (dangling) and stop it if that is the case.
- Parameters
new_status (
Status
) – the behaviour is transitioning to this new status- Return type
None
- class py_trees.decorators.EternalGuard(name: str, child: Behaviour, condition: Any, blackboard_keys: Optional[Union[List[str], Set[str]]] = None)[source]
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.
- Parameters
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.
- class py_trees.decorators.FailureIsRunning(name: str, child: Behaviour)[source]
Bases:
Decorator
Dont stop running.
- class py_trees.decorators.FailureIsSuccess(name: str, child: Behaviour)[source]
Bases:
Decorator
Be positive, always succeed.
- class py_trees.decorators.Inverter(name: str, child: Behaviour)[source]
Bases:
Decorator
A decorator that inverts the result of a class’s update function.
- class py_trees.decorators.OneShot(name: str, child: Behaviour, policy: OneShotPolicy)[source]
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.
With policy
ON_SUCCESSFUL_COMPLETION
, the oneshot will activate only when the underlying child returnsSUCCESS
(i.e. it permits retries).With policy
ON_COMPLETION
, the oneshot will activate when the child returnsSUCCESS
||FAILURE
.
See also
- terminate(new_status: Status) None [source]
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.
- Parameters
new_status (Status) –
- Return type
None
- class py_trees.decorators.PassThrough(name: str, child: Behaviour)[source]
Bases:
Decorator
This decorator simply reflects the child’s current status.
This behaviour is useful for debugging or visualisation purposes.
- class py_trees.decorators.Repeat(name: str, child: Behaviour, num_success: int)[source]
Bases:
Decorator
Repeat.
SUCCESS
isRUNNING
up to a specified number at which point this decorator returnsSUCCESS
.- Parameters
- class py_trees.decorators.Retry(name: str, child: Behaviour, num_failures: int)[source]
Bases:
Decorator
Keep trying, pastafarianism is within reach.
FAILURE
isRUNNING
up to a specified number of attempts.- Parameters
- class py_trees.decorators.RunningIsFailure(name: str, child: Behaviour)[source]
Bases:
Decorator
Got to be snappy! We want results…yesterday.
- class py_trees.decorators.RunningIsSuccess(name: str, child: Behaviour)[source]
Bases:
Decorator
Don’t hang around…
- class py_trees.decorators.StatusToBlackboard(name: str, child: Behaviour, variable_name: str)[source]
Bases:
Decorator
Reflect the status of the decorator’s child to the blackboard.
- Parameters
- class py_trees.decorators.SuccessIsFailure(name: str, child: Behaviour)[source]
Bases:
Decorator
Be depressed, always fail.
- class py_trees.decorators.SuccessIsRunning(name: str, child: Behaviour)[source]
Bases:
Decorator
The tickling never ends…
- class py_trees.decorators.Timeout(name: str, child: Behaviour, duration: float = 5.0)[source]
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 statusFAILURE
otherwise it will simply directly tick and return with the same status as that of it’s encapsulated behaviour.
py_trees.display
Display utilities for the command line.
Behaviour trees are significantly easier to design, monitor and debug with visualisations. Py Trees does provide minimal assistance to render trees to various simple output formats. Currently this includes dot graphs, strings or stdout.
- py_trees.display.ascii_blackboard(key_filter: Optional[Union[List[str], Set[str]]] = None, regex_filter: Optional[str] = None, client_filter: Optional[Union[Set[UUID], List[UUID]]] = None, keys_to_highlight: Optional[List[str]] = None, display_only_key_metadata: bool = False, indent: int = 0) str [source]
Graffiti your console with ascii art for your blackboard.
- Parameters
key_filter (Optional[Union[List[str], Set[str]]]) – filter on a set/list of blackboard keys
client_filter (Optional[Union[Set[UUID], List[UUID]]]) – filter on a set/list of client uuids
keys_to_highlight (Optional[List[str]]) – list of keys to highlight
display_only_key_metadata (bool) – read/write access, … instead of values
indent (int) – the number of characters to indent the blackboard
- Returns
a unicoded blackboard (i.e. in string form)
- Return type
Note
registered variables that have not yet been set are marked with a ‘-’
- py_trees.display.ascii_symbols = {'space': ' ', 'left_arrow': '<-', 'right_arrow': '->', 'left_right_arrow': '<->', 'bold': '', 'bold_reset': '', 'memory': 'M', 'synchronised': 's', 'sequence_with_memory': '{-}', 'selector_with_memory': '{o}', 'sequence_without_memory': '[-]', 'selector_without_memory': '[o]', 'parallel': '/_/', 'decorator': '-^-', 'behaviour': '-->', <Status.SUCCESS: 'SUCCESS'>: 'o', <Status.FAILURE: 'FAILURE'>: 'x', <Status.INVALID: 'INVALID'>: '-', <Status.RUNNING: 'RUNNING'>: '*'}
Symbols for a non-unicode, non-escape sequence capable console.
- py_trees.display.ascii_tree(root: Behaviour, show_only_visited: bool = False, show_status: bool = False, visited: Optional[Dict[UUID, Status]] = None, previously_visited: Optional[Dict[UUID, Status]] = None, indent: int = 0) str [source]
Graffiti your console with ascii art for your trees.
- Parameters
root (Behaviour) – the root of the tree, or subtree you want to show
show_only_visited (bool) – show only visited behaviours
show_status (bool) – always show status and feedback message (i.e. for every element, not just those visited)
visited (dict) – dictionary of (uuid.UUID) and status (
Status
) pairs for behaviours visited on the current tickpreviously_visited (dict) – dictionary of behaviour id/status pairs from the previous tree tick
indent (int) – the number of characters to indent the tree
- Returns
an ascii tree (i.e. in string form)
- Return type
Examples
Use the
SnapshotVisitor
andBehaviourTree
to generate snapshot information at each tick and feed that to a post tick handler that will print the traversed ascii tree complete with status and feedback messages.def post_tick_handler(snapshot_visitor, behaviour_tree): print( py_trees.display.unicode_tree( behaviour_tree.root, visited=snapshot_visitor.visited, previously_visited=snapshot_visitor.visited ) ) root = py_trees.composites.Sequence(name="Sequence", memory=True) for action in ["Action 1", "Action 2", "Action 3"]: b = py_trees.behaviours.StatusQueue( name=action, queue=[py_trees.common.Status.RUNNING], eventually = py_trees.common.Status.SUCCESS ) root.add_child(b) behaviour_tree = py_trees.trees.BehaviourTree(root) snapshot_visitor = py_trees.visitors.SnapshotVisitor() behaviour_tree.add_post_tick_handler( functools.partial(post_tick_handler, snapshot_visitor)) behaviour_tree.visitors.append(snapshot_visitor)
- py_trees.display.dot_tree(root: Behaviour, visibility_level: VisibilityLevel = VisibilityLevel.DETAIL, collapse_decorators: bool = False, with_blackboard_variables: bool = False, with_qualified_names: bool = False) Dot [source]
Paint your tree on a pydot graph.
See also
- Parameters
root (
Behaviour
) – the root of a tree, or subtreevisibility_level (optional) – collapse subtrees at or under this level
collapse_decorators (optional) – only show the decorator (not the child), defaults to False
with_blackboard_variables (optional) – add nodes for the blackboard variables
with_qualified_names (optional) – print the class information for each behaviour in each node, defaults to False
- Returns
graph
- Return type
pydot.Dot
Examples
# convert the pydot graph to a string object print("{}".format(py_trees.display.dot_graph(root).to_string()))
- py_trees.display.render_dot_tree(root: Behaviour, visibility_level: VisibilityLevel = VisibilityLevel.DETAIL, collapse_decorators: bool = False, name: Optional[str] = None, target_directory: Optional[str] = None, with_blackboard_variables: bool = False, with_qualified_names: bool = False) Dict[str, str] [source]
Render the dot tree to dot, svg, png. files.
By default, these are saved in the current working directory and will be named with the root behaviour name.
- Parameters
root (Behaviour) – the root of a tree, or subtree
visibility_level (VisibilityLevel) – collapse subtrees at or under this level
collapse_decorators (bool) – only show the decorator (not the child)
name (Optional[str]) – name to use for the created files (defaults to the root behaviour name)
target_directory (Optional[str]) – default is to use the current working directory, set this to redirect elsewhere
with_blackboard_variables (bool) – add nodes for the blackboard variables
with_qualified_names (bool) – print the class names of each behaviour in the dot node
- Return type
Example
Render a simple tree to dot/svg/png file:
root = py_trees.composites.Sequence(name="Sequence", memory=True) for job in ["Action 1", "Action 2", "Action 3"]: success_after_two = py_trees.behaviours.StatusQueue( name=job, queue=[py_trees.common.Status.RUNNING], eventually = py_trees.common.Status.SUCCESS ) root.add_child(success_after_two) py_trees.display.render_dot_tree(root)
Tip
A good practice is to provide a command line argument for optional rendering of a program so users can quickly visualise what tree the program will execute.
- py_trees.display.unicode_blackboard(key_filter: Optional[Union[List[str], Set[str]]] = None, regex_filter: Optional[str] = None, client_filter: Optional[Union[Set[UUID], List[UUID]]] = None, keys_to_highlight: Optional[List[str]] = None, display_only_key_metadata: bool = False, indent: int = 0) str [source]
Graffiti your console with unicode art for your blackboard.
- Parameters
key_filter (Optional[Union[List[str], Set[str]]]) – filter on a set/list of blackboard keys
client_filter (Optional[Union[Set[UUID], List[UUID]]]) – filter on a set/list of client uuids
keys_to_highlight (Optional[List[str]]) – list of keys to highlight
display_only_key_metadata (bool) – read/write access, … instead of values
indent (int) – the number of characters to indent the blackboard
- Returns
a unicoded blackboard (i.e. in string form)
- Return type
See also
Note
registered variables that have not yet been set are marked with a ‘-’
- py_trees.display.unicode_blackboard_activity_stream(activity_stream: Optional[List[ActivityItem]] = None, indent: int = 0, show_title: bool = True) str [source]
Pretty print the blackboard stream to console.
- py_trees.display.unicode_symbols = {'space': ' ', 'left_arrow': '←', 'right_arrow': '→', 'left_right_arrow': '↔', 'bold': '', 'bold_reset': '', 'memory': 'Ⓜ', 'synchronised': '⚡', 'sequence_with_memory': '{-}', 'selector_with_memory': '{o}', 'sequence_without_memory': '[-]', 'selector_without_memory': '[o]', 'parallel': '/_/', 'decorator': '-^-', 'behaviour': '-->', <Status.SUCCESS: 'SUCCESS'>: '✓', <Status.FAILURE: 'FAILURE'>: '✕', <Status.INVALID: 'INVALID'>: '-', <Status.RUNNING: 'RUNNING'>: '*'}
Symbols for a unicode, escape sequence capable console.
- py_trees.display.unicode_tree(root: Behaviour, show_only_visited: bool = False, show_status: bool = False, visited: Optional[Dict[UUID, Status]] = None, previously_visited: Optional[Dict[UUID, Status]] = None, indent: int = 0) str [source]
Graffiti your console with unicode art for your trees.
- Parameters
root (Behaviour) – the root of the tree, or subtree you want to show
show_only_visited (bool) – show only visited behaviours
show_status (bool) – always show status and feedback message (i.e. for every element, not just those visited)
visited (dict) – dictionary of (uuid.UUID) and status (
Status
) pairs for behaviours visited on the current tickpreviously_visited (dict) – dictionary of behaviour id/status pairs from the previous tree tick
indent (int) – the number of characters to indent the tree
- Returns
a unicode tree (i.e. in string form)
- Return type
- py_trees.display.xhtml_symbols = {'space': '<text> </text>', 'left_arrow': '<text>←</text>', 'right_arrow': '<text>→</text>', 'left_right_arrow': '<text>↔</text>', 'bold': '<b>', 'bold_reset': '</b>', 'memory': '<text>Ⓜ</text>', 'synchronised': '<text>⚡</text>', 'sequence_with_memory': '<text>{-}</text>', 'selector_with_memory': '<text>{o}</text>', 'sequence_without_memory': '<text>[-]</text>', 'selector_without_memory': '<text>[o]</text>', 'parallel': '<text style="color:green;">/_/</text>', 'decorator': '<text>-^-</text>', 'behaviour': '<text>--></text>', <Status.SUCCESS: 'SUCCESS'>: '<text style="color:green;">✓</text>', <Status.FAILURE: 'FAILURE'>: '<text style="color:red;">✕</text>', <Status.INVALID: 'INVALID'>: '<text style="color:darkgoldenrod;">-</text>', <Status.RUNNING: 'RUNNING'>: '<text style="color:blue;">*</text>'}
Symbols for embedding in html.
- py_trees.display.xhtml_tree(root: Behaviour, show_only_visited: bool = False, show_status: bool = False, visited: Optional[Dict[UUID, Status]] = None, previously_visited: Optional[Dict[UUID, Status]] = None, indent: int = 0) str [source]
Paint your tree on an xhtml snippet.
- Parameters
root (Behaviour) – the root of the tree, or subtree you want to show
show_only_visited (bool) – show only visited behaviours
show_status (bool) – always show status and feedback message (i.e. for every element, not just those visited)
visited (Optional[Dict[UUID, Status]]) – dictionary of (uuid.UUID) and status (
Status
) pairs for behaviours visited on the current tickpreviously_visited (Optional[Dict[UUID, Status]]) – dictionary of behaviour id/status pairs from the previous tree tick
indent (int) – the number of characters to indent the tree
- Returns
an ascii tree (i.e. as a xhtml snippet)
- Return type
Examples
import py_trees a = py_trees.behaviours.Success() b = py_trees.behaviours.Success() c = c = py_trees.composites.Sequence(name="Sequence", memory=True, children=[a, b]) c.tick_once() f = open('testies.html', 'w') f.write('<html><head><title>Foo</title><body>') f.write(py_trees.display.xhtml_tree(c, show_status=True)) f.write("</body></html>")
py_trees.idioms
Creators of common subtree patterns.
- py_trees.idioms.either_or(conditions: List[ComparisonExpression], subtrees: List[Behaviour], name: str = 'Either Or', namespace: Optional[str] = None) Behaviour [source]
Create an idiom with selector-like qualities, but no priority concerns.
Often you need a kind of selector that doesn’t implement prioritisations, i.e. you would like different paths to be selected on a first-come, first-served basis.
task_one = py_trees.behaviours.TickCounter(name="Subtree 1", duration=2) task_two = py_trees.behaviours.TickCounter(name="Subtree 2", duration=2) either_or = py_trees.idioms.either_or( name="EitherOr", conditions=[ py_trees.common.ComparisonExpression("joystick_one", "enabled", operator.eq), py_trees.common.ComparisonExpression("joystick_two", "enabled", operator.eq), ], subtrees=[task_one, task_two], namespace="either_or", )
Idiom - Either Or
Up front is an XOR conditional check which locks in the result on the blackboard under the specified namespace. Locking the result in permits the conditional variables to vary in future ticks without interrupting the execution of the chosen subtree (an example of a conditional variable may be one that has registered joystick button presses).
Once the result is locked in, the relevant subtree is activated beneath the selector. The children of the selector are, from left to right, not in any order of priority since the previous xor choice has been locked in and isn’t revisited until the subtree executes to completion. Only one may be active and it cannot be interrupted by the others.
The only means of interrupting the execution is via a higher priority in the tree that this idiom is embedded in.
- Parameters
conditions (List[ComparisonExpression]) – list of triggers that ultimately select the subtree to enable
subtrees (List[Behaviour]) – list of subtrees to tick from in the either_or operation
name (str) – the name to use for this idiom’s root behaviour
preemptible – whether the subtrees may preempt (interrupt) each other
namespace (Optional[str]) – this idiom’s private variables will be put behind this namespace
- Raises
ValueError if the number of conditions does not match the number of subtrees –
- Return type
If no namespace is provided, a unique one is derived from the idiom’s name.
See also
Todo
a version for which other subtrees can preempt (in an unprioritised manner) the active branch
- py_trees.idioms.oneshot(behaviour: Behaviour, name: str = 'Oneshot', variable_name: str = 'oneshot', policy: OneShotPolicy = OneShotPolicy.ON_SUCCESSFUL_COMPLETION) Behaviour [source]
Ensure that a particular pattern is executed through to completion just once.
Thereafter it will just rebound with the completion status.
Note
Set the policy to configure the oneshot to keep trying if failing, or to abort further attempts regardless of whether it finished with status
FAILURE
.- Parameters
behaviour (Behaviour) – single behaviour or composited subtree to oneshot
name (str) – the name to use for the oneshot root (selector)
variable_name (str) – name for the variable used on the blackboard, may be nested
policy (OneShotPolicy) – execute just once regardless of success or failure, or keep trying if failing
- Returns
the root of the oneshot subtree
- Return type
See also
- py_trees.idioms.pick_up_where_you_left_off(name: str, tasks: List[BehaviourSubClass]) Behaviour [source]
Create an idiom that enables a sequence of tasks to pick up where it left off.
Rudely interrupted while enjoying a sandwich, a caveman (just because they wore loincloths does not mean they were not civilised), picks up his club and fends off the sabre-tooth tiger invading his sanctum as if he were swatting away a gnat. Task accomplished, he returns to the joys of munching through the layers of his sandwich.
Note
There are alternative ways to accomplish this idiom with their pros and cons.
a) The tasks in the sequence could be replaced by a factory behaviour that dynamically checks the state of play and spins up the tasks required each time the task sequence is first entered and invalidates/deletes them when it is either finished or invalidated. That has the advantage of not requiring much of the blackboard machinery here, but disadvantage in not making visible the task sequence itself at all times (i.e. burying details under the hood).
b) A new composite which retains the index between initialisations can also achieve the same pattern with fewer blackboard shenanigans, but suffers from an increased logical complexity cost for your trees (each new composite increases decision making complexity (O(n!)).
py_trees.meta
Meta methods to create behaviours without creating behaviours themselves.
- py_trees.meta.create_behaviour_from_function(func: BehaviourUpdateMethod, module: Optional[str] = None) Type[Behaviour] [source]
Create a behaviour from the specified function.
This takes the specified function and drops it in to serve as the the Behaviour
update()
method.The user provided fucntion must include the self argument and return a
Status
value.It also automatically registers a method for the
terminate()
method that clears the feedback message. Other methods are left untouched.
py_trees.timers
Time related behaviours.
- class py_trees.timers.Timer(name: str = 'Timer', duration: float = 5.0)[source]
Bases:
Behaviour
A simple, blocking timer behaviour running off python time.time().
This behaviour is
RUNNING
until the timer runs out, at which point it isSUCCESS
. This can be used in a wide variety of situations - pause, duration, timeout depending on how it is wired into the tree (e.g. pause in a sequence, duration/timeout in a parallel).The timer gets reset either upon entry (
initialise()
) if it hasn’t already been set and gets cleared when it either runs out, or the behaviour is interrupted by a higher priority or parent cancelling it.- Parameters
- Raises
TypeError – if the provided duration is not a real number
Note
This succeeds the first time the behaviour is ticked after the expected finishing time.
Tip
Use the
RunningIsFailure()
decorator if you needFAILURE
until the timer finishes.
py_trees.trees
Tree stewardship.
While a graph of connected behaviours and composites form a tree in their own right (i.e. it can be initialised and ticked), it is usually convenient to wrap your tree in another class to take care of alot of the housework and provide some extra bells and whistles that make your tree flourish.

This package provides a default reference implementation that is directly usable, but can also be easily used as inspiration for your own tree custodians.
- class py_trees.trees.BehaviourTree(root: Behaviour)[source]
Bases:
object
Grow, water, prune your behaviour tree with this, the tree custodian.
It features a few enhancements that go above and beyond just ticking the root behaviour of a tree. These provide richer logging, introspection and dynamic management of the tree itself:
Pre and post tick handlers to execute code automatically before and after a tick
Visitor access to the parts of the tree that were traversed in a tick
Subtree pruning and insertion operations
Continuous tick-tock support
See also
The py-trees-demo-tree-stewardship program demonstrates the above features.
- Parameters
root (
Behaviour
) – root node of the tree- Variables
count – number of times the tree has been ticked.
root – root node of the tree
visitors – entities that visit traversed parts of the tree when it ticks
pre_tick_handlers – functions that run before the entire tree is ticked
post_tick_handlers – functions that run after the entire tree is ticked
- Raises
TypeError – if root variable is not an instance of
Behaviour
- add_post_tick_handler(handler: Callable[[BehaviourTree], None]) None [source]
Add a function to execute after the tree has ticked.
The function must have a single argument of type
BehaviourTree
.Some ideas that are often used:
logging
modifications on the tree itself (e.g. closing down a plan)
sending data to visualisation tools
introspect the state of the tree to make and send reports
- Parameters
handler (Callable[[BehaviourTree], None]) – function
- Return type
None
- add_pre_tick_handler(handler: Callable[[BehaviourTree], None]) None [source]
Add a function to execute before the tree is ticked.
The function must have a single argument of type
BehaviourTree
.Some ideas that are often used:
logging (to file or stdout)
modifications on the tree itself (e.g. starting a new plan)
- Parameters
handler (Callable[[BehaviourTree], None]) – function
- Return type
None
- add_visitor(visitor: VisitorBase) None [source]
Welcome a visitor.
Trees can run multiple visitors on each behaviour as they tick through a tree.
- Parameters
visitor (VisitorBase) – sub-classed instance of a visitor
- Return type
None
See also
- insert_subtree(child: Behaviour, unique_id: UUID, index: int) bool [source]
Insert a subtree as a child of the specified parent.
If the parent is found, this directly calls the parent’s
insert_child()
method using the child and index arguments.- Parameters
- Returns
suceess or failure (parent not found) of the operation
- Raises
- Return type
Todo
Could use better, more informative error handling here. Especially if the insertion has its own error handling (e.g. index out of range). Could also use a different api that relies on the id of the sibling node it should be inserted before/after.
- interrupt() None [source]
Interrupt tick-tock if it is tick-tocking.
Note that this will permit a currently executing tick to finish before interrupting the tick-tock.
- Return type
None
- prune_subtree(unique_id: UUID) bool [source]
Prune a subtree given the unique id of the root of the subtree.
- Parameters
root (unique id of the subtree) –
unique_id (UUID) –
- Returns
success or failure of the operation
- Raises
RuntimeError – if unique id is the root or parent does not have remove_node
- Return type
- replace_subtree(unique_id: UUID, subtree: Behaviour) bool [source]
Replace the subtree with the specified id for the new subtree.
This is a common pattern where we’d like to swap out a whole sub-behaviour for another one.
- Parameters
- Return type
- Raises
AssertionError: if unique id is the behaviour tree’s root node id
- setup(timeout: Union[float, Duration] = Duration.INFINITE, visitor: Optional[VisitorBase] = None, **kwargs: int) None [source]
Crawl across the tree calling
setup()
on each behaviour.Visitors can optionally be provided to provide a node-by-node analysis on the result of each node’s
setup()
before the next node’ssetup()
is called. This is useful on trees with relatively long setup times to progressively report out on the current status of the operation.- Parameters
- Raises
Exception – be ready to catch if any of the behaviours raise an exception
RuntimeError – in case setup() times out
- Return type
None
- shutdown() None [source]
Crawl across the tree, calling
shutdown()
on each behaviour.- Raises
Exception – be ready to catch if any of the behaviours raise an exception
- Return type
None
- tick(pre_tick_handler: Optional[Callable[[BehaviourTree], None]] = None, post_tick_handler: Optional[Callable[[BehaviourTree], None]] = None) None [source]
Tick the tree just once and run any handlers before and after the tick.
This optionally accepts some one-shot handlers (c.f. those added by
add_pre_tick_handler()
andadd_post_tick_handler()
which will be automatically run every time).The handler functions must have a single argument of type
BehaviourTree
.- Parameters
pre_tick_handler (
func
) – function to execute before tickingpost_tick_handler (
func
) – function to execute after tickingself (BehaviourTree) –
- Return type
None
- tick_tock(period_ms: int, number_of_iterations: int = -1, stop_on_terminal_state: bool = False, pre_tick_handler: Optional[Callable[[BehaviourTree], None]] = None, post_tick_handler: Optional[Callable[[BehaviourTree], None]] = None) None [source]
Tick continuously with period as specified.
Depending on the implementation, the period may be more or less accurately tracked. For example, if your tick time is greater than the specified period, the timing will overrun.
This optionally accepts some handlers that will be used for the duration of this tick tock (c.f. those added by
add_pre_tick_handler()
andadd_post_tick_handler()
which will be automatically run every time).The handler functions must have a single argument of type
BehaviourTree
.- Parameters
period_ms (
float
) – sleep this much between ticks (milliseconds)number_of_iterations (
int
) – number of iterations to tick-tock( (stop_on_terminal_state) – obj: bool): if true, stops when the tree’s status is
SUCCESS
or :data:`~py_trees.common.Status.FAILURE.pre_tick_handler (
func
) – function to execute before tickingpost_tick_handler (
func
) – function to execute after tickingself (BehaviourTree) –
stop_on_terminal_state (bool) –
- Return type
None
- py_trees.trees.setup(root: Behaviour, timeout: Union[float, Duration] = Duration.INFINITE, visitor: Optional[VisitorBase] = None, **kwargs: int) None [source]
Crawl across a (sub)tree of behaviours calling
setup()
on each behaviour.Visitors can optionally be provided to provide a node-by-node analysis on the result of each node’s
setup()
before the next node’ssetup()
is called. This is useful on trees with relatively long setup times to progressively report out on the current status of the operation.- Parameters
root (Behaviour) – unmanaged (sub)tree root behaviour
timeout (Union[float, Duration]) – time (s) to wait (use common.Duration.INFINITE to block indefinitely)
visitor (Optional[VisitorBase]) – runnable entities on each node after it’s setup
**kwargs (int) – dictionary of args to distribute to all behaviours in the (sub)tree
- Raises
Exception – be ready to catch if any of the behaviours raise an exception
RuntimeError – in case setup() times out
- Return type
None
py_trees.utilities
Assorted utility functions.
- class py_trees.utilities.Process(*args: Any, **kwargs: Any)[source]
Bases:
Process
Convenience wrapper around multiprocessing.Process.
- py_trees.utilities.get_fully_qualified_name(instance: object) str [source]
Retrieve the fully qualified name of an object.
For example, an instance of
Sequence
becomes ‘py_trees.composites.Sequence’.
- py_trees.utilities.get_valid_filename(s: str) str [source]
Clean up and style a string so that it can be used as a filename.
This is valid only from the perspective of the py_trees package. It does place a few extra constraints on strings to keep string handling and manipulation complexities to a minimum so that sanity prevails.
Removes leading and trailing spaces
Convert other spaces and newlines to underscores
Remove anything that is not an alphanumeric, dash, underscore, or dot
>>> utilities.get_valid_filename("john's portrait in 2004.jpg") 'johns_portrait_in_2004.jpg'
- py_trees.utilities.is_primitive(incoming: Any) bool [source]
Check if an incoming argument is a primitive type with no esoteric accessors.
That is, it has no class attributes or container style [] accessors.
- py_trees.utilities.static_variables(**kwargs: Any) Callable[[C], C] [source]
Attach initialised static variables to a python method.
@static_variables(counter=0) def foo(): foo.counter += 1 print("Counter: {}".format(foo.counter))
py_trees.visitors
Visiting rights to behaviours.
Visitors are entities that can be passed to a tree implementation
(e.g. BehaviourTree
) and used to either visit
each and every behaviour in the tree, or visit behaviours as the tree is
traversed in an executing tick. At each behaviour, the visitor
runs its own method on the behaviour to do as it wishes - logging, introspecting, etc.
Warning
Visitors should not modify the behaviours they visit.
- class py_trees.visitors.DebugVisitor[source]
Bases:
VisitorBase
Picks up and logs feedback messages and the behaviour’s status.
Logging is done with the behaviour’s logger.
- class py_trees.visitors.DisplaySnapshotVisitor(display_only_visited_behaviours: bool = False, display_blackboard: bool = False, display_activity_stream: bool = False)[source]
Bases:
SnapshotVisitor
Visit the tree, capturing the visited path, it’s changes since the last tick.
Additionally print the snapshot to console.
- Parameters
display_only_visited_behaviours (bool) – useful for cropping the unvisited part of a large tree
display_blackboard (bool) – print to the console the relevant part of the blackboard associated with behaviours on the visited path
display_activity_stream (bool) – print to the console a log of the activity on the blackboard over the last tick
- class py_trees.visitors.SnapshotVisitor[source]
Bases:
VisitorBase
Creates a snapshot of the tree state (behaviour status’ only).
Visits the ticked part of a tree, checking off the status against the set of status results recorded in the previous tick. If there has been a change, it flags it. This is useful for determining when to trigger, e.g. logging.
- Variables
changed (Bool) – flagged if there is a difference in the visited path or
Status
of any behaviour on the pathvisited (dict) – dictionary of behaviour id (uuid.UUID) and status (
Status
) pairs from the current tickpreviously_visited (dict) – dictionary of behaviour id (uuid.UUID) and status (
Status
) pairs from the previous tickrunning_nodes ([uuid.UUID]) – list of id’s for behaviours which were traversed in the current tick
previously_running_nodes ([uuid.UUID]) – list of id’s for behaviours which were traversed in the last tick
visited_blackboard_ids (Set[uuid.UUID]) – blackboard client id’s on the visited path
visited_blackboard_keys (Set[str]) – blackboard variable keys on the visited path
See also
The py-trees-demo-logging program demonstrates use of this visitor to trigger logging of a tree serialisation.
- class py_trees.visitors.VisitorBase(full: bool = False)[source]
Bases:
object
Parent template for visitor types.
Visitors are primarily designed to work with
BehaviourTree
but they can be used in the same way for other tree custodian implementations.- Parameters
full (bool) – flag to indicate whether it should be used to visit only traversed nodes or the entire tree
- Variables
full – flag to indicate whether it should be used to visit only traversed nodes or the entire tree
- finalise() None [source]
Override if any work needs to be performed after ticks (i.e. showing data).
- Return type
None
- initialise() None [source]
Override if any resetting of variables needs to be performed between ticks (i.e. visitations).
- Return type
None
- run(behaviour: Behaviour) None [source]
Converse with the behaviour.
This method gets run as each behaviour is ticked. Override it to perform some activity - e.g. introspect the behaviour to store/process logging data for visualisations.
- Parameters
behaviour (
Behaviour
) – behaviour that is ticking- Return type
None