unitelabs-cdk 0.2.7__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 (96) hide show
  1. unitelabs_cdk-0.2.7/LICENSE +21 -0
  2. unitelabs_cdk-0.2.7/PKG-INFO +88 -0
  3. unitelabs_cdk-0.2.7/README.md +54 -0
  4. unitelabs_cdk-0.2.7/pyproject.toml +79 -0
  5. unitelabs_cdk-0.2.7/src/unitelabs/cdk/__init__.py +9 -0
  6. unitelabs_cdk-0.2.7/src/unitelabs/cdk/cli/__init__.py +4 -0
  7. unitelabs_cdk-0.2.7/src/unitelabs/cdk/cli/certificate.py +53 -0
  8. unitelabs_cdk-0.2.7/src/unitelabs/cdk/cli/connector.py +113 -0
  9. unitelabs_cdk-0.2.7/src/unitelabs/cdk/compose_app.py +147 -0
  10. unitelabs_cdk-0.2.7/src/unitelabs/cdk/config.py +13 -0
  11. unitelabs_cdk-0.2.7/src/unitelabs/cdk/connector.py +126 -0
  12. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/core/lock_controller/LockController-v2_0.proto +67 -0
  13. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/core/lock_controller/LockController-v2_0.sila.xml +134 -0
  14. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/core/lock_controller/__init__.py +15 -0
  15. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/core/lock_controller/lock_controller.py +111 -0
  16. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/core/lock_controller/lock_controller_base.py +83 -0
  17. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/core/sila_service/SiLAService-v1_0.proto +130 -0
  18. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/core/sila_service/SiLAService-v1_0.sila.xml +225 -0
  19. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/core/sila_service/__init__.py +3 -0
  20. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/core/sila_service/sila_service.py +146 -0
  21. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/core/simulation_controller/SimulationController-v1_0.sila.xml +76 -0
  22. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/core/simulation_controller/__init__.py +3 -0
  23. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/core/simulation_controller/simulation_controller_base.py +89 -0
  24. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/examples/greeting_provider/__init__.py +3 -0
  25. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/examples/greeting_provider/greeting_provider_base.py +34 -0
  26. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/examples/timer_provider/__init__.py +3 -0
  27. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/examples/timer_provider/timer_provider_base.py +59 -0
  28. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/robot/grip_controller/GripController-v1_0.proto +27 -0
  29. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/robot/grip_controller/GripController-v1_0.sila.xml +21 -0
  30. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/robot/grip_controller/__init__.py +3 -0
  31. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/robot/grip_controller/grip_controller_base.py +27 -0
  32. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/robot/labware_transfer_manipulator_controller/LabwareTransferManipulatorController-v1_0.proto +122 -0
  33. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/robot/labware_transfer_manipulator_controller/LabwareTransferManipulatorController-v1_0.sila.xml +333 -0
  34. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/robot/labware_transfer_manipulator_controller/__init__.py +17 -0
  35. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/robot/labware_transfer_manipulator_controller/labware_transfer_manipulator_controller_base.py +226 -0
  36. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/robot/movement_controller/MovementController-v1_0.proto +62 -0
  37. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/robot/movement_controller/MovementController-v1_0.sila.xml +94 -0
  38. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/robot/movement_controller/__init__.py +3 -0
  39. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/robot/movement_controller/movement_controller_base.py +69 -0
  40. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/basic_data_types_test/BasicDataTypesTest-v1_0.proto +170 -0
  41. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/basic_data_types_test/BasicDataTypesTest-v1_0.sila.xml +242 -0
  42. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/basic_data_types_test/__init__.py +3 -0
  43. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/basic_data_types_test/basic_data_types_test.py +158 -0
  44. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/error_handling_test/ErrorHandlingTest-v1_0.proto +123 -0
  45. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/error_handling_test/ErrorHandlingTest-v1_0.sila.xml +108 -0
  46. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/error_handling_test/__init__.py +3 -0
  47. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/error_handling_test/error_handling_test.py +102 -0
  48. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/list_data_type_test/ListDataTypeTest-v1_0.sila.xml +262 -0
  49. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/list_data_type_test/__init__.py +3 -0
  50. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/list_data_type_test/list_data_type_test.py +208 -0
  51. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/observable_command_test/ObservableCommandTest-v1_0.proto +49 -0
  52. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/observable_command_test/ObservableCommandTest-v1_0.sila.xml +74 -0
  53. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/observable_command_test/__init__.py +3 -0
  54. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/observable_command_test/observable_command_test.py +66 -0
  55. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/observable_property_test/ObservablePropertyTest-v1_0.proto +53 -0
  56. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/observable_property_test/ObservablePropertyTest-v1_0.sila.xml +52 -0
  57. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/observable_property_test/__init__.py +3 -0
  58. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/observable_property_test/observable_property_test.py +56 -0
  59. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/structure_data_type_test/StructureDataTypeTest-v1_0.sila.xml +256 -0
  60. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/structure_data_type_test/__init__.py +3 -0
  61. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/structure_data_type_test/structure_data_type_test.py +181 -0
  62. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/unobservable_command_test/UnobservableCommandTest-v1_0.proto +57 -0
  63. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/unobservable_command_test/UnobservableCommandTest-v1_0.sila.xml +110 -0
  64. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/unobservable_command_test/__init__.py +3 -0
  65. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/unobservable_command_test/unobservable_command_test.py +54 -0
  66. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/unobservable_property_test/UnobservablePropertyTest-v1_0.proto +31 -0
  67. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/unobservable_property_test/UnobservablePropertyTest-v1_0.sila.xml +27 -0
  68. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/unobservable_property_test/__init__.py +3 -0
  69. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/test/unobservable_property_test/unobservable_property_test.py +24 -0
  70. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/weighing/weighing_service/WeighingService-v1_0.proto +105 -0
  71. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/weighing/weighing_service/WeighingService-v1_0.sila.xml +249 -0
  72. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/weighing/weighing_service/__init__.py +3 -0
  73. unitelabs_cdk-0.2.7/src/unitelabs/cdk/features/weighing/weighing_service/weighing_service_base.py +97 -0
  74. unitelabs_cdk-0.2.7/src/unitelabs/cdk/logging.py +23 -0
  75. unitelabs_cdk-0.2.7/src/unitelabs/cdk/py.typed +0 -0
  76. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/__init__.py +40 -0
  77. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/commands/__init__.py +14 -0
  78. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/commands/decorator.py +107 -0
  79. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/commands/intermediate.py +16 -0
  80. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/commands/intermediate_responses.py +101 -0
  81. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/commands/parameters.py +132 -0
  82. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/commands/responses.py +95 -0
  83. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/commands/status.py +24 -0
  84. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/data_types/__init__.py +44 -0
  85. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/data_types/custom_data_type.py +22 -0
  86. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/data_types/data_type_definition.py +38 -0
  87. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/data_types/parser.py +98 -0
  88. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/defined_execution_error.py +38 -0
  89. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/feature.py +32 -0
  90. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/metadata.py +19 -0
  91. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/observable_command.py +111 -0
  92. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/observable_property.py +83 -0
  93. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/unobservable_command.py +100 -0
  94. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/unobservable_property.py +71 -0
  95. unitelabs_cdk-0.2.7/src/unitelabs/cdk/sila/utils.py +75 -0
  96. unitelabs_cdk-0.2.7/src/unitelabs/cdk/utils.py +117 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 UniteLabs
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.
@@ -0,0 +1,88 @@
1
+ Metadata-Version: 2.1
2
+ Name: unitelabs-cdk
3
+ Version: 0.2.7
4
+ Summary: A framework to develop UniteLabs connectors based on the SiLA 2 standard specification.
5
+ Home-page: https://unitelabs.io
6
+ License: MIT
7
+ Keywords: UniteLabs,SiLA 2,laboratory,automation,connectivity
8
+ Author: UniteLabs
9
+ Author-email: developers+cdk@unitelabs.io
10
+ Requires-Python: >=3.9,<4.0
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Healthcare Industry
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3 :: Only
24
+ Classifier: Topic :: Software Development :: Libraries
25
+ Requires-Dist: click (==8.1.7)
26
+ Requires-Dist: pydantic_settings (==2.1.0)
27
+ Requires-Dist: python-dotenv (==1.0.1)
28
+ Requires-Dist: unitelabs-sila (==0.1.5)
29
+ Project-URL: Bug Tracker, https://gitlab.com/unitelabs/dev-tools/python-cdk/-/issues
30
+ Project-URL: Documentation, https://gitlab.com/unitelabs/dev-tools/python-cdk/-/tree/main/docs/
31
+ Project-URL: Repository, https://gitlab.com/unitelabs/dev-tools/python-cdk
32
+ Description-Content-Type: text/markdown
33
+
34
+ # UniteLabs Connector Framework
35
+
36
+ The UniteLabs Connector Framework is a free and open-source framework that enables you to build connectors for
37
+ laboratory hard- and software systems with interfaces that are based on industry standards like
38
+ [SiLA 2](https://sila-standard.com). If you plan on implementing an interface natively for your device or as wrapper
39
+ around an existing proprietary interface, you can use this framework to get it built quickly without deep-diving into
40
+ the standard specifications with our intuitive, code-first approach. It provides configurable modules you can use to
41
+ quickly integrate the hardware or software you want to connect.
42
+
43
+ ## Installation
44
+
45
+ [<img src="https://img.shields.io/badge/python-≥3.9.2-0052FF.svg?logo=LOGO&amp;labelColor=090422">](LINK)
46
+ [<img src="https://img.shields.io/badge/poetry-≥1.3.1-0052FF.svg?logo=LOGO&amp;labelColor=090422">](LINK)
47
+
48
+ The UniteLabs Connector Framework requires Python 3.9 or later. To get started quickly, we recommend to clone one of the
49
+ starter projects with:
50
+
51
+ ```
52
+ $ git clone --depth 1 https://gitlab.com/unitelabs/connector-starter.git <my-connector-name>
53
+ $ cd <my-connector-name>
54
+ $ poetry install
55
+ $ poetry run connector start
56
+ ```
57
+
58
+ You can also manually create a new project from scratch and [install the framework](docs/1.get-started/2.installation.md)
59
+ with pip. In this case, of course, you'll be responsible for creating the project boilerplate files yourself.
60
+
61
+ ```
62
+ $ pip install unitelabs-connector-framework
63
+ ```
64
+
65
+ ## Documentation
66
+
67
+ Explor the UniteLabs [Connector Development Kit documentation](https://docs-unitelabs-web-815d69b03b66df4c3a4817af38d7e7b09a17f7c4b50b.gitlab.io/connectivity/overview)
68
+ on our docs page. From there you can find your way to the tutorials and guides.
69
+
70
+ ## Contribute
71
+
72
+ There are many ways to contribute to this project and our vision of freely and readily available interfaces for laboratory systems.
73
+
74
+ - Check out our [contribution guidelines](docs/6.community/1.contributing.md) to help us improve this project
75
+ - Join the over 400 developers in the [SiLA Slack community](https://sila-standard.org/slack)
76
+ - Give back to the community and add your connectors to the [UniteHub](https://hub.unitelabs.io) by sending us an
77
+ [email](mailto:connectors@unitelabs.io)!
78
+ - Get in touch with our developers regarding feedback and feature requests at [developers@unitelabs.io](mailto:developers@unitelabs.io)
79
+ - Give us a ⭐️ on [GitLab](https://gitlab.com/unitelabs/dev-tools/python-cdk)
80
+
81
+ ## License
82
+
83
+ We, UniteLabs, provide and maintain this free and open-source framework with the aim to enable the community to overcome
84
+ any barriers in digitalizing their laboratory environment. We highly appreciate, if the users of this framework value
85
+ the same principles. Therefore, if you want to make your connectors available for others, we encourage you to share them
86
+ on our sharing platform, the [UniteHub](https://hub.unitelabs.io). As we do not want to enforce disclosure of your work,
87
+ we distribute this framework under the [MIT license](LICENSE).
88
+
@@ -0,0 +1,54 @@
1
+ # UniteLabs Connector Framework
2
+
3
+ The UniteLabs Connector Framework is a free and open-source framework that enables you to build connectors for
4
+ laboratory hard- and software systems with interfaces that are based on industry standards like
5
+ [SiLA 2](https://sila-standard.com). If you plan on implementing an interface natively for your device or as wrapper
6
+ around an existing proprietary interface, you can use this framework to get it built quickly without deep-diving into
7
+ the standard specifications with our intuitive, code-first approach. It provides configurable modules you can use to
8
+ quickly integrate the hardware or software you want to connect.
9
+
10
+ ## Installation
11
+
12
+ [<img src="https://img.shields.io/badge/python-≥3.9.2-0052FF.svg?logo=LOGO&amp;labelColor=090422">](LINK)
13
+ [<img src="https://img.shields.io/badge/poetry-≥1.3.1-0052FF.svg?logo=LOGO&amp;labelColor=090422">](LINK)
14
+
15
+ The UniteLabs Connector Framework requires Python 3.9 or later. To get started quickly, we recommend to clone one of the
16
+ starter projects with:
17
+
18
+ ```
19
+ $ git clone --depth 1 https://gitlab.com/unitelabs/connector-starter.git <my-connector-name>
20
+ $ cd <my-connector-name>
21
+ $ poetry install
22
+ $ poetry run connector start
23
+ ```
24
+
25
+ You can also manually create a new project from scratch and [install the framework](docs/1.get-started/2.installation.md)
26
+ with pip. In this case, of course, you'll be responsible for creating the project boilerplate files yourself.
27
+
28
+ ```
29
+ $ pip install unitelabs-connector-framework
30
+ ```
31
+
32
+ ## Documentation
33
+
34
+ Explor the UniteLabs [Connector Development Kit documentation](https://docs-unitelabs-web-815d69b03b66df4c3a4817af38d7e7b09a17f7c4b50b.gitlab.io/connectivity/overview)
35
+ on our docs page. From there you can find your way to the tutorials and guides.
36
+
37
+ ## Contribute
38
+
39
+ There are many ways to contribute to this project and our vision of freely and readily available interfaces for laboratory systems.
40
+
41
+ - Check out our [contribution guidelines](docs/6.community/1.contributing.md) to help us improve this project
42
+ - Join the over 400 developers in the [SiLA Slack community](https://sila-standard.org/slack)
43
+ - Give back to the community and add your connectors to the [UniteHub](https://hub.unitelabs.io) by sending us an
44
+ [email](mailto:connectors@unitelabs.io)!
45
+ - Get in touch with our developers regarding feedback and feature requests at [developers@unitelabs.io](mailto:developers@unitelabs.io)
46
+ - Give us a ⭐️ on [GitLab](https://gitlab.com/unitelabs/dev-tools/python-cdk)
47
+
48
+ ## License
49
+
50
+ We, UniteLabs, provide and maintain this free and open-source framework with the aim to enable the community to overcome
51
+ any barriers in digitalizing their laboratory environment. We highly appreciate, if the users of this framework value
52
+ the same principles. Therefore, if you want to make your connectors available for others, we encourage you to share them
53
+ on our sharing platform, the [UniteHub](https://hub.unitelabs.io). As we do not want to enforce disclosure of your work,
54
+ we distribute this framework under the [MIT license](LICENSE).
@@ -0,0 +1,79 @@
1
+ [tool.poetry]
2
+ name = "unitelabs-cdk"
3
+ version = "0.2.7"
4
+ description = "A framework to develop UniteLabs connectors based on the SiLA 2 standard specification."
5
+ license = "MIT"
6
+ authors = ["UniteLabs <developers+cdk@unitelabs.io>"]
7
+ readme = "README.md"
8
+ homepage = "https://unitelabs.io"
9
+ repository = "https://gitlab.com/unitelabs/dev-tools/python-cdk"
10
+ documentation = "https://gitlab.com/unitelabs/dev-tools/python-cdk/-/tree/main/docs/"
11
+ keywords = ["UniteLabs", "SiLA 2", "laboratory", "automation", "connectivity"]
12
+ classifiers = [
13
+ "Development Status :: 4 - Beta",
14
+ "Intended Audience :: Developers",
15
+ "Intended Audience :: Healthcare Industry",
16
+ "Intended Audience :: Science/Research",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Operating System :: OS Independent",
19
+ "Programming Language :: Python :: 3 :: Only",
20
+ "Programming Language :: Python :: 3.9",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Topic :: Software Development :: Libraries",
25
+ ]
26
+ packages = [{ include = "unitelabs", from = "src" }]
27
+
28
+ [tool.poetry.urls]
29
+ "Bug Tracker" = "https://gitlab.com/unitelabs/dev-tools/python-cdk/-/issues"
30
+
31
+ [tool.poetry.scripts]
32
+ certificate = 'unitelabs.cdk.cli:certificate'
33
+ connector = 'unitelabs.cdk.cli:connector'
34
+
35
+ [tool.poetry.dependencies]
36
+ python = "^3.9"
37
+ click = "8.1.7"
38
+ pydantic_settings = "2.1.0"
39
+ python-dotenv = "1.0.1"
40
+ unitelabs-sila = {version = "0.1.5", source = "unitelabs"}
41
+
42
+ [tool.poetry.group.dev.dependencies]
43
+ ruff = "^0.5.1"
44
+ pytest = "7.4.4"
45
+ pytest-asyncio = "0.23.3"
46
+ pytest-cov = "4.1.0"
47
+ unitelabs-jsondocs = { version="0.1.1", source="unitelabs" }
48
+
49
+
50
+ [[tool.poetry.source]]
51
+ name = "unitelabs"
52
+ url = "https://gitlab.com/api/v4/groups/1009252/-/packages/pypi/simple"
53
+ priority = "supplemental"
54
+
55
+ [tool.ruff]
56
+ src = ["src", "tests"]
57
+ line-length = 120
58
+ target-version = "py39"
59
+
60
+ [tool.ruff.format]
61
+ docstring-code-format = true
62
+
63
+ [tool.ruff.lint.pydocstyle]
64
+ convention = "google"
65
+
66
+ [tool.pytest.ini_options]
67
+ pythonpath = ["src"]
68
+ testpaths = ["test"]
69
+ asyncio_mode = "auto"
70
+
71
+ [tool.coverage.report]
72
+ exclude_lines = [
73
+ "pragma: no cover",
74
+ "@typing.overload",
75
+ ]
76
+
77
+ [build-system]
78
+ requires = ["poetry-core"]
79
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1,9 @@
1
+ from importlib.metadata import version
2
+
3
+ from .compose_app import AppFactory, compose_app
4
+ from .config import Config
5
+ from .connector import Connector
6
+ from .logging import create_logger
7
+
8
+ __version__ = version("unitelabs_cdk")
9
+ __all__ = ["__version__", "Connector", "Config", "create_logger", "compose_app", "AppFactory"]
@@ -0,0 +1,4 @@
1
+ from .certificate import certificate
2
+ from .connector import connector
3
+
4
+ __all__ = ["certificate", "connector"]
@@ -0,0 +1,53 @@
1
+ from __future__ import annotations
2
+
3
+ import pathlib
4
+
5
+ import click
6
+ import dotenv
7
+
8
+ from sila import server
9
+ from unitelabs.cdk import Config
10
+
11
+ config = Config()
12
+
13
+
14
+ @click.group()
15
+ def certificate() -> None:
16
+ """Utility tool to handle certificates for TLS encryption."""
17
+
18
+ dotenv.load_dotenv()
19
+
20
+
21
+ @certificate.command()
22
+ @click.option(
23
+ "--uuid",
24
+ type=str,
25
+ default=config.sila_server.get("uuid", None),
26
+ required=True,
27
+ help="The SiLA server's uuid.",
28
+ )
29
+ @click.option(
30
+ "--host",
31
+ type=str,
32
+ default=lambda: config.sila_server.get("host", "0.0.0.0"),
33
+ help="The SiLA server's host address.",
34
+ )
35
+ @click.option(
36
+ "--target",
37
+ "-t",
38
+ type=str,
39
+ default=".",
40
+ help="The output directory in which to store the certificate files.",
41
+ )
42
+ def generate(uuid: str, host: str, target: str):
43
+ """Generates a new self-signed certificate according to the SiLA 2 specification."""
44
+ key, cert = server.generate_certificate(uuid, host)
45
+
46
+ directory = pathlib.Path(target)
47
+ directory.mkdir(parents=True, exist_ok=True)
48
+ (directory / "cert.pem").write_bytes(cert)
49
+ (directory / "key.pem").write_bytes(key)
50
+
51
+
52
+ if __name__ == "__main__":
53
+ certificate()
@@ -0,0 +1,113 @@
1
+ import importlib
2
+ import importlib.machinery
3
+ import importlib.metadata
4
+ import importlib.util
5
+ import logging
6
+ import os
7
+ import pathlib
8
+
9
+ import click
10
+ import dotenv
11
+
12
+ from unitelabs.cdk import AppFactory, compose_app, utils
13
+
14
+
15
+ class TLSConfigurationError(Exception):
16
+ pass
17
+
18
+
19
+ @click.group()
20
+ def connector() -> None:
21
+ """Base cli"""
22
+
23
+ dotenv.load_dotenv()
24
+
25
+
26
+ @connector.command()
27
+ @click.option(
28
+ "--app",
29
+ type=str,
30
+ metavar="IMPORT",
31
+ default=utils.find_factory,
32
+ help="The application factory function to load, in the form 'module:name'.",
33
+ )
34
+ @click.option(
35
+ "--tls/--no-tls",
36
+ required=False,
37
+ default=None,
38
+ envvar="SILA_SERVER__TLS",
39
+ help="Use TLS encryption. Alone, this will assume cert and key exist in `certificate.generate` default location.",
40
+ )
41
+ @click.option(
42
+ "-C",
43
+ "--cert",
44
+ required=False,
45
+ envvar="SILA_SERVER__CERT",
46
+ default=None,
47
+ help="The path to the certificate chain file, overriding .env setting of `SILA_SERVER__CERT`, default: ./cert.pem",
48
+ )
49
+ @click.option(
50
+ "-K",
51
+ "--key",
52
+ required=False,
53
+ envvar="SILA_SERVER__KEY",
54
+ default=None,
55
+ help="The path to the private key file, overriding .env setting of `SILA_SERVER__KEY`, default: ./key.pem",
56
+ )
57
+ @click.option(
58
+ "-v",
59
+ "--verbose",
60
+ count=True,
61
+ help="Increase the verbosity of to debug.",
62
+ )
63
+ @utils.coroutine
64
+ async def start(app, tls, cert, key, verbose: int):
65
+ """Application Entrypoint."""
66
+ if tls is not None:
67
+ os.environ["SILA_SERVER__TLS"] = str(tls)
68
+
69
+ if tls:
70
+ cert = pathlib.Path(cert) if cert else pathlib.Path("./cert.pem")
71
+ key = pathlib.Path(key) if key else pathlib.Path("./key.pem")
72
+ cert = cert.resolve()
73
+ key = key.resolve()
74
+
75
+ msg = ""
76
+ if not cert.exists():
77
+ msg += f"Certificate file at {cert} does not exist. Specify path with --cert. "
78
+
79
+ if not key.exists():
80
+ msg += f"Private key file at {key} does not exist. Specify path with --key."
81
+
82
+ if msg:
83
+ raise TLSConfigurationError(msg)
84
+
85
+ os.environb[b"SILA_SERVER__CERT"] = cert.read_bytes()
86
+ os.environb[b"SILA_SERVER__KEY"] = key.read_bytes()
87
+
88
+ log_level = logging.DEBUG if verbose > 0 else logging.INFO
89
+
90
+ create_app = await load_create_app(app)
91
+ app = await compose_app(create_app, log_level=log_level)
92
+
93
+ await app.start()
94
+
95
+
96
+ async def load_create_app(location: str) -> AppFactory:
97
+ """
98
+ Dynamically import the application factory from the given location.
99
+
100
+ Args:
101
+ location: Where to find the app factory formatted as "module:name".
102
+ """
103
+
104
+ module_name, _, factory_name = location.partition(":")
105
+
106
+ module = importlib.import_module(module_name)
107
+ create_app = getattr(module, factory_name)
108
+
109
+ return create_app
110
+
111
+
112
+ if __name__ == "__main__":
113
+ connector()
@@ -0,0 +1,147 @@
1
+ import collections.abc
2
+ import functools
3
+ import inspect
4
+ import logging
5
+ import signal
6
+ import sys
7
+ import types
8
+ import typing
9
+
10
+ from .connector import Connector
11
+ from .logging import create_logger
12
+
13
+ T = typing.TypeVar("T")
14
+
15
+
16
+ Generator = typing.Union[
17
+ collections.abc.Generator[T, None, None],
18
+ collections.abc.AsyncGenerator[T, None],
19
+ ]
20
+
21
+
22
+ AppFactory = collections.abc.Callable[
23
+ ...,
24
+ typing.Union[
25
+ Connector,
26
+ collections.abc.Awaitable[Connector],
27
+ Generator,
28
+ ],
29
+ ]
30
+
31
+
32
+ async def compose_app(create_app: AppFactory, log_level: int = logging.INFO) -> Connector:
33
+ """
34
+ Creates and configures a ready to use Connector.
35
+
36
+ Args:
37
+ create_app: The factory method used to create the Connector instance.
38
+
39
+ Returns:
40
+ The newly created Connector.
41
+
42
+ Raises:
43
+ ValueError: If create_app does not follow the required interface.
44
+ """
45
+
46
+ signal.signal(signal.SIGINT, signal_handler)
47
+ signal.signal(signal.SIGTERM, signal_handler)
48
+
49
+ create_logger("sila", log_level)
50
+ create_logger("unitelabs", log_level)
51
+
52
+ app = await init_app(app_factory=create_app)
53
+
54
+ return app
55
+
56
+
57
+ # pylint: disable-next=unused-argument
58
+ def signal_handler(signum: int, frame: typing.Optional[types.FrameType]) -> None:
59
+ """
60
+ Gracefully handle received signals.
61
+
62
+ Args:
63
+ signum: The signal number.
64
+ frame: The current stack frame.
65
+ """
66
+
67
+ sys.exit(signum)
68
+
69
+
70
+ async def init_app(app_factory: AppFactory) -> Connector:
71
+ """
72
+ Uses the provided factory method to init a new Connector.
73
+
74
+ Args:
75
+ app_factory: The factory method to call.
76
+
77
+ Returns:
78
+ The initialized Connector.
79
+
80
+ Raises:
81
+ ValueError: If app_factory does not follow the required interface.
82
+ """
83
+
84
+ if inspect.isasyncgenfunction(app_factory) or inspect.isgeneratorfunction(app_factory):
85
+ generator: Generator[Connector] = app_factory()
86
+ generator = _sync_to_async_gen(generator)
87
+
88
+ try:
89
+ app = await generator.__anext__()
90
+ except (StopAsyncIteration, StopIteration):
91
+ raise ValueError("Unable to create app: `create_app` did not yield a value.") from None
92
+
93
+ shutdown_handler = functools.partial(_shutdown_yield, generator)
94
+ app.on_shutdown(handler=shutdown_handler)
95
+
96
+ return app
97
+
98
+ if inspect.iscoroutinefunction(app_factory):
99
+ return await app_factory()
100
+
101
+ if inspect.isfunction(app_factory):
102
+ return app_factory()
103
+
104
+ raise ValueError(f"Invalid `create_app`: '{app_factory}'. Provide a callable function that returns a Connector.")
105
+
106
+
107
+ async def _shutdown_yield(generator: collections.abc.AsyncGenerator[T, None]) -> None:
108
+ """
109
+ Execute the shutdown of a factory function by advancing the iterator
110
+ after the yield and ensure the iteration ends (if not it means there is
111
+ more than one yield in the function).
112
+
113
+ Args:
114
+ generator: The factory function to create the app.
115
+ """
116
+
117
+ try:
118
+ await generator.__anext__()
119
+ except (StopAsyncIteration, StopIteration):
120
+ pass
121
+ else:
122
+ await _shutdown_yield(generator)
123
+
124
+
125
+ async def _sync_to_async_gen(generator: Generator[T]) -> collections.abc.AsyncGenerator[T, None]:
126
+ """
127
+ Wraps any generator into an async generator.
128
+
129
+ Args:
130
+ generator: The generator to wrap as async.
131
+
132
+ Returns:
133
+ The async generator.
134
+ """
135
+
136
+ if inspect.isasyncgen(generator):
137
+ async for item in generator:
138
+ yield item
139
+
140
+ return
141
+
142
+ if inspect.isgenerator(generator):
143
+ while True:
144
+ try:
145
+ yield next(generator)
146
+ except StopIteration:
147
+ return
@@ -0,0 +1,13 @@
1
+ from pydantic_settings import BaseSettings, SettingsConfigDict
2
+
3
+ from sila import cloud_connector, server
4
+
5
+
6
+ class Config(BaseSettings):
7
+ model_config = SettingsConfigDict(
8
+ env_file=".env", env_file_encoding="utf-8", env_nested_delimiter="__", extra="ignore"
9
+ )
10
+
11
+ environment: str = "development"
12
+ sila_server: server.ServerConfig = server.ServerConfig()
13
+ cloud_server_endpoint: cloud_connector.CloudServerEndpointConfig = cloud_connector.CloudServerEndpointConfig()