rats-apps 0.2.0.dev20240906121056__py3-none-any.whl → 0.3.0.dev20241001092342__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/_annotations.py +8 -4
- rats/apps/_container.py +70 -28
- rats/cli/__init__.py +3 -1
- rats/cli/_container.py +1 -3
- rats/cli/_plugin.py +17 -0
- rats/logs/_plugin.py +3 -2
- {rats_apps-0.2.0.dev20240906121056.dist-info → rats_apps-0.3.0.dev20241001092342.dist-info}/METADATA +1 -1
- {rats_apps-0.2.0.dev20240906121056.dist-info → rats_apps-0.3.0.dev20241001092342.dist-info}/RECORD +10 -10
- {rats_apps-0.2.0.dev20240906121056.dist-info → rats_apps-0.3.0.dev20241001092342.dist-info}/WHEEL +0 -0
- {rats_apps-0.2.0.dev20240906121056.dist-info → rats_apps-0.3.0.dev20241001092342.dist-info}/entry_points.txt +0 -0
rats/apps/_annotations.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from collections.abc import Callable
|
1
|
+
from collections.abc import Callable, Iterator
|
2
2
|
from typing import Any, Concatenate, Generic, NamedTuple, ParamSpec, TypeVar, cast
|
3
3
|
|
4
4
|
from rats import annotations
|
@@ -26,7 +26,7 @@ def autoid_service(fn: Callable[P, T_ServiceType]) -> Callable[P, T_ServiceType]
|
|
26
26
|
|
27
27
|
def group(
|
28
28
|
group_id: ServiceId[T_ServiceType],
|
29
|
-
) -> Callable[[Callable[P, T_ServiceType]], Callable[P, T_ServiceType]]:
|
29
|
+
) -> Callable[[Callable[P, Iterator[T_ServiceType]]], Callable[P, Iterator[T_ServiceType]]]:
|
30
30
|
"""A group is a collection of services."""
|
31
31
|
return annotations.annotation(ProviderNamespaces.GROUPS, cast(NamedTuple, group_id))
|
32
32
|
|
@@ -43,7 +43,7 @@ def fallback_service(
|
|
43
43
|
|
44
44
|
def fallback_group(
|
45
45
|
group_id: ServiceId[T_ServiceType],
|
46
|
-
) -> Callable[[Callable[P, T_ServiceType]], Callable[P, T_ServiceType]]:
|
46
|
+
) -> Callable[[Callable[P, Iterator[T_ServiceType]]], Callable[P, Iterator[T_ServiceType]]]:
|
47
47
|
"""A fallback group gets used if no group is defined."""
|
48
48
|
return annotations.annotation(
|
49
49
|
ProviderNamespaces.FALLBACK_GROUPS,
|
@@ -69,7 +69,7 @@ def _factory_to_factory_provider(
|
|
69
69
|
return new_method
|
70
70
|
|
71
71
|
|
72
|
-
class
|
72
|
+
class _FactoryService(Generic[P, R]):
|
73
73
|
"""
|
74
74
|
A decorator to create a factory service.
|
75
75
|
|
@@ -89,6 +89,10 @@ class factory_service(Generic[P, R]):
|
|
89
89
|
return service(self._service_id)(new_method)
|
90
90
|
|
91
91
|
|
92
|
+
# alias so we can think of it as a function
|
93
|
+
factory_service = _FactoryService
|
94
|
+
|
95
|
+
|
92
96
|
def autoid_factory_service(
|
93
97
|
method: Callable[Concatenate[T_Container, P], R],
|
94
98
|
) -> Callable[[T_Container], Callable[P, R]]:
|
rats/apps/_container.py
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
import logging
|
2
2
|
from abc import abstractmethod
|
3
3
|
from collections.abc import Callable, Iterator
|
4
|
-
from typing import Generic, NamedTuple, ParamSpec, Protocol, cast
|
4
|
+
from typing import Any, Generic, NamedTuple, ParamSpec, Protocol, cast
|
5
|
+
|
6
|
+
from typing_extensions import NamedTuple as ExtNamedTuple
|
5
7
|
|
6
8
|
from rats import annotations
|
7
9
|
|
@@ -109,9 +111,13 @@ class Container(Protocol):
|
|
109
111
|
) -> Iterator[T_ServiceType]:
|
110
112
|
"""Retrieve a service group by its id."""
|
111
113
|
if not self.has_namespace(ProviderNamespaces.GROUPS, group_id):
|
112
|
-
|
114
|
+
# groups are expected to return iterable services
|
115
|
+
# TODO: we need to clean up the meaning of groups and services somehow
|
116
|
+
for i in self.get_namespaced_group(ProviderNamespaces.FALLBACK_GROUPS, group_id):
|
117
|
+
yield from cast(Iterator[T_ServiceType], i)
|
113
118
|
|
114
|
-
|
119
|
+
for i in self.get_namespaced_group(ProviderNamespaces.GROUPS, group_id):
|
120
|
+
yield from cast(Iterator[T_ServiceType], i)
|
115
121
|
|
116
122
|
def get_namespaced_group(
|
117
123
|
self,
|
@@ -119,31 +125,67 @@ class Container(Protocol):
|
|
119
125
|
group_id: ServiceId[T_ServiceType],
|
120
126
|
) -> Iterator[T_ServiceType]:
|
121
127
|
"""Retrieve a service group by its id, within a given service namespace."""
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
128
|
+
yield from _get_cached_services_for_group(self, namespace, group_id)
|
129
|
+
|
130
|
+
for subcontainer in _get_subcontainers(self):
|
131
|
+
yield from subcontainer.get_namespaced_group(namespace, group_id)
|
132
|
+
|
133
|
+
|
134
|
+
def _get_subcontainers(c: Container) -> Iterator[Container]:
|
135
|
+
yield from _get_cached_services_for_group(
|
136
|
+
c, ProviderNamespaces.CONTAINERS, DEFAULT_CONTAINER_GROUP
|
137
|
+
)
|
138
|
+
|
139
|
+
|
140
|
+
class _ProviderInfo(ExtNamedTuple, Generic[T_ServiceType]):
|
141
|
+
attr: str
|
142
|
+
group_id: ServiceId[T_ServiceType]
|
143
|
+
|
144
|
+
|
145
|
+
def _get_cached_services_for_group(
|
146
|
+
c: Container,
|
147
|
+
namespace: str,
|
148
|
+
group_id: ServiceId[T_ServiceType],
|
149
|
+
) -> Iterator[T_ServiceType]:
|
150
|
+
provider_cache = _get_provider_cache(c)
|
151
|
+
info_cache = _get_provider_info_cache(c)
|
152
|
+
|
153
|
+
if (namespace, group_id) not in info_cache:
|
154
|
+
info_cache[(namespace, group_id)] = list(_get_providers_for_group(c, namespace, group_id))
|
155
|
+
|
156
|
+
for provider in info_cache[(namespace, group_id)]:
|
157
|
+
if provider not in provider_cache:
|
158
|
+
provider_cache[provider] = getattr(c, provider.attr)()
|
159
|
+
|
160
|
+
yield provider_cache[provider]
|
161
|
+
|
162
|
+
|
163
|
+
def _get_provider_cache(obj: object) -> dict[_ProviderInfo[Any], Any]:
|
164
|
+
if not hasattr(obj, "__rats_apps_provider_cache__"):
|
165
|
+
obj.__rats_apps_provider_cache__ = {} # type: ignore[reportAttributeAccessIssue]
|
166
|
+
|
167
|
+
return obj.__rats_apps_provider_cache__ # type: ignore[reportAttributeAccessIssue]
|
168
|
+
|
169
|
+
|
170
|
+
def _get_provider_info_cache(
|
171
|
+
obj: object,
|
172
|
+
) -> dict[tuple[str, ServiceId[Any]], list[_ProviderInfo[Any]]]:
|
173
|
+
if not hasattr(obj, "__rats_apps_provider_info_cache__"):
|
174
|
+
obj.__rats_apps_provider_info_cache__ = {} # type: ignore[reportAttributeAccessIssue]
|
175
|
+
|
176
|
+
return obj.__rats_apps_provider_info_cache__ # type: ignore[reportAttributeAccessIssue]
|
177
|
+
|
178
|
+
|
179
|
+
def _get_providers_for_group(
|
180
|
+
c: Container,
|
181
|
+
namespace: str,
|
182
|
+
group_id: ServiceId[T_ServiceType],
|
183
|
+
) -> Iterator[_ProviderInfo[T_ServiceType]]:
|
184
|
+
tates = annotations.get_class_annotations(type(c))
|
185
|
+
groups = tates.with_group(namespace, cast(NamedTuple, group_id))
|
186
|
+
|
187
|
+
for annotation in groups.annotations:
|
188
|
+
yield _ProviderInfo(annotation.name, group_id)
|
147
189
|
|
148
190
|
|
149
191
|
DEFAULT_CONTAINER_GROUP = ServiceId[Container](f"{__name__}:__default__")
|
rats/cli/__init__.py
CHANGED
@@ -3,13 +3,15 @@
|
|
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 CommandContainer
|
6
|
-
from ._plugin import PluginContainer, PluginServices
|
6
|
+
from ._plugin import PluginContainer, PluginServices, attach, create_group
|
7
7
|
|
8
8
|
__all__ = [
|
9
9
|
"PluginContainer",
|
10
10
|
"command",
|
11
11
|
"get_class_commands",
|
12
12
|
"get_class_groups",
|
13
|
+
"create_group",
|
14
|
+
"attach",
|
13
15
|
"group",
|
14
16
|
"ClickApp",
|
15
17
|
"PluginServices",
|
rats/cli/_container.py
CHANGED
@@ -5,14 +5,12 @@ from typing import Any, Protocol
|
|
5
5
|
|
6
6
|
import click
|
7
7
|
|
8
|
-
from rats import apps
|
9
|
-
|
10
8
|
from ._annotations import get_class_commands
|
11
9
|
|
12
10
|
logger = logging.getLogger(__name__)
|
13
11
|
|
14
12
|
|
15
|
-
class CommandContainer(
|
13
|
+
class CommandContainer(Protocol):
|
16
14
|
"""A container that can attach click commands to a click group."""
|
17
15
|
|
18
16
|
def attach(self, group: click.Group) -> None:
|
rats/cli/_plugin.py
CHANGED
@@ -4,6 +4,23 @@ import click
|
|
4
4
|
|
5
5
|
from rats import apps
|
6
6
|
|
7
|
+
from ._container import CommandContainer
|
8
|
+
|
9
|
+
|
10
|
+
def create_group(group: click.Group, container: CommandContainer) -> click.Group:
|
11
|
+
container.attach(group)
|
12
|
+
return group
|
13
|
+
|
14
|
+
|
15
|
+
def attach(
|
16
|
+
group: click.Group,
|
17
|
+
command: click.Command | click.Group,
|
18
|
+
*commands: click.Command | click.Group,
|
19
|
+
) -> None:
|
20
|
+
group.add_command(command)
|
21
|
+
for c in commands:
|
22
|
+
group.add_command(c)
|
23
|
+
|
7
24
|
|
8
25
|
@apps.autoscope
|
9
26
|
class _PluginEvents:
|
rats/logs/_plugin.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import logging.config
|
2
|
+
from collections.abc import Iterator
|
2
3
|
|
3
4
|
from rats import apps
|
4
5
|
|
@@ -22,9 +23,9 @@ class PluginContainer(apps.Container):
|
|
22
23
|
self._app = app
|
23
24
|
|
24
25
|
@apps.group(PluginServices.EVENTS.CONFIGURE_LOGGING)
|
25
|
-
def _configure_logging(self) -> apps.Executable:
|
26
|
+
def _configure_logging(self) -> Iterator[apps.Executable]:
|
26
27
|
# in the future, we can use this plugin to make logging easily configurable
|
27
|
-
|
28
|
+
yield apps.App(
|
28
29
|
lambda: logging.config.dictConfig(
|
29
30
|
{
|
30
31
|
"version": 1,
|
{rats_apps-0.2.0.dev20240906121056.dist-info → rats_apps-0.3.0.dev20241001092342.dist-info}/RECORD
RENAMED
@@ -4,9 +4,9 @@ rats/annotations/_functions.py,sha256=UkHh3zdBivluE7dBeGQ17zoIfGdyIokMAkFmpWaIlD
|
|
4
4
|
rats/annotations/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
5
|
rats/apps/__init__.py,sha256=SlqFKChSf661J6nlcuSGNQO-fLceqZrwOGn1YoyYDzs,1703
|
6
6
|
rats/apps/__main__.py,sha256=KjdadN4rdP0xhWiLzdmtCsXejWx_gxOK-ah-L1r1dTI,1818
|
7
|
-
rats/apps/_annotations.py,sha256=
|
7
|
+
rats/apps/_annotations.py,sha256=6M_M7K8haNVda0Tx02EpFf3s9EjnWYacNMjTIkNEdRU,4617
|
8
8
|
rats/apps/_composite_container.py,sha256=s_of6NyyrjFVYWGVehyEHe9WJIPRCnbB-tyWyNF8zyc,585
|
9
|
-
rats/apps/_container.py,sha256=
|
9
|
+
rats/apps/_container.py,sha256=Gb7jJmGyKGDZFjoe0s0C_gC7ymSpXaqordfQaJZGJf4,7283
|
10
10
|
rats/apps/_executables.py,sha256=QJ5_UPdZPmDQ1a3cLRJDUoeUMzNMwa3ZHYhYeS3AVq4,971
|
11
11
|
rats/apps/_ids.py,sha256=T8Onrj79t8NPfBMQBk0xI6fIWDKF0m2JfFNrdtXAbWg,353
|
12
12
|
rats/apps/_namespaces.py,sha256=THUV_Xj5PtweC23Ob-zsSpk8exC4fT-qRwjpQ6IDm0U,188
|
@@ -17,17 +17,17 @@ rats/apps/_scoping.py,sha256=6C2-ID22cCPR9Cbexf3CvCF3o9F_7ieURbwqkf6DI68,1360
|
|
17
17
|
rats/apps/_simple_apps.py,sha256=n-3zeHY3iintZ9LN597c7zDHv3DiIdl7c8NTk0gUk1Y,5477
|
18
18
|
rats/apps/_static_container.py,sha256=5lzLh1CUoQVwhxfDhK6ZOQaBrPpudbRHWJkaDppphZo,881
|
19
19
|
rats/apps/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
|
-
rats/cli/__init__.py,sha256=
|
20
|
+
rats/cli/__init__.py,sha256=bBYDOs697TLCf86maID-JZkHeB7rvBfiwk97qDUmMCk,548
|
21
21
|
rats/cli/__main__.py,sha256=3JZ7mrTTrrODQHutefm2zJp1-cQQB7I5-1xhYw7SMBU,1656
|
22
22
|
rats/cli/_annotations.py,sha256=5voM1pNm7iybZpgQTSVpaq3rMIMz33jr4eUyoEmxWJ4,1359
|
23
23
|
rats/cli/_app.py,sha256=NjJfXKZYBdd1CZuLbrXyUFB_wRJQah1Rvtxe_zj4y_M,641
|
24
|
-
rats/cli/_container.py,sha256=
|
25
|
-
rats/cli/_plugin.py,sha256=
|
24
|
+
rats/cli/_container.py,sha256=PsvUIqQgQVXRTUh7BXhpzm42gxXU100-0EaYGwcmAAg,1833
|
25
|
+
rats/cli/_plugin.py,sha256=gOLTR0qZ4TAYJ9ORoeOeFiiiN9JBTakEACtPORlYSTE,1100
|
26
26
|
rats/cli/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
27
27
|
rats/logs/__init__.py,sha256=fCn4pfpYiAcTtt5CsnUZX68CjOB3KJHxMSiYxsma4qE,183
|
28
|
-
rats/logs/_plugin.py,sha256=
|
28
|
+
rats/logs/_plugin.py,sha256=OQ5fXToBm60YJRrMUVJ9_HVytUs3c69vaHY57jpivb0,2221
|
29
29
|
rats/logs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
|
-
rats_apps-0.
|
31
|
-
rats_apps-0.
|
32
|
-
rats_apps-0.
|
33
|
-
rats_apps-0.
|
30
|
+
rats_apps-0.3.0.dev20241001092342.dist-info/METADATA,sha256=_hr4P32onK68GdbiEjuIR3AmMAOLIaR5t3bKtcy1_6A,774
|
31
|
+
rats_apps-0.3.0.dev20241001092342.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
32
|
+
rats_apps-0.3.0.dev20241001092342.dist-info/entry_points.txt,sha256=9oOvf2loQr5ACWQgvuu9Q3KZIVIxKE5Aa-rLuUII5WQ,91
|
33
|
+
rats_apps-0.3.0.dev20241001092342.dist-info/RECORD,,
|
{rats_apps-0.2.0.dev20240906121056.dist-info → rats_apps-0.3.0.dev20241001092342.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|