py-trees 2.2.3__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.3 → py_trees-2.3.0}/PKG-INFO +41 -83
  2. {py_trees-2.2.3 → py_trees-2.3.0}/README.md +33 -77
  3. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/behaviour.py +8 -6
  4. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/behaviours.py +45 -0
  5. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/composites.py +9 -12
  6. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/decorators.py +2 -2
  7. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/timers.py +1 -1
  8. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/trees.py +13 -6
  9. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/version.py +1 -1
  10. {py_trees-2.2.3 → py_trees-2.3.0}/pyproject.toml +5 -4
  11. py_trees-2.2.3/setup.py +0 -60
  12. {py_trees-2.2.3 → py_trees-2.3.0}/LICENSE +0 -0
  13. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/__init__.py +0 -0
  14. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/blackboard.py +0 -0
  15. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/common.py +0 -0
  16. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/console.py +0 -0
  17. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/README.md +0 -0
  18. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/__init__.py +0 -0
  19. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/action.py +0 -0
  20. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/blackboard.py +0 -0
  21. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/blackboard_namespaces.py +0 -0
  22. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/blackboard_remappings.py +0 -0
  23. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/context_switching.py +0 -0
  24. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/display_modes.py +0 -0
  25. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/dot_graphs.py +0 -0
  26. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/either_or.py +0 -0
  27. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/eternal_guard.py +0 -0
  28. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/lifecycle.py +0 -0
  29. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/logging.py +0 -0
  30. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/pick_up_where_you_left_off.py +0 -0
  31. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/selector.py +0 -0
  32. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/sequence.py +0 -0
  33. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/demos/stewardship.py +0 -0
  34. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/display.py +0 -0
  35. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/idioms.py +0 -0
  36. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/logging.py +0 -0
  37. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/meta.py +0 -0
  38. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/programs/__init__.py +0 -0
  39. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/programs/render.py +0 -0
  40. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/py.typed +0 -0
  41. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/syntax_highlighting.py +0 -0
  42. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/tests.py +0 -0
  43. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/utilities.py +0 -0
  44. {py_trees-2.2.3 → py_trees-2.3.0}/py_trees/visitors.py +0 -0
@@ -1,61 +1,62 @@
1
- Metadata-Version: 2.1
2
- Name: py-trees
3
- Version: 2.2.3
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-28] The [2.2.x Release][new-2.2.x] is out! Sequences and Selectors with AND without memory.
48
- * [2023-01-28] [Get Started](#getting-started) with py_trees in under 5mins.
49
- * [2023-01-28] This is now a `poetry` project with configuration governed by `pyproject.toml`.
50
- * The vestigial `setup.py` is only to assist distribution where [PEP-517](https://peps.python.org/pep-0517/) is not yet well supported.
51
+ * [2025-01-11] Support for Python 3.12 was added, and Python 3.8 was dropped.
51
52
 
52
53
  ## Documentation
53
54
 
54
- [![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]
55
56
 
56
57
  ## Getting Started
57
58
 
58
- 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]:
59
60
 
60
61
  1. Fork the project to your personal account
61
62
  2. Click on Code -> Codespaces -> + Create a Codespace
@@ -67,24 +68,24 @@ You can get started on CodeSpaces (with no mismatched environment issues and in
67
68
 
68
69
  # Explore the demos
69
70
  (docker) zen@py_trees:/workspaces/py_trees$ poetry shell
70
- (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>
71
72
  py-trees-demo-action-behaviour py-trees-demo-context-switching py-trees-demo-logging
72
73
  py-trees-demo-behaviour-lifecycle py-trees-demo-display-modes py-trees-demo-pick-up-where-you-left-off
73
74
  py-trees-demo-blackboard py-trees-demo-dot-graphs py-trees-demo-selector
74
75
  py-trees-demo-blackboard-namespaces py-trees-demo-either-or py-trees-demo-sequence
75
76
  py-trees-demo-blackboard-remappings py-trees-demo-eternal-guard py-trees-demo-tree-stewardship
76
- (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
77
78
  ...
78
- (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
79
80
 
80
81
  # Hack some Code
81
82
 
82
83
  # Run the Formatter, Tests, Linters and Mypy
83
84
  (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -l
84
- py38 py310 format check mypy38 mypy310
85
+ py310 py312 format check mypy310 mypy312
85
86
  (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e format
86
87
  ...
87
- (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
88
89
  ...
89
90
  (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e check
90
91
  ...
@@ -93,8 +94,8 @@ py38 py310 format check mypy38 mypy310
93
94
  # https://github.com/splintered-reality/py_trees/blob/devel/CONTRIBUTING.md
94
95
  ```
95
96
 
96
- [1] All of the above will, of course, work in a local environment if you have `poetry` installed. If you're using `VSCode`
97
- 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.
98
99
 
99
100
  ## Next Steps
100
101
 
@@ -103,7 +104,7 @@ On PyPi:
103
104
  * [py_trees_js](https://pypi.org/project/py-trees-js/)
104
105
 
105
106
  Examples:
106
- * [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.
107
108
 
108
109
  Visualisation:
109
110
  * [py_trees_js](https://github.com/splintered-reality/py_trees_js) - a javascript library for building your own runtime visualisation tool
@@ -114,6 +115,7 @@ Robotics:
114
115
 
115
116
  ## Releases
116
117
 
118
+ * `2.3.x` - Support for Python 3.12 was added, and Python 3.8 was dropped.
117
119
  * `2.2.x` - Selectors, Sequences with and without memory. Improved testing and style/type checking.
118
120
  * `2.1.x` - Chooser deprecated. API housekeeping.
119
121
  * `2.0.x` - Blackboards V2!
@@ -122,83 +124,35 @@ Robotics:
122
124
  * `1.0.x` - Behaviours, Decorators, Composites, Blackboards, Tree Management and Viz tools.
123
125
  * `0.y.x` - First open source pre-releases.
124
126
 
125
- | | Devel | 2.2.x | 2.1.x | 2.0.x | 1.2.x | 0.7.x | 0.6.x |
126
- |:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
127
- | 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]
128
- | 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]
129
- | 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] | - | - | - | - | - |
130
- | 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]
131
-
132
- ## Developers
133
-
134
- ### Format, Check, MyPy, Test
135
-
136
- Check against at least one of py38 / py310 [1].
137
-
138
- ```
139
- # Auto-format your code (if using VSCode, install the ufmt extension)
140
- $ poetry run tox -e format
141
-
142
- # Style, Format
143
- $ 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] |
144
133
 
145
- # Type-Check
146
- $ poetry run mypy38
147
-
148
- # Tests
149
- $ poetry run tox -e py38
150
- ```
151
-
152
- [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).
153
-
154
- ### Generate Documentation
155
-
156
- Generate the docs, view them from `./docs/html` in a browser.
157
-
158
- ```
159
- # Install dependencies
160
- $ poetry install --with docs
161
-
162
- # Build
163
- $ poetry run make -C docs html
164
- ```
165
-
166
- On Doc dependency changes, export the requirements for ReadTheDocs
167
-
168
- ```
169
- $ poetry export -f requirements.txt --with docs -o docs/requirements.txt
170
- ```
171
-
172
- ### Publish to PyPi
173
-
174
- If you have permission to publish on pypi:
175
-
176
- ```
177
- $ poetry config http-basic.pypi ${POETRY_HTTP_BASIC_PYPI_USERNAME} ${POETRY_HTTP_BASIC_PYPI_PASSWORD}
178
- $ poetry publish
179
- ```
180
134
 
181
135
  [license-image]: https://img.shields.io/badge/License-BSD%203--Clause-orange.svg?style=plastic
182
136
  [license]: LICENSE
183
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/
184
140
  [python310-image]: https://img.shields.io/badge/python-3.10-green.svg?style=plastic
185
141
  [python310-docs]: https://docs.python.org/3.10/
186
142
  [python38-image]: https://img.shields.io/badge/python-3.8-green.svg?style=plastic
187
143
  [python38-docs]: https://docs.python.org/3.8/
188
144
  [python36-image]: https://img.shields.io/badge/python-3.6-green.svg?style=plastic
189
145
  [python36-docs]: https://docs.python.org/3.6/
190
- [python27-image]: https://img.shields.io/badge/python-2.7-green.svg?style=plastic
191
- [python27-docs]: https://docs.python.org/2.7/
192
146
 
193
147
  [devel-build-status-image]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml/badge.svg
194
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
195
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
196
152
  [2.2.x-build-status]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml
197
153
 
198
- [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
199
-
200
-
201
154
  [docs-devel]: http://py-trees.readthedocs.io/
155
+ [docs-2.3.x]: http://py-trees.readthedocs.io/en/release-2.3.x/
202
156
  [docs-2.2.x]: http://py-trees.readthedocs.io/en/release-2.2.x/
203
157
  [docs-2.1.x]: http://py-trees.readthedocs.io/en/release-2.1.x/
204
158
  [docs-2.0.x]: http://py-trees.readthedocs.io/en/release-2.0.x/
@@ -209,6 +163,7 @@ $ poetry publish
209
163
  [docs-0.5.x]: http://docs.ros.org/kinetic/api/py_trees/html/
210
164
 
211
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
212
167
  [docs-2.2.x-image]: http://img.shields.io/badge/docs-2.2.x-brightgreen.svg?style=plastic
213
168
  [docs-2.1.x-image]: http://img.shields.io/badge/docs-2.1.x-brightgreen.svg?style=plastic
214
169
  [docs-2.0.x-image]: http://img.shields.io/badge/docs-2.0.x-brightgreen.svg?style=plastic
@@ -219,6 +174,7 @@ $ poetry publish
219
174
  [docs-0.5.x-image]: http://img.shields.io/badge/docs-0.5.x-brightgreen.svg?style=plastic
220
175
 
221
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
222
178
  [rtd-2.2.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.2.x&style=plastic
223
179
  [rtd-2.1.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.1.x&style=plastic
224
180
  [rtd-2.0.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.0.x&style=plastic
@@ -230,6 +186,7 @@ $ poetry publish
230
186
  [not-available-docs-image]: http://img.shields.io/badge/docs-n/a-yellow.svg?style=plastic
231
187
 
232
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
233
190
  [sources-2.2.x]: https://github.com/splintered-reality/py_trees/tree/release/2.2.x
234
191
  [sources-2.1.x]: https://github.com/splintered-reality/py_trees/tree/release/2.1.x
235
192
  [sources-2.0.x]: https://github.com/splintered-reality/py_trees/tree/release/2.0.x
@@ -240,6 +197,7 @@ $ poetry publish
240
197
  [sources-0.5.x]: https://github.com/splintered-reality/py_trees/tree/release/0.5.x
241
198
 
242
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
243
201
  [sources-2.2.x-image]: http://img.shields.io/badge/sources-2.2.x-blue.svg?style=plastic
244
202
  [sources-2.1.x-image]: http://img.shields.io/badge/sources-2.1.x-blue.svg?style=plastic
245
203
  [sources-2.0.x-image]: http://img.shields.io/badge/sources-2.0.x-blue.svg?style=plastic
@@ -1,33 +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-28] The [2.2.x Release][new-2.2.x] is out! Sequences and Selectors with AND without memory.
20
- * [2023-01-28] [Get Started](#getting-started) with py_trees in under 5mins.
21
- * [2023-01-28] This is now a `poetry` project with configuration governed by `pyproject.toml`.
22
- * The vestigial `setup.py` is only to assist distribution where [PEP-517](https://peps.python.org/pep-0517/) is not yet well supported.
21
+ * [2025-01-11] Support for Python 3.12 was added, and Python 3.8 was dropped.
23
22
 
24
23
  ## Documentation
25
24
 
26
- [![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]
27
26
 
28
27
  ## Getting Started
29
28
 
30
- 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]:
31
30
 
32
31
  1. Fork the project to your personal account
33
32
  2. Click on Code -> Codespaces -> + Create a Codespace
@@ -39,24 +38,24 @@ You can get started on CodeSpaces (with no mismatched environment issues and in
39
38
 
40
39
  # Explore the demos
41
40
  (docker) zen@py_trees:/workspaces/py_trees$ poetry shell
42
- (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>
43
42
  py-trees-demo-action-behaviour py-trees-demo-context-switching py-trees-demo-logging
44
43
  py-trees-demo-behaviour-lifecycle py-trees-demo-display-modes py-trees-demo-pick-up-where-you-left-off
45
44
  py-trees-demo-blackboard py-trees-demo-dot-graphs py-trees-demo-selector
46
45
  py-trees-demo-blackboard-namespaces py-trees-demo-either-or py-trees-demo-sequence
47
46
  py-trees-demo-blackboard-remappings py-trees-demo-eternal-guard py-trees-demo-tree-stewardship
48
- (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
49
48
  ...
50
- (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
51
50
 
52
51
  # Hack some Code
53
52
 
54
53
  # Run the Formatter, Tests, Linters and Mypy
55
54
  (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -l
56
- py38 py310 format check mypy38 mypy310
55
+ py310 py312 format check mypy310 mypy312
57
56
  (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e format
58
57
  ...
59
- (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
60
59
  ...
61
60
  (docker) zen@py_trees:/workspaces/py_trees$ poetry run tox -e check
62
61
  ...
@@ -65,8 +64,8 @@ py38 py310 format check mypy38 mypy310
65
64
  # https://github.com/splintered-reality/py_trees/blob/devel/CONTRIBUTING.md
66
65
  ```
67
66
 
68
- [1] All of the above will, of course, work in a local environment if you have `poetry` installed. If you're using `VSCode`
69
- 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.
70
69
 
71
70
  ## Next Steps
72
71
 
@@ -75,7 +74,7 @@ On PyPi:
75
74
  * [py_trees_js](https://pypi.org/project/py-trees-js/)
76
75
 
77
76
  Examples:
78
- * [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.
79
78
 
80
79
  Visualisation:
81
80
  * [py_trees_js](https://github.com/splintered-reality/py_trees_js) - a javascript library for building your own runtime visualisation tool
@@ -86,6 +85,7 @@ Robotics:
86
85
 
87
86
  ## Releases
88
87
 
88
+ * `2.3.x` - Support for Python 3.12 was added, and Python 3.8 was dropped.
89
89
  * `2.2.x` - Selectors, Sequences with and without memory. Improved testing and style/type checking.
90
90
  * `2.1.x` - Chooser deprecated. API housekeeping.
91
91
  * `2.0.x` - Blackboards V2!
@@ -94,83 +94,35 @@ Robotics:
94
94
  * `1.0.x` - Behaviours, Decorators, Composites, Blackboards, Tree Management and Viz tools.
95
95
  * `0.y.x` - First open source pre-releases.
96
96
 
97
- | | Devel | 2.2.x | 2.1.x | 2.0.x | 1.2.x | 0.7.x | 0.6.x |
98
- |:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
99
- | 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]
100
- | 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]
101
- | 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] | - | - | - | - | - |
102
- | 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]
103
-
104
- ## Developers
105
-
106
- ### Format, Check, MyPy, Test
107
-
108
- Check against at least one of py38 / py310 [1].
109
-
110
- ```
111
- # Auto-format your code (if using VSCode, install the ufmt extension)
112
- $ poetry run tox -e format
113
-
114
- # Style, Format
115
- $ 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] |
116
103
 
117
- # Type-Check
118
- $ poetry run mypy38
119
-
120
- # Tests
121
- $ poetry run tox -e py38
122
- ```
123
-
124
- [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).
125
-
126
- ### Generate Documentation
127
-
128
- Generate the docs, view them from `./docs/html` in a browser.
129
-
130
- ```
131
- # Install dependencies
132
- $ poetry install --with docs
133
-
134
- # Build
135
- $ poetry run make -C docs html
136
- ```
137
-
138
- On Doc dependency changes, export the requirements for ReadTheDocs
139
-
140
- ```
141
- $ poetry export -f requirements.txt --with docs -o docs/requirements.txt
142
- ```
143
-
144
- ### Publish to PyPi
145
-
146
- If you have permission to publish on pypi:
147
-
148
- ```
149
- $ poetry config http-basic.pypi ${POETRY_HTTP_BASIC_PYPI_USERNAME} ${POETRY_HTTP_BASIC_PYPI_PASSWORD}
150
- $ poetry publish
151
- ```
152
104
 
153
105
  [license-image]: https://img.shields.io/badge/License-BSD%203--Clause-orange.svg?style=plastic
154
106
  [license]: LICENSE
155
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/
156
110
  [python310-image]: https://img.shields.io/badge/python-3.10-green.svg?style=plastic
157
111
  [python310-docs]: https://docs.python.org/3.10/
158
112
  [python38-image]: https://img.shields.io/badge/python-3.8-green.svg?style=plastic
159
113
  [python38-docs]: https://docs.python.org/3.8/
160
114
  [python36-image]: https://img.shields.io/badge/python-3.6-green.svg?style=plastic
161
115
  [python36-docs]: https://docs.python.org/3.6/
162
- [python27-image]: https://img.shields.io/badge/python-2.7-green.svg?style=plastic
163
- [python27-docs]: https://docs.python.org/2.7/
164
116
 
165
117
  [devel-build-status-image]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml/badge.svg
166
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
167
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
168
122
  [2.2.x-build-status]: https://github.com/splintered-reality/py_trees/actions/workflows/pre-merge.yaml
169
123
 
170
- [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
171
-
172
-
173
124
  [docs-devel]: http://py-trees.readthedocs.io/
125
+ [docs-2.3.x]: http://py-trees.readthedocs.io/en/release-2.3.x/
174
126
  [docs-2.2.x]: http://py-trees.readthedocs.io/en/release-2.2.x/
175
127
  [docs-2.1.x]: http://py-trees.readthedocs.io/en/release-2.1.x/
176
128
  [docs-2.0.x]: http://py-trees.readthedocs.io/en/release-2.0.x/
@@ -181,6 +133,7 @@ $ poetry publish
181
133
  [docs-0.5.x]: http://docs.ros.org/kinetic/api/py_trees/html/
182
134
 
183
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
184
137
  [docs-2.2.x-image]: http://img.shields.io/badge/docs-2.2.x-brightgreen.svg?style=plastic
185
138
  [docs-2.1.x-image]: http://img.shields.io/badge/docs-2.1.x-brightgreen.svg?style=plastic
186
139
  [docs-2.0.x-image]: http://img.shields.io/badge/docs-2.0.x-brightgreen.svg?style=plastic
@@ -191,6 +144,7 @@ $ poetry publish
191
144
  [docs-0.5.x-image]: http://img.shields.io/badge/docs-0.5.x-brightgreen.svg?style=plastic
192
145
 
193
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
194
148
  [rtd-2.2.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.2.x&style=plastic
195
149
  [rtd-2.1.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.1.x&style=plastic
196
150
  [rtd-2.0.x-image]: https://readthedocs.org/projects/py-trees/badge/?version=release-2.0.x&style=plastic
@@ -202,6 +156,7 @@ $ poetry publish
202
156
  [not-available-docs-image]: http://img.shields.io/badge/docs-n/a-yellow.svg?style=plastic
203
157
 
204
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
205
160
  [sources-2.2.x]: https://github.com/splintered-reality/py_trees/tree/release/2.2.x
206
161
  [sources-2.1.x]: https://github.com/splintered-reality/py_trees/tree/release/2.1.x
207
162
  [sources-2.0.x]: https://github.com/splintered-reality/py_trees/tree/release/2.0.x
@@ -212,6 +167,7 @@ $ poetry publish
212
167
  [sources-0.5.x]: https://github.com/splintered-reality/py_trees/tree/release/0.5.x
213
168
 
214
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
215
171
  [sources-2.2.x-image]: http://img.shields.io/badge/sources-2.2.x-blue.svg?style=plastic
216
172
  [sources-2.1.x-image]: http://img.shields.io/badge/sources-2.1.x-blue.svg?style=plastic
217
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)
@@ -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.3"
17
+ __version__ = "2.3.0"
@@ -1,9 +1,9 @@
1
1
  [tool.poetry]
2
2
  name = "py_trees"
3
- version = "2.2.3"
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.3/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.3',
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-28] The [2.2.x Release][new-2.2.x] is out! Sequences and Selectors with AND without memory.\n* [2023-01-28] [Get Started](#getting-started) with py_trees in under 5mins.\n* [2023-01-28] This is now a `poetry` project with configuration governed by `pyproject.toml`.\n * The vestigial `setup.py` is only to assist distribution where [PEP-517](https://peps.python.org/pep-0517/) is not yet well supported.\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