rats-apps 0.1.3.dev1__py3-none-any.whl → 0.1.3.dev9__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/__init__.py +8 -0
- rats/apps/_annotations.py +58 -13
- rats/apps/_scoping.py +6 -2
- {rats_apps-0.1.3.dev1.dist-info → rats_apps-0.1.3.dev9.dist-info}/METADATA +1 -1
- {rats_apps-0.1.3.dev1.dist-info → rats_apps-0.1.3.dev9.dist-info}/RECORD +7 -7
- {rats_apps-0.1.3.dev1.dist-info → rats_apps-0.1.3.dev9.dist-info}/WHEEL +0 -0
- {rats_apps-0.1.3.dev1.dist-info → rats_apps-0.1.3.dev9.dist-info}/entry_points.txt +0 -0
rats/apps/__init__.py
CHANGED
@@ -7,17 +7,21 @@ domain.
|
|
7
7
|
|
8
8
|
from ._annotations import (
|
9
9
|
AnnotatedContainer,
|
10
|
+
autoid_service,
|
10
11
|
config,
|
11
12
|
container,
|
12
13
|
fallback_config,
|
13
14
|
fallback_group,
|
14
15
|
fallback_service,
|
15
16
|
group,
|
17
|
+
method_service_id,
|
16
18
|
service,
|
17
19
|
)
|
20
|
+
from ._composite_container import CompositeContainer
|
18
21
|
from ._container import Container, DuplicateServiceError, ServiceNotFoundError
|
19
22
|
from ._ids import ConfigId, ServiceId
|
20
23
|
from ._namespaces import ProviderNamespaces
|
24
|
+
from ._plugin_container import PluginContainers
|
21
25
|
from ._scoping import autoscope
|
22
26
|
|
23
27
|
__all__ = [
|
@@ -36,4 +40,8 @@ __all__ = [
|
|
36
40
|
"fallback_service",
|
37
41
|
"group",
|
38
42
|
"service",
|
43
|
+
"method_service_id",
|
44
|
+
"autoid_service",
|
45
|
+
"CompositeContainer",
|
46
|
+
"PluginContainers",
|
39
47
|
]
|
rats/apps/_annotations.py
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
from collections import defaultdict
|
2
2
|
from collections.abc import Callable, Iterator
|
3
3
|
from functools import cache
|
4
|
-
from typing import Any, cast
|
4
|
+
from typing import Any, ParamSpec, cast
|
5
5
|
|
6
6
|
from typing_extensions import NamedTuple
|
7
7
|
|
8
8
|
from ._container import Container
|
9
9
|
from ._ids import ConfigId, ServiceId, T_ConfigType, T_ServiceType
|
10
10
|
from ._namespaces import ProviderNamespaces
|
11
|
+
from ._scoping import scope_service_name
|
11
12
|
|
12
13
|
DEFAULT_CONTAINER_GROUP = ServiceId[Container]("__default__")
|
13
14
|
|
@@ -57,6 +58,9 @@ class FunctionAnnotationsBuilder:
|
|
57
58
|
def add(self, namespace: str, service_id: ServiceId[T_ServiceType]) -> None:
|
58
59
|
self._service_ids[namespace].append(service_id)
|
59
60
|
|
61
|
+
def get_service_names(self, namespace: str) -> tuple[str, ...]:
|
62
|
+
return tuple(s.name for s in self._service_ids.get(namespace, []))
|
63
|
+
|
60
64
|
def make(self, name: str) -> tuple[GroupAnnotations, ...]:
|
61
65
|
return tuple(
|
62
66
|
[
|
@@ -84,57 +88,98 @@ class AnnotatedContainer(Container):
|
|
84
88
|
yield from c.get_namespaced_group(namespace, group_id)
|
85
89
|
|
86
90
|
|
91
|
+
P = ParamSpec("P")
|
92
|
+
|
93
|
+
|
87
94
|
def service(
|
88
95
|
service_id: ServiceId[T_ServiceType],
|
89
|
-
) -> Callable[
|
96
|
+
) -> Callable[[Callable[P, T_ServiceType]], Callable[P, T_ServiceType]]:
|
90
97
|
return fn_annotation_decorator(ProviderNamespaces.SERVICES, service_id)
|
91
98
|
|
92
99
|
|
100
|
+
def autoid_service(fn: Callable[P, T_ServiceType]) -> Callable[P, T_ServiceType]:
|
101
|
+
_service_id = method_service_id(fn)
|
102
|
+
_add_annotation(ProviderNamespaces.SERVICES, fn, _service_id)
|
103
|
+
cached_fn = cache(fn)
|
104
|
+
return cast(Callable[P, T_ServiceType], cached_fn)
|
105
|
+
|
106
|
+
|
93
107
|
def group(
|
94
108
|
group_id: ServiceId[T_ServiceType],
|
95
|
-
) -> Callable[
|
109
|
+
) -> Callable[[Callable[P, T_ServiceType]], Callable[P, T_ServiceType]]:
|
96
110
|
return fn_annotation_decorator(ProviderNamespaces.GROUPS, group_id)
|
97
111
|
|
98
112
|
|
99
113
|
def config(
|
100
114
|
config_id: ConfigId[T_ConfigType],
|
101
|
-
) -> Callable[
|
115
|
+
) -> Callable[[Callable[P, T_ConfigType]], Callable[P, T_ConfigType]]:
|
102
116
|
return fn_annotation_decorator(ProviderNamespaces.SERVICES, config_id)
|
103
117
|
|
104
118
|
|
105
119
|
def fallback_service(
|
106
120
|
service_id: ServiceId[T_ServiceType],
|
107
|
-
) -> Callable[
|
121
|
+
) -> Callable[[Callable[P, T_ServiceType]], Callable[P, T_ServiceType]]:
|
108
122
|
return fn_annotation_decorator(ProviderNamespaces.FALLBACK_SERVICES, service_id)
|
109
123
|
|
110
124
|
|
111
125
|
def fallback_group(
|
112
126
|
group_id: ServiceId[T_ServiceType],
|
113
|
-
) -> Callable[
|
127
|
+
) -> Callable[[Callable[P, T_ServiceType]], Callable[P, T_ServiceType]]:
|
114
128
|
return fn_annotation_decorator(ProviderNamespaces.FALLBACK_GROUPS, group_id)
|
115
129
|
|
116
130
|
|
117
131
|
def fallback_config(
|
118
132
|
config_id: ConfigId[T_ConfigType],
|
119
|
-
) -> Callable[
|
133
|
+
) -> Callable[[Callable[P, T_ConfigType]], Callable[P, T_ConfigType]]:
|
120
134
|
return fn_annotation_decorator(ProviderNamespaces.FALLBACK_SERVICES, config_id)
|
121
135
|
|
122
136
|
|
123
137
|
def container(
|
124
138
|
group_id: ServiceId[T_ServiceType] = DEFAULT_CONTAINER_GROUP,
|
125
|
-
) -> Callable[
|
139
|
+
) -> Callable[[Callable[P, T_ServiceType]], Callable[P, T_ServiceType]]:
|
126
140
|
return fn_annotation_decorator(ProviderNamespaces.CONTAINERS, group_id)
|
127
141
|
|
128
142
|
|
143
|
+
def _get_method_service_id_name(method: Callable[..., Any]) -> str:
|
144
|
+
existing_names = _get_annotations_builder(method).get_service_names(
|
145
|
+
ProviderNamespaces.SERVICES
|
146
|
+
)
|
147
|
+
if existing_names:
|
148
|
+
return existing_names[0]
|
149
|
+
else:
|
150
|
+
module_name = method.__module__
|
151
|
+
class_name, method_name = method.__qualname__.rsplit(".", 1)
|
152
|
+
service_name = scope_service_name(module_name, class_name, method_name)
|
153
|
+
return service_name
|
154
|
+
|
155
|
+
|
156
|
+
def method_service_id(method: Callable[..., T_ServiceType]) -> ServiceId[T_ServiceType]:
|
157
|
+
"""
|
158
|
+
Get a service id for a method.
|
159
|
+
|
160
|
+
The service id is constructed from the module, class and method name. It should be identical
|
161
|
+
regardless of whether the method is bound or not, and regardless of the instance it is bound
|
162
|
+
to.
|
163
|
+
|
164
|
+
The service type is the return type of the method.
|
165
|
+
"""
|
166
|
+
service_name = _get_method_service_id_name(method)
|
167
|
+
return ServiceId[T_ServiceType](service_name)
|
168
|
+
|
169
|
+
|
129
170
|
def fn_annotation_decorator(
|
130
171
|
namespace: str,
|
131
172
|
service_id: ServiceId[T_ServiceType],
|
132
|
-
) -> Callable[
|
173
|
+
) -> Callable[[Callable[P, T_ServiceType]], Callable[P, T_ServiceType]]:
|
133
174
|
def wrapper(
|
134
|
-
fn: Callable[
|
135
|
-
) -> Callable[
|
136
|
-
|
137
|
-
|
175
|
+
fn: Callable[P, T_ServiceType],
|
176
|
+
) -> Callable[P, T_ServiceType]:
|
177
|
+
_service_id = service_id
|
178
|
+
_add_annotation(namespace, fn, _service_id)
|
179
|
+
cached_fn = cache(fn)
|
180
|
+
# The static type of cached_fn should be correct, but it does not maintain the param-spec,
|
181
|
+
# so we need to cast.
|
182
|
+
return cast(Callable[P, T_ServiceType], cached_fn)
|
138
183
|
|
139
184
|
return wrapper
|
140
185
|
|
rats/apps/_scoping.py
CHANGED
@@ -8,6 +8,10 @@ T = TypeVar("T")
|
|
8
8
|
P = ParamSpec("P")
|
9
9
|
|
10
10
|
|
11
|
+
def scope_service_name(module_name: str, cls_name: str, name: str) -> str:
|
12
|
+
return f"{module_name}:{cls_name}[{name}]"
|
13
|
+
|
14
|
+
|
11
15
|
def autoscope(cls: type[T]) -> type[T]:
|
12
16
|
"""
|
13
17
|
Decorator that replaces all ServiceId instances in the class with scoped ServiceId instances.
|
@@ -22,7 +26,7 @@ def autoscope(cls: type[T]) -> type[T]:
|
|
22
26
|
if not isinstance(result, ServiceId):
|
23
27
|
return result
|
24
28
|
|
25
|
-
return ServiceId[Any](
|
29
|
+
return ServiceId[Any](scope_service_name(cls.__module__, cls.__name__, result.name))
|
26
30
|
|
27
31
|
return cast(FunctionType, wrapper)
|
28
32
|
|
@@ -37,7 +41,7 @@ def autoscope(cls: type[T]) -> type[T]:
|
|
37
41
|
if not isinstance(non_ns, ServiceId):
|
38
42
|
continue
|
39
43
|
|
40
|
-
prop = ServiceId[Any](
|
44
|
+
prop = ServiceId[Any](scope_service_name(cls.__module__, cls.__name__, non_ns.name))
|
41
45
|
setattr(cls, prop_name, prop)
|
42
46
|
|
43
47
|
return cls
|
@@ -1,13 +1,13 @@
|
|
1
|
-
rats/apps/__init__.py,sha256=
|
2
|
-
rats/apps/_annotations.py,sha256=
|
1
|
+
rats/apps/__init__.py,sha256=5Mi9YL80YF6Z1Jy2uB_L1oWDG_w0Tl00yViprVuO_LQ,1099
|
2
|
+
rats/apps/_annotations.py,sha256=GT2VGkLO2Re0oZsVd6oQlm0WdJj5NSirGA0cpPmmiik,6993
|
3
3
|
rats/apps/_composite_container.py,sha256=wSWVQWPin2xxIlEoSgk_D1rlc3N2gpTxQ2y9UFdqXy0,553
|
4
4
|
rats/apps/_container.py,sha256=5uiCyxN6HS2z97XcTOFP-t72cNoB1U1sJMkMcfSfDps,3129
|
5
5
|
rats/apps/_ids.py,sha256=dxWCPMpMA_vpaTDJEKNByIBJaX97Db203XqWLhaOezo,457
|
6
6
|
rats/apps/_namespaces.py,sha256=THUV_Xj5PtweC23Ob-zsSpk8exC4fT-qRwjpQ6IDm0U,188
|
7
7
|
rats/apps/_plugin_container.py,sha256=W_xQD2btc0N2dEb3c5tXM-ZZ4A4diMpkCjbOZdlXYuI,853
|
8
|
-
rats/apps/_scoping.py,sha256=
|
8
|
+
rats/apps/_scoping.py,sha256=plSVEq3rJ8JFAu2epVg2NQpuTbpSTA3a0Tha_DwJL_Y,1453
|
9
9
|
rats/apps/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
-
rats_apps-0.1.3.
|
11
|
-
rats_apps-0.1.3.
|
12
|
-
rats_apps-0.1.3.
|
13
|
-
rats_apps-0.1.3.
|
10
|
+
rats_apps-0.1.3.dev9.dist-info/METADATA,sha256=rWKB-G07Xc5Nm0CIT0W3fyNrXWDPg632uRdkrYF6Z0o,716
|
11
|
+
rats_apps-0.1.3.dev9.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
12
|
+
rats_apps-0.1.3.dev9.dist-info/entry_points.txt,sha256=Vu1IgAPQvL4xMJzW_OG2JSPFac7HalCHyXiRr0-OfCI,86
|
13
|
+
rats_apps-0.1.3.dev9.dist-info/RECORD,,
|
File without changes
|
File without changes
|