py-trees 2.2.2__tar.gz → 2.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. {py_trees-2.2.2 → py_trees-2.3.0}/PKG-INFO +41 -81
  2. {py_trees-2.2.2 → py_trees-2.3.0}/README.md +33 -75
  3. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/behaviour.py +8 -6
  4. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/behaviours.py +45 -0
  5. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/composites.py +9 -12
  6. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/decorators.py +29 -2
  7. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/timers.py +1 -1
  8. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/trees.py +13 -6
  9. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/version.py +1 -1
  10. {py_trees-2.2.2 → py_trees-2.3.0}/pyproject.toml +5 -4
  11. py_trees-2.2.2/setup.py +0 -60
  12. {py_trees-2.2.2 → py_trees-2.3.0}/LICENSE +0 -0
  13. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/__init__.py +0 -0
  14. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/blackboard.py +0 -0
  15. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/common.py +0 -0
  16. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/console.py +0 -0
  17. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/README.md +0 -0
  18. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/__init__.py +0 -0
  19. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/action.py +0 -0
  20. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/blackboard.py +0 -0
  21. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/blackboard_namespaces.py +0 -0
  22. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/blackboard_remappings.py +0 -0
  23. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/context_switching.py +0 -0
  24. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/display_modes.py +0 -0
  25. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/dot_graphs.py +0 -0
  26. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/either_or.py +0 -0
  27. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/eternal_guard.py +0 -0
  28. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/lifecycle.py +0 -0
  29. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/logging.py +0 -0
  30. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/pick_up_where_you_left_off.py +0 -0
  31. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/selector.py +0 -0
  32. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/sequence.py +0 -0
  33. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/demos/stewardship.py +0 -0
  34. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/display.py +0 -0
  35. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/idioms.py +0 -0
  36. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/logging.py +0 -0
  37. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/meta.py +0 -0
  38. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/programs/__init__.py +0 -0
  39. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/programs/render.py +0 -0
  40. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/py.typed +0 -0
  41. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/syntax_highlighting.py +0 -0
  42. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/tests.py +0 -0
  43. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/utilities.py +0 -0
  44. {py_trees-2.2.2 → py_trees-2.3.0}/py_trees/visitors.py +0 -0
@@ -1,59 +1,62 @@
1
- Metadata-Version: 2.1
2
- Name: py-trees
3
- Version: 2.2.2
1
+ Metadata-Version: 2.3
2
+ Name: py_trees
3
+ Version: 2.3.0
4
4
  Summary: pythonic implementation of behaviour trees
5
- Home-page: https://github.com/splintered-reality/py_trees
6
5
  License: BSD
7
6
  Keywords: py_trees,py-trees,behaviour-trees
8
7
  Author: Daniel Stonier
9
8
  Maintainer: Daniel Stonier
10
9
  Maintainer-email: d.stonier@gmail.com
11
- Requires-Python: >=3.8,<4.0
10
+ Requires-Python: >=3.9,<4.0
12
11
  Classifier: Environment :: Console
13
12
  Classifier: Intended Audience :: Developers
14
13
  Classifier: License :: OSI Approved :: BSD License
15
14
  Classifier: License :: Other/Proprietary License
16
15
  Classifier: Programming Language :: Python
17
16
  Classifier: Programming Language :: Python :: 3
18
- Classifier: Programming Language :: Python :: 3.8
19
17
  Classifier: Programming Language :: Python :: 3.9
20
18
  Classifier: Programming Language :: Python :: 3.10
21
19
  Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
22
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
23
  Classifier: Topic :: Software Development :: Libraries
24
+ Requires-Dist: py (>=1.11.0,<2.0.0)
24
25
  Requires-Dist: pydot (>=1.4)
25
26
  Project-URL: Documentation, https://py-trees.readthedocs.io/en/devel/
27
+ Project-URL: Homepage, https://github.com/splintered-reality/py_trees
26
28
  Project-URL: Repository, https://github.com/splintered-reality/py_trees
27
29
  Description-Content-Type: text/markdown
28
30
 
29
- # Py Trees
31
+ # PyTrees
30
32
 
31
- [[About](#about)] [[What's New?](#whats-new)] [[Documentation](#documentation)] [[Getting Started](#getting-started)] [[Next Steps](#next-steps)] [[Releases](#releases)] [[Developers](#developers)]
33
+ [[About](#about)] [[What's New?](#whats-new)] [[Documentation](#documentation)] [[Getting Started](#getting-started)] [[Next Steps](#next-steps)] [[Releases](#releases)]
32
34
 
33
35
  ----
34
36
 
35
37
  ## About
36
38
 
37
- PyTrees is a python implementation of behaviour trees designed to facilitate the rapid development of medium sized decision making engines for use in fields like robotics. Brief feature list:
39
+ PyTrees is a Python implementation of behaviour trees designed to facilitate the rapid development of medium sized decision making engines for use in fields like robotics.
40
+
41
+ Brief feature list:
38
42
 
39
43
  * Behaviours, Decorators, Sequences, Selectors, Parallels and BehaviourTree.
40
44
  * Blackboards for data sharing.
41
- * A useful library of behaviours, decorators and idioms.
45
+ * A useful library of behaviours, decorators, and idioms.
42
46
  * Serialise to a dot graph or render to ascii/unicode in a terminal.
43
47
  * Tested on Linux and Mac (YMMV with Windows).
44
48
 
45
49
  ## What's New?
46
50
 
47
- * [2023-01-23] The [2.2.x Release][new-2.2.x] is out! Sequences and Selectors with AND without memory.
48
- * [2023-01-23] [Get Started](#getting-started) with py_trees in under 5mins.
51
+ * [2025-01-11] Support for Python 3.12 was added, and Python 3.8 was dropped.
49
52
 
50
53
  ## Documentation
51
54
 
52
- [![devel][docs-devel-image]][docs-devel] [![2.2.x][docs-2.2.x-image]][docs-2.2.x] [![2.1.x][docs-2.1.x-image]][docs-2.1.x] [![0.7.x][docs-0.7.x-image]][docs-0.7.x] [![0.6.x][docs-0.6.x-image]][docs-0.6.x]
55
+ [![devel][docs-devel-image]][docs-devel] [![2.3.x][docs-2.3.x-image]][docs-2.3.x] [![2.2.x][docs-2.2.x-image]][docs-2.2.x] [![2.1.x][docs-2.1.x-image]][docs-2.1.x]
53
56
 
54
57
  ## Getting Started
55
58
 
56
- You can get started on CodeSpaces (with no mismatched environment issues and in under 5mins) [1]:
59
+ You can get started on Codespaces (with no mismatched environment issues and in under 5 minutes) [1]:
57
60
 
58
61
  1. Fork the project to your personal account
59
62
  2. Click on Code -> Codespaces -> + Create a Codespace
@@ -65,24 +68,24 @@ You can get started on CodeSpaces (with no mismatched environment issues and in
65
68
 
66
69
  # Explore the demos
67
70
  (docker) zen@py_trees:/workspaces/py_trees$ poetry shell
68
- (py-trees-py3.8) (docker) zen@py_trees:/workspaces/py_trees$ py-trees-demo-<tab>-<tab>
71
+ (py-trees-py3.10) (docker) zen@py_trees:/workspaces/py_trees$ py-trees-demo-<tab>-<tab>
69
72
  py-trees-demo-action-behaviour py-trees-demo-context-switching py-trees-demo-logging
70
73
  py-trees-demo-behaviour-lifecycle py-trees-demo-display-modes py-trees-demo-pick-up-where-you-left-off
71
74
  py-trees-demo-blackboard py-trees-demo-dot-graphs py-trees-demo-selector
72
75
  py-trees-demo-blackboard-namespaces py-trees-demo-either-or py-trees-demo-sequence
73
76
  py-trees-demo-blackboard-remappings py-trees-demo-eternal-guard py-trees-demo-tree-stewardship
74
- (py-trees-py3.8) (docker) zen@py_trees:/workspaces/py_trees$ py-trees-demo-blackboard
77
+ (py-trees-py3.10) (docker) zen@py_trees:/workspaces/py_trees$ py-trees-demo-blackboard
75
78
  ...
76
- (py-trees-py3.8) (docker) zen@py_trees:/workspaces/py_trees$ exit
79
+ (py-trees-py3.10) (docker) zen@py_trees:/workspaces/py_trees$ exit
77
80
 
78
81
  # Hack some Code
79
82
 
80
83
  # Run the Formatter, Tests, Linters and Mypy
81
84
  (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -l
82
- py38 py310 format check mypy38 mypy310
85
+ py310 py312 format check mypy310 mypy312
83
86
  (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e format
84
87
  ...
85
- (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e py38
88
+ (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e py310
86
89
  ...
87
90
  (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e check
88
91
  ...
@@ -91,8 +94,8 @@ py38 py310 format check mypy38 mypy310
91
94
  # https://github.com/splintered-reality/py_trees/blob/devel/CONTRIBUTING.md
92
95
  ```
93
96
 
94
- [1] All of the above will, of course, work in a local environment if you have `poetry` installed. If you're using `VSCode`
95
- you don't even need that, just reopen the project in the [devcontainer](.devcontainer/devcontainer.json) and be froody.
97
+ [1] All of the above will, of course, work in a local environment if you have `poetry` installed.
98
+ If you're using `VSCode` you don't even need that, just reopen the project in the [devcontainer](.devcontainer/devcontainer.json) and be froody.
96
99
 
97
100
  ## Next Steps
98
101
 
@@ -101,7 +104,7 @@ On PyPi:
101
104
  * [py_trees_js](https://pypi.org/project/py-trees-js/)
102
105
 
103
106
  Examples:
104
- * [ReadTheDocs - PyTrees ROS Tutorials](https://py-trees-ros-tutorials.readthedocs.io/en/release-2.0.x/index.html) - significantly more edifying than the demos, these incrementally walk through the process of building a decision making layer for a robot. These use ROS2 (sparsely), but merely browsing should be enlightening regardless.
107
+ * [ReadTheDocs - PyTrees ROS Tutorials](https://py-trees-ros-tutorials.readthedocs.io/en/devel/index.html) - significantly more edifying than the demos, these incrementally walk through the process of building a decision making layer for a robot. These use ROS2 (sparsely), but merely browsing should be enlightening regardless.
105
108
 
106
109
  Visualisation:
107
110
  * [py_trees_js](https://github.com/splintered-reality/py_trees_js) - a javascript library for building your own runtime visualisation tool
@@ -112,6 +115,7 @@ Robotics:
112
115
 
113
116
  ## Releases
114
117
 
118
+ * `2.3.x` - Support for Python 3.12 was added, and Python 3.8 was dropped.
115
119
  * `2.2.x` - Selectors, Sequences with and without memory. Improved testing and style/type checking.
116
120
  * `2.1.x` - Chooser deprecated. API housekeeping.
117
121
  * `2.0.x` - Blackboards V2!
@@ -120,83 +124,35 @@ Robotics:
120
124
  * `1.0.x` - Behaviours, Decorators, Composites, Blackboards, Tree Management and Viz tools.
121
125
  * `0.y.x` - First open source pre-releases.
122
126
 
123
- | | Devel | 2.2.x | 2.1.x | 2.0.x | 1.2.x | 0.7.x | 0.6.x |
124
- |:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
125
- | Sources | [![devel][sources-devel-image]][sources-devel] | [![2.1.x][sources-2.2.x-image]][sources-2.2.x] | [![2.1.x][sources-2.1.x-image]][sources-2.1.x] | [![2.0.x][sources-2.0.x-image]][sources-2.0.x] | [![1.2.x][sources-1.2.x-image]][sources-1.2.x] | [![0.7.x][sources-0.7.x-image]][sources-0.7.x] | [![0.6.x][sources-0.6.x-image]][sources-0.6.x]
126
- | Compatibility | [![Python 3.10][python310-image]][python310-docs] [![Python 3.8][python38-image]][python38-docs] | [![Python 3.10][python310-image]][python310-docs] [![Python 3.8][python38-image]][python38-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 2.7][python27-image]][python27-docs]
127
- | CI | [![devel-Status][devel-build-status-image]][devel-build-status] | [![2.2.x-Status][2.2.x-build-status-image]][2.2.x-build-status] | - | - | - | - | - |
128
- | Documentation | [![devel-Docs][rtd-devel-image]][docs-devel] | [![2.2.x-Docs][rtd-2.2.x-image]][docs-2.2.x] | [![2.1.x-Docs][rtd-2.1.x-image]][docs-2.1.x] | [![2.0.x-Docs][rtd-2.0.x-image]][docs-2.0.x] | [![1.2.x-Docs][rtd-1.2.x-image]][docs-1.2.x] | [![0.7.x-Docs][rtd-0.7.x-image]][docs-0.7.x] | [![0.6.x-Docs][rtd-0.6.x-image]][docs-0.6.x]
129
-
130
- ## Developers
131
-
132
- ### Format, Check, MyPy, Test
133
-
134
- Check against at least one of py38 / py310 [1].
135
-
136
- ```
137
- # Auto-format your code (if using VSCode, install the ufmt extension)
138
- $ poetry run tox -e format
139
-
140
- # Style, Format
141
- $ poetry run tox -e check
127
+ | | Devel | 2.3.x | 2.2.x | 2.1.x | 2.0.x | 1.2.x |
128
+ |:---:|:---:|:---:|:---:|:---:|:---:|:---:|
129
+ | Sources | [![devel][sources-devel-image]][sources-devel] | [![2.3.x][sources-2.3.x-image]][sources-2.3.x] | [![2.2.x][sources-2.2.x-image]][sources-2.2.x] | [![2.1.x][sources-2.1.x-image]][sources-2.1.x] | [![2.0.x][sources-2.0.x-image]][sources-2.0.x] | [![1.2.x][sources-1.2.x-image]][sources-1.2.x] |
130
+ | Compatibility | [![Python 3.12][python312-image]][python312-docs]<br/>[![Python 3.10][python310-image]][python310-docs] | [![Python 3.12][python312-image]][python312-docs]<br/>[![Python 3.10][python310-image]][python310-docs] | [![Python 3.10][python310-image]][python310-docs]<br/>[![Python 3.8][python38-image]][python38-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] |
131
+ | CI | [![devel-Status][devel-build-status-image]][devel-build-status] | [![2.3.x-Status][2.3.x-build-status-image]][2.3.x-build-status] | [![2.2.x-Status][2.2.x-build-status-image]][2.2.x-build-status] | - | - | - | - | - |
132
+ | Documentation | [![devel-Docs][rtd-devel-image]][docs-devel] | [![2.3.x-Docs][rtd-2.3.x-image]][docs-2.3.x] | [![2.2.x-Docs][rtd-2.2.x-image]][docs-2.2.x] | [![2.1.x-Docs][rtd-2.1.x-image]][docs-2.1.x] | [![2.0.x-Docs][rtd-2.0.x-image]][docs-2.0.x] | [![1.2.x-Docs][rtd-1.2.x-image]][docs-1.2.x] |
142
133
 
143
- # Type-Check
144
- $ poetry run mypy38
145
-
146
- # Tests
147
- $ poetry run tox -e py38
148
- ```
149
-
150
- [1] CI will test against both python versions for you, but should you wish to do so locally, open up two VSCode windows, one with the project opened in the default [py38 devcontainer](.devcontainer) and the other with the [py310 devcontainer](.devcontainer/py310).
151
-
152
- ### Generate Documentation
153
-
154
- Generate the docs, view them from `./docs/html` in a browser.
155
-
156
- ```
157
- # Install dependencies
158
- $ poetry install --with docs
159
-
160
- # Build
161
- $ poetry run make -C docs html
162
- ```
163
-
164
- On Doc dependency changes, export the requirements for ReadTheDocs
165
-
166
- ```
167
- $ poetry export -f requirements.txt --with docs -o docs/requirements.txt
168
- ```
169
-
170
- ### Publish to PyPi
171
-
172
- If you have permission to publish on pypi:
173
-
174
- ```
175
- $ poetry config http-basic.pypi ${POETRY_HTTP_BASIC_PYPI_USERNAME} ${POETRY_HTTP_BASIC_PYPI_PASSWORD}
176
- $ poetry publish
177
- ```
178
134
 
179
135
  [license-image]: https://img.shields.io/badge/License-BSD%203--Clause-orange.svg?style=plastic
180
136
  [license]: LICENSE
181
137
 
138
+ [python312-image]: https://img.shields.io/badge/python-3.12-green.svg?style=plastic
139
+ [python312-docs]: https://docs.python.org/3.12/
182
140
  [python310-image]: https://img.shields.io/badge/python-3.10-green.svg?style=plastic
183
141
  [python310-docs]: https://docs.python.org/3.10/
184
142
  [python38-image]: https://img.shields.io/badge/python-3.8-green.svg?style=plastic
185
143
  [python38-docs]: https://docs.python.org/3.8/
186
144
  [python36-image]: https://img.shields.io/badge/python-3.6-green.svg?style=plastic
187
145
  [python36-docs]: https://docs.python.org/3.6/
188
- [python27-image]: https://img.shields.io/badge/python-2.7-green.svg?style=plastic
189
- [python27-docs]: https://docs.python.org/2.7/
190
146
 
191
147
  [devel-build-status-image]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml/badge.svg
192
148
  [devel-build-status]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml
149
+ [2.3.x-build-status-image]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml/badge.svg??branch=release/2.3.x
150
+ [2.3.x-build-status]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml
193
151
  [2.2.x-build-status-image]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml/badge.svg??branch=release/2.2.x
194
152
  [2.2.x-build-status]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml
195
153
 
196
- [new-2.2.x]: https://github.com/splintered-reality/py_trees/blob/devel/CHANGELOG.rst#22x-2023-01-23---sequences-and-selectors-with-and-without-memory
197
-
198
-
199
154
  [docs-devel]: http://py-trees.readthedocs.io/
155
+ [docs-2.3.x]: http://py-trees.readthedocs.io/en/release-2.3.x/
200
156
  [docs-2.2.x]: http://py-trees.readthedocs.io/en/release-2.2.x/
201
157
  [docs-2.1.x]: http://py-trees.readthedocs.io/en/release-2.1.x/
202
158
  [docs-2.0.x]: http://py-trees.readthedocs.io/en/release-2.0.x/
@@ -207,6 +163,7 @@ $ poetry publish
207
163
  [docs-0.5.x]: http://docs.ros.org/kinetic/api/py_trees/html/
208
164
 
209
165
  [docs-devel-image]: http://img.shields.io/badge/docs-devel-brightgreen.svg?style=plastic
166
+ [docs-2.3.x-image]: http://img.shields.io/badge/docs-2.3.x-brightgreen.svg?style=plastic
210
167
  [docs-2.2.x-image]: http://img.shields.io/badge/docs-2.2.x-brightgreen.svg?style=plastic
211
168
  [docs-2.1.x-image]: http://img.shields.io/badge/docs-2.1.x-brightgreen.svg?style=plastic
212
169
  [docs-2.0.x-image]: http://img.shields.io/badge/docs-2.0.x-brightgreen.svg?style=plastic
@@ -217,6 +174,7 @@ $ poetry publish
217
174
  [docs-0.5.x-image]: http://img.shields.io/badge/docs-0.5.x-brightgreen.svg?style=plastic
218
175
 
219
176
  [rtd-devel-image]: https://readthedocs.org/projects/py-trees/badge/?version=devel&style=plastic
177
+ [rtd-2.3.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.3.x&style=plastic
220
178
  [rtd-2.2.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.2.x&style=plastic
221
179
  [rtd-2.1.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.1.x&style=plastic
222
180
  [rtd-2.0.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.0.x&style=plastic
@@ -228,6 +186,7 @@ $ poetry publish
228
186
  [not-available-docs-image]: http://img.shields.io/badge/docs-n/a-yellow.svg?style=plastic
229
187
 
230
188
  [sources-devel]: https://github.com/splintered-reality/py_trees/tree/devel
189
+ [sources-2.3.x]: https://github.com/splintered-reality/py_trees/tree/release/2.3.x
231
190
  [sources-2.2.x]: https://github.com/splintered-reality/py_trees/tree/release/2.2.x
232
191
  [sources-2.1.x]: https://github.com/splintered-reality/py_trees/tree/release/2.1.x
233
192
  [sources-2.0.x]: https://github.com/splintered-reality/py_trees/tree/release/2.0.x
@@ -238,6 +197,7 @@ $ poetry publish
238
197
  [sources-0.5.x]: https://github.com/splintered-reality/py_trees/tree/release/0.5.x
239
198
 
240
199
  [sources-devel-image]: http://img.shields.io/badge/sources-devel-blue.svg?style=plastic
200
+ [sources-2.3.x-image]: http://img.shields.io/badge/sources-2.3.x-blue.svg?style=plastic
241
201
  [sources-2.2.x-image]: http://img.shields.io/badge/sources-2.2.x-blue.svg?style=plastic
242
202
  [sources-2.1.x-image]: http://img.shields.io/badge/sources-2.1.x-blue.svg?style=plastic
243
203
  [sources-2.0.x-image]: http://img.shields.io/badge/sources-2.0.x-blue.svg?style=plastic
@@ -1,31 +1,32 @@
1
- # Py Trees
1
+ # PyTrees
2
2
 
3
- [[About](#about)] [[What's New?](#whats-new)] [[Documentation](#documentation)] [[Getting Started](#getting-started)] [[Next Steps](#next-steps)] [[Releases](#releases)] [[Developers](#developers)]
3
+ [[About](#about)] [[What's New?](#whats-new)] [[Documentation](#documentation)] [[Getting Started](#getting-started)] [[Next Steps](#next-steps)] [[Releases](#releases)]
4
4
 
5
5
  ----
6
6
 
7
7
  ## About
8
8
 
9
- PyTrees is a python implementation of behaviour trees designed to facilitate the rapid development of medium sized decision making engines for use in fields like robotics. Brief feature list:
9
+ PyTrees is a Python implementation of behaviour trees designed to facilitate the rapid development of medium sized decision making engines for use in fields like robotics.
10
+
11
+ Brief feature list:
10
12
 
11
13
  * Behaviours, Decorators, Sequences, Selectors, Parallels and BehaviourTree.
12
14
  * Blackboards for data sharing.
13
- * A useful library of behaviours, decorators and idioms.
15
+ * A useful library of behaviours, decorators, and idioms.
14
16
  * Serialise to a dot graph or render to ascii/unicode in a terminal.
15
17
  * Tested on Linux and Mac (YMMV with Windows).
16
18
 
17
19
  ## What's New?
18
20
 
19
- * [2023-01-23] The [2.2.x Release][new-2.2.x] is out! Sequences and Selectors with AND without memory.
20
- * [2023-01-23] [Get Started](#getting-started) with py_trees in under 5mins.
21
+ * [2025-01-11] Support for Python 3.12 was added, and Python 3.8 was dropped.
21
22
 
22
23
  ## Documentation
23
24
 
24
- [![devel][docs-devel-image]][docs-devel] [![2.2.x][docs-2.2.x-image]][docs-2.2.x] [![2.1.x][docs-2.1.x-image]][docs-2.1.x] [![0.7.x][docs-0.7.x-image]][docs-0.7.x] [![0.6.x][docs-0.6.x-image]][docs-0.6.x]
25
+ [![devel][docs-devel-image]][docs-devel] [![2.3.x][docs-2.3.x-image]][docs-2.3.x] [![2.2.x][docs-2.2.x-image]][docs-2.2.x] [![2.1.x][docs-2.1.x-image]][docs-2.1.x]
25
26
 
26
27
  ## Getting Started
27
28
 
28
- You can get started on CodeSpaces (with no mismatched environment issues and in under 5mins) [1]:
29
+ You can get started on Codespaces (with no mismatched environment issues and in under 5 minutes) [1]:
29
30
 
30
31
  1. Fork the project to your personal account
31
32
  2. Click on Code -> Codespaces -> + Create a Codespace
@@ -37,24 +38,24 @@ You can get started on CodeSpaces (with no mismatched environment issues and in
37
38
 
38
39
  # Explore the demos
39
40
  (docker) zen@py_trees:/workspaces/py_trees$ poetry shell
40
- (py-trees-py3.8) (docker) zen@py_trees:/workspaces/py_trees$ py-trees-demo-<tab>-<tab>
41
+ (py-trees-py3.10) (docker) zen@py_trees:/workspaces/py_trees$ py-trees-demo-<tab>-<tab>
41
42
  py-trees-demo-action-behaviour py-trees-demo-context-switching py-trees-demo-logging
42
43
  py-trees-demo-behaviour-lifecycle py-trees-demo-display-modes py-trees-demo-pick-up-where-you-left-off
43
44
  py-trees-demo-blackboard py-trees-demo-dot-graphs py-trees-demo-selector
44
45
  py-trees-demo-blackboard-namespaces py-trees-demo-either-or py-trees-demo-sequence
45
46
  py-trees-demo-blackboard-remappings py-trees-demo-eternal-guard py-trees-demo-tree-stewardship
46
- (py-trees-py3.8) (docker) zen@py_trees:/workspaces/py_trees$ py-trees-demo-blackboard
47
+ (py-trees-py3.10) (docker) zen@py_trees:/workspaces/py_trees$ py-trees-demo-blackboard
47
48
  ...
48
- (py-trees-py3.8) (docker) zen@py_trees:/workspaces/py_trees$ exit
49
+ (py-trees-py3.10) (docker) zen@py_trees:/workspaces/py_trees$ exit
49
50
 
50
51
  # Hack some Code
51
52
 
52
53
  # Run the Formatter, Tests, Linters and Mypy
53
54
  (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -l
54
- py38 py310 format check mypy38 mypy310
55
+ py310 py312 format check mypy310 mypy312
55
56
  (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e format
56
57
  ...
57
- (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e py38
58
+ (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e py310
58
59
  ...
59
60
  (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e check
60
61
  ...
@@ -63,8 +64,8 @@ py38 py310 format check mypy38 mypy310
63
64
  # https://github.com/splintered-reality/py_trees/blob/devel/CONTRIBUTING.md
64
65
  ```
65
66
 
66
- [1] All of the above will, of course, work in a local environment if you have `poetry` installed. If you're using `VSCode`
67
- you don't even need that, just reopen the project in the [devcontainer](.devcontainer/devcontainer.json) and be froody.
67
+ [1] All of the above will, of course, work in a local environment if you have `poetry` installed.
68
+ If you're using `VSCode` you don't even need that, just reopen the project in the [devcontainer](.devcontainer/devcontainer.json) and be froody.
68
69
 
69
70
  ## Next Steps
70
71
 
@@ -73,7 +74,7 @@ On PyPi:
73
74
  * [py_trees_js](https://pypi.org/project/py-trees-js/)
74
75
 
75
76
  Examples:
76
- * [ReadTheDocs - PyTrees ROS Tutorials](https://py-trees-ros-tutorials.readthedocs.io/en/release-2.0.x/index.html) - significantly more edifying than the demos, these incrementally walk through the process of building a decision making layer for a robot. These use ROS2 (sparsely), but merely browsing should be enlightening regardless.
77
+ * [ReadTheDocs - PyTrees ROS Tutorials](https://py-trees-ros-tutorials.readthedocs.io/en/devel/index.html) - significantly more edifying than the demos, these incrementally walk through the process of building a decision making layer for a robot. These use ROS2 (sparsely), but merely browsing should be enlightening regardless.
77
78
 
78
79
  Visualisation:
79
80
  * [py_trees_js](https://github.com/splintered-reality/py_trees_js) - a javascript library for building your own runtime visualisation tool
@@ -84,6 +85,7 @@ Robotics:
84
85
 
85
86
  ## Releases
86
87
 
88
+ * `2.3.x` - Support for Python 3.12 was added, and Python 3.8 was dropped.
87
89
  * `2.2.x` - Selectors, Sequences with and without memory. Improved testing and style/type checking.
88
90
  * `2.1.x` - Chooser deprecated. API housekeeping.
89
91
  * `2.0.x` - Blackboards V2!
@@ -92,83 +94,35 @@ Robotics:
92
94
  * `1.0.x` - Behaviours, Decorators, Composites, Blackboards, Tree Management and Viz tools.
93
95
  * `0.y.x` - First open source pre-releases.
94
96
 
95
- | | Devel | 2.2.x | 2.1.x | 2.0.x | 1.2.x | 0.7.x | 0.6.x |
96
- |:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
97
- | Sources | [![devel][sources-devel-image]][sources-devel] | [![2.1.x][sources-2.2.x-image]][sources-2.2.x] | [![2.1.x][sources-2.1.x-image]][sources-2.1.x] | [![2.0.x][sources-2.0.x-image]][sources-2.0.x] | [![1.2.x][sources-1.2.x-image]][sources-1.2.x] | [![0.7.x][sources-0.7.x-image]][sources-0.7.x] | [![0.6.x][sources-0.6.x-image]][sources-0.6.x]
98
- | Compatibility | [![Python 3.10][python310-image]][python310-docs] [![Python 3.8][python38-image]][python38-docs] | [![Python 3.10][python310-image]][python310-docs] [![Python 3.8][python38-image]][python38-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 2.7][python27-image]][python27-docs]
99
- | CI | [![devel-Status][devel-build-status-image]][devel-build-status] | [![2.2.x-Status][2.2.x-build-status-image]][2.2.x-build-status] | - | - | - | - | - |
100
- | Documentation | [![devel-Docs][rtd-devel-image]][docs-devel] | [![2.2.x-Docs][rtd-2.2.x-image]][docs-2.2.x] | [![2.1.x-Docs][rtd-2.1.x-image]][docs-2.1.x] | [![2.0.x-Docs][rtd-2.0.x-image]][docs-2.0.x] | [![1.2.x-Docs][rtd-1.2.x-image]][docs-1.2.x] | [![0.7.x-Docs][rtd-0.7.x-image]][docs-0.7.x] | [![0.6.x-Docs][rtd-0.6.x-image]][docs-0.6.x]
101
-
102
- ## Developers
103
-
104
- ### Format, Check, MyPy, Test
105
-
106
- Check against at least one of py38 / py310 [1].
107
-
108
- ```
109
- # Auto-format your code (if using VSCode, install the ufmt extension)
110
- $ poetry run tox -e format
111
-
112
- # Style, Format
113
- $ poetry run tox -e check
97
+ | | Devel | 2.3.x | 2.2.x | 2.1.x | 2.0.x | 1.2.x |
98
+ |:---:|:---:|:---:|:---:|:---:|:---:|:---:|
99
+ | Sources | [![devel][sources-devel-image]][sources-devel] | [![2.3.x][sources-2.3.x-image]][sources-2.3.x] | [![2.2.x][sources-2.2.x-image]][sources-2.2.x] | [![2.1.x][sources-2.1.x-image]][sources-2.1.x] | [![2.0.x][sources-2.0.x-image]][sources-2.0.x] | [![1.2.x][sources-1.2.x-image]][sources-1.2.x] |
100
+ | Compatibility | [![Python 3.12][python312-image]][python312-docs]<br/>[![Python 3.10][python310-image]][python310-docs] | [![Python 3.12][python312-image]][python312-docs]<br/>[![Python 3.10][python310-image]][python310-docs] | [![Python 3.10][python310-image]][python310-docs]<br/>[![Python 3.8][python38-image]][python38-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] |
101
+ | CI | [![devel-Status][devel-build-status-image]][devel-build-status] | [![2.3.x-Status][2.3.x-build-status-image]][2.3.x-build-status] | [![2.2.x-Status][2.2.x-build-status-image]][2.2.x-build-status] | - | - | - | - | - |
102
+ | Documentation | [![devel-Docs][rtd-devel-image]][docs-devel] | [![2.3.x-Docs][rtd-2.3.x-image]][docs-2.3.x] | [![2.2.x-Docs][rtd-2.2.x-image]][docs-2.2.x] | [![2.1.x-Docs][rtd-2.1.x-image]][docs-2.1.x] | [![2.0.x-Docs][rtd-2.0.x-image]][docs-2.0.x] | [![1.2.x-Docs][rtd-1.2.x-image]][docs-1.2.x] |
114
103
 
115
- # Type-Check
116
- $ poetry run mypy38
117
-
118
- # Tests
119
- $ poetry run tox -e py38
120
- ```
121
-
122
- [1] CI will test against both python versions for you, but should you wish to do so locally, open up two VSCode windows, one with the project opened in the default [py38 devcontainer](.devcontainer) and the other with the [py310 devcontainer](.devcontainer/py310).
123
-
124
- ### Generate Documentation
125
-
126
- Generate the docs, view them from `./docs/html` in a browser.
127
-
128
- ```
129
- # Install dependencies
130
- $ poetry install --with docs
131
-
132
- # Build
133
- $ poetry run make -C docs html
134
- ```
135
-
136
- On Doc dependency changes, export the requirements for ReadTheDocs
137
-
138
- ```
139
- $ poetry export -f requirements.txt --with docs -o docs/requirements.txt
140
- ```
141
-
142
- ### Publish to PyPi
143
-
144
- If you have permission to publish on pypi:
145
-
146
- ```
147
- $ poetry config http-basic.pypi ${POETRY_HTTP_BASIC_PYPI_USERNAME} ${POETRY_HTTP_BASIC_PYPI_PASSWORD}
148
- $ poetry publish
149
- ```
150
104
 
151
105
  [license-image]: https://img.shields.io/badge/License-BSD%203--Clause-orange.svg?style=plastic
152
106
  [license]: LICENSE
153
107
 
108
+ [python312-image]: https://img.shields.io/badge/python-3.12-green.svg?style=plastic
109
+ [python312-docs]: https://docs.python.org/3.12/
154
110
  [python310-image]: https://img.shields.io/badge/python-3.10-green.svg?style=plastic
155
111
  [python310-docs]: https://docs.python.org/3.10/
156
112
  [python38-image]: https://img.shields.io/badge/python-3.8-green.svg?style=plastic
157
113
  [python38-docs]: https://docs.python.org/3.8/
158
114
  [python36-image]: https://img.shields.io/badge/python-3.6-green.svg?style=plastic
159
115
  [python36-docs]: https://docs.python.org/3.6/
160
- [python27-image]: https://img.shields.io/badge/python-2.7-green.svg?style=plastic
161
- [python27-docs]: https://docs.python.org/2.7/
162
116
 
163
117
  [devel-build-status-image]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml/badge.svg
164
118
  [devel-build-status]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml
119
+ [2.3.x-build-status-image]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml/badge.svg??branch=release/2.3.x
120
+ [2.3.x-build-status]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml
165
121
  [2.2.x-build-status-image]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml/badge.svg??branch=release/2.2.x
166
122
  [2.2.x-build-status]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml
167
123
 
168
- [new-2.2.x]: https://github.com/splintered-reality/py_trees/blob/devel/CHANGELOG.rst#22x-2023-01-23---sequences-and-selectors-with-and-without-memory
169
-
170
-
171
124
  [docs-devel]: http://py-trees.readthedocs.io/
125
+ [docs-2.3.x]: http://py-trees.readthedocs.io/en/release-2.3.x/
172
126
  [docs-2.2.x]: http://py-trees.readthedocs.io/en/release-2.2.x/
173
127
  [docs-2.1.x]: http://py-trees.readthedocs.io/en/release-2.1.x/
174
128
  [docs-2.0.x]: http://py-trees.readthedocs.io/en/release-2.0.x/
@@ -179,6 +133,7 @@ $ poetry publish
179
133
  [docs-0.5.x]: http://docs.ros.org/kinetic/api/py_trees/html/
180
134
 
181
135
  [docs-devel-image]: http://img.shields.io/badge/docs-devel-brightgreen.svg?style=plastic
136
+ [docs-2.3.x-image]: http://img.shields.io/badge/docs-2.3.x-brightgreen.svg?style=plastic
182
137
  [docs-2.2.x-image]: http://img.shields.io/badge/docs-2.2.x-brightgreen.svg?style=plastic
183
138
  [docs-2.1.x-image]: http://img.shields.io/badge/docs-2.1.x-brightgreen.svg?style=plastic
184
139
  [docs-2.0.x-image]: http://img.shields.io/badge/docs-2.0.x-brightgreen.svg?style=plastic
@@ -189,6 +144,7 @@ $ poetry publish
189
144
  [docs-0.5.x-image]: http://img.shields.io/badge/docs-0.5.x-brightgreen.svg?style=plastic
190
145
 
191
146
  [rtd-devel-image]: https://readthedocs.org/projects/py-trees/badge/?version=devel&style=plastic
147
+ [rtd-2.3.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.3.x&style=plastic
192
148
  [rtd-2.2.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.2.x&style=plastic
193
149
  [rtd-2.1.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.1.x&style=plastic
194
150
  [rtd-2.0.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.0.x&style=plastic
@@ -200,6 +156,7 @@ $ poetry publish
200
156
  [not-available-docs-image]: http://img.shields.io/badge/docs-n/a-yellow.svg?style=plastic
201
157
 
202
158
  [sources-devel]: https://github.com/splintered-reality/py_trees/tree/devel
159
+ [sources-2.3.x]: https://github.com/splintered-reality/py_trees/tree/release/2.3.x
203
160
  [sources-2.2.x]: https://github.com/splintered-reality/py_trees/tree/release/2.2.x
204
161
  [sources-2.1.x]: https://github.com/splintered-reality/py_trees/tree/release/2.1.x
205
162
  [sources-2.0.x]: https://github.com/splintered-reality/py_trees/tree/release/2.0.x
@@ -210,6 +167,7 @@ $ poetry publish
210
167
  [sources-0.5.x]: https://github.com/splintered-reality/py_trees/tree/release/0.5.x
211
168
 
212
169
  [sources-devel-image]: http://img.shields.io/badge/sources-devel-blue.svg?style=plastic
170
+ [sources-2.3.x-image]: http://img.shields.io/badge/sources-2.3.x-blue.svg?style=plastic
213
171
  [sources-2.2.x-image]: http://img.shields.io/badge/sources-2.2.x-blue.svg?style=plastic
214
172
  [sources-2.1.x-image]: http://img.shields.io/badge/sources-2.1.x-blue.svg?style=plastic
215
173
  [sources-2.0.x-image]: http://img.shields.io/badge/sources-2.0.x-blue.svg?style=plastic
@@ -79,9 +79,9 @@ class Behaviour(abc.ABC):
79
79
  ) # convenience
80
80
  self.status = common.Status.INVALID
81
81
  self.iterator = self.tick()
82
- self.parent: typing.Optional[
83
- Behaviour
84
- ] = None # will get set if a behaviour is added to a composite
82
+ self.parent: typing.Optional[Behaviour] = (
83
+ None # will get set if a behaviour is added to a composite
84
+ )
85
85
  self.children: typing.List[Behaviour] = [] # only set by composite behaviours
86
86
  self.logger = logging.Logger(name)
87
87
  self.feedback_message = "" # useful for debugging, or human readable updates, but not necessary to implement
@@ -376,9 +376,11 @@ class Behaviour(abc.ABC):
376
376
  "%s.stop(%s)"
377
377
  % (
378
378
  self.__class__.__name__,
379
- "%s->%s" % (self.status, new_status)
380
- if self.status != new_status
381
- else "%s" % new_status,
379
+ (
380
+ "%s->%s" % (self.status, new_status)
381
+ if self.status != new_status
382
+ else "%s" % new_status
383
+ ),
382
384
  )
383
385
  )
384
386
  self.terminate(new_status)
@@ -16,6 +16,7 @@
16
16
  import copy
17
17
  import functools
18
18
  import operator
19
+ import random
19
20
  import typing
20
21
 
21
22
  from . import behaviour, blackboard, common, meta
@@ -736,3 +737,47 @@ class CheckBlackboardVariableValues(behaviour.Behaviour):
736
737
  "|".join(["T" if result else "F" for result in results])
737
738
  )
738
739
  return common.Status.FAILURE
740
+
741
+
742
+ class ProbabilisticBehaviour(behaviour.Behaviour):
743
+ """
744
+ Return a status based on a probability distribution. If unspecified - a uniform distribution will be used.
745
+
746
+ Args:
747
+ name: name of the behaviour
748
+ weights: 3 probabilities that correspond to returning :data:`~py_trees.common.Status.SUCCESS`,
749
+ :data:`~py_trees.common.Status.FAILURE` and :data:`~py_trees.common.Status.RUNNING` respectively.
750
+
751
+ .. note:: Probability distribution does not need to be normalised, it will be normalised internally.
752
+
753
+ Raises:
754
+ ValueError if only some probabilities are specified
755
+
756
+ """
757
+
758
+ def __init__(self, name: str, weights: typing.Optional[typing.List[float]] = None):
759
+ if weights is not None and (type(weights) is not list or len(weights) != 3):
760
+ raise ValueError(
761
+ "Either all or none of the probabilities must be specified"
762
+ )
763
+
764
+ super(ProbabilisticBehaviour, self).__init__(name=name)
765
+
766
+ self._population = [
767
+ common.Status.SUCCESS,
768
+ common.Status.FAILURE,
769
+ common.Status.RUNNING,
770
+ ]
771
+ self._weights = weights if weights is not None else [1.0, 1.0, 1.0]
772
+
773
+ def update(self) -> common.Status:
774
+ """
775
+ Return a status based on a probability distribution.
776
+
777
+ Returns:
778
+ :data:`~py_trees.common.Status.SUCCESS` with probability weights[0],
779
+ :data:`~py_trees.common.Status.FAILURE` with probability weights[1] and
780
+ :data:`~py_trees.common.Status.RUNNING` with probability weights[2].
781
+ """
782
+ self.logger.debug("%s.update()" % self.__class__.__name__)
783
+ return random.choices(self._population, self._weights, k=1)[0]
@@ -83,7 +83,7 @@ class Composite(behaviour.Behaviour, abc.ABC):
83
83
  def __init__(
84
84
  self,
85
85
  name: str,
86
- children: typing.Optional[typing.List[behaviour.Behaviour]] = None,
86
+ children: typing.Optional[typing.Sequence[behaviour.Behaviour]] = None,
87
87
  ):
88
88
  super(Composite, self).__init__(name)
89
89
  if children is not None:
@@ -381,7 +381,7 @@ class Selector(Composite):
381
381
  self,
382
382
  name: str,
383
383
  memory: bool,
384
- children: typing.Optional[typing.List[behaviour.Behaviour]] = None,
384
+ children: typing.Optional[typing.Sequence[behaviour.Behaviour]] = None,
385
385
  ):
386
386
  super(Selector, self).__init__(name, children)
387
387
  self.memory = memory
@@ -517,7 +517,7 @@ class Sequence(Composite):
517
517
  self,
518
518
  name: str,
519
519
  memory: bool,
520
- children: typing.Optional[typing.List[behaviour.Behaviour]] = None,
520
+ children: typing.Optional[typing.Sequence[behaviour.Behaviour]] = None,
521
521
  ):
522
522
  super(Sequence, self).__init__(name, children)
523
523
  self.memory = memory
@@ -647,7 +647,7 @@ class Parallel(Composite):
647
647
  self,
648
648
  name: str,
649
649
  policy: common.ParallelPolicy.Base,
650
- children: typing.Optional[typing.List[behaviour.Behaviour]] = None,
650
+ children: typing.Optional[typing.Sequence[behaviour.Behaviour]] = None,
651
651
  ):
652
652
  """
653
653
  Initialise the behaviour with name, policy and a list of children.
@@ -731,14 +731,11 @@ class Parallel(Composite):
731
731
  new_status = common.Status.SUCCESS
732
732
  self.current_child = self.children[-1]
733
733
  elif type(self.policy) is common.ParallelPolicy.SuccessOnOne:
734
- successful = [
735
- child
736
- for child in self.children
737
- if child.status == common.Status.SUCCESS
738
- ]
739
- if successful:
740
- new_status = common.Status.SUCCESS
741
- self.current_child = successful[-1]
734
+ for child in reversed(self.children):
735
+ if child.status == common.Status.SUCCESS:
736
+ new_status = common.Status.SUCCESS
737
+ self.current_child = child
738
+ break
742
739
  elif type(self.policy) is common.ParallelPolicy.SuccessOnSelected:
743
740
  if all(
744
741
  [c.status == common.Status.SUCCESS for c in self.policy.children]
@@ -431,9 +431,9 @@ class EternalGuard(Decorator):
431
431
 
432
432
  # condition check
433
433
  result = self.condition()
434
- if type(result) == common.Status:
434
+ if isinstance(result, common.Status):
435
435
  result = False if result == common.Status.FAILURE else True
436
- elif type(result) != bool:
436
+ elif not isinstance(result, bool):
437
437
  error_message = (
438
438
  "conditional check must return 'bool' or 'common.Status' [{}]".format(
439
439
  type(result)
@@ -893,3 +893,30 @@ class Condition(Decorator):
893
893
  if self.decorated.status == self.succeed_status:
894
894
  return common.Status.SUCCESS
895
895
  return common.Status.RUNNING
896
+
897
+
898
+ class PassThrough(Decorator):
899
+ """
900
+ This decorator simply reflects the child's current status.
901
+
902
+ This behaviour is useful for debugging or visualisation purposes.
903
+ """
904
+
905
+ def __init__(self, name: str, child: behaviour.Behaviour):
906
+ """
907
+ Initialise with the standard decorator arguments.
908
+
909
+ Args:
910
+ name: the decorator name
911
+ child: the child to be decorated
912
+ """
913
+ super(PassThrough, self).__init__(name=name, child=child)
914
+
915
+ def update(self) -> common.Status:
916
+ """
917
+ Just reflect the child status.
918
+
919
+ Returns:
920
+ the behaviour's new status :class:`~py_trees.common.Status`
921
+ """
922
+ return self.decorated.status
@@ -54,7 +54,7 @@ class Timer(behaviour.Behaviour):
54
54
 
55
55
  def __init__(self, name: str = "Timer", duration: float = 5.0):
56
56
  super(Timer, self).__init__(name)
57
- if not isinstance(duration, float):
57
+ if not isinstance(duration, (int, float)):
58
58
  raise TypeError(
59
59
  "Timer: duration should be int or float, but you passed in {}".format(
60
60
  type(duration)
@@ -122,7 +122,7 @@ def setup(
122
122
  signal.signal(
123
123
  _SIGNAL,
124
124
  functools.partial(
125
- signal_handler, original_signal_handler=original_signal_handler
125
+ signal_handler, original_signal_handler=original_signal_handler # type: ignore[arg-type]
126
126
  ),
127
127
  )
128
128
  try:
@@ -430,6 +430,7 @@ class BehaviourTree(object):
430
430
  self: BehaviourTree,
431
431
  period_ms: int,
432
432
  number_of_iterations: int = CONTINUOUS_TICK_TOCK,
433
+ stop_on_terminal_state: bool = False,
433
434
  pre_tick_handler: typing.Optional[
434
435
  typing.Callable[[BehaviourTree], None]
435
436
  ] = None,
@@ -440,10 +441,8 @@ class BehaviourTree(object):
440
441
  """
441
442
  Tick continuously with period as specified.
442
443
 
443
- Depending on the implementation, the
444
- period may be more or less accurate and may drift in some cases (the default
445
- implementation here merely assumes zero time in tick and sleeps for this duration
446
- of time and consequently, will drift).
444
+ Depending on the implementation, the period may be more or less accurately tracked.
445
+ For example, if your tick time is greater than the specified period, the timing will overrun.
447
446
 
448
447
  This optionally accepts some handlers that will
449
448
  be used for the duration of this tick tock (c.f. those added by
@@ -456,20 +455,28 @@ class BehaviourTree(object):
456
455
  Args:
457
456
  period_ms (:obj:`float`): sleep this much between ticks (milliseconds)
458
457
  number_of_iterations (:obj:`int`): number of iterations to tick-tock
458
+ stop_on_terminal_state (:obj: `bool`): if true, stops when the tree's status is
459
+ :data:`~py_trees.common.Status.SUCCESS` or `:data:`~py_trees.common.Status.FAILURE`.
459
460
  pre_tick_handler (:obj:`func`): function to execute before ticking
460
461
  post_tick_handler (:obj:`func`): function to execute after ticking
461
462
  """
462
463
  tick_tocks = 0
464
+ period_s = period_ms / 1000.0
463
465
  while not self.interrupt_tick_tocking and (
464
466
  tick_tocks < number_of_iterations
465
467
  or number_of_iterations == CONTINUOUS_TICK_TOCK
466
468
  ):
469
+ start_time = time.time()
467
470
  self.tick(pre_tick_handler, post_tick_handler)
468
471
  try:
469
- time.sleep(period_ms / 1000.0)
472
+ time.sleep(max(0.0, period_s + start_time - time.time()))
470
473
  except KeyboardInterrupt:
471
474
  break
472
475
  tick_tocks += 1
476
+
477
+ if stop_on_terminal_state and self.root.status != common.Status.RUNNING:
478
+ break
479
+
473
480
  self.interrupt_tick_tocking = False
474
481
 
475
482
  def tip(self) -> typing.Optional[behaviour.Behaviour]:
@@ -14,4 +14,4 @@
14
14
 
15
15
  # When changing, Also update setup.py and package.xml
16
16
  # TODO: use pkg_resources to fetch the version from setup.py
17
- __version__ = "2.2.2"
17
+ __version__ = "2.3.0"
@@ -1,9 +1,9 @@
1
1
  [tool.poetry]
2
2
  name = "py_trees"
3
- version = "2.2.2"
3
+ version = "2.3.0"
4
4
  description = "pythonic implementation of behaviour trees"
5
5
  authors = ["Daniel Stonier", "Naveed Usmani", "Michal Staniaszek"]
6
- maintainers = ["Daniel Stonier <d.stonier@gmail.com>"]
6
+ maintainers = ["Daniel Stonier <d.stonier@gmail.com>", "Sebastian Castro <sebas.a.castro@gmail.com>"]
7
7
  readme = "README.md"
8
8
  license = "BSD"
9
9
  homepage = "https://github.com/splintered-reality/py_trees"
@@ -23,14 +23,15 @@ classifiers = [
23
23
  keywords=["py_trees", "py-trees", "behaviour-trees"]
24
24
 
25
25
  [tool.poetry.dependencies]
26
- python = "^3.8"
26
+ python = ">=3.9,<4.0"
27
27
  pydot = ">=1.4"
28
+ py = "^1.11.0"
28
29
 
29
30
  [tool.poetry.group.dev.dependencies]
30
31
  tox = ">=3.26"
31
32
  tox-poetry-installer = {extras = ["poetry"], version = ">=0.9.0"}
32
33
  pytest = [
33
- { version = ">=7.1", python = "^3.7" }
34
+ { version = ">=7.1", python = ">=3.9,<4.0" }
34
35
  ]
35
36
  pytest-console-scripts = ">=1.3"
36
37
  pytest-cov = ">=3.0.0" # transitively depends on coverage[toml]
py_trees-2.2.2/setup.py DELETED
@@ -1,60 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- from setuptools import setup
3
-
4
- packages = \
5
- ['py_trees', 'py_trees.demos', 'py_trees.programs']
6
-
7
- package_data = \
8
- {'': ['*']}
9
-
10
- install_requires = \
11
- ['pydot>=1.4']
12
-
13
- entry_points = \
14
- {'console_scripts': ['py-trees-demo-action-behaviour = '
15
- 'py_trees.demos.action:main',
16
- 'py-trees-demo-behaviour-lifecycle = '
17
- 'py_trees.demos.lifecycle:main',
18
- 'py-trees-demo-blackboard = '
19
- 'py_trees.demos.blackboard:main',
20
- 'py-trees-demo-blackboard-namespaces = '
21
- 'py_trees.demos.blackboard_namespaces:main',
22
- 'py-trees-demo-blackboard-remappings = '
23
- 'py_trees.demos.blackboard_remappings:main',
24
- 'py-trees-demo-context-switching = '
25
- 'py_trees.demos.context_switching:main',
26
- 'py-trees-demo-display-modes = '
27
- 'py_trees.demos.display_modes:main',
28
- 'py-trees-demo-dot-graphs = '
29
- 'py_trees.demos.dot_graphs:main',
30
- 'py-trees-demo-either-or = py_trees.demos.either_or:main',
31
- 'py-trees-demo-eternal-guard = '
32
- 'py_trees.demos.eternal_guard:main',
33
- 'py-trees-demo-logging = py_trees.demos.logging:main',
34
- 'py-trees-demo-pick-up-where-you-left-off = '
35
- 'py_trees.demos.pick_up_where_you_left_off:main',
36
- 'py-trees-demo-selector = py_trees.demos.selector:main',
37
- 'py-trees-demo-sequence = py_trees.demos.sequence:main',
38
- 'py-trees-demo-tree-stewardship = '
39
- 'py_trees.demos.stewardship:main',
40
- 'py-trees-render = py_trees.programs.render:main']}
41
-
42
- setup_kwargs = {
43
- 'name': 'py-trees',
44
- 'version': '2.2.2',
45
- 'description': 'pythonic implementation of behaviour trees',
46
- 'long_description': "# Py Trees\n\n[[About](#about)] [[What's New?](#whats-new)] [[Documentation](#documentation)] [[Getting Started](#getting-started)] [[Next Steps](#next-steps)] [[Releases](#releases)] [[Developers](#developers)]\n\n----\n\n## About\n\nPyTrees is a python implementation of behaviour trees designed to facilitate the rapid development of medium sized decision making engines for use in fields like robotics. Brief feature list:\n\n* Behaviours, Decorators, Sequences, Selectors, Parallels and BehaviourTree.\n* Blackboards for data sharing.\n* A useful library of behaviours, decorators and idioms.\n* Serialise to a dot graph or render to ascii/unicode in a terminal.\n* Tested on Linux and Mac (YMMV with Windows).\n\n## What's New?\n\n* [2023-01-23] The [2.2.x Release][new-2.2.x] is out! Sequences and Selectors with AND without memory.\n* [2023-01-23] [Get Started](#getting-started) with py_trees in under 5mins.\n\n## Documentation\n\n[![devel][docs-devel-image]][docs-devel] [![2.2.x][docs-2.2.x-image]][docs-2.2.x] [![2.1.x][docs-2.1.x-image]][docs-2.1.x] [![0.7.x][docs-0.7.x-image]][docs-0.7.x] [![0.6.x][docs-0.6.x-image]][docs-0.6.x]\n\n## Getting Started\n\nYou can get started on CodeSpaces (with no mismatched environment issues and in under 5mins) [1]:\n\n1. Fork the project to your personal account\n2. Click on Code -> Codespaces -> + Create a Codespace\n3. Enter the Terminal\n\n```\n# Install Dependencies\n(docker) zen@py_trees:/workspaces/py_trees$ poetry install\n\n# Explore the demos\n(docker) zen@py_trees:/workspaces/py_trees$ poetry shell\n(py-trees-py3.8) (docker) zen@py_trees:/workspaces/py_trees$ py-trees-demo-<tab>-<tab>\npy-trees-demo-action-behaviour py-trees-demo-context-switching py-trees-demo-logging\npy-trees-demo-behaviour-lifecycle py-trees-demo-display-modes py-trees-demo-pick-up-where-you-left-off\npy-trees-demo-blackboard py-trees-demo-dot-graphs py-trees-demo-selector\npy-trees-demo-blackboard-namespaces py-trees-demo-either-or py-trees-demo-sequence\npy-trees-demo-blackboard-remappings py-trees-demo-eternal-guard py-trees-demo-tree-stewardship\n(py-trees-py3.8) (docker) zen@py_trees:/workspaces/py_trees$ py-trees-demo-blackboard\n...\n(py-trees-py3.8) (docker) zen@py_trees:/workspaces/py_trees$ exit\n\n# Hack some Code\n\n# Run the Formatter, Tests, Linters and Mypy\n(docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -l\npy38 py310 format check mypy38 mypy310\n(docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e format\n...\n(docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e py38\n...\n(docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e check\n...\n\n# Contribute a PR!\n# https://github.com/splintered-reality/py_trees/blob/devel/CONTRIBUTING.md\n```\n\n[1] All of the above will, of course, work in a local environment if you have `poetry` installed. If you're using `VSCode`\nyou don't even need that, just reopen the project in the [devcontainer](.devcontainer/devcontainer.json) and be froody.\n\n## Next Steps\n\nOn PyPi:\n* [py_trees](https://pypi.org/project/py-trees/)\n* [py_trees_js](https://pypi.org/project/py-trees-js/)\n\nExamples:\n* [ReadTheDocs - PyTrees ROS Tutorials](https://py-trees-ros-tutorials.readthedocs.io/en/release-2.0.x/index.html) - significantly more edifying than the demos, these incrementally walk through the process of building a decision making layer for a robot. These use ROS2 (sparsely), but merely browsing should be enlightening regardless.\n\nVisualisation:\n* [py_trees_js](https://github.com/splintered-reality/py_trees_js) - a javascript library for building your own runtime visualisation tool\n\nRobotics:\n* [py_trees_ros](https://github.com/splintered-reality/py_trees_ros) - a tree manager and behaviours designed for use specifically with `ROS2`\n* [py_trees_ros_viewer](https://github.com/splintered-reality/py_trees_ros_viewer) - a `Qt/ROS2` implementation of `py_trees_js`\n\n## Releases\n\n* `2.2.x` - Selectors, Sequences with and without memory. Improved testing and style/type checking.\n* `2.1.x` - Chooser deprecated. API housekeeping.\n* `2.0.x` - Blackboards V2!\n* `1.2.x` - Trees can now shutdown cleanly. StatusToBlackboard and EternalGuard, Visitors get finalise().\n* `1.1.x` - Fixes for setup, tick-tock, viz.\n* `1.0.x` - Behaviours, Decorators, Composites, Blackboards, Tree Management and Viz tools.\n* `0.y.x` - First open source pre-releases.\n\n| | Devel | 2.2.x | 2.1.x | 2.0.x | 1.2.x | 0.7.x | 0.6.x |\n|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n| Sources | [![devel][sources-devel-image]][sources-devel] | [![2.1.x][sources-2.2.x-image]][sources-2.2.x] | [![2.1.x][sources-2.1.x-image]][sources-2.1.x] | [![2.0.x][sources-2.0.x-image]][sources-2.0.x] | [![1.2.x][sources-1.2.x-image]][sources-1.2.x] | [![0.7.x][sources-0.7.x-image]][sources-0.7.x] | [![0.6.x][sources-0.6.x-image]][sources-0.6.x]\n| Compatibility | [![Python 3.10][python310-image]][python310-docs] [![Python 3.8][python38-image]][python38-docs] | [![Python 3.10][python310-image]][python310-docs] [![Python 3.8][python38-image]][python38-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 3.6][python36-image]][python36-docs] | [![Python 2.7][python27-image]][python27-docs]\n| CI | [![devel-Status][devel-build-status-image]][devel-build-status] | [![2.2.x-Status][2.2.x-build-status-image]][2.2.x-build-status] | - | - | - | - | - | \n| Documentation | [![devel-Docs][rtd-devel-image]][docs-devel] | [![2.2.x-Docs][rtd-2.2.x-image]][docs-2.2.x] | [![2.1.x-Docs][rtd-2.1.x-image]][docs-2.1.x] | [![2.0.x-Docs][rtd-2.0.x-image]][docs-2.0.x] | [![1.2.x-Docs][rtd-1.2.x-image]][docs-1.2.x] | [![0.7.x-Docs][rtd-0.7.x-image]][docs-0.7.x] | [![0.6.x-Docs][rtd-0.6.x-image]][docs-0.6.x]\n\n## Developers\n\n### Format, Check, MyPy, Test\n\nCheck against at least one of py38 / py310 [1].\n\n```\n# Auto-format your code (if using VSCode, install the ufmt extension)\n$ poetry run tox -e format\n\n# Style, Format\n$ poetry run tox -e check\n\n# Type-Check\n$ poetry run mypy38\n\n# Tests\n$ poetry run tox -e py38\n```\n\n[1] CI will test against both python versions for you, but should you wish to do so locally, open up two VSCode windows, one with the project opened in the default [py38 devcontainer](.devcontainer) and the other with the [py310 devcontainer](.devcontainer/py310).\n\n### Generate Documentation\n\nGenerate the docs, view them from `./docs/html` in a browser.\n\n```\n# Install dependencies\n$ poetry install --with docs\n\n# Build\n$ poetry run make -C docs html\n```\n\nOn Doc dependency changes, export the requirements for ReadTheDocs\n\n```\n$ poetry export -f requirements.txt --with docs -o docs/requirements.txt\n```\n\n### Publish to PyPi\n\nIf you have permission to publish on pypi:\n\n```\n$ poetry config http-basic.pypi ${POETRY_HTTP_BASIC_PYPI_USERNAME} ${POETRY_HTTP_BASIC_PYPI_PASSWORD}\n$ poetry publish\n```\n\n[license-image]: https://img.shields.io/badge/License-BSD%203--Clause-orange.svg?style=plastic\n[license]: LICENSE\n\n[python310-image]: https://img.shields.io/badge/python-3.10-green.svg?style=plastic\n[python310-docs]: https://docs.python.org/3.10/\n[python38-image]: https://img.shields.io/badge/python-3.8-green.svg?style=plastic\n[python38-docs]: https://docs.python.org/3.8/\n[python36-image]: https://img.shields.io/badge/python-3.6-green.svg?style=plastic\n[python36-docs]: https://docs.python.org/3.6/\n[python27-image]: https://img.shields.io/badge/python-2.7-green.svg?style=plastic\n[python27-docs]: https://docs.python.org/2.7/\n\n[devel-build-status-image]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml/badge.svg\n[devel-build-status]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml\n[2.2.x-build-status-image]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml/badge.svg??branch=release/2.2.x\n[2.2.x-build-status]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml\n\n[new-2.2.x]: https://github.com/splintered-reality/py_trees/blob/devel/CHANGELOG.rst#22x-2023-01-23---sequences-and-selectors-with-and-without-memory\n\n\n[docs-devel]: http://py-trees.readthedocs.io/\n[docs-2.2.x]: http://py-trees.readthedocs.io/en/release-2.2.x/\n[docs-2.1.x]: http://py-trees.readthedocs.io/en/release-2.1.x/\n[docs-2.0.x]: http://py-trees.readthedocs.io/en/release-2.0.x/\n[docs-1.3.x]: http://py-trees.readthedocs.io/en/release-1.3.x/\n[docs-1.2.x]: http://py-trees.readthedocs.io/en/release-1.2.x/\n[docs-0.7.x]: http://py-trees.readthedocs.io/en/release-0.7.x/\n[docs-0.6.x]: http://py-trees.readthedocs.io/en/release-0.6.x/\n[docs-0.5.x]: http://docs.ros.org/kinetic/api/py_trees/html/\n\n[docs-devel-image]: http://img.shields.io/badge/docs-devel-brightgreen.svg?style=plastic\n[docs-2.2.x-image]: http://img.shields.io/badge/docs-2.2.x-brightgreen.svg?style=plastic\n[docs-2.1.x-image]: http://img.shields.io/badge/docs-2.1.x-brightgreen.svg?style=plastic\n[docs-2.0.x-image]: http://img.shields.io/badge/docs-2.0.x-brightgreen.svg?style=plastic\n[docs-1.3.x-image]: http://img.shields.io/badge/docs-1.3.x-brightgreen.svg?style=plastic\n[docs-1.2.x-image]: http://img.shields.io/badge/docs-1.2.x-brightgreen.svg?style=plastic\n[docs-0.7.x-image]: http://img.shields.io/badge/docs-0.7.x-brightgreen.svg?style=plastic\n[docs-0.6.x-image]: http://img.shields.io/badge/docs-0.6.x-brightgreen.svg?style=plastic\n[docs-0.5.x-image]: http://img.shields.io/badge/docs-0.5.x-brightgreen.svg?style=plastic\n\n[rtd-devel-image]: https://readthedocs.org/projects/py-trees/badge/?version=devel&style=plastic\n[rtd-2.2.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.2.x&style=plastic\n[rtd-2.1.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.1.x&style=plastic\n[rtd-2.0.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.0.x&style=plastic\n[rtd-1.3.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-1.3.x&style=plastic\n[rtd-1.2.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-1.2.x&style=plastic\n[rtd-0.7.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-0.7.x&style=plastic\n[rtd-0.6.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-0.6.x&style=plastic\n[rtd-0.5.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-0.5.x&style=plastic\n[not-available-docs-image]: http://img.shields.io/badge/docs-n/a-yellow.svg?style=plastic\n\n[sources-devel]: https://github.com/splintered-reality/py_trees/tree/devel\n[sources-2.2.x]: https://github.com/splintered-reality/py_trees/tree/release/2.2.x\n[sources-2.1.x]: https://github.com/splintered-reality/py_trees/tree/release/2.1.x\n[sources-2.0.x]: https://github.com/splintered-reality/py_trees/tree/release/2.0.x\n[sources-1.3.x]: https://github.com/splintered-reality/py_trees/tree/release/1.3.x\n[sources-1.2.x]: https://github.com/splintered-reality/py_trees/tree/release/1.2.x\n[sources-0.7.x]: https://github.com/splintered-reality/py_trees/tree/release/0.7.x\n[sources-0.6.x]: https://github.com/splintered-reality/py_trees/tree/release/0.6.x\n[sources-0.5.x]: https://github.com/splintered-reality/py_trees/tree/release/0.5.x\n\n[sources-devel-image]: http://img.shields.io/badge/sources-devel-blue.svg?style=plastic\n[sources-2.2.x-image]: http://img.shields.io/badge/sources-2.2.x-blue.svg?style=plastic\n[sources-2.1.x-image]: http://img.shields.io/badge/sources-2.1.x-blue.svg?style=plastic\n[sources-2.0.x-image]: http://img.shields.io/badge/sources-2.0.x-blue.svg?style=plastic\n[sources-1.3.x-image]: http://img.shields.io/badge/sources-1.3.x-blue.svg?style=plastic\n[sources-1.2.x-image]: http://img.shields.io/badge/sources-1.2.x-blue.svg?style=plastic\n[sources-0.7.x-image]: http://img.shields.io/badge/sources-0.7.x-blue.svg?style=plastic\n[sources-0.6.x-image]: http://img.shields.io/badge/sources-0.6.x-blue.svg?style=plastic\n[sources-0.5.x-image]: http://img.shields.io/badge/sources-0.5.x-blue.svg?style=plastic\n",
47
- 'author': 'Daniel Stonier',
48
- 'author_email': 'None',
49
- 'maintainer': 'Daniel Stonier',
50
- 'maintainer_email': 'd.stonier@gmail.com',
51
- 'url': 'https://github.com/splintered-reality/py_trees',
52
- 'packages': packages,
53
- 'package_data': package_data,
54
- 'install_requires': install_requires,
55
- 'entry_points': entry_points,
56
- 'python_requires': '>=3.8,<4.0',
57
- }
58
-
59
-
60
- setup(**setup_kwargs)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes