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 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.3'
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["ContainerObserver"]] = None,
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
 
@@ -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 inspect.isclass(obj):
146
- meta = getattr(obj, PICO_META, {})
147
- if "on_missing" in meta:
148
- sel = meta["on_missing"]["selector"]
149
- pr = int(meta["on_missing"].get("priority", 0))
150
- self._on_missing.append((pr, sel, obj))
151
- continue
152
-
153
- infra = getattr(obj, PICO_INFRA, None)
154
- if infra == "component":
155
- self._register_component_class(obj)
156
- elif infra == "factory":
157
- self._register_factory_class(obj)
158
- elif infra == "configured":
159
- enabled = self._enabled_by_condition(obj)
160
- reg_data = self._config_manager.register_configured_class(obj, enabled)
161
- if reg_data:
162
- self._queue(reg_data[0], reg_data[1], reg_data[2])
163
-
164
- for _, fn in inspect.getmembers(module, predicate=inspect.isfunction):
165
- if getattr(fn, PICO_INFRA, None) == "provides":
166
- self._register_provides_function(fn)
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, max_scopes_per_type: int = 2048) -> None:
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.1.3
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 injection,inversion of control,decorator
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
  [![Docs](https://img.shields.io/badge/Docs-pico--ioc-blue?style=flat&logo=readthedocs&logoColor=white)](https://dperezcabrera.github.io/pico-ioc/)
63
63
  [![Interactive Lab](https://img.shields.io/badge/Learn-online-green?style=flat&logo=python&logoColor=white)](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.0+)
99
+ ## 🧩 Highlights (v2.2+)
101
100
 
102
- - Unified Configuration: Use `@configured` to bind both flat (ENV-like) and tree (YAML/JSON) sources via the `configuration(...)` builder (ADR-0010).
103
- - Async-aware AOP system: Method interceptors via `@intercepted_by`.
104
- - Scoped resolution: singleton, prototype, request, session, transaction, and custom scopes.
105
- - `UnifiedComponentProxy`: Transparent `lazy=True` and AOP proxy supporting serialization.
106
- - Tree-based configuration runtime: Advanced mapping with reusable adapters and discriminators (`Annotated[Union[...], Discriminator(...)]`).
107
- - Observable container context: Built-in stats, health checks (`@health`), observer hooks (`ContainerObserver`), dependency graph export (`export_graph`), and async cleanup.
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
- ```bash
122
- pip install pico-ioc[yaml]
123
- ```
120
+ ```bash
121
+ pip install pico-ioc[yaml]
122
+ ```
124
123
 
125
124
  -----
126
125
 
127
- ### ⚠️ Important Note for v2.1.3+
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
- **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.
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 or whose providers are async.
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
- ```python
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
- - Health checks:
318
- - Annotate health probes inside components with `@health` for container-level reporting.
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
- - For sync components: `container.close()`
323
- - For async components/resources: `await container.aclose()`
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](./CHANGELOG.md) — Significant redesigns and features in v2.0+.
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=i25Obx7aH_Oy5b6yjjnCswDgni7InIjrGEcG6vLAw6I,2414
2
- pico_ioc/_version.py,sha256=hgD1miBO_f3fboq1GKyV4DdK_igCLGJFnZRD7l9oNRs,22
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=0pcRFHzhDcX8ijd67xAsVrTejwXuJKz7kTKRUrIuX2s,6161
6
- pico_ioc/component_scanner.py,sha256=S-9XNxrgyq_JFdc4Uqn2bEb-HxafSgIWylIurxyN_UA,7955
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=SEEJCUHIOUz4Dghdmac2rDrv65Zlm2wiBKZt4WbZoDc,21354
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=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,,
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,,