pico-ioc 2.1.3__py3-none-any.whl → 2.2.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.
- pico_ioc/__init__.py +2 -1
- pico_ioc/_version.py +1 -1
- pico_ioc/api.py +9 -3
- pico_ioc/component_scanner.py +48 -24
- pico_ioc/container.py +4 -0
- pico_ioc/registrar.py +3 -5
- pico_ioc/scope.py +1 -2
- {pico_ioc-2.1.3.dist-info → pico_ioc-2.2.0.dist-info}/METADATA +48 -52
- {pico_ioc-2.1.3.dist-info → pico_ioc-2.2.0.dist-info}/RECORD +12 -12
- {pico_ioc-2.1.3.dist-info → pico_ioc-2.2.0.dist-info}/WHEEL +0 -0
- {pico_ioc-2.1.3.dist-info → pico_ioc-2.2.0.dist-info}/licenses/LICENSE +0 -0
- {pico_ioc-2.1.3.dist-info → pico_ioc-2.2.0.dist-info}/top_level.txt +0 -0
pico_ioc/__init__.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# src/pico_ioc/__init__.py
|
|
2
1
|
from .constants import LOGGER_NAME, LOGGER, PICO_INFRA, PICO_NAME, PICO_KEY, PICO_META
|
|
3
2
|
from .exceptions import (
|
|
4
3
|
PicoError,
|
|
@@ -31,6 +30,7 @@ from .container import PicoContainer
|
|
|
31
30
|
from .event_bus import EventBus, ExecPolicy, ErrorPolicy, Event, subscribe, AutoSubscriberMixin
|
|
32
31
|
from .config_runtime import JsonTreeSource, YamlTreeSource, DictSource, Discriminator, Value
|
|
33
32
|
from .analysis import DependencyRequest, analyze_callable_dependencies
|
|
33
|
+
from .component_scanner import CustomScanner
|
|
34
34
|
|
|
35
35
|
__all__ = [
|
|
36
36
|
"LOGGER_NAME",
|
|
@@ -91,4 +91,5 @@ __all__ = [
|
|
|
91
91
|
"Value",
|
|
92
92
|
"DependencyRequest",
|
|
93
93
|
"analyze_callable_dependencies",
|
|
94
|
+
"CustomScanner",
|
|
94
95
|
]
|
pico_ioc/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = '2.
|
|
1
|
+
__version__ = '2.2.0'
|
pico_ioc/api.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# src/pico_ioc/api.py
|
|
2
|
-
|
|
3
1
|
import importlib
|
|
4
2
|
import pkgutil
|
|
5
3
|
import logging
|
|
@@ -13,6 +11,8 @@ from .container import PicoContainer
|
|
|
13
11
|
from .decorators import component, factory, provides, Qualifier, configure, cleanup, configured
|
|
14
12
|
from .config_builder import ContextConfig, configuration
|
|
15
13
|
from .registrar import Registrar
|
|
14
|
+
from .aop import ContainerObserver
|
|
15
|
+
from .component_scanner import CustomScanner
|
|
16
16
|
|
|
17
17
|
KeyT = Union[str, type]
|
|
18
18
|
Provider = Callable[[], Any]
|
|
@@ -63,7 +63,8 @@ def init(
|
|
|
63
63
|
custom_scopes: Optional[Iterable[str]] = None,
|
|
64
64
|
validate_only: bool = False,
|
|
65
65
|
container_id: Optional[str] = None,
|
|
66
|
-
observers: Optional[List[
|
|
66
|
+
observers: Optional[List[ContainerObserver]] = None,
|
|
67
|
+
custom_scanners: Optional[List[CustomScanner]] = None,
|
|
67
68
|
) -> PicoContainer:
|
|
68
69
|
active = tuple(p.strip() for p in profiles if p)
|
|
69
70
|
|
|
@@ -82,6 +83,11 @@ def init(
|
|
|
82
83
|
|
|
83
84
|
pico = PicoContainer(factory, caches, scopes, container_id=container_id, profiles=active, observers=observers or [])
|
|
84
85
|
registrar = Registrar(factory, profiles=active, environ=environ, logger=logger, config=config)
|
|
86
|
+
|
|
87
|
+
if custom_scanners:
|
|
88
|
+
for scanner in custom_scanners:
|
|
89
|
+
registrar.register_custom_scanner(scanner)
|
|
90
|
+
|
|
85
91
|
for m in _iter_input_modules(modules):
|
|
86
92
|
registrar.register_module(m)
|
|
87
93
|
|
pico_ioc/component_scanner.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import os
|
|
3
|
-
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, Set
|
|
3
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, Set, Protocol
|
|
4
4
|
from .constants import PICO_INFRA, PICO_NAME, PICO_KEY, PICO_META
|
|
5
5
|
from .factory import ProviderMetadata, DeferredProvider
|
|
6
6
|
from .decorators import get_return_type
|
|
@@ -10,6 +10,10 @@ from .analysis import analyze_callable_dependencies, DependencyRequest
|
|
|
10
10
|
KeyT = Union[str, type]
|
|
11
11
|
Provider = Callable[[], Any]
|
|
12
12
|
|
|
13
|
+
class CustomScanner(Protocol):
|
|
14
|
+
def should_scan(self, obj: Any) -> bool: ...
|
|
15
|
+
def scan(self, obj: Any) -> Optional[Tuple[KeyT, Provider, ProviderMetadata]]: ...
|
|
16
|
+
|
|
13
17
|
class ComponentScanner:
|
|
14
18
|
def __init__(self, profiles: Set[str], environ: Dict[str, str], config_manager: ConfigurationManager):
|
|
15
19
|
self._profiles = profiles
|
|
@@ -19,6 +23,10 @@ class ComponentScanner:
|
|
|
19
23
|
self._on_missing: List[Tuple[int, KeyT, type]] = []
|
|
20
24
|
self._deferred: List[DeferredProvider] = []
|
|
21
25
|
self._provides_functions: Dict[KeyT, Callable[..., Any]] = {}
|
|
26
|
+
self._custom_scanners: List[CustomScanner] = []
|
|
27
|
+
|
|
28
|
+
def register_custom_scanner(self, scanner: CustomScanner) -> None:
|
|
29
|
+
self._custom_scanners.append(scanner)
|
|
22
30
|
|
|
23
31
|
def get_scan_results(self) -> Tuple[Dict[KeyT, List[Tuple[bool, Provider, ProviderMetadata]]], List[Tuple[int, KeyT, type]], List[DeferredProvider], Dict[KeyT, Callable[..., Any]]]:
|
|
24
32
|
return self._candidates, self._on_missing, self._deferred, self._provides_functions
|
|
@@ -86,7 +94,6 @@ class ComponentScanner:
|
|
|
86
94
|
if has_instance_provides:
|
|
87
95
|
factory_deps = analyze_callable_dependencies(cls.__init__)
|
|
88
96
|
|
|
89
|
-
|
|
90
97
|
for name in dir(cls):
|
|
91
98
|
try:
|
|
92
99
|
raw = inspect.getattr_static(cls, name)
|
|
@@ -140,27 +147,44 @@ class ComponentScanner:
|
|
|
140
147
|
self._queue(k, provider, md)
|
|
141
148
|
self._provides_functions[k] = fn
|
|
142
149
|
|
|
150
|
+
def _try_custom_scanners(self, obj: Any) -> bool:
|
|
151
|
+
for scanner in self._custom_scanners:
|
|
152
|
+
if scanner.should_scan(obj):
|
|
153
|
+
result = scanner.scan(obj)
|
|
154
|
+
if result:
|
|
155
|
+
key, provider, md = result
|
|
156
|
+
self._queue(key, provider, md)
|
|
157
|
+
if isinstance(provider, DeferredProvider):
|
|
158
|
+
self._deferred.append(provider)
|
|
159
|
+
return True
|
|
160
|
+
return False
|
|
161
|
+
|
|
143
162
|
def scan_module(self, module: Any) -> None:
|
|
144
163
|
for _, obj in inspect.getmembers(module):
|
|
145
|
-
if
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
self.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
if self._try_custom_scanners(obj):
|
|
165
|
+
continue
|
|
166
|
+
|
|
167
|
+
if inspect.isclass(obj) or getattr(obj, "_is_protocol", False):
|
|
168
|
+
if inspect.isclass(obj):
|
|
169
|
+
meta = getattr(obj, PICO_META, {})
|
|
170
|
+
|
|
171
|
+
if "on_missing" in meta:
|
|
172
|
+
sel = meta["on_missing"]["selector"]
|
|
173
|
+
pr = int(meta["on_missing"].get("priority", 0))
|
|
174
|
+
self._on_missing.append((pr, sel, obj))
|
|
175
|
+
continue
|
|
176
|
+
|
|
177
|
+
infra = getattr(obj, PICO_INFRA, None)
|
|
178
|
+
if infra == "component":
|
|
179
|
+
self._register_component_class(obj)
|
|
180
|
+
elif infra == "factory":
|
|
181
|
+
self._register_factory_class(obj)
|
|
182
|
+
elif infra == "configured":
|
|
183
|
+
enabled = self._enabled_by_condition(obj)
|
|
184
|
+
reg_data = self._config_manager.register_configured_class(obj, enabled)
|
|
185
|
+
if reg_data:
|
|
186
|
+
self._queue(reg_data[0], reg_data[1], reg_data[2])
|
|
187
|
+
|
|
188
|
+
elif inspect.isfunction(obj):
|
|
189
|
+
if getattr(obj, PICO_INFRA, None) == "provides":
|
|
190
|
+
self._register_provides_function(obj)
|
pico_ioc/container.py
CHANGED
|
@@ -384,6 +384,10 @@ class PicoContainer:
|
|
|
384
384
|
self.cleanup_all()
|
|
385
385
|
PicoContainer._container_registry.pop(self.container_id, None)
|
|
386
386
|
|
|
387
|
+
async def ashutdown(self) -> None:
|
|
388
|
+
await self.cleanup_all_async()
|
|
389
|
+
PicoContainer._container_registry.pop(self.container_id, None)
|
|
390
|
+
|
|
387
391
|
def build_resolution_graph(self):
|
|
388
392
|
return _build_resolution_graph(self._locator)
|
|
389
393
|
|
pico_ioc/registrar.py
CHANGED
|
@@ -15,7 +15,7 @@ from .config_runtime import TreeSource
|
|
|
15
15
|
from .config_registrar import ConfigurationManager
|
|
16
16
|
from .provider_selector import ProviderSelector
|
|
17
17
|
from .dependency_validator import DependencyValidator
|
|
18
|
-
from .component_scanner import ComponentScanner
|
|
18
|
+
from .component_scanner import ComponentScanner, CustomScanner
|
|
19
19
|
from .analysis import analyze_callable_dependencies, DependencyRequest
|
|
20
20
|
from .container import PicoContainer
|
|
21
21
|
|
|
@@ -49,6 +49,8 @@ class Registrar:
|
|
|
49
49
|
self._deferred: List[DeferredProvider] = []
|
|
50
50
|
self._provides_functions: Dict[KeyT, Callable[..., Any]] = {}
|
|
51
51
|
|
|
52
|
+
def register_custom_scanner(self, scanner: CustomScanner) -> None:
|
|
53
|
+
self._scanner.register_custom_scanner(scanner)
|
|
52
54
|
|
|
53
55
|
def locator(self) -> ComponentLocator:
|
|
54
56
|
loc = ComponentLocator(dict(self._metadata), dict(self._indexes))
|
|
@@ -65,16 +67,13 @@ class Registrar:
|
|
|
65
67
|
return UnifiedComponentProxy(container=_p, object_creator=_orig, component_key=_k)
|
|
66
68
|
self._factory.bind(key, lazy_proxy_provider)
|
|
67
69
|
|
|
68
|
-
|
|
69
70
|
def _bind_if_absent(self, key: KeyT, provider: Provider) -> None:
|
|
70
71
|
if not self._factory.has(key):
|
|
71
72
|
self._factory.bind(key, provider)
|
|
72
73
|
|
|
73
|
-
|
|
74
74
|
def register_module(self, module: Any) -> None:
|
|
75
75
|
self._scanner.scan_module(module)
|
|
76
76
|
|
|
77
|
-
|
|
78
77
|
def _find_md_for_type(self, t: type) -> Optional[ProviderMetadata]:
|
|
79
78
|
cands: List[ProviderMetadata] = []
|
|
80
79
|
for md in self._metadata.values():
|
|
@@ -133,7 +132,6 @@ class Registrar:
|
|
|
133
132
|
if md.pico_name is not None:
|
|
134
133
|
add("pico_name", md.pico_name, k)
|
|
135
134
|
|
|
136
|
-
|
|
137
135
|
def finalize(self, overrides: Optional[Dict[KeyT, Any]], *, pico_instance: PicoContainer) -> None:
|
|
138
136
|
candidates, on_missing, deferred_providers, provides_functions = self._scanner.get_scan_results()
|
|
139
137
|
self._deferred = deferred_providers
|
pico_ioc/scope.py
CHANGED
|
@@ -92,10 +92,9 @@ class ScopeManager:
|
|
|
92
92
|
return self.signature(self.names())
|
|
93
93
|
|
|
94
94
|
class ScopedCaches:
|
|
95
|
-
def __init__(self
|
|
95
|
+
def __init__(self) -> None:
|
|
96
96
|
self._singleton = ComponentContainer()
|
|
97
97
|
self._by_scope: Dict[str, Dict[Any, ComponentContainer]] = {}
|
|
98
|
-
self._max = int(max_scopes_per_type)
|
|
99
98
|
self._no_cache = _NoCacheContainer()
|
|
100
99
|
|
|
101
100
|
def _cleanup_object(self, obj: Any) -> None:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pico-ioc
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
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
|
|
@@ -28,7 +28,7 @@ License: MIT License
|
|
|
28
28
|
Project-URL: Homepage, https://github.com/dperezcabrera/pico-ioc
|
|
29
29
|
Project-URL: Repository, https://github.com/dperezcabrera/pico-ioc
|
|
30
30
|
Project-URL: Issue Tracker, https://github.com/dperezcabrera/pico-ioc/issues
|
|
31
|
-
Keywords: ioc,di,dependency
|
|
31
|
+
Keywords: python,ioc,dependency-injection,di-container,inversion-of-control,ioc-container,zero-dependency,minimalistic,async,asyncio,modular,pluggable,ioc-framework,ioc-containers,inversion-of-control-container
|
|
32
32
|
Classifier: Development Status :: 4 - Beta
|
|
33
33
|
Classifier: Programming Language :: Python :: 3
|
|
34
34
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
@@ -62,7 +62,6 @@ Dynamic: license-file
|
|
|
62
62
|
[](https://dperezcabrera.github.io/pico-ioc/)
|
|
63
63
|
[](https://dperezcabrera.github.io/learn-pico-ioc/)
|
|
64
64
|
|
|
65
|
-
|
|
66
65
|
**Pico-IoC** is a **lightweight, async-ready, decorator-driven IoC container** built for clarity, testability, and performance.
|
|
67
66
|
It brings Inversion of Control and dependency injection to Python in a deterministic, modern, and framework-agnostic way.
|
|
68
67
|
|
|
@@ -97,14 +96,14 @@ Pico-IoC eliminates that friction by letting you declare how components relate
|
|
|
97
96
|
|
|
98
97
|
---
|
|
99
98
|
|
|
100
|
-
## 🧩 Highlights (v2.
|
|
99
|
+
## 🧩 Highlights (v2.2+)
|
|
101
100
|
|
|
102
|
-
- Unified Configuration
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
- Tree-based configuration
|
|
107
|
-
- Observable
|
|
101
|
+
- **Unified Configuration**: Use `@configured` to bind both flat (ENV-like) and tree (YAML/JSON) sources via the `configuration(...)` builder (ADR-0010).
|
|
102
|
+
- **Extensible Scanning**: Use `CustomScanner` to hook into the discovery phase and register functions or custom decorators (ADR-0011).
|
|
103
|
+
- **Async-aware AOP**: Method interceptors via `@intercepted_by`.
|
|
104
|
+
- **Scoped resolution**: singleton, prototype, request, session, transaction, and custom scopes.
|
|
105
|
+
- **Tree-based configuration**: Advanced mapping with reusable adapters (`Annotated[Union[...], Discriminator(...)]`).
|
|
106
|
+
- **Observable context**: Built-in stats, health checks (`@health`), observer hooks (`ContainerObserver`), and dependency graph export.
|
|
108
107
|
|
|
109
108
|
---
|
|
110
109
|
|
|
@@ -116,20 +115,21 @@ pip install pico-ioc
|
|
|
116
115
|
|
|
117
116
|
Optional extras:
|
|
118
117
|
|
|
119
|
-
- YAML configuration support (requires PyYAML)
|
|
118
|
+
- YAML configuration support (requires PyYAML)
|
|
120
119
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
```bash
|
|
121
|
+
pip install pico-ioc[yaml]
|
|
122
|
+
```
|
|
124
123
|
|
|
125
124
|
-----
|
|
126
125
|
|
|
127
|
-
### ⚠️ Important Note
|
|
126
|
+
### ⚠️ Important Note
|
|
127
|
+
|
|
128
|
+
**Breaking Behavior in Scope Management (v2.1.3+):**
|
|
129
|
+
**Scope LRU Eviction has been removed** to guarantee data integrity.
|
|
128
130
|
|
|
129
|
-
**
|
|
130
|
-
|
|
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.
|
|
131
|
+
* **Frameworks (pico-fastapi):** Handled automatically.
|
|
132
|
+
* **Manual usage:** You **must** explicitly call `container._caches.cleanup_scope("scope_name", scope_id)` when a context ends to prevent memory leaks.
|
|
133
133
|
|
|
134
134
|
-----
|
|
135
135
|
|
|
@@ -247,12 +247,16 @@ async def main():
|
|
|
247
247
|
container = init(modules=[__name__])
|
|
248
248
|
repo = await container.aget(AsyncRepo) # Async resolution
|
|
249
249
|
print(await repo.fetch())
|
|
250
|
+
|
|
251
|
+
# Graceful async shutdown (calls @cleanup async methods)
|
|
252
|
+
await container.ashutdown()
|
|
250
253
|
|
|
251
254
|
asyncio.run(main())
|
|
252
255
|
```
|
|
253
256
|
|
|
254
|
-
- `__ainit__` runs after construction if defined.
|
|
255
|
-
- Use `container.aget(Type)` to resolve components that require async initialization
|
|
257
|
+
- `__ainit__` runs after construction if defined.
|
|
258
|
+
- Use `container.aget(Type)` to resolve components that require async initialization.
|
|
259
|
+
- Use `await container.ashutdown()` to close resources cleanly.
|
|
256
260
|
|
|
257
261
|
-----
|
|
258
262
|
|
|
@@ -292,35 +296,26 @@ result = c.get(Demo).work()
|
|
|
292
296
|
print(f"Result: {result}")
|
|
293
297
|
```
|
|
294
298
|
|
|
295
|
-
Output:
|
|
296
|
-
|
|
297
|
-
```
|
|
298
|
-
→ calling Demo.work
|
|
299
|
-
Working...
|
|
300
|
-
← Demo.work done (10.xxms)
|
|
301
|
-
Result: ok
|
|
302
|
-
```
|
|
303
|
-
|
|
304
299
|
-----
|
|
305
300
|
|
|
306
301
|
## 👁️ Observability & Cleanup
|
|
307
302
|
|
|
308
|
-
- Export a dependency graph in DOT format:
|
|
303
|
+
- Export a dependency graph in DOT format:
|
|
304
|
+
|
|
305
|
+
```python
|
|
306
|
+
c = init(modules=[...])
|
|
307
|
+
c.export_graph("dependencies.dot") # Writes directly to file
|
|
308
|
+
```
|
|
309
309
|
|
|
310
|
-
|
|
311
|
-
c = init(modules=[...])
|
|
312
|
-
dot = c.export_graph() # Returns DOT graph as a string
|
|
313
|
-
with open("dependencies.dot", "w") as f:
|
|
314
|
-
f.write(dot)
|
|
315
|
-
```
|
|
310
|
+
- Health checks:
|
|
316
311
|
|
|
317
|
-
-
|
|
318
|
-
|
|
319
|
-
- The container exposes health information that can be queried in observability tooling.
|
|
312
|
+
- Annotate health probes inside components with `@health` for container-level reporting.
|
|
313
|
+
- The container exposes health information that can be queried in observability tooling.
|
|
320
314
|
|
|
321
|
-
- Container cleanup:
|
|
322
|
-
|
|
323
|
-
|
|
315
|
+
- Container cleanup:
|
|
316
|
+
|
|
317
|
+
- For sync apps: `container.shutdown()`
|
|
318
|
+
- For async apps: `await container.ashutdown()`
|
|
324
319
|
|
|
325
320
|
Use cleanup in application shutdown hooks to release resources deterministically.
|
|
326
321
|
|
|
@@ -330,14 +325,14 @@ Use cleanup in application shutdown hooks to release resources deterministically
|
|
|
330
325
|
|
|
331
326
|
The full documentation is available within the `docs/` directory of the project repository. Start with `docs/README.md` for navigation.
|
|
332
327
|
|
|
333
|
-
- Getting Started: `docs/getting-started.md`
|
|
334
|
-
- User Guide: `docs/user-guide/README.md`
|
|
335
|
-
- Advanced Features: `docs/advanced-features/README.md`
|
|
336
|
-
- Observability: `docs/observability/README.md`
|
|
337
|
-
- Cookbook (Patterns): `docs/cookbook/README.md`
|
|
338
|
-
- Architecture: `docs/architecture/README.md`
|
|
339
|
-
- API Reference: `docs/api-reference/README.md`
|
|
340
|
-
- ADR Index: `docs/adr/README.md`
|
|
328
|
+
- Getting Started: `docs/getting-started.md`
|
|
329
|
+
- User Guide: `docs/user-guide/README.md`
|
|
330
|
+
- Advanced Features: `docs/advanced-features/README.md`
|
|
331
|
+
- Observability: `docs/observability/README.md`
|
|
332
|
+
- Cookbook (Patterns): `docs/cookbook/README.md`
|
|
333
|
+
- Architecture: `docs/architecture/README.md`
|
|
334
|
+
- API Reference: `docs/api-reference/README.md`
|
|
335
|
+
- ADR Index: `docs/adr/README.md`
|
|
341
336
|
|
|
342
337
|
-----
|
|
343
338
|
|
|
@@ -352,10 +347,11 @@ tox
|
|
|
352
347
|
|
|
353
348
|
## 🧾 Changelog
|
|
354
349
|
|
|
355
|
-
See [CHANGELOG.md](
|
|
350
|
+
See [CHANGELOG.md](https://www.google.com/search?q=./CHANGELOG.md) — Significant redesigns and features in v2.0+.
|
|
356
351
|
|
|
357
352
|
-----
|
|
358
353
|
|
|
359
354
|
## 📜 License
|
|
360
355
|
|
|
361
356
|
MIT — [LICENSE](https://opensource.org/licenses/MIT)
|
|
357
|
+
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
pico_ioc/__init__.py,sha256=
|
|
2
|
-
pico_ioc/_version.py,sha256=
|
|
1
|
+
pico_ioc/__init__.py,sha256=MDneoBBB0JHD_o0_xzkOUeW4e3XjDJSaGMNTb5miBqw,2453
|
|
2
|
+
pico_ioc/_version.py,sha256=Vyf6P6UCZKFeQtRzYujPmFfdlqSfnc01VEMWE3O0ZrA,22
|
|
3
3
|
pico_ioc/analysis.py,sha256=cxlg3F3bwRIb-kVIqHp1RLYj-sk-GuIgCChE-pf0a7c,4189
|
|
4
4
|
pico_ioc/aop.py,sha256=VkmLzoztPbFjLIqBmXohcCNd4w6UC9ZrqYOE8DsMQ7I,14417
|
|
5
|
-
pico_ioc/api.py,sha256=
|
|
6
|
-
pico_ioc/component_scanner.py,sha256=
|
|
5
|
+
pico_ioc/api.py,sha256=KlZjI_4pJfD_1T32DgmOykii6L1V-5Xtcynd5d57YIA,6400
|
|
6
|
+
pico_ioc/component_scanner.py,sha256=rRZSQbJ7SkssJ5SJBr_m2ih-lpFvVnDQpt-JrYH5Xsg,8999
|
|
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
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=ipTpMwtCYuYfmJCjd7dfEtFFVR1PG0C1lZQp-wJ_UHw,21512
|
|
12
12
|
pico_ioc/decorators.py,sha256=ru_YeqyJ3gbfb6M8WeJZlBxfcBBEuGDvxpHJGzU6FIs,6412
|
|
13
13
|
pico_ioc/dependency_validator.py,sha256=BIR6pKntACiabF6CjNZ3m00RMnet9BPK1_9y1iCJ5KQ,4144
|
|
14
14
|
pico_ioc/event_bus.py,sha256=NSfmFPX6Zm2OmMJz16gJFYMhh65iI0n9UlC9M8GmO0c,8428
|
|
@@ -16,10 +16,10 @@ 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.
|
|
22
|
-
pico_ioc-2.
|
|
23
|
-
pico_ioc-2.
|
|
24
|
-
pico_ioc-2.
|
|
25
|
-
pico_ioc-2.
|
|
19
|
+
pico_ioc/registrar.py,sha256=0abgnJMJrEvEyqsvxBNTi6wl0iJHHjSaw75IuqGk56c,8531
|
|
20
|
+
pico_ioc/scope.py,sha256=TFchqFE9ooDCtYV_9YaLdeJDMtmLdNbB63nbZp-AqI8,6349
|
|
21
|
+
pico_ioc-2.2.0.dist-info/licenses/LICENSE,sha256=N1_nOvHTM6BobYnOTNXiQkroDqCEi6EzfGBv8lWtyZ0,1077
|
|
22
|
+
pico_ioc-2.2.0.dist-info/METADATA,sha256=HnQ9xsjsyPFA7zCIkzkkHLSngVut4bZQUjHHBsk9PXI,12901
|
|
23
|
+
pico_ioc-2.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
24
|
+
pico_ioc-2.2.0.dist-info/top_level.txt,sha256=_7_RLu616z_dtRw16impXn4Mw8IXe2J4BeX5912m5dQ,9
|
|
25
|
+
pico_ioc-2.2.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|