pico-ioc 2.1.2__py3-none-any.whl → 2.1.3__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.
- pico_ioc/_version.py +1 -1
- pico_ioc/analysis.py +3 -4
- pico_ioc/aop.py +52 -17
- pico_ioc/config_runtime.py +5 -2
- pico_ioc/container.py +16 -6
- pico_ioc/event_bus.py +22 -19
- pico_ioc/registrar.py +2 -2
- pico_ioc/scope.py +21 -14
- {pico_ioc-2.1.2.dist-info → pico_ioc-2.1.3.dist-info}/METADATA +10 -1
- {pico_ioc-2.1.2.dist-info → pico_ioc-2.1.3.dist-info}/RECORD +13 -13
- {pico_ioc-2.1.2.dist-info → pico_ioc-2.1.3.dist-info}/WHEEL +0 -0
- {pico_ioc-2.1.2.dist-info → pico_ioc-2.1.3.dist-info}/licenses/LICENSE +0 -0
- {pico_ioc-2.1.2.dist-info → pico_ioc-2.1.3.dist-info}/top_level.txt +0 -0
pico_ioc/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = '2.1.
|
|
1
|
+
__version__ = '2.1.3'
|
pico_ioc/analysis.py
CHANGED
|
@@ -8,6 +8,7 @@ from typing import (
|
|
|
8
8
|
Dict, Mapping
|
|
9
9
|
)
|
|
10
10
|
from .decorators import Qualifier
|
|
11
|
+
from .constants import LOGGER
|
|
11
12
|
|
|
12
13
|
KeyT = Union[str, type]
|
|
13
14
|
|
|
@@ -47,20 +48,18 @@ def _check_optional(ann: Any) -> Tuple[Any, bool]:
|
|
|
47
48
|
def analyze_callable_dependencies(callable_obj: Callable[..., Any]) -> Tuple[DependencyRequest, ...]:
|
|
48
49
|
try:
|
|
49
50
|
sig = inspect.signature(callable_obj)
|
|
50
|
-
except (ValueError, TypeError):
|
|
51
|
+
except (ValueError, TypeError) as e:
|
|
52
|
+
LOGGER.debug(f"Could not analyze dependencies for {callable_obj!r}: {e}")
|
|
51
53
|
return ()
|
|
52
54
|
|
|
53
55
|
plan: List[DependencyRequest] = []
|
|
54
56
|
|
|
55
57
|
SUPPORTED_COLLECTION_ORIGINS = (
|
|
56
|
-
# Runtime types
|
|
57
58
|
list,
|
|
58
59
|
set,
|
|
59
60
|
tuple,
|
|
60
61
|
frozenset,
|
|
61
62
|
collections.deque,
|
|
62
|
-
|
|
63
|
-
# Typing ABCs (from get_origin)
|
|
64
63
|
collections.abc.Iterable,
|
|
65
64
|
collections.abc.Collection,
|
|
66
65
|
collections.abc.Sequence,
|
pico_ioc/aop.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# src/pico_ioc/aop.py
|
|
2
|
-
|
|
3
1
|
import inspect
|
|
4
2
|
import pickle
|
|
5
3
|
import threading
|
|
@@ -75,15 +73,18 @@ def health(fn):
|
|
|
75
73
|
return fn
|
|
76
74
|
|
|
77
75
|
class UnifiedComponentProxy:
|
|
78
|
-
__slots__ = ("_target", "_creator", "_container", "_cache", "_lock")
|
|
79
|
-
|
|
76
|
+
__slots__ = ("_target", "_creator", "_container", "_cache", "_lock", "_component_key")
|
|
77
|
+
|
|
78
|
+
def __init__(self, *, container: Any, target: Any = None, object_creator: Callable[[], Any] | None = None, component_key: Any = None):
|
|
80
79
|
if container is None:
|
|
81
80
|
raise ValueError("UnifiedComponentProxy requires a non-null container")
|
|
82
81
|
if target is None and object_creator is None:
|
|
83
82
|
raise ValueError("UnifiedComponentProxy requires either a target or an object_creator")
|
|
83
|
+
|
|
84
84
|
object.__setattr__(self, "_container", container)
|
|
85
85
|
object.__setattr__(self, "_target", target)
|
|
86
86
|
object.__setattr__(self, "_creator", object_creator)
|
|
87
|
+
object.__setattr__(self, "_component_key", component_key)
|
|
87
88
|
object.__setattr__(self, "_cache", {})
|
|
88
89
|
object.__setattr__(self, "_lock", threading.RLock())
|
|
89
90
|
|
|
@@ -98,6 +99,7 @@ class UnifiedComponentProxy:
|
|
|
98
99
|
def __setstate__(self, state):
|
|
99
100
|
object.__setattr__(self, "_container", None)
|
|
100
101
|
object.__setattr__(self, "_creator", None)
|
|
102
|
+
object.__setattr__(self, "_component_key", None)
|
|
101
103
|
object.__setattr__(self, "_cache", {})
|
|
102
104
|
object.__setattr__(self, "_lock", threading.RLock())
|
|
103
105
|
try:
|
|
@@ -110,14 +112,17 @@ class UnifiedComponentProxy:
|
|
|
110
112
|
tgt = object.__getattribute__(self, "_target")
|
|
111
113
|
if tgt is not None:
|
|
112
114
|
return tgt
|
|
115
|
+
|
|
113
116
|
lock = object.__getattribute__(self, "_lock")
|
|
114
117
|
with lock:
|
|
115
118
|
tgt = object.__getattribute__(self, "_target")
|
|
116
119
|
if tgt is not None:
|
|
117
120
|
return tgt
|
|
121
|
+
|
|
118
122
|
creator = object.__getattribute__(self, "_creator")
|
|
119
123
|
if not callable(creator):
|
|
120
124
|
raise TypeError("UnifiedComponentProxy object_creator must be callable")
|
|
125
|
+
|
|
121
126
|
tgt = creator()
|
|
122
127
|
if tgt is None:
|
|
123
128
|
raise RuntimeError("UnifiedComponentProxy object_creator returned None")
|
|
@@ -128,27 +133,51 @@ class UnifiedComponentProxy:
|
|
|
128
133
|
if inspect.isawaitable(res):
|
|
129
134
|
raise AsyncResolutionError(
|
|
130
135
|
f"Lazy component {type(tgt).__name__} requires async "
|
|
131
|
-
"@configure but was resolved via sync
|
|
136
|
+
"@configure but was resolved via sync access (proxy __getattr__). "
|
|
137
|
+
"Use 'await container.aget(Component)' to force initialization."
|
|
132
138
|
)
|
|
133
139
|
|
|
134
140
|
object.__setattr__(self, "_target", tgt)
|
|
135
141
|
return tgt
|
|
142
|
+
|
|
143
|
+
async def _async_init_if_needed(self) -> None:
|
|
144
|
+
if object.__getattribute__(self, "_target") is not None:
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
lock = object.__getattribute__(self, "_lock")
|
|
148
|
+
tgt = object.__getattribute__(self, "_target")
|
|
149
|
+
if tgt is not None:
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
creator = object.__getattribute__(self, "_creator")
|
|
153
|
+
container = object.__getattribute__(self, "_container")
|
|
154
|
+
|
|
155
|
+
tgt = creator()
|
|
156
|
+
|
|
157
|
+
if container and hasattr(container, "_run_configure_methods"):
|
|
158
|
+
res = container._run_configure_methods(tgt)
|
|
159
|
+
if inspect.isawaitable(res):
|
|
160
|
+
await res
|
|
161
|
+
|
|
162
|
+
with lock:
|
|
163
|
+
object.__setattr__(self, "_target", tgt)
|
|
136
164
|
|
|
137
165
|
def _scope_signature(self) -> Tuple[Any, ...]:
|
|
138
166
|
container = object.__getattribute__(self, "_container")
|
|
139
|
-
|
|
167
|
+
key = object.__getattribute__(self, "_component_key")
|
|
140
168
|
loc = getattr(container, "_locator", None)
|
|
141
|
-
|
|
169
|
+
|
|
170
|
+
if not loc or key is None:
|
|
142
171
|
return ()
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
172
|
+
|
|
173
|
+
if key in loc._metadata:
|
|
174
|
+
md = loc._metadata[key]
|
|
175
|
+
sc = md.scope
|
|
176
|
+
if sc == "singleton":
|
|
177
|
+
return ()
|
|
178
|
+
|
|
179
|
+
return (container.scopes.get_id(sc),)
|
|
180
|
+
|
|
152
181
|
return ()
|
|
153
182
|
|
|
154
183
|
def _build_wrapped(self, name: str, bound: Callable[..., Any], interceptors_cls: Tuple[type, ...]):
|
|
@@ -212,6 +241,7 @@ class UnifiedComponentProxy:
|
|
|
212
241
|
lock = object.__getattribute__(self, "_lock")
|
|
213
242
|
with lock:
|
|
214
243
|
cache: Dict[str, Tuple[Tuple[Any, ...], Callable[..., Any], Tuple[type, ...]]] = object.__getattribute__(self, "_cache")
|
|
244
|
+
|
|
215
245
|
cur_sig = self._scope_signature()
|
|
216
246
|
cached = cache.get(name)
|
|
217
247
|
|
|
@@ -224,7 +254,12 @@ class UnifiedComponentProxy:
|
|
|
224
254
|
cache[name] = (sig, wrapped, cls_tuple)
|
|
225
255
|
return wrapped
|
|
226
256
|
|
|
227
|
-
def __setattr__(self, name, value):
|
|
257
|
+
def __setattr__(self, name, value):
|
|
258
|
+
if name in ("_target", "_creator", "_container", "_cache", "_lock", "_component_key"):
|
|
259
|
+
object.__setattr__(self, name, value)
|
|
260
|
+
else:
|
|
261
|
+
setattr(self._get_real_object(), name, value)
|
|
262
|
+
|
|
228
263
|
def __delattr__(self, name): delattr(self._get_real_object(), name)
|
|
229
264
|
def __str__(self): return str(self._get_real_object())
|
|
230
265
|
def __repr__(self): return repr(self._get_real_object())
|
pico_ioc/config_runtime.py
CHANGED
|
@@ -305,8 +305,11 @@ class ObjectGraphBuilder:
|
|
|
305
305
|
if t is int:
|
|
306
306
|
if isinstance(node, int):
|
|
307
307
|
return node
|
|
308
|
-
if isinstance(node, str)
|
|
309
|
-
|
|
308
|
+
if isinstance(node, str):
|
|
309
|
+
try:
|
|
310
|
+
return int(node.strip())
|
|
311
|
+
except ValueError:
|
|
312
|
+
pass
|
|
310
313
|
raise ConfigurationError(f"Expected int at {'.'.join(path)}")
|
|
311
314
|
if t is float:
|
|
312
315
|
if isinstance(node, (int, float)):
|
pico_ioc/container.py
CHANGED
|
@@ -205,7 +205,11 @@ class PicoContainer:
|
|
|
205
205
|
args = self._resolve_args(configure_deps)
|
|
206
206
|
res = m(**args)
|
|
207
207
|
if inspect.isawaitable(res):
|
|
208
|
-
|
|
208
|
+
raise AsyncResolutionError(
|
|
209
|
+
f"Component {type(instance).__name__} returned an awaitable from synchronous "
|
|
210
|
+
f"@configure method '{m.__name__}'. You must use 'await container.aget()' "
|
|
211
|
+
"or make the method synchronous."
|
|
212
|
+
)
|
|
209
213
|
return instance
|
|
210
214
|
|
|
211
215
|
async def runner():
|
|
@@ -252,10 +256,12 @@ class PicoContainer:
|
|
|
252
256
|
async def aget(self, key: KeyT) -> Any:
|
|
253
257
|
instance_or_awaitable, took_ms, was_cached = self._resolve_or_create_internal(key)
|
|
254
258
|
|
|
259
|
+
instance = instance_or_awaitable
|
|
255
260
|
if was_cached:
|
|
256
|
-
|
|
261
|
+
if isinstance(instance, UnifiedComponentProxy):
|
|
262
|
+
await instance._async_init_if_needed()
|
|
263
|
+
return instance
|
|
257
264
|
|
|
258
|
-
instance = instance_or_awaitable
|
|
259
265
|
if inspect.isawaitable(instance_or_awaitable):
|
|
260
266
|
instance = await instance_or_awaitable
|
|
261
267
|
|
|
@@ -269,6 +275,10 @@ class PicoContainer:
|
|
|
269
275
|
instance = instance_or_awaitable_configured
|
|
270
276
|
|
|
271
277
|
final_instance = self._maybe_wrap_with_aspects(key, instance)
|
|
278
|
+
|
|
279
|
+
if isinstance(final_instance, UnifiedComponentProxy):
|
|
280
|
+
await final_instance._async_init_if_needed()
|
|
281
|
+
|
|
272
282
|
cache = self._cache_for(key)
|
|
273
283
|
cache.put(key, final_instance)
|
|
274
284
|
self.context.resolve_count += 1
|
|
@@ -282,7 +292,7 @@ class PicoContainer:
|
|
|
282
292
|
cls = type(instance)
|
|
283
293
|
for _, fn in inspect.getmembers(cls, predicate=lambda m: inspect.isfunction(m) or inspect.ismethod(m) or inspect.iscoroutinefunction(m)):
|
|
284
294
|
if getattr(fn, "_pico_interceptors_", None):
|
|
285
|
-
return UnifiedComponentProxy(container=self, target=instance)
|
|
295
|
+
return UnifiedComponentProxy(container=self, target=instance, component_key=key)
|
|
286
296
|
return instance
|
|
287
297
|
|
|
288
298
|
def _iterate_cleanup_targets(self) -> Iterable[Any]:
|
|
@@ -374,7 +384,7 @@ class PicoContainer:
|
|
|
374
384
|
self.cleanup_all()
|
|
375
385
|
PicoContainer._container_registry.pop(self.container_id, None)
|
|
376
386
|
|
|
377
|
-
def build_resolution_graph(self)
|
|
387
|
+
def build_resolution_graph(self):
|
|
378
388
|
return _build_resolution_graph(self._locator)
|
|
379
389
|
|
|
380
390
|
def export_graph(
|
|
@@ -424,7 +434,7 @@ class PicoContainer:
|
|
|
424
434
|
pid = _node_id(parent)
|
|
425
435
|
for child in deps:
|
|
426
436
|
cid = _node_id(child)
|
|
427
|
-
lines.append(f" {pid} -> {
|
|
437
|
+
lines.append(f" {pid} -> {child};")
|
|
428
438
|
|
|
429
439
|
lines.append("}")
|
|
430
440
|
|
pico_ioc/event_bus.py
CHANGED
|
@@ -155,25 +155,28 @@ class EventBus:
|
|
|
155
155
|
raise EventBusClosedError()
|
|
156
156
|
if self._queue is None:
|
|
157
157
|
raise EventBusError("Worker queue not initialized. Call start_worker().")
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
158
|
+
|
|
159
|
+
queue_ref = self._queue
|
|
160
|
+
loop_ref = self._worker_loop
|
|
161
|
+
|
|
162
|
+
if loop_ref and loop_ref.is_running():
|
|
163
|
+
try:
|
|
164
|
+
current_loop = asyncio.get_running_loop()
|
|
165
|
+
if current_loop is loop_ref:
|
|
166
|
+
try:
|
|
167
|
+
queue_ref.put_nowait(event)
|
|
168
|
+
return
|
|
169
|
+
except asyncio.QueueFull:
|
|
170
|
+
raise EventBusQueueFullError()
|
|
171
|
+
except RuntimeError:
|
|
172
|
+
pass
|
|
173
|
+
try:
|
|
174
|
+
loop_ref.call_soon_threadsafe(queue_ref.put_nowait, event)
|
|
175
|
+
return
|
|
176
|
+
except asyncio.QueueFull:
|
|
177
|
+
raise EventBusQueueFullError()
|
|
178
|
+
else:
|
|
179
|
+
raise EventBusError("Worker queue not initialized or loop not running. Call start_worker().")
|
|
177
180
|
|
|
178
181
|
async def aclose(self) -> None:
|
|
179
182
|
await self.stop_worker()
|
pico_ioc/registrar.py
CHANGED
|
@@ -61,8 +61,8 @@ class Registrar:
|
|
|
61
61
|
for key, md in list(self._metadata.items()):
|
|
62
62
|
if md.lazy:
|
|
63
63
|
original = self._factory.get(key, origin='lazy')
|
|
64
|
-
def lazy_proxy_provider(_orig=original, _p=pico):
|
|
65
|
-
return UnifiedComponentProxy(container=_p, object_creator=_orig)
|
|
64
|
+
def lazy_proxy_provider(_orig=original, _p=pico, _k=key):
|
|
65
|
+
return UnifiedComponentProxy(container=_p, object_creator=_orig, component_key=_k)
|
|
66
66
|
self._factory.bind(key, lazy_proxy_provider)
|
|
67
67
|
|
|
68
68
|
|
pico_ioc/scope.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# src/pico_ioc/scope.py
|
|
2
1
|
import contextvars
|
|
3
2
|
import inspect
|
|
4
3
|
from typing import Any, Dict, Optional, Tuple
|
|
@@ -95,9 +94,10 @@ class ScopeManager:
|
|
|
95
94
|
class ScopedCaches:
|
|
96
95
|
def __init__(self, max_scopes_per_type: int = 2048) -> None:
|
|
97
96
|
self._singleton = ComponentContainer()
|
|
98
|
-
self._by_scope: Dict[str,
|
|
97
|
+
self._by_scope: Dict[str, Dict[Any, ComponentContainer]] = {}
|
|
99
98
|
self._max = int(max_scopes_per_type)
|
|
100
99
|
self._no_cache = _NoCacheContainer()
|
|
100
|
+
|
|
101
101
|
def _cleanup_object(self, obj: Any) -> None:
|
|
102
102
|
try:
|
|
103
103
|
from .constants import PICO_META
|
|
@@ -132,15 +132,19 @@ class ScopedCaches:
|
|
|
132
132
|
return self._singleton
|
|
133
133
|
if scope == "prototype":
|
|
134
134
|
return self._no_cache
|
|
135
|
+
|
|
135
136
|
sid = scopes.get_id(scope)
|
|
136
|
-
|
|
137
|
+
|
|
138
|
+
if sid is None:
|
|
139
|
+
raise ScopeError(
|
|
140
|
+
f"Cannot resolve component in scope '{scope}': No active scope ID found. "
|
|
141
|
+
f"Are you trying to use a {scope}-scoped component outside of its context?"
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
bucket = self._by_scope.setdefault(scope, {})
|
|
137
145
|
if sid in bucket:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return c
|
|
141
|
-
if len(bucket) >= self._max:
|
|
142
|
-
_, old = bucket.popitem(last=False)
|
|
143
|
-
self._cleanup_container(old)
|
|
146
|
+
return bucket[sid]
|
|
147
|
+
|
|
144
148
|
c = ComponentContainer()
|
|
145
149
|
bucket[sid] = c
|
|
146
150
|
return c
|
|
@@ -159,8 +163,11 @@ class ScopedCaches:
|
|
|
159
163
|
bucket = self._by_scope.get(scope)
|
|
160
164
|
if not bucket:
|
|
161
165
|
return
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
166
|
+
|
|
167
|
+
# Manual cleanup if needed, though we rely on explicit cleanup now
|
|
168
|
+
if len(bucket) > keep:
|
|
169
|
+
# Simple eviction strategy if forced manually
|
|
170
|
+
keys_to_remove = list(bucket.keys())[:len(bucket)-keep]
|
|
171
|
+
for k in keys_to_remove:
|
|
172
|
+
container = bucket.pop(k)
|
|
173
|
+
self._cleanup_container(container)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pico-ioc
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.3
|
|
4
4
|
Summary: A minimalist, zero-dependency Inversion of Control (IoC) container for Python.
|
|
5
5
|
Author-email: David Perez Cabrera <dperezcabrera@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -124,6 +124,15 @@ Optional extras:
|
|
|
124
124
|
|
|
125
125
|
-----
|
|
126
126
|
|
|
127
|
+
### ⚠️ Important Note for v2.1.3+
|
|
128
|
+
|
|
129
|
+
**Breaking Behavior in Custom Integrations:**
|
|
130
|
+
As of version 2.1.3, **Scope LRU Eviction has been removed** to guarantee data integrity under high load.
|
|
131
|
+
* **If you use `pico-fastapi`:** You are safe (the middleware handles cleanup automatically).
|
|
132
|
+
* **If you perform manual scope management:** You **must** explicitly call `container._caches.cleanup_scope("scope_name", scope_id)` when a context ends. Failing to do so will result in a memory leak, as scopes are no longer automatically discarded when the container fills up.
|
|
133
|
+
|
|
134
|
+
-----
|
|
135
|
+
|
|
127
136
|
## ⚙️ Quick Example (Unified Configuration)
|
|
128
137
|
|
|
129
138
|
```python
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
pico_ioc/__init__.py,sha256=i25Obx7aH_Oy5b6yjjnCswDgni7InIjrGEcG6vLAw6I,2414
|
|
2
|
-
pico_ioc/_version.py,sha256=
|
|
3
|
-
pico_ioc/analysis.py,sha256=
|
|
4
|
-
pico_ioc/aop.py,sha256=
|
|
2
|
+
pico_ioc/_version.py,sha256=hgD1miBO_f3fboq1GKyV4DdK_igCLGJFnZRD7l9oNRs,22
|
|
3
|
+
pico_ioc/analysis.py,sha256=cxlg3F3bwRIb-kVIqHp1RLYj-sk-GuIgCChE-pf0a7c,4189
|
|
4
|
+
pico_ioc/aop.py,sha256=VkmLzoztPbFjLIqBmXohcCNd4w6UC9ZrqYOE8DsMQ7I,14417
|
|
5
5
|
pico_ioc/api.py,sha256=0pcRFHzhDcX8ijd67xAsVrTejwXuJKz7kTKRUrIuX2s,6161
|
|
6
6
|
pico_ioc/component_scanner.py,sha256=S-9XNxrgyq_JFdc4Uqn2bEb-HxafSgIWylIurxyN_UA,7955
|
|
7
7
|
pico_ioc/config_builder.py,sha256=7kcYIq1Yrb46Tic7uLeaCDvLA-Sa_p1PIoGF00mivso,2848
|
|
8
8
|
pico_ioc/config_registrar.py,sha256=34iNQY1TUEPTXbb-QV1T-c5VKAn18hBcNt5MLhzDSfY,8456
|
|
9
|
-
pico_ioc/config_runtime.py,sha256=
|
|
9
|
+
pico_ioc/config_runtime.py,sha256=qdPIbGMXOf6KWMM7cva6W-hhbhybEY0swZN01R1emCg,12756
|
|
10
10
|
pico_ioc/constants.py,sha256=AhIt0ieDZ9Turxb_YbNzj11wUbBbzjKfWh1BDlSx2Nw,183
|
|
11
|
-
pico_ioc/container.py,sha256=
|
|
11
|
+
pico_ioc/container.py,sha256=SEEJCUHIOUz4Dghdmac2rDrv65Zlm2wiBKZt4WbZoDc,21354
|
|
12
12
|
pico_ioc/decorators.py,sha256=ru_YeqyJ3gbfb6M8WeJZlBxfcBBEuGDvxpHJGzU6FIs,6412
|
|
13
13
|
pico_ioc/dependency_validator.py,sha256=BIR6pKntACiabF6CjNZ3m00RMnet9BPK1_9y1iCJ5KQ,4144
|
|
14
|
-
pico_ioc/event_bus.py,sha256=
|
|
14
|
+
pico_ioc/event_bus.py,sha256=NSfmFPX6Zm2OmMJz16gJFYMhh65iI0n9UlC9M8GmO0c,8428
|
|
15
15
|
pico_ioc/exceptions.py,sha256=FBuajj5g29hAGODt2tAWuy2sG5mQojdSddaqFzim-aY,2383
|
|
16
16
|
pico_ioc/factory.py,sha256=oJXx_BYJuvV8oxYzs5I3gx9WM6uLYZ8GCc43gukNanc,1671
|
|
17
17
|
pico_ioc/locator.py,sha256=JD6psgdGGsBoCwov-G76BrmTfKUoJ22sdwa6wVdmQV8,5064
|
|
18
18
|
pico_ioc/provider_selector.py,sha256=pU7NbI5vifvUlJEjlRJmvveQUZVD47T24QmiP0CHRw0,1213
|
|
19
|
-
pico_ioc/registrar.py,sha256=
|
|
20
|
-
pico_ioc/scope.py,sha256=
|
|
21
|
-
pico_ioc-2.1.
|
|
22
|
-
pico_ioc-2.1.
|
|
23
|
-
pico_ioc-2.1.
|
|
24
|
-
pico_ioc-2.1.
|
|
25
|
-
pico_ioc-2.1.
|
|
19
|
+
pico_ioc/registrar.py,sha256=O22FYrMXQ4TvBf25b0CB1wwu9tjL-5e00n9Ubd8suNs,8394
|
|
20
|
+
pico_ioc/scope.py,sha256=JmFJPSb9uG2oRSZ7YreCozOgqDHfYsYLcyCpqVI4luU,6427
|
|
21
|
+
pico_ioc-2.1.3.dist-info/licenses/LICENSE,sha256=N1_nOvHTM6BobYnOTNXiQkroDqCEi6EzfGBv8lWtyZ0,1077
|
|
22
|
+
pico_ioc-2.1.3.dist-info/METADATA,sha256=-PWHmvXzShw_t9D-_vbGBN24aG7afVchr3ZFyGR0TrQ,12910
|
|
23
|
+
pico_ioc-2.1.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
24
|
+
pico_ioc-2.1.3.dist-info/top_level.txt,sha256=_7_RLu616z_dtRw16impXn4Mw8IXe2J4BeX5912m5dQ,9
|
|
25
|
+
pico_ioc-2.1.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|