Skip to main content

bscript

PyPI - Version PyPI - Python Version


bscript

bscript is a python behavior specification library for agents respectively robots. It is similar to hierarchical finite state machines, but primarily uses decorated python generators -- called tasks -- instead of finite state machines. This provides an imperative scripting like approach to behavior engineering.

tasks are callable singletons which wrap a generator and can be called like regular functions:

@task
def foo():
    yield 1
    return 2

assert foo() == 1
assert foo() == 2
assert foo() == 1

These "state based functions" can be used to describe complex and deliberate hierarchical behaviors:

@task
def eat():
    try:
        while peel_banana(): yield Running
        while eat_banana(): yield Running
    except Failure:
        while eat_apple(): yield Running

    # implicit return Success

Table of Contents

Installation

# only available for python >= 3.13
pip install bscript

Basics

  • a node is usually a task -- which is a superset of a function
    • (finite state machine-ish nodes are also available)
  • each node in the hierarchy should usually return either Running (== True) or Success (== None)
  • when a node finishes its execution without returning or yielding a value, it implicitly returns None (== Success)
  • a Failure is an exception and must be raised (and caught)

actions

low level nodes that execute actions can often be written as functions:

@task
def drive_to(target):
    output().target = target
    return Success if target_reached(target) else Running

or as a generator:

@task
def drive_to(target):
    while not target_reached(target):
        output().target = target
        yield Running

    # Success (implicit return None / Success)

high level behaviors

sequence of sub behaviors

@task
def eat():
    while peel_banana(): yield Running
    while eat_banana(): yield Running

    # Success (implicit return None / Success)

failures and fallbacks

@task
def eat():
    try:
        while peel_banana(): yield Running
        while eat_banana(): yield Running
    except Failure:
        while eat_apple(): yield Running

parallel execution of behaviors

@task
def walk_to_bus_stop():
    while walk_to(next_bus_stop()):
        listen_to_music()
        eat_an_apple()
        yield Running

conditions

@task
def emergency():
    # callers can make decisions based on whether this task is Running or not
    if random() > 0.9:
        yield Running
        yield Running # always running for 2 frames in a row

@task
def some_behavior():
    if emergency():
        run_away()
        return Running
    else:
        return do_something()

conditional parallel execution

@task
def attend_talk():
    while listen_to_talk():
        if new_message():
            read_message()
        elif hungry():
            eat_an_apple()
        yield Running

how this works

tasks

tasks are generators -- a superset of functions -- that can be called like functions. They are implemented as callable singeltons and update their parameters (local variables inside the generator namespace). A StopIteration is transformed into a return statement like behavior.

A task is pretty much a "function with an internal state" or a "function with yield statements".

yield and return statements can be mixed inside python generators -- and therefor inside tasks aswell. They behave as expected:

  • yield returns a value and resumes the execution
  • return returns a value and restarts the execution

the result is pretty similar to functions:

from bscript import task

@task
def foo_pass():
    pass
    # implicit return None, like regular functions

assert foo_pass() == None

@task
def foo_return():
    return 1

assert foo_return() == 1

@task
def foo_yield():
    yield 1
    # implicit return None

assert foo_yield() == 1
assert foo_yield() == None
assert foo_yield() == 1

@task
def foobar():
    yield 1
    yield 2
    return 99
    yield 4

assert foobar() == 1
assert foobar() == 2
assert foobar() == 99
assert foobar() == 1

@task
def foox(x):
    yield x
    yield x

assert foox(4) == 4
assert foox(9) == 9
assert foox(1) == None

Running & Success

bscript defines the states Running and Success. It turns out defining them like this...

Running = True
Success = None

...has pretty interesting properties, especially since each function or task always returns something -- explicitly or implicitly None:

assert True is Running is not Success
assert None is Success is not Running

def always_successful():
    pass
    # implicit return None / Success

def always_running():
    return Running

assert always_successful() is Success
assert always_successful() is not Running

assert always_running() is Running
assert always_running() is not Success

while and if in combination with Running & Success

  • while do_something(): is equivalent to

    • while do_something() is Running:
    • while do_something() is not Success:
  • if something(): is equivalent to:

    • if something() is Running:
    • if something() is not Success:

finite state machin-ish nodes, context handling, input & output and more

-> docs/details.md

Examples

The lunch behavior and the irsim behavior show basic example applications.

License

bscript is distributed under the terms of the MIT license.

Release files for bscript 0.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bscript 0.0.2
File Size Uploaded
bscript-0.0.2.tar.gz 11.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bscript 0.0.2
File Interpreter ABI Platform
bscript-0.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 18.9 kB

Release files / bscript-0.0.2.tar.gz

Download URL bscript-0.0.2.tar.gz
Size 11.4 kB
Tags Source
SHA-256 checksum
How to use checksums
f3d8feac17f991f2232cc0962f82012e98a4543373babba2b33489fbd4e6ecf5
BLAKE2b-256 checksum
How to use checksums
8943f50213ad4c1547897be055742fb5cda363a3f2452fc436f082e81b18af27
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via python-httpx/0.28.1

Release files / bscript-0.0.2-py3-none-any.whl

Download URL bscript-0.0.2-py3-none-any.whl
Size 7.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9117eacacaf2e1c5274f67509f3d7ee4728428b6803ebbb4466db6f4c4d3b682
BLAKE2b-256 checksum
How to use checksums
80e44d813a000287729178d979b3eeeecf7938f1075bbebfcb3aa839a636122b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via python-httpx/0.28.1

Release history Release notifications | RSS feed

This release

0.0.2 This release

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page