pico-ioc 1.5.0__tar.gz → 2.0.1__tar.gz

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.
Files changed (149) hide show
  1. {pico_ioc-1.5.0 → pico_ioc-2.0.1}/.github/workflows/ci.yml +1 -1
  2. pico_ioc-2.0.1/CHANGELOG.md +97 -0
  3. pico_ioc-2.0.1/PKG-INFO +243 -0
  4. pico_ioc-2.0.1/README.md +193 -0
  5. pico_ioc-2.0.1/docs/README.md +89 -0
  6. pico_ioc-2.0.1/docs/adr/README.md +15 -0
  7. pico_ioc-2.0.1/docs/adr/adr-0001-async-native.md +31 -0
  8. pico_ioc-2.0.1/docs/adr/adr-0002-tree-based-configuration.md +31 -0
  9. pico_ioc-2.0.1/docs/adr/adr-0003-context-aware-scopes.md +39 -0
  10. pico_ioc-2.0.1/docs/adr/adr-0004-observability.md +35 -0
  11. pico_ioc-2.0.1/docs/adr/adr-0005-aop.md +31 -0
  12. pico_ioc-2.0.1/docs/adr/adr-0006-eager-validation.md +32 -0
  13. pico_ioc-2.0.1/docs/adr/adr-0007-event_bus.md +31 -0
  14. pico_ioc-2.0.1/docs/adr/adr-0008-circular-dependencies.md +34 -0
  15. pico_ioc-2.0.1/docs/adr/adr-0009-flexible-provides.md +85 -0
  16. pico_ioc-2.0.1/docs/advanced-features/README.md +21 -0
  17. pico_ioc-2.0.1/docs/advanced-features/aop-interceptors.md +278 -0
  18. pico_ioc-2.0.1/docs/advanced-features/async-resolution.md +197 -0
  19. pico_ioc-2.0.1/docs/advanced-features/conditional-binding.md +198 -0
  20. pico_ioc-2.0.1/docs/advanced-features/event-bus.md +265 -0
  21. pico_ioc-2.0.1/docs/advanced-features/health-checks.md +137 -0
  22. pico_ioc-2.0.1/docs/api-reference/README.md +19 -0
  23. pico_ioc-2.0.1/docs/api-reference/container.md +202 -0
  24. pico_ioc-2.0.1/docs/api-reference/decorators.md +95 -0
  25. pico_ioc-2.0.1/docs/api-reference/glossary.md +73 -0
  26. pico_ioc-2.0.1/docs/api-reference/protocols.md +155 -0
  27. pico_ioc-2.0.1/docs/architecture/README.md +23 -0
  28. pico_ioc-2.0.1/docs/architecture/comparison.md +114 -0
  29. pico_ioc-2.0.1/docs/architecture/design-principles.md +97 -0
  30. pico_ioc-2.0.1/docs/architecture/internals.md +194 -0
  31. pico_ioc-2.0.1/docs/cookbook/README.md +24 -0
  32. pico_ioc-2.0.1/docs/cookbook/pattern-aop-feature-toggle.md +277 -0
  33. pico_ioc-2.0.1/docs/cookbook/pattern-aop-profiling.md +82 -0
  34. pico_ioc-2.0.1/docs/cookbook/pattern-aop-security.md +369 -0
  35. pico_ioc-2.0.1/docs/cookbook/pattern-aop-structured-logging.md +289 -0
  36. pico_ioc-2.0.1/docs/cookbook/pattern-cli-app.md +198 -0
  37. pico_ioc-2.0.1/docs/cookbook/pattern-cqrs.md +208 -0
  38. pico_ioc-2.0.1/docs/cookbook/pattern-dynamic-langchain.md +212 -0
  39. pico_ioc-2.0.1/docs/cookbook/pattern-hot-reload.md +234 -0
  40. pico_ioc-2.0.1/docs/cookbook/pattern-multi-tenant.md +232 -0
  41. pico_ioc-2.0.1/docs/getting-started.md +195 -0
  42. pico_ioc-2.0.1/docs/integrations/README.md +19 -0
  43. pico_ioc-2.0.1/docs/integrations/ai-langchain.md +293 -0
  44. pico_ioc-2.0.1/docs/integrations/web-django.md +158 -0
  45. pico_ioc-2.0.1/docs/integrations/web-fastapi.md +231 -0
  46. pico_ioc-2.0.1/docs/integrations/web-flask.md +253 -0
  47. pico_ioc-2.0.1/docs/observability/README.md +21 -0
  48. pico_ioc-2.0.1/docs/observability/container-context.md +143 -0
  49. pico_ioc-2.0.1/docs/observability/exporting-graph.md +144 -0
  50. pico_ioc-2.0.1/docs/observability/observers-metrics.md +167 -0
  51. pico_ioc-2.0.1/docs/overview.md +241 -0
  52. pico_ioc-2.0.1/docs/user-guide/README.md +22 -0
  53. pico_ioc-2.0.1/docs/user-guide/configuration-basic.md +63 -0
  54. pico_ioc-2.0.1/docs/user-guide/configuration-binding.md +155 -0
  55. pico_ioc-2.0.1/docs/user-guide/core-concepts.md +199 -0
  56. pico_ioc-2.0.1/docs/user-guide/qualifiers-lists.md +180 -0
  57. pico_ioc-2.0.1/docs/user-guide/scopes-lifecycle.md +281 -0
  58. pico_ioc-2.0.1/docs/user-guide/testing.md +216 -0
  59. {pico_ioc-1.5.0 → pico_ioc-2.0.1}/pyproject.toml +7 -1
  60. pico_ioc-2.0.1/src/pico_ioc/__init__.py +93 -0
  61. pico_ioc-2.0.1/src/pico_ioc/_version.py +1 -0
  62. pico_ioc-2.0.1/src/pico_ioc/aop.py +281 -0
  63. pico_ioc-2.0.1/src/pico_ioc/api.py +1161 -0
  64. pico_ioc-2.0.1/src/pico_ioc/config_runtime.py +289 -0
  65. pico_ioc-2.0.1/src/pico_ioc/constants.py +10 -0
  66. pico_ioc-2.0.1/src/pico_ioc/container.py +440 -0
  67. pico_ioc-2.0.1/src/pico_ioc/event_bus.py +223 -0
  68. pico_ioc-2.0.1/src/pico_ioc/exceptions.py +72 -0
  69. pico_ioc-2.0.1/src/pico_ioc/factory.py +48 -0
  70. pico_ioc-2.0.1/src/pico_ioc/locator.py +53 -0
  71. pico_ioc-2.0.1/src/pico_ioc/scope.py +157 -0
  72. pico_ioc-2.0.1/src/pico_ioc.egg-info/PKG-INFO +243 -0
  73. pico_ioc-2.0.1/src/pico_ioc.egg-info/SOURCES.txt +90 -0
  74. pico_ioc-2.0.1/src/pico_ioc.egg-info/requires.txt +6 -0
  75. pico_ioc-2.0.1/test.txt +1272 -0
  76. pico_ioc-2.0.1/tests/test_configured.py +310 -0
  77. pico_ioc-2.0.1/tests/test_container_context.py +51 -0
  78. pico_ioc-2.0.1/tests/test_container_runtime.py +102 -0
  79. pico_ioc-2.0.1/tests/test_event_bus.py +107 -0
  80. pico_ioc-2.0.1/tests/test_pico_extends.py +459 -0
  81. pico_ioc-2.0.1/tests/test_pico_integration.py +317 -0
  82. pico_ioc-2.0.1/tests/test_provides_module_functions.py +96 -0
  83. pico_ioc-2.0.1/tests/test_provides_static_methods.py +39 -0
  84. pico_ioc-2.0.1/tests/test_resolution_graph.py +63 -0
  85. {pico_ioc-1.5.0 → pico_ioc-2.0.1}/tox.ini +9 -2
  86. pico_ioc-1.5.0/.llm/ARCHITECTURE.md +0 -437
  87. pico_ioc-1.5.0/.llm/DECISIONS.md +0 -197
  88. pico_ioc-1.5.0/.llm/FEATURES/FEATURE-2025-0001-scope-subgraphs.md +0 -151
  89. pico_ioc-1.5.0/.llm/FEATURES/FEATURE-2025-0003-interceptor-auto-registration.md +0 -148
  90. pico_ioc-1.5.0/.llm/FEATURES/FEATURE-2025-0004-config-injection.md +0 -158
  91. pico_ioc-1.5.0/.llm/GUIDE-CONFIGURATION-INJECTION.md +0 -129
  92. pico_ioc-1.5.0/.llm/GUIDE-CQRS.md +0 -110
  93. pico_ioc-1.5.0/.llm/GUIDE-CREATING-PLUGINS-AND-INTERCEPTORS.md +0 -224
  94. pico_ioc-1.5.0/.llm/GUIDE.md +0 -522
  95. pico_ioc-1.5.0/.llm/OVERVIEW.md +0 -167
  96. pico_ioc-1.5.0/CHANGELOG.md +0 -140
  97. pico_ioc-1.5.0/PKG-INFO +0 -249
  98. pico_ioc-1.5.0/README.md +0 -204
  99. pico_ioc-1.5.0/src/pico_ioc/__init__.py +0 -68
  100. pico_ioc-1.5.0/src/pico_ioc/_state.py +0 -75
  101. pico_ioc-1.5.0/src/pico_ioc/_version.py +0 -1
  102. pico_ioc-1.5.0/src/pico_ioc/api.py +0 -222
  103. pico_ioc-1.5.0/src/pico_ioc/builder.py +0 -210
  104. pico_ioc-1.5.0/src/pico_ioc/config.py +0 -332
  105. pico_ioc-1.5.0/src/pico_ioc/container.py +0 -168
  106. pico_ioc-1.5.0/src/pico_ioc/decorators.py +0 -120
  107. pico_ioc-1.5.0/src/pico_ioc/infra.py +0 -196
  108. pico_ioc-1.5.0/src/pico_ioc/interceptors.py +0 -76
  109. pico_ioc-1.5.0/src/pico_ioc/plugins.py +0 -28
  110. pico_ioc-1.5.0/src/pico_ioc/policy.py +0 -245
  111. pico_ioc-1.5.0/src/pico_ioc/proxy.py +0 -115
  112. pico_ioc-1.5.0/src/pico_ioc/public_api.py +0 -76
  113. pico_ioc-1.5.0/src/pico_ioc/resolver.py +0 -101
  114. pico_ioc-1.5.0/src/pico_ioc/scanner.py +0 -178
  115. pico_ioc-1.5.0/src/pico_ioc/scope.py +0 -41
  116. pico_ioc-1.5.0/src/pico_ioc/utils.py +0 -25
  117. pico_ioc-1.5.0/src/pico_ioc.egg-info/PKG-INFO +0 -249
  118. pico_ioc-1.5.0/src/pico_ioc.egg-info/SOURCES.txt +0 -65
  119. pico_ioc-1.5.0/tests/conftest.py +0 -22
  120. pico_ioc-1.5.0/tests/helpers.py +0 -46
  121. pico_ioc-1.5.0/tests/test_api.py +0 -135
  122. pico_ioc-1.5.0/tests/test_config_injection.py +0 -176
  123. pico_ioc-1.5.0/tests/test_container.py +0 -181
  124. pico_ioc-1.5.0/tests/test_core_helpers_and_errors.py +0 -86
  125. pico_ioc-1.5.0/tests/test_decorator_on_missing.py +0 -103
  126. pico_ioc-1.5.0/tests/test_decorators.py +0 -139
  127. pico_ioc-1.5.0/tests/test_defaults.py +0 -69
  128. pico_ioc-1.5.0/tests/test_factory_policy_and_defaults.py +0 -179
  129. pico_ioc-1.5.0/tests/test_fingerprint_public.py +0 -25
  130. pico_ioc-1.5.0/tests/test_infrastructure.py +0 -364
  131. pico_ioc-1.5.0/tests/test_init.py +0 -316
  132. pico_ioc-1.5.0/tests/test_no_overrides_needed_with_on_missing.py +0 -30
  133. pico_ioc-1.5.0/tests/test_policy_and_container_helpers.py +0 -106
  134. pico_ioc-1.5.0/tests/test_policy_env_activation.py +0 -33
  135. pico_ioc-1.5.0/tests/test_policy_profile_primary.py +0 -35
  136. pico_ioc-1.5.0/tests/test_proxy_unit.py +0 -188
  137. pico_ioc-1.5.0/tests/test_public_api.py +0 -220
  138. pico_ioc-1.5.0/tests/test_qualifiers_unit.py +0 -70
  139. pico_ioc-1.5.0/tests/test_resolver_unit.py +0 -121
  140. pico_ioc-1.5.0/tests/test_scanner_providers.py +0 -146
  141. pico_ioc-1.5.0/tests/test_scanner_unit.py +0 -190
  142. pico_ioc-1.5.0/tests/test_scope.py +0 -326
  143. {pico_ioc-1.5.0 → pico_ioc-2.0.1}/.coveragerc +0 -0
  144. {pico_ioc-1.5.0 → pico_ioc-2.0.1}/.github/workflows/publish-to-pypi.yml +0 -0
  145. {pico_ioc-1.5.0 → pico_ioc-2.0.1}/LICENSE +0 -0
  146. {pico_ioc-1.5.0 → pico_ioc-2.0.1}/MANIFEST.in +0 -0
  147. {pico_ioc-1.5.0 → pico_ioc-2.0.1}/setup.cfg +0 -0
  148. {pico_ioc-1.5.0 → pico_ioc-2.0.1}/src/pico_ioc.egg-info/dependency_links.txt +0 -0
  149. {pico_ioc-1.5.0 → pico_ioc-2.0.1}/src/pico_ioc.egg-info/top_level.txt +0 -0
@@ -13,7 +13,7 @@ jobs:
13
13
  strategy:
14
14
  fail-fast: false
15
15
  matrix:
16
- python-version: [ "3.10", "3.11", "3.12", "3.13" ]
16
+ python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ]
17
17
 
18
18
  steps:
19
19
  - name: Checkout
@@ -0,0 +1,97 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.html).
7
+
8
+ ---
9
+
10
+ ## [2.0.0] - 2025-10-23
11
+
12
+ This version marks a significant redesign and the first major public release, establishing the core architecture and feature set based on the principles outlined in the Architecture Decision Records (ADRs).
13
+
14
+ ### 🚀 Highlights
15
+
16
+ * **Async-Native Core:** Introduced first-class `async`/`await` support across component resolution (`container.aget`), initialization (`__ainit__`), lifecycle hooks (`@configure`, `@cleanup`), AOP interceptors, and the event bus (ADR-001).
17
+ * **Tree-Based Configuration:** Added `@configured` decorator and `TreeSource` protocol for binding complex, nested configuration (YAML/JSON) to dataclass graphs, including interpolation and type coercion (ADR-002).
18
+ * **Context-Aware Scopes:** Implemented `contextvars`-based scopes (e.g., `"request"`, `"session"`) for managing component lifecycles tied to specific contexts (ADR-003).
19
+ * **Observability Features:** Integrated container context (`container_id`, `as_current`), basic stats (`container.stats()`), observer protocol (`ContainerObserver`), and dependency graph export (`container.export_graph()`) (ADR-004).
20
+ * **Aspect-Oriented Programming (AOP):** Implemented method interception via `MethodInterceptor` protocol and `@intercepted_by` decorator, using a dynamic proxy (`UnifiedComponentProxy`) (ADR-005).
21
+ * **Eager Startup Validation:** Added fail-fast validation during `init()` to detect missing dependencies and configuration errors before runtime (ADR-006).
22
+ * **Built-in Event Bus:** Included an asynchronous, in-process event bus (`EventBus`, `@subscribe`, `AutoSubscriberMixin`) for decoupled communication (ADR-007).
23
+ * **Explicit Circular Dependency Handling:** Implemented detection and fail-fast for circular dependencies, requiring explicit resolution patterns (ADR-008).
24
+ * **Unified Decorator API:** Consolidated component metadata into parameterized decorators (`@component`, `@factory`, `@provides`), removing older stacked decorators (ADR-009).
25
+
26
+ ### ✨ Added
27
+
28
+ * Core registration decorators: `@component`, `@factory`, `@provides`.
29
+ * Configuration decorators: `@configuration` (flat key-value) and `@configured` (tree-based).
30
+ * Lifecycle decorators: `@configure`, `@cleanup`.
31
+ * AOP decorator: `@intercepted_by`.
32
+ * Event bus decorator: `@subscribe`.
33
+ * Health check decorator: `@health`.
34
+ * Async resolution: `container.aget()` and `__ainit__` convention.
35
+ * Async cleanup: `container.cleanup_all_async()`.
36
+ * Qualifier support (`Qualifier` class) for list injection (`Annotated[List[Type], Qualifier(...)]`).
37
+ * Support for `lazy=True` parameter for deferred component instantiation.
38
+ * Conditional binding parameters (`conditional_profiles`, `conditional_require_env`, `conditional_predicate`).
39
+ * Fallback binding parameters (`on_missing_selector`, `on_missing_priority`).
40
+ * Primary selection parameter (`primary=True`).
41
+ * Testing support via `init(overrides={...})` and `init(profiles=(...))`.
42
+ * Container context management (`as_current`, `get_current`, `shutdown`, `all_containers`).
43
+ * Scope management API (`activate_scope`, `deactivate_scope`, `scope` context manager).
44
+ * Configuration sources: `EnvSource`, `FileSource` (flat); `JsonTreeSource`, `YamlTreeSource`, `DictSource` (tree).
45
+ * Protocols for extension: `MethodInterceptor`, `ContainerObserver`, `ScopeProtocol`, `ConfigSource`, `TreeSource`.
46
+
47
+ ### ⚠️ Breaking Changes
48
+
49
+ * Complete redesign compared to any prior internal/unreleased versions. APIs are not backward compatible.
50
+ * Requires Python 3.10+.
51
+
52
+ ### 📚 Docs
53
+
54
+ * Established new documentation structure including ADRs, Architecture, User Guide, Advanced Features, Cookbook, Integrations, and API Reference.
55
+
56
+ ### 🧪 Testing
57
+
58
+ * Added comprehensive test suite covering core features, async behavior, AOP, configuration, scopes, and error handling.
59
+ * Introduced patterns for testing with overrides and profiles.
60
+
61
+ ---
62
+
63
+ ## [2.0.1] - 2025-10-25
64
+
65
+ ### Added ✨
66
+
67
+ - **ADR-0009: Flexible `@provides` Support**
68
+ Implemented support for using `@provides` in additional contexts:
69
+ - `@staticmethod` methods within `@factory` classes
70
+ - `@classmethod` methods within `@factory` classes
71
+ - Module-level functions
72
+ These new provider types are discovered automatically during module scanning and participate fully in dependency resolution, validation, and graph generation.
73
+
74
+ - **Dependency Graph and Validation Enhancements**
75
+ - `_build_resolution_graph` now includes edges for all `@provides` functions, regardless of where they are defined.
76
+ - Fail-fast validation checks now cover static/class/module-level providers, reporting missing bindings consistently.
77
+ - Scope inference and promotion logic apply equally to these new provider types.
78
+
79
+ ### Documentation 📚
80
+
81
+ - Expanded `docs/overview.md` to document the new flexible provider options (`@staticmethod`, `@classmethod`, module-level functions).
82
+ - Updated `docs/guide.md` with practical examples showing when to use each style of provider.
83
+ - Linked ADR-0009 for design rationale and migration guidance.
84
+
85
+ ### Notes 📝
86
+
87
+ - This is a **minor feature release** introducing a major ergonomics improvement (ADR-0009).
88
+ - Fully backward compatible with existing factories, components, and configuration mechanisms.
89
+ - Encourages a lighter, more Pythonic style for simple provider declarations.
90
+
91
+
92
+ ---
93
+
94
+ ## [<2.0.0]
95
+
96
+ * Internal development and prototyping phase. Basic dependency injection concepts established. Architecture significantly reworked for the v2.0.0 release.
97
+
@@ -0,0 +1,243 @@
1
+ Metadata-Version: 2.4
2
+ Name: pico-ioc
3
+ Version: 2.0.1
4
+ Summary: A minimalist, zero-dependency Inversion of Control (IoC) container for Python.
5
+ Author-email: David Perez Cabrera <dperezcabrera@gmail.com>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 David Pérez Cabrera
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://github.com/dperezcabrera/pico-ioc
29
+ Project-URL: Repository, https://github.com/dperezcabrera/pico-ioc
30
+ Project-URL: Issue Tracker, https://github.com/dperezcabrera/pico-ioc/issues
31
+ Keywords: ioc,di,dependency injection,inversion of control,decorator
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Programming Language :: Python :: 3
34
+ Classifier: Programming Language :: Python :: 3 :: Only
35
+ Classifier: Programming Language :: Python :: 3.10
36
+ Classifier: Programming Language :: Python :: 3.11
37
+ Classifier: Programming Language :: Python :: 3.12
38
+ Classifier: Programming Language :: Python :: 3.13
39
+ Classifier: Programming Language :: Python :: 3.14
40
+ Classifier: License :: OSI Approved :: MIT License
41
+ Classifier: Operating System :: OS Independent
42
+ Requires-Python: >=3.8
43
+ Description-Content-Type: text/markdown
44
+ License-File: LICENSE
45
+ Provides-Extra: yaml
46
+ Requires-Dist: PyYAML; extra == "yaml"
47
+ Provides-Extra: graphviz
48
+ Requires-Dist: graphviz; extra == "graphviz"
49
+ Dynamic: license-file
50
+
51
+ # 📦 Pico-IoC: A Robust, Async-Native IoC Container for Python
52
+
53
+ [![PyPI](https://img.shields.io/pypi/v/pico-ioc.svg)](https://pypi.org/project/pico-ioc/)
54
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/dperezcabrera/pico-ioc)
55
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
56
+ ![CI (tox matrix)](https://github.com/dperezcabrera/pico-ioc/actions/workflows/ci.yml/badge.svg)
57
+ [![codecov](https://codecov.io/gh/dperezcabrera/pico-ioc/branch/main/graph/badge.svg)](https://codecov.io/gh/dperezcabrera/pico-ioc)
58
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-ioc&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-ioc)
59
+ [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-ioc&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-ioc)
60
+ [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-ioc&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-ioc)
61
+
62
+ **Pico-IoC** is a **lightweight, async-ready, decorator-driven IoC container** built for clarity, testability, and performance.
63
+ It brings *Inversion of Control* and *dependency injection* to Python in a deterministic, modern, and framework-agnostic way.
64
+
65
+ > 🐍 Requires **Python 3.10+**
66
+
67
+ ---
68
+
69
+ ## ⚖️ Core Principles
70
+
71
+ - **Single Purpose** – Do one thing: dependency management.
72
+ - **Declarative** – Use simple decorators (`@component`, `@factory`, `@configuration`) instead of config files or YAML magic.
73
+ - **Deterministic** – No hidden scanning or side-effects; everything flows from an explicit `init()`.
74
+ - **Async-Native** – Fully supports async providers, async lifecycle hooks, and async interceptors.
75
+ - **Fail-Fast** – Detects missing bindings and circular dependencies at bootstrap.
76
+ - **Testable by Design** – Use `overrides` and `profiles` to swap components instantly.
77
+ - **Zero Core Dependencies** – Built entirely on the Python standard library. Optional features may require external packages (see Installation).
78
+
79
+ ---
80
+
81
+ ## 🚀 Why Pico-IoC?
82
+
83
+ As Python systems evolve, wiring dependencies by hand becomes fragile and unmaintainable.
84
+ **Pico-IoC** eliminates that friction by letting you declare how components relate — not how they’re created.
85
+
86
+ | Feature | Manual Wiring | With Pico-IoC |
87
+ | :------------- | :------------------------- | :------------------------------ |
88
+ | Object creation| `svc = Service(Repo(Config()))` | `svc = container.get(Service)` |
89
+ | Replacing deps | Monkey-patch | `overrides={Repo: FakeRepo()}` |
90
+ | Coupling | Tight | Loose |
91
+ | Testing | Painful | Instant |
92
+ | Async support | Manual | Built-in |
93
+
94
+ ---
95
+
96
+ ## 🧩 Highlights (v2.0.0)
97
+
98
+ - **Full redesign:** unified architecture with simpler, more powerful APIs.
99
+ - **Async-aware AOP system** — method interceptors via `@intercepted_by`.
100
+ - **Typed configuration** — dataclasses with JSON/YAML/env sources.
101
+ - **Scoped resolution** — singleton, prototype, request, session, transaction.
102
+ - **UnifiedComponentProxy** — transparent lazy/AOP proxy supporting serialization.
103
+ - **Tree-based configuration runtime** with reusable adapters and discriminators.
104
+ - **Observable container context** with stats, health checks, and async cleanup.
105
+
106
+ ---
107
+
108
+ ## 📦 Installation
109
+
110
+ ```bash
111
+ pip install pico-ioc
112
+ ```
113
+
114
+ For optional features, you can install extras:
115
+
116
+ * **YAML Configuration:**
117
+
118
+ ```bash
119
+ pip install pico-ioc[yaml]
120
+ ```
121
+
122
+ (Requires `PyYAML`)
123
+
124
+ * **Dependency Graph Export:**
125
+
126
+ ```bash
127
+ pip install pico-ioc[graphviz]
128
+ ```
129
+
130
+ (Requires the `graphviz` Python package and the Graphviz command-line tools)
131
+
132
+ -----
133
+
134
+ ## ⚙️ Quick Example
135
+
136
+ ```python
137
+ from dataclasses import dataclass
138
+ from pico_ioc import component, configuration, init
139
+
140
+ @configuration
141
+ @dataclass
142
+ class Config:
143
+ db_url: str = "sqlite:///demo.db"
144
+
145
+ @component
146
+ class Repo:
147
+ def __init__(self, cfg: Config):
148
+ self.cfg = cfg
149
+ def fetch(self):
150
+ return f"fetching from {self.cfg.db_url}"
151
+
152
+ @component
153
+ class Service:
154
+ def __init__(self, repo: Repo):
155
+ self.repo = repo
156
+ def run(self):
157
+ return self.repo.fetch()
158
+
159
+ container = init(modules=[__name__])
160
+ svc = container.get(Service)
161
+ print(svc.run())
162
+ ```
163
+
164
+ **Output:**
165
+
166
+ ```
167
+ fetching from sqlite:///demo.db
168
+ ```
169
+
170
+ -----
171
+
172
+ ## 🧪 Testing with Overrides
173
+
174
+ ```python
175
+ class FakeRepo:
176
+ def fetch(self): return "fake-data"
177
+
178
+ container = init(modules=[__name__], overrides={Repo: FakeRepo()})
179
+ svc = container.get(Service)
180
+ assert svc.run() == "fake-data"
181
+ ```
182
+
183
+ -----
184
+
185
+ ## 🩺 Lifecycle & AOP
186
+
187
+ ```python
188
+ from pico_ioc import intercepted_by, MethodInterceptor, MethodCtx
189
+
190
+ class LogInterceptor(MethodInterceptor):
191
+ def invoke(self, ctx: MethodCtx, call_next):
192
+ print(f"→ calling {ctx.name}")
193
+ res = call_next(ctx)
194
+ print(f"← {ctx.name} done")
195
+ return res
196
+
197
+ @component
198
+ class Demo:
199
+ @intercepted_by(LogInterceptor)
200
+ def work(self):
201
+ return "ok"
202
+
203
+ c = init(modules=[__name__])
204
+ c.get(Demo).work()
205
+ ```
206
+
207
+ -----
208
+
209
+ ## 📖 Documentation
210
+
211
+ The full documentation is available within the `docs/` directory of the project repository. Start with `docs/README.md` for navigation.
212
+
213
+ * **Getting Started:** `docs/getting-started.md`
214
+ * **User Guide:** `docs/user-guide/README.md`
215
+ * **Advanced Features:** `docs/advanced-features/README.md`
216
+ * **Observability:** `docs/observability/README.md`
217
+ * **Integrations:** `docs/integrations/README.md`
218
+ * **Cookbook (Patterns):** `docs/cookbook/README.md`
219
+ * **Architecture:** `docs/architecture/README.md`
220
+ * **API Reference:** `docs/api-reference/README.md`
221
+ * **ADR Index:** `docs/adr/README.md`
222
+
223
+ -----
224
+
225
+ ## 🧩 Development
226
+
227
+ ```bash
228
+ pip install tox
229
+ tox
230
+ ```
231
+
232
+ -----
233
+
234
+ ## 🧾 Changelog
235
+
236
+ See [CHANGELOG.md](./CHANGELOG.md) — *Full redesign for v2.0.0.*
237
+
238
+ -----
239
+
240
+ ## 📜 License
241
+
242
+ MIT — [LICENSE](https://opensource.org/licenses/MIT)
243
+
@@ -0,0 +1,193 @@
1
+ # 📦 Pico-IoC: A Robust, Async-Native IoC Container for Python
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/pico-ioc.svg)](https://pypi.org/project/pico-ioc/)
4
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/dperezcabrera/pico-ioc)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
+ ![CI (tox matrix)](https://github.com/dperezcabrera/pico-ioc/actions/workflows/ci.yml/badge.svg)
7
+ [![codecov](https://codecov.io/gh/dperezcabrera/pico-ioc/branch/main/graph/badge.svg)](https://codecov.io/gh/dperezcabrera/pico-ioc)
8
+ [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-ioc&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-ioc)
9
+ [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-ioc&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-ioc)
10
+ [![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=dperezcabrera_pico-ioc&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-ioc)
11
+
12
+ **Pico-IoC** is a **lightweight, async-ready, decorator-driven IoC container** built for clarity, testability, and performance.
13
+ It brings *Inversion of Control* and *dependency injection* to Python in a deterministic, modern, and framework-agnostic way.
14
+
15
+ > 🐍 Requires **Python 3.10+**
16
+
17
+ ---
18
+
19
+ ## ⚖️ Core Principles
20
+
21
+ - **Single Purpose** – Do one thing: dependency management.
22
+ - **Declarative** – Use simple decorators (`@component`, `@factory`, `@configuration`) instead of config files or YAML magic.
23
+ - **Deterministic** – No hidden scanning or side-effects; everything flows from an explicit `init()`.
24
+ - **Async-Native** – Fully supports async providers, async lifecycle hooks, and async interceptors.
25
+ - **Fail-Fast** – Detects missing bindings and circular dependencies at bootstrap.
26
+ - **Testable by Design** – Use `overrides` and `profiles` to swap components instantly.
27
+ - **Zero Core Dependencies** – Built entirely on the Python standard library. Optional features may require external packages (see Installation).
28
+
29
+ ---
30
+
31
+ ## 🚀 Why Pico-IoC?
32
+
33
+ As Python systems evolve, wiring dependencies by hand becomes fragile and unmaintainable.
34
+ **Pico-IoC** eliminates that friction by letting you declare how components relate — not how they’re created.
35
+
36
+ | Feature | Manual Wiring | With Pico-IoC |
37
+ | :------------- | :------------------------- | :------------------------------ |
38
+ | Object creation| `svc = Service(Repo(Config()))` | `svc = container.get(Service)` |
39
+ | Replacing deps | Monkey-patch | `overrides={Repo: FakeRepo()}` |
40
+ | Coupling | Tight | Loose |
41
+ | Testing | Painful | Instant |
42
+ | Async support | Manual | Built-in |
43
+
44
+ ---
45
+
46
+ ## 🧩 Highlights (v2.0.0)
47
+
48
+ - **Full redesign:** unified architecture with simpler, more powerful APIs.
49
+ - **Async-aware AOP system** — method interceptors via `@intercepted_by`.
50
+ - **Typed configuration** — dataclasses with JSON/YAML/env sources.
51
+ - **Scoped resolution** — singleton, prototype, request, session, transaction.
52
+ - **UnifiedComponentProxy** — transparent lazy/AOP proxy supporting serialization.
53
+ - **Tree-based configuration runtime** with reusable adapters and discriminators.
54
+ - **Observable container context** with stats, health checks, and async cleanup.
55
+
56
+ ---
57
+
58
+ ## 📦 Installation
59
+
60
+ ```bash
61
+ pip install pico-ioc
62
+ ```
63
+
64
+ For optional features, you can install extras:
65
+
66
+ * **YAML Configuration:**
67
+
68
+ ```bash
69
+ pip install pico-ioc[yaml]
70
+ ```
71
+
72
+ (Requires `PyYAML`)
73
+
74
+ * **Dependency Graph Export:**
75
+
76
+ ```bash
77
+ pip install pico-ioc[graphviz]
78
+ ```
79
+
80
+ (Requires the `graphviz` Python package and the Graphviz command-line tools)
81
+
82
+ -----
83
+
84
+ ## ⚙️ Quick Example
85
+
86
+ ```python
87
+ from dataclasses import dataclass
88
+ from pico_ioc import component, configuration, init
89
+
90
+ @configuration
91
+ @dataclass
92
+ class Config:
93
+ db_url: str = "sqlite:///demo.db"
94
+
95
+ @component
96
+ class Repo:
97
+ def __init__(self, cfg: Config):
98
+ self.cfg = cfg
99
+ def fetch(self):
100
+ return f"fetching from {self.cfg.db_url}"
101
+
102
+ @component
103
+ class Service:
104
+ def __init__(self, repo: Repo):
105
+ self.repo = repo
106
+ def run(self):
107
+ return self.repo.fetch()
108
+
109
+ container = init(modules=[__name__])
110
+ svc = container.get(Service)
111
+ print(svc.run())
112
+ ```
113
+
114
+ **Output:**
115
+
116
+ ```
117
+ fetching from sqlite:///demo.db
118
+ ```
119
+
120
+ -----
121
+
122
+ ## 🧪 Testing with Overrides
123
+
124
+ ```python
125
+ class FakeRepo:
126
+ def fetch(self): return "fake-data"
127
+
128
+ container = init(modules=[__name__], overrides={Repo: FakeRepo()})
129
+ svc = container.get(Service)
130
+ assert svc.run() == "fake-data"
131
+ ```
132
+
133
+ -----
134
+
135
+ ## 🩺 Lifecycle & AOP
136
+
137
+ ```python
138
+ from pico_ioc import intercepted_by, MethodInterceptor, MethodCtx
139
+
140
+ class LogInterceptor(MethodInterceptor):
141
+ def invoke(self, ctx: MethodCtx, call_next):
142
+ print(f"→ calling {ctx.name}")
143
+ res = call_next(ctx)
144
+ print(f"← {ctx.name} done")
145
+ return res
146
+
147
+ @component
148
+ class Demo:
149
+ @intercepted_by(LogInterceptor)
150
+ def work(self):
151
+ return "ok"
152
+
153
+ c = init(modules=[__name__])
154
+ c.get(Demo).work()
155
+ ```
156
+
157
+ -----
158
+
159
+ ## 📖 Documentation
160
+
161
+ The full documentation is available within the `docs/` directory of the project repository. Start with `docs/README.md` for navigation.
162
+
163
+ * **Getting Started:** `docs/getting-started.md`
164
+ * **User Guide:** `docs/user-guide/README.md`
165
+ * **Advanced Features:** `docs/advanced-features/README.md`
166
+ * **Observability:** `docs/observability/README.md`
167
+ * **Integrations:** `docs/integrations/README.md`
168
+ * **Cookbook (Patterns):** `docs/cookbook/README.md`
169
+ * **Architecture:** `docs/architecture/README.md`
170
+ * **API Reference:** `docs/api-reference/README.md`
171
+ * **ADR Index:** `docs/adr/README.md`
172
+
173
+ -----
174
+
175
+ ## 🧩 Development
176
+
177
+ ```bash
178
+ pip install tox
179
+ tox
180
+ ```
181
+
182
+ -----
183
+
184
+ ## 🧾 Changelog
185
+
186
+ See [CHANGELOG.md](./CHANGELOG.md) — *Full redesign for v2.0.0.*
187
+
188
+ -----
189
+
190
+ ## 📜 License
191
+
192
+ MIT — [LICENSE](https://opensource.org/licenses/MIT)
193
+
@@ -0,0 +1,89 @@
1
+ # Welcome to pico-ioc
2
+
3
+ `pico-ioc` is a powerful, async-native, and observability-first Inversion of Control (IoC) container for Python. It's designed to bring the power of enterprise-grade dependency injection, configuration binding, and AOP (Aspect-Oriented Programming) from frameworks like Spring into the modern Python ecosystem.
4
+
5
+ This documentation site guides you from your first component to building complex, observable, and testable applications.
6
+
7
+ ## Key Features
8
+
9
+ * 🚀 **Async-Native:** Full support for `async`/`await` in component resolution (`aget`), lifecycle methods (`__ainit__`, `@cleanup`), AOP interceptors, and the Event Bus.
10
+ * 🌳 **Advanced Tree-Binding:** Use `@configured` to map complex YAML/JSON configuration trees directly to `dataclass` graphs, including support for `Union` types and custom discriminators.
11
+ * 🔬 **Observability-First:** Built-in container contexts (`as_current`), stats (`.stats()`), and observer protocols (`ContainerObserver`) to monitor, trace, and debug your application's components.
12
+ * ✨ **Powerful AOP:** Intercept method calls for cross-cutting concerns (like logging, tracing, or caching) using `@intercepted_by` without modifying your business logic.
13
+ * ✅ **Fail-Fast Validation:** The container validates all component dependencies at startup (`init()`), preventing `ProviderNotFoundError` exceptions at runtime.
14
+ * 🧩 **Rich Lifecycle:** Full control over component lifecycles with `scope`, `lazy` instantiation, `@configure` setup methods, and `@cleanup` teardown hooks.
15
+
16
+ ## Documentation Structure
17
+
18
+ | Section | Focus | Start Here |
19
+ | :--- | :--- | :--- |
20
+ | **1. Getting Started** | Installation and 5-minute quick start. | [Quick Start](./getting-started.md) |
21
+ | **2. User Guide** | Core concepts, configuration, scopes, and testing. | [User Guide Overview](./user-guide/README.md) |
22
+ | **3. Advanced Features** | Async, AOP, Event Bus, and conditional logic. | [Advanced Features Overview](./advanced-features/README.md) |
23
+ | **4. Observability** | Context, metrics, tracing, and graph export. | [Observability Overview](./observability/README.md) |
24
+ | **5. Integrations** | FastAPI, Flask, Django, and AI/LangChain recipes. | [Integrations Overview](./integrations/README.md) |
25
+ | **6. Cookbook (Patterns)** | Full architectural solutions (Multi-tenant, Hot-reload, CQRS). | [Cookbook Overview](./cookbook/README.md) |
26
+ | **7. Architecture** | Design principles and internal deep-dive. | [Architecture Overview](./architecture/README.md) |
27
+ | **8. API Reference** | Glossary and decorator/method cheatsheets. | [API Reference Overview](./api-reference/README.md) |
28
+
29
+
30
+ ## Overview
31
+
32
+ **Pico IOC** is a Dependency Injection (DI) container for Python that implements advanced enterprise architecture patterns. Its design is inspired by frameworks like Spring (Java) and Guice, adapted for the Python ecosystem.
33
+
34
+ It provides a robust, type-safe, and testable foundation for complex applications by managing component lifecycles, configuration, and runtime dependencies.
35
+
36
+ ---
37
+
38
+ ## Core Strengths
39
+
40
+ The framework is built on specific principles:
41
+
42
+ * **Fail-Fast at Startup:** All wiring errors are detected during `init()`, preventing runtime surprises.
43
+ * **Async-Native:** Full integration of `async`/`await` across the resolution and lifecycle systems.
44
+ * **AOP and Observability:** Built-in tools for cross-cutting concerns and monitoring runtime behavior.
45
+
46
+ ---
47
+
48
+ ## Getting Started: A Simple Example
49
+
50
+ ```python
51
+ from dataclasses import dataclass
52
+ from pico_ioc import component, init
53
+
54
+ # 1. Define your components
55
+ class Greeter:
56
+     def say_hello(self) -> str: ...
57
+
58
+ @component
59
+ class EnglishGreeter(Greeter):
60
+     def say_hello(self) -> str:
61
+         return "Hello!"
62
+
63
+ @component
64
+ class App:
65
+     # 2. Declare dependencies in the constructor
66
+     def __init__(self, greeter: Greeter):
67
+         self.greeter = greeter
68
+     
69
+     def run(self):
70
+         print(self.greeter.say_hello())
71
+
72
+ # 3. Initialize the container
73
+ # The 'modules' list tells pico_ioc where to scan for @component
74
+ container = init(modules=[__name__])
75
+
76
+ # 4. Get the root component and run
77
+ app = container.get(App)
78
+ app.run()
79
+
80
+ # Output: Hello!
81
+ ```
82
+
83
+ -----
84
+
85
+ ## Navigation
86
+
87
+ | [⬅️ Anterior: Inicio](./README.md) | [🏠 Índice Principal](./README.md) | [Siguiente ➡️: Guía de Usuario](./user-guide/README.md) |
88
+ | :--- | :--- | :--- |
89
+
@@ -0,0 +1,15 @@
1
+ # Architecture Decision Records (ADRs)
2
+
3
+ This index lists all significant architecture decisions for the `pico-ioc` project. Keep it sorted by ADR number.
4
+
5
+ ---
6
+
7
+ * [ADR-001: Native Asyncio Support](./adr-0001-async-native.md) — Accepted
8
+ * [ADR-002: Tree-Based Configuration](./adr-0002-tree-based-configuration.md) — Accepted
9
+ * [ADR-003: Context-Aware Scopes](./adr-0003-context-aware-scopes.md) — Accepted
10
+ * [ADR-004: Observability Features](./adr-0004-observability.md) — Accepted
11
+ * [ADR-005: Aspect-Oriented Programming (AOP)](./adr-0005-aop.md) — Accepted
12
+ * [ADR-006: Eager Validation](./adr-0006-eager-validation.md) — Accepted
13
+ * [ADR-007: Built-in Asynchronous Event Bus](./adr-0007-event_bus.md) — Accepted
14
+ * [ADR-008: Explicit Handling of Circular Dependencies](./adr-0008-circular-dependencies.md) — Accepted
15
+ * [ADR-009: Flexible @provides for Static and Module-level Functions](./adr-0009-flexible-provides.md) — Accepted
@@ -0,0 +1,31 @@
1
+ ## ADR-001: Native Asyncio Support
2
+
3
+ **Status:** Accepted
4
+
5
+ ### Context
6
+
7
+ Modern Python web frameworks and I/O-bound applications heavily rely on `asyncio`. A synchronous DI container forces awkward workarounds (like running async initialization in `__init__` via `asyncio.run()`, which blocks) or cannot properly manage async resources. V1 lacked native support, hindering its use in async applications. We needed first-class `async`/`await` integration across the component lifecycle.
8
+
9
+ ### Decision
10
+
11
+ We decided to make `pico-ioc` **async-native**. This involved several key changes:
12
+
13
+ 1. Introduce `container.aget(key)` as the asynchronous counterpart to `container.get(key)`. `aget` correctly handles `await`ing async operations during resolution without blocking the event loop.
14
+ 2. Support `async def` methods decorated with `@provides` within factories.
15
+ 3. Introduce the `async def __ainit__(self, ...)` convention for components needing async initialization after `__init__`. Dependencies can be injected into `__ainit__`.
16
+ 4. Allow `@configure` and `@cleanup` methods to be `async def`. A corresponding `container.cleanup_all_async()` method was added.
17
+ 5. Ensure the AOP (`MethodInterceptor`) mechanism is async-aware, correctly `await`ing `call_next(ctx)` and allowing `async def invoke`.
18
+ 6. Make the built-in `EventBus` fully asynchronous.
19
+
20
+ ### Consequences
21
+
22
+ **Positive:** 👍
23
+ * Seamless integration with `asyncio`-based applications (FastAPI, etc.).
24
+ * Correct handling of async component initialization and cleanup without blocking.
25
+ * Enables fully asynchronous AOP and event handling.
26
+ * Improves developer experience for async projects.
27
+
28
+ **Negative:** 👎
29
+ * Introduces a dual API (`get`/`aget`), requiring developers to choose the correct one based on context.
30
+ * Slightly increases internal complexity to manage async operations correctly.
31
+ * Requires users to use `container.cleanup_all_async()` instead of `cleanup_all()` if any async cleanup methods exist.