rats-apps 0.4.0.dev20241212213929__py3-none-any.whl → 0.5.0__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/annotations/__init__.py +4 -4
- rats/apps/__init__.py +35 -24
- rats/apps/_app_containers.py +199 -0
- rats/apps/_container.py +0 -4
- rats/apps/_executables.py +15 -1
- rats/apps/_mains.py +42 -0
- rats/apps/_plugin_container.py +2 -2
- rats/apps/_runtimes.py +20 -8
- rats/apps/_static_container.py +44 -7
- rats/cli/__init__.py +8 -9
- rats/cli/__main__.py +7 -15
- rats/cli/_plugin.py +1 -9
- rats/logs/__init__.py +2 -3
- rats/logs/_app.py +45 -0
- {rats_apps-0.4.0.dev20241212213929.dist-info → rats_apps-0.5.0.dist-info}/METADATA +2 -3
- rats_apps-0.5.0.dist-info/RECORD +40 -0
- {rats_apps-0.4.0.dev20241212213929.dist-info → rats_apps-0.5.0.dist-info}/WHEEL +1 -1
- rats_e2e/apps/__init__.py +7 -0
- rats_e2e/apps/__main__.py +17 -0
- rats_e2e/apps/_example_cli.py +82 -0
- rats_e2e/apps/inputs/__init__.py +31 -0
- rats_e2e/apps/inputs/__main__.py +6 -0
- rats_e2e/apps/inputs/_app.py +46 -0
- rats_e2e/apps/minimal/__init__.py +26 -0
- rats_e2e/apps/minimal/__main__.py +6 -0
- rats_e2e/apps/minimal/_app.py +28 -0
- rats/apps/__main__.py +0 -79
- rats/apps/_plugins.py +0 -23
- rats/apps/_simple_apps.py +0 -163
- rats/logs/_plugin.py +0 -64
- rats_apps-0.4.0.dev20241212213929.dist-info/RECORD +0 -33
- rats_apps-0.4.0.dev20241212213929.dist-info/entry_points.txt +0 -4
rats/annotations/__init__.py
CHANGED
@@ -15,11 +15,11 @@ from ._functions import (
|
|
15
15
|
)
|
16
16
|
|
17
17
|
__all__ = [
|
18
|
-
"annotation",
|
19
|
-
"DecoratorType",
|
20
18
|
"AnnotationsContainer",
|
21
|
-
"
|
22
|
-
"get_class_annotations",
|
19
|
+
"DecoratorType",
|
23
20
|
"GroupAnnotations",
|
24
21
|
"T_GroupType",
|
22
|
+
"annotation",
|
23
|
+
"get_annotations",
|
24
|
+
"get_class_annotations",
|
25
25
|
]
|
rats/apps/__init__.py
CHANGED
@@ -15,6 +15,14 @@ from ._annotations import (
|
|
15
15
|
group,
|
16
16
|
service,
|
17
17
|
)
|
18
|
+
from ._app_containers import (
|
19
|
+
AppBundle,
|
20
|
+
AppContainer,
|
21
|
+
AppPlugin,
|
22
|
+
CompositePlugin,
|
23
|
+
ContainerPlugin,
|
24
|
+
PluginMixin,
|
25
|
+
)
|
18
26
|
from ._composite_container import CompositeContainer
|
19
27
|
from ._container import (
|
20
28
|
Container,
|
@@ -22,51 +30,54 @@ from ._container import (
|
|
22
30
|
GroupProvider,
|
23
31
|
Provider,
|
24
32
|
ServiceNotFoundError,
|
25
|
-
ServiceProvider,
|
26
33
|
container,
|
27
34
|
)
|
28
35
|
from ._executables import App, Executable
|
29
36
|
from ._ids import ServiceId, T_ExecutableType, T_ServiceType
|
37
|
+
from ._mains import run, run_plugin
|
30
38
|
from ._namespaces import ProviderNamespaces
|
31
|
-
from ._plugin_container import
|
32
|
-
from .
|
33
|
-
from ._runtimes import NullRuntime, Runtime
|
39
|
+
from ._plugin_container import PythonEntryPointContainer
|
40
|
+
from ._runtimes import NullRuntime, Runtime, StandardRuntime
|
34
41
|
from ._scoping import autoscope
|
35
|
-
from .
|
36
|
-
from ._static_container import StaticContainer, StaticProvider
|
42
|
+
from ._static_container import StaticContainer, StaticProvider, static_group, static_service
|
37
43
|
|
38
44
|
__all__ = [
|
39
45
|
"App",
|
46
|
+
"AppBundle",
|
47
|
+
"AppContainer",
|
48
|
+
"AppPlugin",
|
40
49
|
"CompositeContainer",
|
50
|
+
"CompositePlugin",
|
41
51
|
"Container",
|
42
|
-
"
|
43
|
-
"StaticProvider",
|
52
|
+
"ContainerPlugin",
|
44
53
|
"DuplicateServiceError",
|
45
54
|
"Executable",
|
46
|
-
"PluginContainers",
|
47
|
-
"ProviderNamespaces",
|
48
|
-
"ServiceProvider",
|
49
|
-
"Provider",
|
50
55
|
"GroupProvider",
|
56
|
+
"NullRuntime",
|
57
|
+
"PluginMixin",
|
58
|
+
"Provider",
|
59
|
+
"ProviderNamespaces",
|
60
|
+
"PythonEntryPointContainer",
|
61
|
+
"Runtime",
|
51
62
|
"ServiceId",
|
52
63
|
"ServiceNotFoundError",
|
64
|
+
"StandardRuntime",
|
65
|
+
"StaticContainer",
|
66
|
+
"StaticProvider",
|
67
|
+
"T_ExecutableType",
|
68
|
+
"T_ServiceType",
|
69
|
+
"autoid",
|
70
|
+
"autoid_factory_service",
|
53
71
|
"autoid_service",
|
54
72
|
"autoscope",
|
55
73
|
"container",
|
56
|
-
"
|
74
|
+
"factory_service",
|
57
75
|
"fallback_group",
|
58
76
|
"fallback_service",
|
59
77
|
"group",
|
60
|
-
"
|
78
|
+
"run",
|
79
|
+
"run_plugin",
|
61
80
|
"service",
|
62
|
-
"
|
63
|
-
"
|
64
|
-
"Runtime",
|
65
|
-
"NullRuntime",
|
66
|
-
"AppServices",
|
67
|
-
"StandardRuntime",
|
68
|
-
"StandardRuntime",
|
69
|
-
"SimpleApplication",
|
70
|
-
"factory_service",
|
71
|
-
"autoid_factory_service",
|
81
|
+
"static_group",
|
82
|
+
"static_service",
|
72
83
|
]
|
@@ -0,0 +1,199 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import logging
|
4
|
+
from abc import abstractmethod
|
5
|
+
from collections.abc import Callable
|
6
|
+
from functools import cache
|
7
|
+
from typing import Protocol, final
|
8
|
+
|
9
|
+
from ._composite_container import CompositeContainer
|
10
|
+
from ._container import Container, container
|
11
|
+
from ._executables import Executable
|
12
|
+
|
13
|
+
logger = logging.getLogger(__name__)
|
14
|
+
EMPTY_CONTEXT = CompositeContainer()
|
15
|
+
|
16
|
+
|
17
|
+
def _empty_plugin(app: Container) -> Container:
|
18
|
+
return CompositeContainer()
|
19
|
+
|
20
|
+
|
21
|
+
EMPTY_PLUGIN = _empty_plugin
|
22
|
+
|
23
|
+
|
24
|
+
class AppContainer(Container, Executable, Protocol):
|
25
|
+
"""The combination of a [rats.apps.Container][] an [rats.apps.Executable][]."""
|
26
|
+
|
27
|
+
def execute(self) -> None:
|
28
|
+
"""The main application entry point."""
|
29
|
+
logger.warning(f"empty execute method in application: {self.__class__}")
|
30
|
+
|
31
|
+
|
32
|
+
class _AppPluginType(Protocol):
|
33
|
+
@abstractmethod
|
34
|
+
def __call__(self, app: Container) -> AppContainer:
|
35
|
+
pass
|
36
|
+
|
37
|
+
|
38
|
+
class _ContainerPluginType(Protocol):
|
39
|
+
@abstractmethod
|
40
|
+
def __call__(self, app: Container) -> Container:
|
41
|
+
pass
|
42
|
+
|
43
|
+
|
44
|
+
AppPlugin = _AppPluginType | Callable[[Container], AppContainer]
|
45
|
+
"""
|
46
|
+
Main interface for a function that returns an [rats.apps.AppContainer][] instance.
|
47
|
+
|
48
|
+
Functions that act as runners or application factories often take this as their input type in
|
49
|
+
order to manage the top most [rats.apps.Container][] instance, allowing most containers to use the
|
50
|
+
[rats.apps.PluginMixin][] mixin and rely on the top most container being managed automatically.
|
51
|
+
This is the companion type to [rats.apps.ContainerPlugin][].
|
52
|
+
"""
|
53
|
+
|
54
|
+
ContainerPlugin = _ContainerPluginType | Callable[[Container], Container]
|
55
|
+
"""
|
56
|
+
Main interface for a function that returns an [rats.apps.Container][] instance.
|
57
|
+
|
58
|
+
Containers that implement this type—for example, by using the [rats.apps.PluginMixin][] mixin—can
|
59
|
+
be used easily in functions that need to defer the construction of an application container. See
|
60
|
+
[rats.apps.AppBundle][] for additional examples.
|
61
|
+
"""
|
62
|
+
|
63
|
+
|
64
|
+
class PluginMixin:
|
65
|
+
"""
|
66
|
+
Mix into your [Container][] classes to add our default constructor.
|
67
|
+
|
68
|
+
This mixin adds a common constructor to a `Container` in order to quickly create types that
|
69
|
+
are compatible with functions asking for `AppPlugin` and `ContainerPlugin` arguments.
|
70
|
+
|
71
|
+
!!! warning
|
72
|
+
Avoid using mixins as an input type to your functions, because we don't want to restrict
|
73
|
+
others to containers with a private `_app` property. Instead, use this as a shortcut to
|
74
|
+
some commonly used implementation details.
|
75
|
+
|
76
|
+
Example:
|
77
|
+
```python
|
78
|
+
from rats import apps
|
79
|
+
|
80
|
+
class ExampleApplication(apps.AppContainer, apps.PluginMixin):
|
81
|
+
|
82
|
+
def execute() -> None:
|
83
|
+
print("hello, world!")
|
84
|
+
|
85
|
+
|
86
|
+
if __name__ == "__main__":
|
87
|
+
apps.run_plugin(ExampleApplication)
|
88
|
+
```
|
89
|
+
"""
|
90
|
+
|
91
|
+
_app: Container
|
92
|
+
|
93
|
+
def __init__(self, app: Container) -> None:
|
94
|
+
self._app = app
|
95
|
+
|
96
|
+
|
97
|
+
class CompositePlugin:
|
98
|
+
"""
|
99
|
+
Similar to [rats.apps.CompositeContainer][] but takes a list of plugin container types.
|
100
|
+
|
101
|
+
Example:
|
102
|
+
```python
|
103
|
+
from rats import apps
|
104
|
+
from rats_e2e.apps import inputs
|
105
|
+
|
106
|
+
|
107
|
+
class ExamplePlugin1(apps.Container, apps.PluginMixin):
|
108
|
+
pass
|
109
|
+
|
110
|
+
|
111
|
+
class ExamplePlugin2(apps.Container, apps.PluginMixin):
|
112
|
+
pass
|
113
|
+
|
114
|
+
|
115
|
+
apps.run(
|
116
|
+
apps.AppBundle(
|
117
|
+
app_plugin=inputs.Application,
|
118
|
+
container_plugin=apps.CompositePlugin(
|
119
|
+
ExamplePlugin1,
|
120
|
+
ExamplePlugin2,
|
121
|
+
),
|
122
|
+
)
|
123
|
+
)
|
124
|
+
```
|
125
|
+
"""
|
126
|
+
|
127
|
+
_plugins: tuple[ContainerPlugin, ...]
|
128
|
+
|
129
|
+
def __init__(self, *plugins: ContainerPlugin) -> None:
|
130
|
+
self._plugins = plugins
|
131
|
+
|
132
|
+
def __call__(self, app: Container) -> Container:
|
133
|
+
return CompositeContainer(*[plugin(app) for plugin in self._plugins])
|
134
|
+
|
135
|
+
|
136
|
+
@final
|
137
|
+
class AppBundle(AppContainer):
|
138
|
+
"""
|
139
|
+
Brings together different types of containers to construct an executable application.
|
140
|
+
|
141
|
+
Use this class to defer the creation of an [rats.apps.AppContainer][] instance in order to
|
142
|
+
combine services with additional [rats.apps.ContainerPlugin][] classes.
|
143
|
+
"""
|
144
|
+
|
145
|
+
_app_plugin: AppPlugin
|
146
|
+
_container_plugin: ContainerPlugin
|
147
|
+
_context: Container
|
148
|
+
|
149
|
+
def __init__(
|
150
|
+
self,
|
151
|
+
*,
|
152
|
+
app_plugin: AppPlugin,
|
153
|
+
container_plugin: ContainerPlugin = EMPTY_PLUGIN,
|
154
|
+
context: Container = EMPTY_CONTEXT,
|
155
|
+
):
|
156
|
+
"""
|
157
|
+
Create an instance by providing the [rats.apps.AppPlugin] type and any additional context.
|
158
|
+
|
159
|
+
Example:
|
160
|
+
```python
|
161
|
+
from rats import apps
|
162
|
+
|
163
|
+
|
164
|
+
class ExamplePlugin(apps.Container, apps.PluginMixin):
|
165
|
+
@apps.service(apps.ServiceId[str]("some-value"))
|
166
|
+
def _some_value() -> str:
|
167
|
+
return "hello, world!"
|
168
|
+
|
169
|
+
|
170
|
+
class ExampleApplication(apps.AppContainer, apps.PluginMixin):
|
171
|
+
def execute() -> None:
|
172
|
+
print(self._app.get(apps.ServiceId[str]("some-value")))
|
173
|
+
|
174
|
+
|
175
|
+
if __name__ == "__main__":
|
176
|
+
apps.run(apps.AppBundle(ExampleApplication, ExamplePlugin))
|
177
|
+
```
|
178
|
+
|
179
|
+
Args:
|
180
|
+
app_plugin: the class reference to the application container.
|
181
|
+
container_plugin: the class reference to an additional plugin container.
|
182
|
+
context: an optional plugin container to make part of the container tree.
|
183
|
+
"""
|
184
|
+
self._app_plugin = app_plugin
|
185
|
+
self._container_plugin = container_plugin
|
186
|
+
self._context = context
|
187
|
+
|
188
|
+
def execute(self) -> None:
|
189
|
+
"""Initializes a new [rats.apps.AppContainer] with the provided nodes before executing it."""
|
190
|
+
app, _ = self._get_or_create_containers()
|
191
|
+
app.execute()
|
192
|
+
|
193
|
+
@container()
|
194
|
+
def _plugins(self) -> Container:
|
195
|
+
return CompositeContainer(*self._get_or_create_containers(), self._context)
|
196
|
+
|
197
|
+
@cache # noqa: B019
|
198
|
+
def _get_or_create_containers(self) -> tuple[AppContainer, Container]:
|
199
|
+
return self._app_plugin(self), self._container_plugin(self)
|
rats/apps/_container.py
CHANGED
@@ -19,10 +19,6 @@ class Provider(Protocol[Tco_ServiceType]):
|
|
19
19
|
"""Return the service instance."""
|
20
20
|
|
21
21
|
|
22
|
-
# temporary alias for backwards compatibility
|
23
|
-
ServiceProvider = Provider
|
24
|
-
|
25
|
-
|
26
22
|
class GroupProvider(Protocol[Tco_ServiceType]):
|
27
23
|
@abstractmethod
|
28
24
|
def __call__(self) -> Iterator[Tco_ServiceType]:
|
rats/apps/_executables.py
CHANGED
@@ -19,16 +19,30 @@ class Executable(Protocol):
|
|
19
19
|
|
20
20
|
class App(Executable):
|
21
21
|
"""
|
22
|
-
Wraps a plain callable objects as
|
22
|
+
Wraps a plain callable objects as a [rats.apps.Executable][].
|
23
23
|
|
24
24
|
This simple object allows for turning any callable object into an executable that is recognized
|
25
25
|
by the rest of the rats application.
|
26
|
+
|
27
|
+
Example:
|
28
|
+
```python
|
29
|
+
from rats import apps
|
30
|
+
|
31
|
+
apps.App(lambda: print("hello, world")).execute()
|
32
|
+
```
|
26
33
|
"""
|
27
34
|
|
28
35
|
_callback: Callable[[], None]
|
29
36
|
|
30
37
|
def __init__(self, callback: Callable[[], None]) -> None:
|
38
|
+
"""
|
39
|
+
Created by providing a reference to a `Callable[[], None]` function.
|
40
|
+
|
41
|
+
Args:
|
42
|
+
callback: called when the application instance is executed.
|
43
|
+
"""
|
31
44
|
self._callback = callback
|
32
45
|
|
33
46
|
def execute(self) -> None:
|
47
|
+
"""Runs the provided callback."""
|
34
48
|
self._callback()
|
rats/apps/_mains.py
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
import logging
|
2
|
+
|
3
|
+
from ._app_containers import AppBundle, AppPlugin
|
4
|
+
from ._executables import Executable
|
5
|
+
|
6
|
+
logger = logging.getLogger(__name__)
|
7
|
+
|
8
|
+
|
9
|
+
def run(*apps: Executable) -> None:
|
10
|
+
"""Shortcut for running a list of apps."""
|
11
|
+
for app in apps:
|
12
|
+
app.execute()
|
13
|
+
|
14
|
+
|
15
|
+
def run_plugin(*app_plugins: AppPlugin) -> None:
|
16
|
+
"""
|
17
|
+
Shortcut to create and execute instances of `apps.AppPlugin`.
|
18
|
+
|
19
|
+
This function is most commonly used in a `console_script` function `main()` entry point.
|
20
|
+
|
21
|
+
Example:
|
22
|
+
```python
|
23
|
+
from rats import apps
|
24
|
+
|
25
|
+
|
26
|
+
class Application(apps.AppContainer, apps.AppPlugin):
|
27
|
+
def execute(self) -> None:
|
28
|
+
print("hello, world")
|
29
|
+
|
30
|
+
|
31
|
+
def main() -> None:
|
32
|
+
apps.run_plugin(Application)
|
33
|
+
|
34
|
+
|
35
|
+
if __name__ == "__main__":
|
36
|
+
main()
|
37
|
+
```
|
38
|
+
|
39
|
+
Args:
|
40
|
+
*app_plugins: one or more class types to be instantiated and executed.
|
41
|
+
"""
|
42
|
+
run(*[AppBundle(app_plugin=plugin) for plugin in app_plugins])
|
rats/apps/_plugin_container.py
CHANGED
@@ -6,9 +6,9 @@ from ._container import Container
|
|
6
6
|
from ._ids import ServiceId, T_ServiceType
|
7
7
|
|
8
8
|
|
9
|
-
class
|
9
|
+
class PythonEntryPointContainer(Container):
|
10
10
|
"""
|
11
|
-
A container that loads plugins using importlib.metadata.entry_points.
|
11
|
+
A container that loads plugins using [importlib.metadata.entry_points][].
|
12
12
|
|
13
13
|
When looking for groups, the container loads the specified entry_points and defers the lookups
|
14
14
|
to the plugins. Plugin containers are expected to be Callable[[Container], Container] objects,
|
rats/apps/_runtimes.py
CHANGED
@@ -3,6 +3,7 @@ from abc import abstractmethod
|
|
3
3
|
from collections.abc import Callable
|
4
4
|
from typing import Protocol, final
|
5
5
|
|
6
|
+
from ._container import Container
|
6
7
|
from ._ids import ServiceId, T_ExecutableType
|
7
8
|
|
8
9
|
logger = logging.getLogger(__name__)
|
@@ -23,14 +24,6 @@ class Runtime(Protocol):
|
|
23
24
|
parallel or in any order that is convenient.
|
24
25
|
"""
|
25
26
|
|
26
|
-
@abstractmethod
|
27
|
-
def execute_callable(self, *callables: Callable[[], None]) -> None:
|
28
|
-
"""
|
29
|
-
Execute provided callables by automatically turning them into apps.Executable objects.
|
30
|
-
|
31
|
-
The used ServiceId is determined by the Runtime implementation.
|
32
|
-
"""
|
33
|
-
|
34
27
|
|
35
28
|
@final
|
36
29
|
class NullRuntime(Runtime):
|
@@ -48,3 +41,22 @@ class NullRuntime(Runtime):
|
|
48
41
|
|
49
42
|
def execute_callable(self, *callables: Callable[[], None]) -> None:
|
50
43
|
raise NotImplementedError(f"NullRuntime cannot execute callables: {callables}")
|
44
|
+
|
45
|
+
|
46
|
+
@final
|
47
|
+
class StandardRuntime(Runtime):
|
48
|
+
"""A simple runtime that executes sequentially and in a single thread."""
|
49
|
+
|
50
|
+
_app: Container
|
51
|
+
|
52
|
+
def __init__(self, app: Container) -> None:
|
53
|
+
self._app = app
|
54
|
+
|
55
|
+
def execute(self, *exe_ids: ServiceId[T_ExecutableType]) -> None:
|
56
|
+
for exe_id in exe_ids:
|
57
|
+
self._app.get(exe_id).execute()
|
58
|
+
|
59
|
+
def execute_group(self, *exe_group_ids: ServiceId[T_ExecutableType]) -> None:
|
60
|
+
for exe_group_id in exe_group_ids:
|
61
|
+
for exe in self._app.get_group(exe_group_id):
|
62
|
+
exe.execute()
|
rats/apps/_static_container.py
CHANGED
@@ -1,16 +1,17 @@
|
|
1
|
-
from collections.abc import
|
1
|
+
from collections.abc import Iterator
|
2
|
+
from dataclasses import dataclass
|
2
3
|
from typing import Any, Generic
|
3
4
|
|
4
|
-
from
|
5
|
-
|
6
|
-
from ._container import Container
|
5
|
+
from ._container import Container, Provider
|
7
6
|
from ._ids import ServiceId, T_ServiceType
|
7
|
+
from ._namespaces import ProviderNamespaces
|
8
8
|
|
9
9
|
|
10
|
-
|
10
|
+
@dataclass(frozen=True)
|
11
|
+
class StaticProvider(Generic[T_ServiceType]):
|
11
12
|
namespace: str
|
12
13
|
service_id: ServiceId[T_ServiceType]
|
13
|
-
|
14
|
+
call: Provider[T_ServiceType]
|
14
15
|
|
15
16
|
|
16
17
|
class StaticContainer(Container):
|
@@ -26,4 +27,40 @@ class StaticContainer(Container):
|
|
26
27
|
) -> Iterator[T_ServiceType]:
|
27
28
|
for provider in self._providers:
|
28
29
|
if provider.namespace == namespace and provider.service_id == group_id:
|
29
|
-
yield provider.
|
30
|
+
yield provider.call()
|
31
|
+
|
32
|
+
|
33
|
+
def static_service(
|
34
|
+
service_id: ServiceId[T_ServiceType],
|
35
|
+
provider: Provider[T_ServiceType],
|
36
|
+
) -> StaticProvider[T_ServiceType]:
|
37
|
+
"""
|
38
|
+
Factory function for a `StaticProvider` instance for `ProviderNamespaces.SERVICES`.
|
39
|
+
|
40
|
+
Args:
|
41
|
+
service_id: the identifier for the provided service.
|
42
|
+
provider: a callable that returns an instance of T_ServiceType.
|
43
|
+
|
44
|
+
Returns: StaticProvider instance for the provided service_id.
|
45
|
+
"""
|
46
|
+
return StaticProvider(ProviderNamespaces.SERVICES, service_id, provider)
|
47
|
+
|
48
|
+
|
49
|
+
def static_group(
|
50
|
+
group_id: ServiceId[T_ServiceType],
|
51
|
+
provider: Provider[T_ServiceType],
|
52
|
+
) -> StaticProvider[T_ServiceType]:
|
53
|
+
"""
|
54
|
+
Factory function for a `StaticProvider` instance for `ProviderNamespaces.GROUPS`.
|
55
|
+
|
56
|
+
!!! warning
|
57
|
+
Unlike group providers in a container, the provider function argument here should return
|
58
|
+
a single instance of the service group.
|
59
|
+
|
60
|
+
Args:
|
61
|
+
group_id: the identifier for the provided service group.
|
62
|
+
provider: a callable that returns an instance of T_ServiceType.
|
63
|
+
|
64
|
+
Returns: StaticProvider instance for the provided group_id.
|
65
|
+
"""
|
66
|
+
return StaticProvider(ProviderNamespaces.GROUPS, group_id, provider)
|
rats/cli/__init__.py
CHANGED
@@ -3,19 +3,18 @@
|
|
3
3
|
from ._annotations import CommandId, command, get_class_commands, get_class_groups, group
|
4
4
|
from ._app import ClickApp
|
5
5
|
from ._container import CompositeContainer, Container
|
6
|
-
from ._plugin import
|
6
|
+
from ._plugin import PluginServices, attach, create_group
|
7
7
|
|
8
8
|
__all__ = [
|
9
|
-
"
|
9
|
+
"ClickApp",
|
10
|
+
"CommandId",
|
11
|
+
"CompositeContainer",
|
12
|
+
"Container",
|
13
|
+
"PluginServices",
|
14
|
+
"attach",
|
10
15
|
"command",
|
16
|
+
"create_group",
|
11
17
|
"get_class_commands",
|
12
18
|
"get_class_groups",
|
13
|
-
"create_group",
|
14
|
-
"attach",
|
15
19
|
"group",
|
16
|
-
"ClickApp",
|
17
|
-
"PluginServices",
|
18
|
-
"CommandId",
|
19
|
-
"Container",
|
20
|
-
"CompositeContainer",
|
21
20
|
]
|
rats/cli/__main__.py
CHANGED
@@ -41,24 +41,16 @@ class ExampleServices:
|
|
41
41
|
MAIN = apps.ServiceId[apps.Executable]("main")
|
42
42
|
|
43
43
|
|
44
|
-
class ExampleContainer(apps.Container):
|
44
|
+
class ExampleContainer(apps.Container, apps.PluginMixin):
|
45
45
|
"""An example container of services."""
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
"""The root container allows us to access services in other plugins."""
|
51
|
-
self._app = app
|
52
|
-
|
53
|
-
@apps.service(ExampleServices.MAIN)
|
54
|
-
def _main(self) -> apps.Executable:
|
55
|
-
return cli.ClickApp(
|
47
|
+
def execute(self) -> None:
|
48
|
+
"""Run our ExampleCommands click group."""
|
49
|
+
cli.create_group(
|
56
50
|
group=click.Group("example", help="An example application."),
|
57
|
-
|
58
|
-
)
|
51
|
+
container=ExampleCommands(),
|
52
|
+
)()
|
59
53
|
|
60
54
|
|
61
55
|
if __name__ == "__main__":
|
62
|
-
apps.
|
63
|
-
ExampleServices.MAIN,
|
64
|
-
)
|
56
|
+
apps.run_plugin(ExampleContainer)
|
rats/cli/_plugin.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from typing import cast
|
1
|
+
from typing import cast
|
2
2
|
|
3
3
|
import click
|
4
4
|
|
@@ -41,11 +41,3 @@ class PluginServices:
|
|
41
41
|
@staticmethod
|
42
42
|
def click_command(cmd_id: apps.ServiceId[apps.Executable]) -> apps.ServiceId[click.Group]:
|
43
43
|
return cast(apps.ServiceId[click.Group], cmd_id)
|
44
|
-
|
45
|
-
|
46
|
-
@final
|
47
|
-
class PluginContainer(apps.Container):
|
48
|
-
_app: apps.Container
|
49
|
-
|
50
|
-
def __init__(self, app: apps.Container) -> None:
|
51
|
-
self._app = app
|
rats/logs/__init__.py
CHANGED
rats/logs/_app.py
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
import logging.config
|
2
|
+
|
3
|
+
from rats import apps
|
4
|
+
|
5
|
+
logger = logging.getLogger(__name__)
|
6
|
+
|
7
|
+
|
8
|
+
class ConfigureApplication(apps.AppContainer, apps.PluginMixin):
|
9
|
+
def execute(self) -> None:
|
10
|
+
logging.config.dictConfig(
|
11
|
+
{
|
12
|
+
"version": 1,
|
13
|
+
"disable_existing_loggers": False,
|
14
|
+
"formatters": {
|
15
|
+
"colored": {
|
16
|
+
"()": "colorlog.ColoredFormatter",
|
17
|
+
"format": (
|
18
|
+
"%(log_color)s%(asctime)s %(levelname)-8s [%(name)s][%(lineno)d]: "
|
19
|
+
"%(message)s%(reset)s"
|
20
|
+
),
|
21
|
+
"datefmt": "%Y-%m-%d %H:%M:%S",
|
22
|
+
"log_colors": {
|
23
|
+
"DEBUG": "white",
|
24
|
+
"INFO": "green",
|
25
|
+
"WARNING": "yellow",
|
26
|
+
"ERROR": "red,",
|
27
|
+
"CRITICAL": "bold_red",
|
28
|
+
},
|
29
|
+
}
|
30
|
+
},
|
31
|
+
"handlers": {
|
32
|
+
"console": {
|
33
|
+
"class": "logging.StreamHandler",
|
34
|
+
"level": "DEBUG",
|
35
|
+
"formatter": "colored",
|
36
|
+
"stream": "ext://sys.stderr",
|
37
|
+
}
|
38
|
+
},
|
39
|
+
"loggers": {
|
40
|
+
"": {"level": "INFO", "handlers": ["console"]},
|
41
|
+
"azure": {"level": "WARNING", "handlers": ["console"]},
|
42
|
+
},
|
43
|
+
}
|
44
|
+
)
|
45
|
+
logger.debug("done configuring logging")
|
@@ -1,8 +1,7 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: rats-apps
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.5.0
|
4
4
|
Summary: research analysis tools for building applications
|
5
|
-
Home-page: https://github.com/microsoft/rats/
|
6
5
|
License: MIT
|
7
6
|
Keywords: pipelines,machine learning,research
|
8
7
|
Requires-Python: >=3.10,<4.0
|