orca-lab 25.9.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 (74) hide show
  1. orca_lab-25.9.0/LICENSE +22 -0
  2. orca_lab-25.9.0/MANIFEST.in +38 -0
  3. orca_lab-25.9.0/PKG-INFO +181 -0
  4. orca_lab-25.9.0/README.md +141 -0
  5. orca_lab-25.9.0/orca_lab.egg-info/SOURCES.txt +71 -0
  6. orca_lab-25.9.0/orcalab/__init__.py +0 -0
  7. orca_lab-25.9.0/orcalab/actor.py +146 -0
  8. orca_lab-25.9.0/orcalab/application_bus.py +17 -0
  9. orca_lab-25.9.0/orcalab/asset_service.py +50 -0
  10. orca_lab-25.9.0/orcalab/asset_service_bus.py +22 -0
  11. orca_lab-25.9.0/orcalab/asset_sync_service.py +389 -0
  12. orca_lab-25.9.0/orcalab/asset_sync_ui.py +212 -0
  13. orca_lab-25.9.0/orcalab/assets/assets.qrc +11 -0
  14. orca_lab-25.9.0/orcalab/assets/gen.py +7 -0
  15. orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_add_20_filled.svg +3 -0
  16. orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_eye_20_regular.svg +3 -0
  17. orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_eye_off_20_regular.svg +3 -0
  18. orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_filter_20_filled.svg +3 -0
  19. orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_lock_closed_20_regular.svg +3 -0
  20. orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_lock_open_20_regular.svg +3 -0
  21. orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_pause_20_filled.svg +3 -0
  22. orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_play_20_filled_green.svg +3 -0
  23. orca_lab-25.9.0/orcalab/assets/icons/ic_fluent_stop_20_filled_red.svg +3 -0
  24. orca_lab-25.9.0/orcalab/assets/rc_assets.py +302 -0
  25. orca_lab-25.9.0/orcalab/auth_service.py +242 -0
  26. orca_lab-25.9.0/orcalab/config_service.py +163 -0
  27. orca_lab-25.9.0/orcalab/copilot/__init__.py +10 -0
  28. orca_lab-25.9.0/orcalab/copilot/service.py +456 -0
  29. orca_lab-25.9.0/orcalab/event_bus.py +105 -0
  30. orca_lab-25.9.0/orcalab/local_scene.py +223 -0
  31. orca_lab-25.9.0/orcalab/math.py +334 -0
  32. orca_lab-25.9.0/orcalab/path.py +101 -0
  33. orca_lab-25.9.0/orcalab/project_util.py +152 -0
  34. orca_lab-25.9.0/orcalab/protos/__init__.py +3 -0
  35. orca_lab-25.9.0/orcalab/protos/edit_service.proto +265 -0
  36. orca_lab-25.9.0/orcalab/protos/edit_service_pb2.py +134 -0
  37. orca_lab-25.9.0/orcalab/protos/edit_service_pb2_grpc.py +1043 -0
  38. orca_lab-25.9.0/orcalab/protos/generate_proto.py +32 -0
  39. orca_lab-25.9.0/orcalab/protos/url_service.proto +21 -0
  40. orca_lab-25.9.0/orcalab/protos/url_service_pb2.py +42 -0
  41. orca_lab-25.9.0/orcalab/protos/url_service_pb2_grpc.py +97 -0
  42. orca_lab-25.9.0/orcalab/pyside_util.py +27 -0
  43. orca_lab-25.9.0/orcalab/remote_scene.py +688 -0
  44. orca_lab-25.9.0/orcalab/scene_edit_bus.py +219 -0
  45. orca_lab-25.9.0/orcalab/scene_edit_service.py +246 -0
  46. orca_lab-25.9.0/orcalab/sim_process.py +28 -0
  47. orca_lab-25.9.0/orcalab/token_storage.py +107 -0
  48. orca_lab-25.9.0/orcalab/ui/__init__.py +0 -0
  49. orca_lab-25.9.0/orcalab/ui/actor_editor.py +200 -0
  50. orca_lab-25.9.0/orcalab/ui/actor_outline.py +320 -0
  51. orca_lab-25.9.0/orcalab/ui/actor_outline_model.py +394 -0
  52. orca_lab-25.9.0/orcalab/ui/asset_browser.py +245 -0
  53. orca_lab-25.9.0/orcalab/ui/auth_window.py +191 -0
  54. orca_lab-25.9.0/orcalab/ui/copilot.py +580 -0
  55. orca_lab-25.9.0/orcalab/ui/float_edit.py +141 -0
  56. orca_lab-25.9.0/orcalab/ui/launch_dialog.py +280 -0
  57. orca_lab-25.9.0/orcalab/ui/main_window.py +883 -0
  58. orca_lab-25.9.0/orcalab/ui/rename_dialog.py +84 -0
  59. orca_lab-25.9.0/orcalab/ui/sync_progress_window.py +358 -0
  60. orca_lab-25.9.0/orcalab/ui/terminal_widget.py +308 -0
  61. orca_lab-25.9.0/orcalab/ui/tool_bar.py +43 -0
  62. orca_lab-25.9.0/orcalab/ui/transform_edit.py +131 -0
  63. orca_lab-25.9.0/orcalab/ui/viewport.py +64 -0
  64. orca_lab-25.9.0/orcalab/undo_service/command.py +90 -0
  65. orca_lab-25.9.0/orcalab/undo_service/undo_service.py +171 -0
  66. orca_lab-25.9.0/orcalab/undo_service/undo_service_bus.py +48 -0
  67. orca_lab-25.9.0/orcalab/url_service/__init__.py +0 -0
  68. orca_lab-25.9.0/orcalab/url_service/url_handler.py +57 -0
  69. orca_lab-25.9.0/orcalab/url_service/url_service.py +51 -0
  70. orca_lab-25.9.0/orcalab/url_service/url_util.py +58 -0
  71. orca_lab-25.9.0/orcalab/url_service/url_util_linux.py +74 -0
  72. orca_lab-25.9.0/orcalab/url_service/url_util_windows.py +67 -0
  73. orca_lab-25.9.0/pyproject.toml +62 -0
  74. orca_lab-25.9.0/setup.cfg +4 -0
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Shanghai Songying Technology Co.,Ltd.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,38 @@
1
+ # Include package data files
2
+ include README.md
3
+ include LICENSE
4
+ include pyproject.toml
5
+
6
+ # Include proto files
7
+ recursive-include orcalab/protos *.proto
8
+
9
+ # Include asset files
10
+ recursive-include orcalab/assets *.qrc
11
+ recursive-include orcalab/assets *.svg
12
+ recursive-include orcalab/assets *.png
13
+ recursive-include orcalab/assets *.jpg
14
+ recursive-include orcalab/assets *.jpeg
15
+
16
+ # Include configuration files
17
+ recursive-include orcalab *.toml
18
+ recursive-include orcalab *.yaml
19
+ recursive-include orcalab *.yml
20
+
21
+ # Include type hints
22
+ recursive-include orcalab *.pyi
23
+
24
+ # Exclude test files
25
+ recursive-exclude test *
26
+ recursive-exclude tests *
27
+ recursive-exclude examples *
28
+ recursive-exclude doc *
29
+ recursive-exclude docs *
30
+
31
+ # Exclude build artifacts
32
+ exclude Makefile
33
+ recursive-exclude scripts *
34
+ recursive-exclude .git *
35
+ recursive-exclude __pycache__ *
36
+ recursive-exclude *.pyc
37
+ recursive-exclude *.pyo
38
+ recursive-exclude *.egg-info *
@@ -0,0 +1,181 @@
1
+ Metadata-Version: 2.4
2
+ Name: orca-lab
3
+ Version: 25.9.0
4
+ Summary: OrcaLab - Cloud-native robotics simulation platform with advanced UI and asset management
5
+ Author-email: 松应科技 <huangwei@orca3d.cn>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/openverse-orca/OrcaLab
8
+ Project-URL: Documentation, https://github.com/openverse-orca/OrcaLab
9
+ Project-URL: Repository, https://github.com/openverse-orca/OrcaLab
10
+ Project-URL: Bug Tracker, https://github.com/openverse-orca/OrcaLab/issues
11
+ Keywords: robotics,simulation,ui,asset-management,orca,pyside
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
+ Classifier: Topic :: Software Development :: User Interfaces
19
+ Requires-Python: >=3.12
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: orca-gym
23
+ Requires-Dist: numpy>=2.0.0
24
+ Requires-Dist: scipy
25
+ Requires-Dist: scipy-stubs
26
+ Requires-Dist: grpcio==1.66.1
27
+ Requires-Dist: grpcio-tools==1.66.1
28
+ Requires-Dist: pyside6==6.9.2
29
+ Requires-Dist: aiohttp
30
+ Requires-Dist: aiofiles
31
+ Requires-Dist: qasync
32
+ Requires-Dist: psutil
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest; extra == "dev"
35
+ Requires-Dist: pytest-cov; extra == "dev"
36
+ Requires-Dist: flake8; extra == "dev"
37
+ Requires-Dist: black; extra == "dev"
38
+ Requires-Dist: mypy; extra == "dev"
39
+ Dynamic: license-file
40
+
41
+ # OrcaLab
42
+
43
+ OrcaLab is a front-end of OrcaGym. It provides a user-interface for scene assembling and simulation.
44
+
45
+ ## Features
46
+
47
+ - TODO
48
+
49
+ ## Requirements
50
+
51
+ - Python 3.12 or higher
52
+ - [OrcaGym](https://github.com/your-org/OrcaGym) (required dependency)
53
+ - Other dependencies listed in `pyproject.toml`
54
+
55
+ ## Development Requirements
56
+
57
+ For building and releasing packages, the following pip packages are required:
58
+
59
+ ### Core Build Tools
60
+ ```bash
61
+ pip install build twine wheel setuptools
62
+ ```
63
+
64
+ ### Development Tools (Optional)
65
+ ```bash
66
+ pip install pytest pytest-cov flake8 black mypy
67
+ ```
68
+
69
+ ### Make Commands and Required Packages
70
+
71
+ The project includes a `Makefile` with various commands. Here are the required packages for each command:
72
+
73
+ | Make Command | Required pip packages | Description |
74
+ |-------------|----------------------|-------------|
75
+ | `make build` | `build`, `setuptools`, `wheel` | Build distribution packages |
76
+ | `make check` | `twine` | Check package quality |
77
+ | `make test-install` | `build`, `setuptools`, `wheel` | Test local installation |
78
+ | `make test-install-testpypi` | `build`, `setuptools`, `wheel` | Test TestPyPI installation |
79
+ | `make test-install-pypi` | `build`, `setuptools`, `wheel` | Test PyPI installation |
80
+ | `make release-test` | `build`, `twine`, `setuptools`, `wheel` | Release to TestPyPI |
81
+ | `make release-prod` | `build`, `twine`, `setuptools`, `wheel` | Release to PyPI |
82
+ | `make bump-version` | None (uses sed) | Bump version number |
83
+ | `make setup-pypirc` | None | Setup PyPI configuration file |
84
+ | `make check-pypirc` | None | Check PyPI configuration |
85
+ | `make clean` | None | Clean build artifacts |
86
+ | `make test` | `pytest`, `pytest-cov` | Run tests |
87
+ | `make format` | `black` | Format code |
88
+ | `make lint` | `flake8`, `mypy` | Lint code |
89
+
90
+ ### Quick Setup for Development
91
+ ```bash
92
+ # Install development dependencies
93
+ pip install build twine wheel setuptools pytest pytest-cov flake8 black mypy
94
+
95
+ # Or install from the project's optional dependencies
96
+ pip install -e ".[dev]"
97
+ ```
98
+
99
+ ## Release Process
100
+
101
+ ### Quick Release
102
+ ```bash
103
+ # Setup PyPI configuration (first time only)
104
+ make setup-pypirc
105
+
106
+ # Release to TestPyPI
107
+ ./scripts/release/release.sh test
108
+
109
+ # Release to PyPI
110
+ ./scripts/release/release.sh prod
111
+ ```
112
+
113
+ ### Step-by-step Release
114
+ ```bash
115
+ # Clean, build, check, and upload
116
+ ./scripts/release/clean.sh
117
+ ./scripts/release/build.sh
118
+ ./scripts/release/check.sh
119
+ ./scripts/release/upload_test.sh # or upload_prod.sh
120
+ ```
121
+
122
+ ## Installation
123
+
124
+ 1. Install OrcaGym (required):
125
+ ```bash
126
+ # Please follow the OrcaGym installation instructions
127
+ ```
128
+ 2. Clone this repository and install OrcaLab in editable mode:
129
+ ```bash
130
+ # required by pyside
131
+ sudo apt install libxcb-cursor0
132
+
133
+ git clone https://github.com/openverse-orca/OrcaLab.git
134
+ cd OrcaLab
135
+ pip install -e .
136
+ ```
137
+
138
+
139
+ ## Usage
140
+
141
+ To start OrcaLab, run:
142
+
143
+ ```bash
144
+ python run.py
145
+ ```
146
+
147
+
148
+ ## Notice
149
+
150
+ - Blocking function (like QDialog.exec()) should not be called in async function directly. It will stop the async loop in a strange way. There are two ways to work around:
151
+ - wrap in `qasync.asyncWrap`
152
+ - invoke by a qt signal.
153
+
154
+ ``` python
155
+ # wrap in `qasync.asyncWrap`
156
+
157
+ async def foo():
158
+ def bloc_task():
159
+ return dialog.exec()
160
+
161
+ await asyncWrap(bloc_task)
162
+
163
+ # invoke by a qt signal
164
+
165
+ def bloc_task():
166
+ return dialog.exec()
167
+
168
+ some_signal.connect(bloc_task)
169
+
170
+ ```
171
+
172
+ ## 常见问题
173
+
174
+ ### Linux上出现 version `GLIBCXX_3.4.30' not found
175
+ conda update -c conda-forge libstdcxx-ng
176
+
177
+
178
+
179
+ ## License
180
+
181
+ This project is licensed under the terms of the [LICENSE](LICENSE) file.
@@ -0,0 +1,141 @@
1
+ # OrcaLab
2
+
3
+ OrcaLab is a front-end of OrcaGym. It provides a user-interface for scene assembling and simulation.
4
+
5
+ ## Features
6
+
7
+ - TODO
8
+
9
+ ## Requirements
10
+
11
+ - Python 3.12 or higher
12
+ - [OrcaGym](https://github.com/your-org/OrcaGym) (required dependency)
13
+ - Other dependencies listed in `pyproject.toml`
14
+
15
+ ## Development Requirements
16
+
17
+ For building and releasing packages, the following pip packages are required:
18
+
19
+ ### Core Build Tools
20
+ ```bash
21
+ pip install build twine wheel setuptools
22
+ ```
23
+
24
+ ### Development Tools (Optional)
25
+ ```bash
26
+ pip install pytest pytest-cov flake8 black mypy
27
+ ```
28
+
29
+ ### Make Commands and Required Packages
30
+
31
+ The project includes a `Makefile` with various commands. Here are the required packages for each command:
32
+
33
+ | Make Command | Required pip packages | Description |
34
+ |-------------|----------------------|-------------|
35
+ | `make build` | `build`, `setuptools`, `wheel` | Build distribution packages |
36
+ | `make check` | `twine` | Check package quality |
37
+ | `make test-install` | `build`, `setuptools`, `wheel` | Test local installation |
38
+ | `make test-install-testpypi` | `build`, `setuptools`, `wheel` | Test TestPyPI installation |
39
+ | `make test-install-pypi` | `build`, `setuptools`, `wheel` | Test PyPI installation |
40
+ | `make release-test` | `build`, `twine`, `setuptools`, `wheel` | Release to TestPyPI |
41
+ | `make release-prod` | `build`, `twine`, `setuptools`, `wheel` | Release to PyPI |
42
+ | `make bump-version` | None (uses sed) | Bump version number |
43
+ | `make setup-pypirc` | None | Setup PyPI configuration file |
44
+ | `make check-pypirc` | None | Check PyPI configuration |
45
+ | `make clean` | None | Clean build artifacts |
46
+ | `make test` | `pytest`, `pytest-cov` | Run tests |
47
+ | `make format` | `black` | Format code |
48
+ | `make lint` | `flake8`, `mypy` | Lint code |
49
+
50
+ ### Quick Setup for Development
51
+ ```bash
52
+ # Install development dependencies
53
+ pip install build twine wheel setuptools pytest pytest-cov flake8 black mypy
54
+
55
+ # Or install from the project's optional dependencies
56
+ pip install -e ".[dev]"
57
+ ```
58
+
59
+ ## Release Process
60
+
61
+ ### Quick Release
62
+ ```bash
63
+ # Setup PyPI configuration (first time only)
64
+ make setup-pypirc
65
+
66
+ # Release to TestPyPI
67
+ ./scripts/release/release.sh test
68
+
69
+ # Release to PyPI
70
+ ./scripts/release/release.sh prod
71
+ ```
72
+
73
+ ### Step-by-step Release
74
+ ```bash
75
+ # Clean, build, check, and upload
76
+ ./scripts/release/clean.sh
77
+ ./scripts/release/build.sh
78
+ ./scripts/release/check.sh
79
+ ./scripts/release/upload_test.sh # or upload_prod.sh
80
+ ```
81
+
82
+ ## Installation
83
+
84
+ 1. Install OrcaGym (required):
85
+ ```bash
86
+ # Please follow the OrcaGym installation instructions
87
+ ```
88
+ 2. Clone this repository and install OrcaLab in editable mode:
89
+ ```bash
90
+ # required by pyside
91
+ sudo apt install libxcb-cursor0
92
+
93
+ git clone https://github.com/openverse-orca/OrcaLab.git
94
+ cd OrcaLab
95
+ pip install -e .
96
+ ```
97
+
98
+
99
+ ## Usage
100
+
101
+ To start OrcaLab, run:
102
+
103
+ ```bash
104
+ python run.py
105
+ ```
106
+
107
+
108
+ ## Notice
109
+
110
+ - Blocking function (like QDialog.exec()) should not be called in async function directly. It will stop the async loop in a strange way. There are two ways to work around:
111
+ - wrap in `qasync.asyncWrap`
112
+ - invoke by a qt signal.
113
+
114
+ ``` python
115
+ # wrap in `qasync.asyncWrap`
116
+
117
+ async def foo():
118
+ def bloc_task():
119
+ return dialog.exec()
120
+
121
+ await asyncWrap(bloc_task)
122
+
123
+ # invoke by a qt signal
124
+
125
+ def bloc_task():
126
+ return dialog.exec()
127
+
128
+ some_signal.connect(bloc_task)
129
+
130
+ ```
131
+
132
+ ## 常见问题
133
+
134
+ ### Linux上出现 version `GLIBCXX_3.4.30' not found
135
+ conda update -c conda-forge libstdcxx-ng
136
+
137
+
138
+
139
+ ## License
140
+
141
+ This project is licensed under the terms of the [LICENSE](LICENSE) file.
@@ -0,0 +1,71 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ orcalab/__init__.py
6
+ orcalab/actor.py
7
+ orcalab/application_bus.py
8
+ orcalab/asset_service.py
9
+ orcalab/asset_service_bus.py
10
+ orcalab/asset_sync_service.py
11
+ orcalab/asset_sync_ui.py
12
+ orcalab/auth_service.py
13
+ orcalab/config_service.py
14
+ orcalab/event_bus.py
15
+ orcalab/local_scene.py
16
+ orcalab/math.py
17
+ orcalab/path.py
18
+ orcalab/project_util.py
19
+ orcalab/pyside_util.py
20
+ orcalab/remote_scene.py
21
+ orcalab/scene_edit_bus.py
22
+ orcalab/scene_edit_service.py
23
+ orcalab/sim_process.py
24
+ orcalab/token_storage.py
25
+ orcalab/assets/assets.qrc
26
+ orcalab/assets/gen.py
27
+ orcalab/assets/rc_assets.py
28
+ orcalab/assets/icons/ic_fluent_add_20_filled.svg
29
+ orcalab/assets/icons/ic_fluent_eye_20_regular.svg
30
+ orcalab/assets/icons/ic_fluent_eye_off_20_regular.svg
31
+ orcalab/assets/icons/ic_fluent_filter_20_filled.svg
32
+ orcalab/assets/icons/ic_fluent_lock_closed_20_regular.svg
33
+ orcalab/assets/icons/ic_fluent_lock_open_20_regular.svg
34
+ orcalab/assets/icons/ic_fluent_pause_20_filled.svg
35
+ orcalab/assets/icons/ic_fluent_play_20_filled_green.svg
36
+ orcalab/assets/icons/ic_fluent_stop_20_filled_red.svg
37
+ orcalab/copilot/__init__.py
38
+ orcalab/copilot/service.py
39
+ orcalab/protos/__init__.py
40
+ orcalab/protos/edit_service.proto
41
+ orcalab/protos/edit_service_pb2.py
42
+ orcalab/protos/edit_service_pb2_grpc.py
43
+ orcalab/protos/generate_proto.py
44
+ orcalab/protos/url_service.proto
45
+ orcalab/protos/url_service_pb2.py
46
+ orcalab/protos/url_service_pb2_grpc.py
47
+ orcalab/ui/__init__.py
48
+ orcalab/ui/actor_editor.py
49
+ orcalab/ui/actor_outline.py
50
+ orcalab/ui/actor_outline_model.py
51
+ orcalab/ui/asset_browser.py
52
+ orcalab/ui/auth_window.py
53
+ orcalab/ui/copilot.py
54
+ orcalab/ui/float_edit.py
55
+ orcalab/ui/launch_dialog.py
56
+ orcalab/ui/main_window.py
57
+ orcalab/ui/rename_dialog.py
58
+ orcalab/ui/sync_progress_window.py
59
+ orcalab/ui/terminal_widget.py
60
+ orcalab/ui/tool_bar.py
61
+ orcalab/ui/transform_edit.py
62
+ orcalab/ui/viewport.py
63
+ orcalab/undo_service/command.py
64
+ orcalab/undo_service/undo_service.py
65
+ orcalab/undo_service/undo_service_bus.py
66
+ orcalab/url_service/__init__.py
67
+ orcalab/url_service/url_handler.py
68
+ orcalab/url_service/url_service.py
69
+ orcalab/url_service/url_util.py
70
+ orcalab/url_service/url_util_linux.py
71
+ orcalab/url_service/url_util_windows.py
File without changes
@@ -0,0 +1,146 @@
1
+ from typing import List, override
2
+
3
+ from orcalab.path import Path
4
+ from orcalab.math import Transform
5
+
6
+ import copy
7
+
8
+ type ParentActor = GroupActor | None
9
+
10
+
11
+ class BaseActor:
12
+ def __init__(self, name: str, parent: ParentActor):
13
+ self._name = ""
14
+ self._parent = None
15
+ self._transform = Transform()
16
+ self._world_transform = None
17
+ self.name = name
18
+ self.parent = parent
19
+
20
+ def __repr__(self):
21
+ return f"BaseActor(name={self._name})"
22
+
23
+ @property
24
+ def name(self):
25
+ return self._name
26
+
27
+ @name.setter
28
+ def name(self, value):
29
+ if not isinstance(value, str) or not Path.is_valid_name(value):
30
+ raise ValueError(f"Invalid name: {value}")
31
+ self._name = value
32
+
33
+ @property
34
+ def parent(self) -> ParentActor:
35
+ return self._parent
36
+
37
+ @parent.setter
38
+ def parent(self, parent_actor):
39
+ if parent_actor is not None and not isinstance(parent_actor, GroupActor):
40
+ raise TypeError("parent must be an instance of GroupActor or None.")
41
+
42
+ if parent_actor == self._parent:
43
+ return
44
+
45
+ if self._parent is not None:
46
+ self._parent._children.remove(self)
47
+
48
+ if parent_actor is not None:
49
+ parent_actor._children.append(self)
50
+
51
+ self._parent = parent_actor
52
+ self._world_transform = None # Invalidate world transform cache
53
+
54
+ @property
55
+ def transform(self):
56
+ return copy.deepcopy(self._transform)
57
+
58
+ @transform.setter
59
+ def transform(self, value):
60
+ if not isinstance(value, Transform):
61
+ raise TypeError("transform must be an instance of Transform.")
62
+ self._transform = copy.deepcopy(value)
63
+
64
+ self._world_transform = None # Invalidate world transform cache
65
+
66
+ @property
67
+ def world_transform(self) -> Transform:
68
+ if self._world_transform is not None:
69
+ return self._world_transform
70
+
71
+ if self.parent is None:
72
+ self._world_transform = self.transform
73
+ else:
74
+ self._world_transform = self.parent.world_transform * self.transform
75
+
76
+ return self._world_transform
77
+
78
+ @world_transform.setter
79
+ def world_transform(self, value: Transform):
80
+ if not isinstance(value, Transform):
81
+ raise TypeError("world_transform must be an instance of Transform.")
82
+
83
+ if self.parent is None:
84
+ self.transform = value
85
+ else:
86
+ self.transform = self.parent.world_transform.inverse() * value
87
+
88
+ self._world_transform = value
89
+
90
+
91
+ class GroupActor(BaseActor):
92
+ def __init__(self, name: str, parent: ParentActor = None):
93
+ self._children: List[BaseActor] = []
94
+ super().__init__(name, parent)
95
+
96
+ def __repr__(self):
97
+ return f"GroupActor(name={self.name}, children_count={len(self._children)})"
98
+
99
+ @property
100
+ def children(self):
101
+ return self._children.copy()
102
+
103
+ def insert_child(self, index: int, child: BaseActor):
104
+ if not isinstance(child, BaseActor):
105
+ raise TypeError("Child must be an instance of GroupActor or AssetActor.")
106
+
107
+ if child in self._children:
108
+ raise ValueError(f"{child.name} is already a child of {self.name}")
109
+
110
+ if child.parent is not None:
111
+ child.parent.remove_child(child)
112
+
113
+ if index < 0 or index > len(self._children):
114
+ self._children.append(child)
115
+ else:
116
+ self._children.insert(index, child)
117
+
118
+ child._parent = self
119
+
120
+ def add_child(self, child: BaseActor):
121
+ self.insert_child(-1, child)
122
+
123
+ def remove_child(self, child: BaseActor):
124
+ if child in self._children:
125
+ self._children.remove(child)
126
+ child._parent = None
127
+ # Don't raise error if child is not in the list - this can happen during cleanup
128
+
129
+
130
+ class AssetActor(BaseActor):
131
+ def __init__(self, name: str, asset_path: str, parent: GroupActor = None):
132
+ super().__init__(name, parent)
133
+ self._asset_path = asset_path
134
+
135
+ def __repr__(self):
136
+ return f"AssetActor(name={self.name})"
137
+
138
+ @property
139
+ def asset_path(self):
140
+ return self._asset_path
141
+
142
+ @asset_path.setter
143
+ def asset_path(self, value):
144
+ if not isinstance(value, str) or len(value) == 0:
145
+ raise ValueError("asset_path name must be non-empty string")
146
+ self._asset_path = value
@@ -0,0 +1,17 @@
1
+ from orcalab.event_bus import create_event_bus
2
+ from typing import List
3
+
4
+ class ApplicationRequest:
5
+
6
+ def get_cache_folder(self, output: List[str]) -> None:
7
+ pass
8
+
9
+
10
+ ApplicationRequestBus = create_event_bus(ApplicationRequest)
11
+
12
+
13
+ class ApplicationNotification:
14
+ pass
15
+
16
+
17
+ ApplicationNotificationBus = create_event_bus(ApplicationNotification)
@@ -0,0 +1,50 @@
1
+ from datetime import datetime
2
+ from orcalab.asset_service_bus import AssetServiceRequest, AssetServiceRequestBus, AssetServiceNotificationBus
3
+ from orcalab.application_bus import ApplicationRequestBus
4
+
5
+ import aiohttp
6
+ import aiofiles
7
+
8
+ from typing import override
9
+
10
+
11
+ class AssetService(AssetServiceRequest):
12
+
13
+ def __init__(self):
14
+ super().__init__()
15
+ AssetServiceRequestBus.connect(self)
16
+
17
+ def destroy(self):
18
+ AssetServiceRequestBus.disconnect(self)
19
+
20
+ @override
21
+ async def download_asset_to_file(self, url: str, file: str) -> None:
22
+ async with aiofiles.open(file, "wb") as f:
23
+ async with aiohttp.ClientSession() as session:
24
+ async with session.get(url) as response:
25
+ if response.status != 200:
26
+ raise Exception(
27
+ f"Failed to download asset. Status code: {response.status}"
28
+ )
29
+ data = await response.read()
30
+ await f.write(data)
31
+
32
+ @override
33
+ async def download_asset_to_cache(self, url: str) -> None:
34
+ cache_folder = []
35
+ ApplicationRequestBus().get_cache_folder(cache_folder)
36
+
37
+ if len(cache_folder) == 0:
38
+ raise Exception("Cache folder is not set.")
39
+
40
+ cache_folder: str = cache_folder[0]
41
+
42
+ # name file with time and date.
43
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
44
+ filename = f"asset_{timestamp}.pak"
45
+
46
+ file_path = cache_folder + "/" + filename
47
+
48
+ await self.download_asset_to_file(url, file_path)
49
+
50
+ await AssetServiceNotificationBus().on_asset_downloaded(file_path)
@@ -0,0 +1,22 @@
1
+ from orcalab.event_bus import create_event_bus
2
+
3
+
4
+ class AssetServiceRequest:
5
+
6
+ async def download_asset_to_file(self, url: str, file: str) -> None:
7
+ pass
8
+
9
+ async def download_asset_to_cache(self, url: str) -> None:
10
+ pass
11
+
12
+
13
+ AssetServiceRequestBus = create_event_bus(AssetServiceRequest)
14
+
15
+
16
+ class AssetServiceNotification:
17
+
18
+ async def on_asset_downloaded(self, file: str) -> None:
19
+ pass
20
+
21
+
22
+ AssetServiceNotificationBus = create_event_bus(AssetServiceNotification)