rats-apps 0.11.1.dev20250528085636__py3-none-any.whl → 0.11.1.dev20250528191803__py3-none-any.whl
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.
- rats/apps/_container.py +8 -2
- rats_apps-0.11.1.dev20250528191803.dist-info/METADATA +238 -0
- {rats_apps-0.11.1.dev20250528085636.dist-info → rats_apps-0.11.1.dev20250528191803.dist-info}/RECORD +5 -5
- rats_apps-0.11.1.dev20250528085636.dist-info/METADATA +0 -27
- {rats_apps-0.11.1.dev20250528085636.dist-info → rats_apps-0.11.1.dev20250528191803.dist-info}/WHEEL +0 -0
- {rats_apps-0.11.1.dev20250528085636.dist-info → rats_apps-0.11.1.dev20250528191803.dist-info}/entry_points.txt +0 -0
rats/apps/_container.py
CHANGED
@@ -108,7 +108,6 @@ class Container(Protocol):
|
|
108
108
|
"""Retrieve a service group by its id."""
|
109
109
|
if not self.has_namespace(ProviderNamespaces.GROUPS, group_id):
|
110
110
|
# groups are expected to return iterable services
|
111
|
-
# TODO: we need to clean up the meaning of groups and services somehow
|
112
111
|
for i in self.get_namespaced_group(ProviderNamespaces.FALLBACK_GROUPS, group_id):
|
113
112
|
yield from cast(Iterator[T_ServiceType], i)
|
114
113
|
|
@@ -151,7 +150,14 @@ def _get_cached_services_for_group(
|
|
151
150
|
|
152
151
|
for provider in info_cache[(namespace, group_id)]:
|
153
152
|
if provider not in provider_cache:
|
154
|
-
|
153
|
+
if namespace in [
|
154
|
+
ProviderNamespaces.CONTAINERS,
|
155
|
+
ProviderNamespaces.SERVICES,
|
156
|
+
ProviderNamespaces.FALLBACK_SERVICES,
|
157
|
+
]:
|
158
|
+
provider_cache[provider] = getattr(c, provider.attr)()
|
159
|
+
else:
|
160
|
+
provider_cache[provider] = list(getattr(c, provider.attr)())
|
155
161
|
|
156
162
|
yield provider_cache[provider]
|
157
163
|
|
@@ -0,0 +1,238 @@
|
|
1
|
+
Metadata-Version: 2.3
|
2
|
+
Name: rats-apps
|
3
|
+
Version: 0.11.1.dev20250528191803
|
4
|
+
Summary: research analysis tools for building applications
|
5
|
+
License: MIT
|
6
|
+
Keywords: pipelines,machine learning,research
|
7
|
+
Author: Elon Portugaly
|
8
|
+
Author-email: elonp@microsoft.com
|
9
|
+
Requires-Python: >=3.10,<4.0
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
16
|
+
Requires-Dist: click
|
17
|
+
Requires-Dist: colorlog
|
18
|
+
Requires-Dist: dataclass-wizard
|
19
|
+
Requires-Dist: pyyaml
|
20
|
+
Requires-Dist: typing-extensions
|
21
|
+
Project-URL: Documentation, https://microsoft.github.io/rats
|
22
|
+
Project-URL: Repository, https://github.com/microsoft/rats
|
23
|
+
Description-Content-Type: text/markdown
|
24
|
+
|
25
|
+
---
|
26
|
+
title: introduction
|
27
|
+
---
|
28
|
+
|
29
|
+
The `rats-apps` package helps create applications; a small set of modules that eliminate the most
|
30
|
+
common boilerplate code when creating applications of any kind. We do this mainly by providing a
|
31
|
+
set of libraries to define service containers, and using the service containers to hide the
|
32
|
+
complexity of creating services–like authentication, storage, or database clients–from other parts
|
33
|
+
of the system, allowing developers to focus on the business logic of the application. Often referred
|
34
|
+
to as [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection), we use our
|
35
|
+
service containers to separate the concerns of constructing objects and using them.
|
36
|
+
|
37
|
+
## Installation
|
38
|
+
|
39
|
+
Use `pip` or your favorite packaging tool to install the package from PyPI.
|
40
|
+
|
41
|
+
```bash
|
42
|
+
pip install rats-apps
|
43
|
+
```
|
44
|
+
|
45
|
+
## What is an application?
|
46
|
+
|
47
|
+
Let's start with a standard python script, and slowly migrate it to be a rats application in order
|
48
|
+
to explain a few main details. Creating a `__main__.py` file in a package makes it executable.
|
49
|
+
After the common python boilerplate code is added, this is typically what we find in the wild:
|
50
|
+
|
51
|
+
=== ":material-language-python: ~/code/src/foo/\_\_main\_\_.py"
|
52
|
+
```python
|
53
|
+
def main() -> None:
|
54
|
+
print("hello, world")
|
55
|
+
|
56
|
+
|
57
|
+
if __name__ == "__main__":
|
58
|
+
main()
|
59
|
+
```
|
60
|
+
|
61
|
+
=== ":material-console: ~/code"
|
62
|
+
```bash
|
63
|
+
python -m foo
|
64
|
+
```
|
65
|
+
|
66
|
+
Using this pattern, we can define our application with a small modification, turning our `main()`
|
67
|
+
function into a runnable rats application, and then running it:
|
68
|
+
|
69
|
+
=== ":material-language-python: ~/code/src/foo/\_\_main\_\_.py"
|
70
|
+
```python
|
71
|
+
from rats import apps
|
72
|
+
|
73
|
+
|
74
|
+
def main() -> None:
|
75
|
+
print("hello, world")
|
76
|
+
|
77
|
+
|
78
|
+
if __name__ == "__main__":
|
79
|
+
apps.run(apps.App(main))
|
80
|
+
```
|
81
|
+
|
82
|
+
!!! info
|
83
|
+
The [rats.apps.App][] class is used to quickly turn a script entry point–`Callable[[], None]`
|
84
|
+
–into an object with an `execute()` method, defined by our [rats.apps.Executable][]
|
85
|
+
interface.
|
86
|
+
|
87
|
+
## Application Containers & Plugins
|
88
|
+
|
89
|
+
We can start to leverage [rats.apps][] to make our application easy to extend. Let's replace our use
|
90
|
+
of the [rats.apps.App][] wrapper and move our `main()` function into a class. Using the
|
91
|
+
[rats.apps.AppContainer][] and [rats.apps.PluginMixin][] classes, we finish adapting our example
|
92
|
+
to be a rats application.
|
93
|
+
|
94
|
+
=== ":material-language-python: ~/code/src/foo/\_\_main\_\_.py"
|
95
|
+
|
96
|
+
```python
|
97
|
+
from rats import apps
|
98
|
+
|
99
|
+
|
100
|
+
class Application(apps.AppContainer, apps.PluginMixin):
|
101
|
+
def execute() -> None:
|
102
|
+
print("hello, world")
|
103
|
+
|
104
|
+
|
105
|
+
if __name__ == "__main__":
|
106
|
+
apps.run_plugin(Application)
|
107
|
+
```
|
108
|
+
|
109
|
+
!!! info
|
110
|
+
If you're making these changes to an existing code base, you should be able to run things to
|
111
|
+
validate that everything still works as it did before. Your `main()` function is now in
|
112
|
+
the `execute()` method of your new `Application` class, but none of the behavior of your
|
113
|
+
application should have been affected.
|
114
|
+
|
115
|
+
Now that we have a fully defined rats application; we can use [rats.apps.Container][] instances to
|
116
|
+
make services available to our application while remaining decoupled from the details of how these
|
117
|
+
services are initialized. A common use case for this is to give our team access to the azure
|
118
|
+
storage clients without needing to specify the authentication details; allowing us to ensure our
|
119
|
+
application is functional in many compute environments.
|
120
|
+
|
121
|
+
=== ":material-language-python: ~/code/src/foo/\_\_init\_\_.py"
|
122
|
+
|
123
|
+
```python
|
124
|
+
from ._plugin import PluginContainer
|
125
|
+
|
126
|
+
__all__ = ["PluginContainer"]
|
127
|
+
```
|
128
|
+
|
129
|
+
=== ":material-language-python: ~/code/src/foo/\_\_main\_\_.py"
|
130
|
+
|
131
|
+
```python
|
132
|
+
from rats import apps
|
133
|
+
import foo
|
134
|
+
|
135
|
+
|
136
|
+
class Application(apps.AppContainer, apps.PluginMixin):
|
137
|
+
|
138
|
+
def execute() -> None:
|
139
|
+
blob_client = self._app.get(foo.BLOB_SERVICE_ID)
|
140
|
+
print(f"hello, world. loaded blob client: {blob_client}")
|
141
|
+
|
142
|
+
@apps.container()
|
143
|
+
def _plugins(self) -> apps.Container:
|
144
|
+
return foo.PluginContainer(self._app)
|
145
|
+
|
146
|
+
|
147
|
+
if __name__ == "__main__":
|
148
|
+
apps.run_plugin(Application)
|
149
|
+
```
|
150
|
+
|
151
|
+
=== ":material-language-python: ~/code/src/foo/_plugin.py"
|
152
|
+
|
153
|
+
```python
|
154
|
+
from rats import apps
|
155
|
+
from azure.storage.blob import BlobServiceClient
|
156
|
+
|
157
|
+
BLOB_SERVICE_ID = apps.ServiceId[BlobServiceClient]("blob-client")
|
158
|
+
|
159
|
+
|
160
|
+
class PluginContainer(apps.Container, apps.PluginMixin):
|
161
|
+
|
162
|
+
@apps.service(BLOB_SERVICE_ID)
|
163
|
+
def _blob_client(self) -> BlobServiceClient:
|
164
|
+
credential = DefaultAzureCredential()
|
165
|
+
return BlobServiceClient(
|
166
|
+
account_url=f"https://example.blob.core.windows.net/",
|
167
|
+
credential=credential,
|
168
|
+
)
|
169
|
+
```
|
170
|
+
|
171
|
+
!!! success
|
172
|
+
Following these patterns, we can make services available to others with plugin containers; and
|
173
|
+
we can combine these containers to create applications. The [rats.apps][] module has additional
|
174
|
+
libraries to help define different types of applications, designed to help your solutions
|
175
|
+
evolve as ideas mature. Our first runnable example was a single instance of the
|
176
|
+
[rats.apps.AppContainer][] interface with an `execute()` method; but a larger project might
|
177
|
+
have a few modules providing different aspects of the application's needs by sharing a set of
|
178
|
+
service ids and a plugin container.
|
179
|
+
|
180
|
+
## Installable Plugins
|
181
|
+
|
182
|
+
We use the standard [Entry Points](https://packaging.python.org/en/latest/specifications/entry-points/)
|
183
|
+
mechanism to allow authors to make their application extensible. These plugins are instances of
|
184
|
+
[rats.apps.Container][] and loaded into applications like our previous examples.
|
185
|
+
|
186
|
+
=== ":material-file-settings: ~/code/pyproject.toml"
|
187
|
+
```toml
|
188
|
+
[tool.poetry.plugins."foo.plugins"]
|
189
|
+
"foo" = "foo:PluginContainer"
|
190
|
+
```
|
191
|
+
|
192
|
+
=== ":material-language-python: ~/code/src/foo/\_\_main\_\_.py"
|
193
|
+
```python
|
194
|
+
from rats import apps
|
195
|
+
import foo
|
196
|
+
|
197
|
+
|
198
|
+
class Application(apps.AppContainer, apps.PluginMixin):
|
199
|
+
|
200
|
+
def execute() -> None:
|
201
|
+
blob_client = self._app.get(foo.BLOB_SERVICE_ID)
|
202
|
+
print(f"hello, world. loaded blob client: {blob_client}")
|
203
|
+
|
204
|
+
@apps.container()
|
205
|
+
def _plugins(self) -> apps.Container:
|
206
|
+
return apps.PythonEntryPointContainer("foo.plugins")
|
207
|
+
|
208
|
+
|
209
|
+
if __name__ == "__main__":
|
210
|
+
apps.run_plugin(Application)
|
211
|
+
```
|
212
|
+
|
213
|
+
!!! success
|
214
|
+
We used [rats.app] to define an application, and used a service provided by a plugin container
|
215
|
+
that is loaded through a python entry point. You can create a script entry in your
|
216
|
+
`pyproject.toml` file to expose your application through a terminal command:
|
217
|
+
|
218
|
+
=== ":material-language-python: ~/code/src/foo/\_\_init\_\_.py"
|
219
|
+
```python
|
220
|
+
from ._app import Application, main
|
221
|
+
from ._plugin import PluginContainer
|
222
|
+
|
223
|
+
|
224
|
+
__all__ = [
|
225
|
+
"Application",
|
226
|
+
"main",
|
227
|
+
"PluginContainer",
|
228
|
+
]
|
229
|
+
```
|
230
|
+
=== ":material-file-settings: ~/code/pyproject.toml"
|
231
|
+
```toml
|
232
|
+
[tool.poetry.plugins."foo.plugins"]
|
233
|
+
"foo" = "foo:PluginContainer"
|
234
|
+
|
235
|
+
[tool.poetry.scripts]
|
236
|
+
foo = "foo:main"
|
237
|
+
```
|
238
|
+
|
{rats_apps-0.11.1.dev20250528085636.dist-info → rats_apps-0.11.1.dev20250528191803.dist-info}/RECORD
RENAMED
@@ -11,7 +11,7 @@ rats/apps/__init__.py,sha256=6B5qQvzx1xlRrNRY4QJi6GEywuQ1MoW454kC4nO2Yqg,2084
|
|
11
11
|
rats/apps/_annotations.py,sha256=6M_M7K8haNVda0Tx02EpFf3s9EjnWYacNMjTIkNEdRU,4617
|
12
12
|
rats/apps/_app_containers.py,sha256=1rtq92rOGvCbroQmDgOM24jxxcNNFQHy65fBLO5LIXo,6920
|
13
13
|
rats/apps/_composite_container.py,sha256=FdpmH_xIly6LxNZrA_nZCznukptjVLXttXTMtf_tnv8,695
|
14
|
-
rats/apps/_container.py,sha256=
|
14
|
+
rats/apps/_container.py,sha256=N8qR0oBLi03xZvPfc8SxaSci0oVYfX_rftzfaBkTSfQ,7415
|
15
15
|
rats/apps/_executables.py,sha256=hXExNmAnuPU1KJXihNw1jEDAQpMlQ9E9_aPV8tpGbOY,1347
|
16
16
|
rats/apps/_ids.py,sha256=T8Onrj79t8NPfBMQBk0xI6fIWDKF0m2JfFNrdtXAbWg,353
|
17
17
|
rats/apps/_mains.py,sha256=2Q97mNk1cBzYROc_pJcm57EEeHmwRbXOWpfYXH37qcA,995
|
@@ -55,7 +55,7 @@ rats_e2e/runtime/_data.py,sha256=3d1F_JO2gEOPUjBp_KYMP3TefyneiG_ktlJjdIIYUy8,125
|
|
55
55
|
rats_e2e/runtime/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
56
56
|
rats_resources/runtime/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
57
57
|
rats_resources/runtime/example-context.yaml,sha256=eiLsNFquFfkIpUhxUCQLzLigH21QF2F00fzA_e_aOKk,215
|
58
|
-
rats_apps-0.11.1.
|
59
|
-
rats_apps-0.11.1.
|
60
|
-
rats_apps-0.11.1.
|
61
|
-
rats_apps-0.11.1.
|
58
|
+
rats_apps-0.11.1.dev20250528191803.dist-info/METADATA,sha256=xMdoOiWZ_vPeg7CCv98iIgL2UJg2JPLTrM-WRfemGTk,8292
|
59
|
+
rats_apps-0.11.1.dev20250528191803.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
60
|
+
rats_apps-0.11.1.dev20250528191803.dist-info/entry_points.txt,sha256=Gf6bPwxIVjWd3Xx71upZo7eDJA5cujniLew6fxJMgA4,117
|
61
|
+
rats_apps-0.11.1.dev20250528191803.dist-info/RECORD,,
|
@@ -1,27 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.3
|
2
|
-
Name: rats-apps
|
3
|
-
Version: 0.11.1.dev20250528085636
|
4
|
-
Summary: research analysis tools for building applications
|
5
|
-
License: MIT
|
6
|
-
Keywords: pipelines,machine learning,research
|
7
|
-
Author: Elon Portugaly
|
8
|
-
Author-email: elonp@microsoft.com
|
9
|
-
Requires-Python: >=3.10,<4.0
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
15
|
-
Classifier: Programming Language :: Python :: 3.13
|
16
|
-
Requires-Dist: click
|
17
|
-
Requires-Dist: colorlog
|
18
|
-
Requires-Dist: dataclass-wizard
|
19
|
-
Requires-Dist: pyyaml
|
20
|
-
Requires-Dist: typing-extensions
|
21
|
-
Project-URL: Documentation, https://microsoft.github.io/rats
|
22
|
-
Project-URL: Repository, https://github.com/microsoft/rats
|
23
|
-
Description-Content-Type: text/markdown
|
24
|
-
|
25
|
-
# rats-apps
|
26
|
-
...
|
27
|
-
|
{rats_apps-0.11.1.dev20250528085636.dist-info → rats_apps-0.11.1.dev20250528191803.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|