{ "info": { "author": "Jerome Guibert", "author_email": "jguibert@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 5 - Production/Stable", "Framework :: AsyncIO", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.7", "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed" ], "description": "# Async Behaviour Tree for Python\n\n\n[![Unix Build Status](https://img.shields.io/travis/geronimo-iia/async-btree/master.svg?label=unix)](https://travis-ci.org/geronimo-iia/async-btree)\n[![Coverage Status](https://img.shields.io/coveralls/geronimo-iia/async-btree/master.svg)](https://coveralls.io/r/geronimo-iia/async-btree)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/fe669a02b4aa46b5b1faf619ba2bf382)](https://www.codacy.com/app/geronimo-iia/async-btree?utm_source=github.com&utm_medium=referral&utm_content=geronimo-iia/async-btree&utm_campaign=Badge_Grade)\n[![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/geronimo-iia/async-btree.svg)](https://scrutinizer-ci.com/g/geronimo-iia/async-btree/?branch=master)\n[![PyPI Version](https://img.shields.io/pypi/v/async-btree.svg)](https://pypi.org/project/async-btree)\n[![PyPI License](https://img.shields.io/pypi/l/async-btree.svg)](https://pypi.org/project/async-btree)\n\nVersions following [Semantic Versioning](https://semver.org/)\n\n## Overview\n\n\n### What's a behavior tree ?\n\n> Unlike a Finite State Machine, a Behaviour Tree is a tree of hierarchical nodes that controls the flow of decision and the execution of \"tasks\" or, as we will call them further, \"Actions\".\n> -- [behaviortree](https://www.behaviortree.dev/bt_basics/)\n\nIf your new (or not) about behavior tree, you could spend some time on this few links:\n\n- [Behavior trees for AI: How they work](https://www.gamasutra.com/blogs/ChrisSimpson/20140717/221339/Behavior_trees_for_AI_How_they_work.php) by Chris Simpson\n- [Introduction to BTs](https://www.behaviortree.dev/bt_basics/)\n\nFew implementation libraries:\n\n- [task_behavior_engine](https://github.com/ToyotaResearchInstitute/task_behavior_engine) A behavior tree based task engine written in Python\n- [pi_trees](https://github.com/pirobot/pi_trees/) a Python/ROS library for implementing Behavior Trees\n- [pr_behavior_tree](https://github.com/personalrobotics/pr_behavior_tree) A simple python behavior tree library based on coroutines\n- [btsk](https://github.com/aigamedev/btsk) Behavior Tree Starter Kit\n- [behave](https://github.com/fuchen/behave) A behavior tree implementation in Python\n\n\n### Why another library so ?\n\n__SIMPLICITY__\n\nWhen you study behavior tree implementation, reactive node, dynamic change, runtime execution, etc ... \nAt a moment you're build more or less something that mimic an evaluator 'eval/apply' or a compilator, with a complex hierachical set of class.\nAll complexity came with internal state management, using tree of blackboard to avoid global variable, multithreading issue, maybe few callback etc ...\nThis break the simplicity and beauty of your initial design.\n\nWhat I find usefull with behavior tree:\n\n- clarity of expression\n- node tree representation\n- possibility to reuse behavior\n- add external measure to dynamicaly change a behavior, a first step on observable pattern...\n\nAs I've used OOP for years (very long time), I will try to avoid class tree and prefer using the power of functionnal programming to obtain what I want: add metadata on a sematic construction, deal with closure, use function in parameters or in return value...\n\nAnd a last reason, more personal, it that i would explore python expressivity.\n\n__SO HOW ?__\n\nIn this module, I purpose you to use the concept of coroutines, and their mecanisms to manage the execution flow.\nBy this way:\n\n- we reuse simple language idiom to manage state, parameter, etc\n- no design constraint on action implementation\n- most of language build block could be reused\n\nYou could build expression like this:\n\n```python\n\nasync def a_func():\n \"\"\"A great function\"\"\"\n return \"a\"\n\nasync def b_decorator(child_value, other=\"\"):\n \"\"\"A great decorator...\"\"\"\n return f\"b{child_value}{other}\"\n\nassert run(decorate(a_func, b_decorator)) == \"ba\"\n\n```\nThis expression apply ```b_decorator``` on function ```a_func```. \nNote that ```decorate(a_func, b_decorator)``` is not an async function, only action, or condition are async function.\n\n\nFew guidelines of this implementation:\n\n- In order to mimic all NodeStatus (success, failure, running), I replace this by truthy/falsy meaning of evaluation value.\n A special dedicated exception decorate standard exception in order to give them a Falsy meaning.\n- Blackboard pattern, act as a manager of context variable for behavior tree.\n With python 3, please... simply use [contextvars](https://docs.python.org/3/library/contextvars.html) !\n- In order to be able to build a sematic tree, I've introduce a metadata tuple added on function implementation.\n\nThe rest is just implementation details..\n\n\n\nA little note:\n\n> You should not use this until you're ready to think about what you're doing :)\n\n\n### Note about 'async' framework\n\nAs we use async function as underlaying mechanism to manage the execution flow, the standard library asyncio is pretty fine.\nBut, (always a but somewhere isn't it...), you should read this [amazing blog post}(https://vorpus.org/blog/some-thoughts-on-asynchronous-api-design-in-a-post-asyncawait-world/) by Nathaniel J. Smith.\nAnd next study [curio](https://github.com/dabeaz/curio) framework in deep.\n\nAs curio say:\n> Don't Use Curio if You're Allergic to Curio\n\nPersonaly, after few time of testing and reading curio code, I'm pretty addict.\n\n\n## Setup\n\n### Requirements\n\n* Python 3.7+\n\n### Installation\n\nInstall this library directly into an activated virtual environment:\n\n```text\n$ pip install async-btree\n```\n\nor add it to your [Poetry](https://poetry.eustace.io/) project:\n\n```text\n$ poetry add async-btree\n```\n\n## Usage\n\nAfter installation, the package can imported:\n\n```text\n$ python\n>>> import async_btree\n>>> async_btree.__version__\n```\n\nSee [Api documentation](https://geronimo-iia.github.io/async-btree/api-overview)\n\n## License\n\n[The MIT License (MIT)](https://geronimo-iia.github.io/async-btree/license)\n\n\n## Contributing\n\nSee [Contributing](https://geronimo-iia.github.io/async-btree/contributing)\n\n## TODO\n\n- add examples\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://pypi.org/project/async_btree", "keywords": "behavior-tree,asyncio", "license": "MIT", "maintainer": "Jerome Guibert", "maintainer_email": "jguibert@gmail.com", "name": "async-btree", "package_url": "https://pypi.org/project/async-btree/", "platform": "", "project_url": "https://pypi.org/project/async-btree/", "project_urls": { "Documentation": "https://geronimo-iia.github.io/async-btree/", "Homepage": "https://pypi.org/project/async_btree", "Repository": "https://github.com/geronimo-iia/async-btree" }, "release_url": "https://pypi.org/project/async-btree/1.0.0/", "requires_dist": [ "curio (>=0.9,<0.10); extra == \"curio\"" ], "requires_python": ">=3.7,<4.0", "summary": "Async behavior tree", "version": "1.0.0" }, "last_serial": 5768337, "releases": { "0.0.1a0": [ { "comment_text": "", "digests": { "md5": "1094412d2fc5050156957394513a96dc", "sha256": "eee6539e9577d0c7229808781ffbaccbd0a03a386174c72a4a81c32b3fdc546c" }, "downloads": -1, "filename": "async_btree-0.0.1a0-py3-none-any.whl", "has_sig": false, "md5_digest": "1094412d2fc5050156957394513a96dc", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 18690, "upload_time": "2019-06-27T23:36:38", "url": "https://files.pythonhosted.org/packages/fa/77/00178a3195c82b16846efd2d4b92f5dad8270d6eeeb3df449f401dad576b/async_btree-0.0.1a0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ffc9aa020cbaebb40624302c46635361", "sha256": "1098bbda8311ef9ce8be7d9c51b1f046c2df986eae792645a335e39e48e9be5f" }, "downloads": -1, "filename": "async_btree-0.0.1a0.tar.gz", "has_sig": false, "md5_digest": "ffc9aa020cbaebb40624302c46635361", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 16077, "upload_time": "2019-06-27T23:36:40", "url": "https://files.pythonhosted.org/packages/2a/19/8f41005e8552ec4a86e9f2db6cded70cac7396ea0250a89c3b4ee8d63f4a/async_btree-0.0.1a0.tar.gz" } ], "0.1.0": [ { "comment_text": "", "digests": { "md5": "c6e7191e163260919a06f6fe5c4a7516", "sha256": "da34ea9a635a42d24380adc45d62b063f55056b75eafbb442860f65330ca6a0a" }, "downloads": -1, "filename": "async_btree-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "c6e7191e163260919a06f6fe5c4a7516", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 12935, "upload_time": "2019-07-05T10:03:00", "url": "https://files.pythonhosted.org/packages/0f/41/cfce8b8beb53733b2d77d9b0570b3eef8dcdf6aafc32db7a8fa9d5164d31/async_btree-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "30ca5d89404581a76cc111d1b87c7377", "sha256": "6de026b5aa0a83ee243113ba0d9f02ba6ce2558205c98f1a11bff35e0cc26e6a" }, "downloads": -1, "filename": "async_btree-0.1.0.tar.gz", "has_sig": false, "md5_digest": "30ca5d89404581a76cc111d1b87c7377", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 13558, "upload_time": "2019-07-05T10:03:02", "url": "https://files.pythonhosted.org/packages/ab/73/64c9c1fbc49a133c4ac78b7ccf8441e02ab0a6f979acd465626231da2ffd/async_btree-0.1.0.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "93d2df1f278e0b83719618617c8db44e", "sha256": "575734596e6389dab223e8051d5594186233df2d5d77c5047987fb3f589843d7" }, "downloads": -1, "filename": "async_btree-0.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "93d2df1f278e0b83719618617c8db44e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 12920, "upload_time": "2019-07-05T10:08:33", "url": "https://files.pythonhosted.org/packages/f0/bf/fa31d0396d3638ddaeee4022b19cadd5decb60be1dd0389ea4d66bfe0441/async_btree-0.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0a49f66a7f15179eb16a8692d92612cf", "sha256": "76f7947c15b143efc59011ccf6734d0fa6c81e7cdab4fdd1bd7487ed3e1a94f1" }, "downloads": -1, "filename": "async_btree-0.1.2.tar.gz", "has_sig": false, "md5_digest": "0a49f66a7f15179eb16a8692d92612cf", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 13535, "upload_time": "2019-07-05T10:08:35", "url": "https://files.pythonhosted.org/packages/60/14/3a067f2fb78de90d3ef2a6845c698e14bb30bf5a5102e66b1e03cfa91129/async_btree-0.1.2.tar.gz" } ], "1.0.0": [ { "comment_text": "", "digests": { "md5": "33a839127e4d86863eb5abbeacef6a1f", "sha256": "ec8c7e388b4a59d2db8a32fdeae04de1b7dd005368646d971bf00bfbb5ad8c59" }, "downloads": -1, "filename": "async_btree-1.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "33a839127e4d86863eb5abbeacef6a1f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 13624, "upload_time": "2019-09-01T23:16:39", "url": "https://files.pythonhosted.org/packages/23/e6/6f3c5bc7b96c8ec47eb305eaea14c40113f76d4fd6328e33315222ad4cbc/async_btree-1.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3105567f42c5657fea689e6cce357f6f", "sha256": "4b0cb3d3ba2036e88a19038730dff0cb5606b95cdebeccad1c44f312c0816c59" }, "downloads": -1, "filename": "async_btree-1.0.0.tar.gz", "has_sig": false, "md5_digest": "3105567f42c5657fea689e6cce357f6f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 14208, "upload_time": "2019-09-01T23:16:41", "url": "https://files.pythonhosted.org/packages/1a/eb/189a97c896f9972098bee25d748793e2cfdae551f86f1df6902367ac0a79/async_btree-1.0.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "33a839127e4d86863eb5abbeacef6a1f", "sha256": "ec8c7e388b4a59d2db8a32fdeae04de1b7dd005368646d971bf00bfbb5ad8c59" }, "downloads": -1, "filename": "async_btree-1.0.0-py3-none-any.whl", "has_sig": false, "md5_digest": "33a839127e4d86863eb5abbeacef6a1f", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.7,<4.0", "size": 13624, "upload_time": "2019-09-01T23:16:39", "url": "https://files.pythonhosted.org/packages/23/e6/6f3c5bc7b96c8ec47eb305eaea14c40113f76d4fd6328e33315222ad4cbc/async_btree-1.0.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "3105567f42c5657fea689e6cce357f6f", "sha256": "4b0cb3d3ba2036e88a19038730dff0cb5606b95cdebeccad1c44f312c0816c59" }, "downloads": -1, "filename": "async_btree-1.0.0.tar.gz", "has_sig": false, "md5_digest": "3105567f42c5657fea689e6cce357f6f", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.7,<4.0", "size": 14208, "upload_time": "2019-09-01T23:16:41", "url": "https://files.pythonhosted.org/packages/1a/eb/189a97c896f9972098bee25d748793e2cfdae551f86f1df6902367ac0a79/async_btree-1.0.0.tar.gz" } ] }