https://github.com/dperezcabrera/pico-ioc
A minimalist, zero-dependency Inversion of Control (IoC) container for Python. π It uses decorators for automatic component discovery and lazy instantiation, helping you build clean, modular, and easily testable applications.
https://github.com/dperezcabrera/pico-ioc
dependency-injection di-container inversion-of-control inversion-of-control-container ioc ioc-container ioc-containers ioc-framework minimalistic python zero-dependency
Last synced: 5 months ago
JSON representation
A minimalist, zero-dependency Inversion of Control (IoC) container for Python. π It uses decorators for automatic component discovery and lazy instantiation, helping you build clean, modular, and easily testable applications.
- Host: GitHub
- URL: https://github.com/dperezcabrera/pico-ioc
- Owner: dperezcabrera
- License: mit
- Created: 2025-08-08T15:53:36.000Z (11 months ago)
- Default Branch: main
- Last Pushed: 2026-02-04T00:14:13.000Z (5 months ago)
- Last Synced: 2026-02-04T12:30:51.559Z (5 months ago)
- Topics: dependency-injection, di-container, inversion-of-control, inversion-of-control-container, ioc, ioc-container, ioc-containers, ioc-framework, minimalistic, python, zero-dependency
- Language: Python
- Homepage:
- Size: 866 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# π¦ Pico-IoC: A Robust, Async-Native IoC Container for Python
[](https://pypi.org/project/pico-ioc/)
[](https://deepwiki.com/dperezcabrera/pico-ioc)
[](https://opensource.org/licenses/MIT)

[](https://codecov.io/gh/dperezcabrera/pico-ioc)
[](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-ioc)
[](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-ioc)
[](https://sonarcloud.io/summary/new_code?id=dperezcabrera_pico-ioc)
[](https://pepy.tech/projects/pico-ioc)
[](https://dperezcabrera.github.io/pico-ioc/)
[](https://dperezcabrera.github.io/learn-pico-ioc/)
**Pico-IoC** is a **lightweight, async-ready, decorator-driven IoC container** built for clarity, testability, and performance.
It brings Inversion of Control and dependency injection to Python in a deterministic, modern, and framework-agnostic way.
> π Requires Python 3.11+
---
## βοΈ Core Principles
- Single Purpose β Do one thing: dependency management.
- Declarative β Use simple decorators (`@component`, `@factory`, `@provides`, `@configured`) instead of complex config files.
- Deterministic β No hidden scanning or side-effects; everything flows from an explicit `init()`.
- Async-Native β Fully supports async providers, async lifecycle hooks (`__ainit__`), and async interceptors.
- Fail-Fast β Detects missing bindings and circular dependencies at bootstrap (`init()`).
- Testable by Design β Use `overrides` and `profiles` to swap components instantly.
- Zero Core Dependencies β Built entirely on the Python standard library. Optional features may require external packages (see Installation).
---
## π Why Pico-IoC?
As Python systems evolve, wiring dependencies by hand becomes fragile and unmaintainable.
Pico-IoC eliminates that friction by letting you declare how components relate β not how theyβre created.
| Feature | Manual Wiring | With Pico-IoC |
| :-------------- | :----------------------------- | :------------------------------ |
| Object creation | `svc = Service(Repo(Config()))` | `svc = container.get(Service)` |
| Replacing deps | Monkey-patch | `overrides={Repo: FakeRepo()}` |
| Coupling | Tight | Loose |
| Testing | Painful | Instant |
| Async support | Manual | Built-in (`aget`, `__ainit__`) |
---
## π§© Highlights (v2.2+)
- **Unified Configuration**: Use `@configured` to bind both flat (ENV-like) and tree (YAML/JSON) sources via the `configuration(...)` builder (ADR-0010).
- **Extensible Scanning**: Use `CustomScanner` to hook into the discovery phase and register functions or custom decorators (ADR-0011).
- **Async-aware AOP**: Method interceptors via `@intercepted_by`.
- **Scoped resolution**: singleton, prototype, request, session, transaction, and custom scopes.
- **Tree-based configuration**: Advanced mapping with reusable adapters (`Annotated[Union[...], Discriminator(...)]`).
- **Observable context**: Built-in stats, health checks (`@health`), observer hooks (`ContainerObserver`), and dependency graph export.
---
## π¦ Installation
```bash
pip install pico-ioc
```
Optional extras:
- YAML configuration support (requires PyYAML)
```bash
pip install pico-ioc[yaml]
```
-----
### β οΈ Important Note
**Breaking Behavior in Scope Management (v2.1.3+):**
**Scope LRU Eviction has been removed** to guarantee data integrity.
* **Frameworks (pico-fastapi):** Handled automatically.
* **Manual usage:** You **must** explicitly call `container._caches.cleanup_scope("scope_name", scope_id)` when a context ends to prevent memory leaks.
-----
## βοΈ Quick Example (Unified Configuration)
```python
import os
from dataclasses import dataclass
from pico_ioc import component, configured, configuration, init, EnvSource
# 1. Define configuration with @configured
@configured(prefix="APP_", mapping="auto") # Auto-detects flat mapping
@dataclass
class Config:
db_url: str = "sqlite:///demo.db"
# 2. Define components
@component
class Repo:
def __init__(self, cfg: Config): # Inject config
self.cfg = cfg
def fetch(self):
return f"fetching from {self.cfg.db_url}"
@component
class Service:
def __init__(self, repo: Repo): # Inject Repo
self.repo = repo
def run(self):
return self.repo.fetch()
# --- Example Setup ---
os.environ['APP_DB_URL'] = 'postgresql://user:pass@host/db'
# 3. Build configuration context
config_ctx = configuration(
EnvSource(prefix="") # Read APP_DB_URL from environment
)
# 4. Initialize container
container = init(modules=[__name__], config=config_ctx) # Pass context via 'config'
# 5. Get and use the service
svc = container.get(Service)
print(svc.run())
# --- Cleanup ---
del os.environ['APP_DB_URL']
```
Output:
```
fetching from postgresql://user:pass@host/db
```
-----
## π§ͺ Testing with Overrides
```python
class FakeRepo:
def fetch(self): return "fake-data"
# Build configuration context (might be empty or specific for test)
test_config_ctx = configuration()
# Use overrides during init
container = init(
modules=[__name__],
config=test_config_ctx,
overrides={Repo: FakeRepo()} # Replace Repo with FakeRepo
)
svc = container.get(Service)
assert svc.run() == "fake-data"
```
-----
## π§° Profiles
Use profiles to enable/disable components or configuration branches conditionally.
```python
# Enable "test" profile when bootstrapping the container
container = init(
modules=[__name__],
profiles=["test"]
)
```
Profiles are typically referenced in decorators or configuration mappings to include/exclude components and bindings.
-----
## β‘ Async Components
Pico-IoC supports async lifecycle and resolution.
```python
import asyncio
from pico_ioc import component, init
@component
class AsyncRepo:
async def __ainit__(self):
# e.g., open async connections
self.ready = True
async def fetch(self):
return "async-data"
async def main():
container = init(modules=[__name__])
repo = await container.aget(AsyncRepo) # Async resolution
print(await repo.fetch())
# Graceful async shutdown (calls @cleanup async methods)
await container.ashutdown()
asyncio.run(main())
```
- `__ainit__` runs after construction if defined.
- Use `container.aget(Type)` to resolve components that require async initialization.
- Use `await container.ashutdown()` to close resources cleanly.
-----
## π©Ί Lifecycle & AOP
```python
import time
from pico_ioc import component, init, intercepted_by, MethodInterceptor, MethodCtx
# Define an interceptor component
@component
class LogInterceptor(MethodInterceptor):
def invoke(self, ctx: MethodCtx, call_next):
print(f"β calling {ctx.cls.__name__}.{ctx.name}")
start = time.perf_counter()
try:
res = call_next(ctx)
duration = (time.perf_counter() - start) * 1000
print(f"β {ctx.cls.__name__}.{ctx.name} done ({duration:.2f}ms)")
return res
except Exception as e:
duration = (time.perf_counter() - start) * 1000
print(f"β {ctx.cls.__name__}.{ctx.name} failed ({duration:.2f}ms): {e}")
raise
@component
class Demo:
@intercepted_by(LogInterceptor) # Apply the interceptor
def work(self):
print(" Working...")
time.sleep(0.01)
return "ok"
# Initialize container (must scan module containing interceptor too)
c = init(modules=[__name__])
result = c.get(Demo).work()
print(f"Result: {result}")
```
-----
## ποΈ Observability & Cleanup
- Export a dependency graph in DOT format:
```python
c = init(modules=[...])
c.export_graph("dependencies.dot") # Writes directly to file
```
- Health checks:
- Annotate health probes inside components with `@health` for container-level reporting.
- The container exposes health information that can be queried in observability tooling.
- Container cleanup:
- For sync apps: `container.shutdown()`
- For async apps: `await container.ashutdown()`
Use cleanup in application shutdown hooks to release resources deterministically.
-----
## π Documentation
The full documentation is available within the `docs/` directory of the project repository. Start with `docs/README.md` for navigation.
- Getting Started: `docs/getting-started.md`
- User Guide: `docs/user-guide/README.md`
- Advanced Features: `docs/advanced-features/README.md`
- Observability: `docs/observability/README.md`
- Cookbook (Patterns): `docs/cookbook/README.md`
- Architecture: `docs/architecture/README.md`
- API Reference: `docs/api-reference/README.md`
- ADR Index: `docs/adr/README.md`
-----
## π§© Development
```bash
pip install tox
tox
```
-----
## π§Ύ Changelog
See [CHANGELOG.md](./CHANGELOG.md) β Significant redesigns and features in v2.0+.
-----
## π€ Claude Code Skills
This project includes pre-designed skills for [Claude Code](https://claude.ai/claude-code), enabling AI-assisted development with pico-ioc patterns.
| Skill | Command | Description |
|-------|---------|-------------|
| **Pico Component Creator** | `/pico-component` | Creates components with DI, scopes, factories and interceptors |
| **Pico Test Generator** | `/pico-tests` | Generates tests for pico-framework components |
See [Skills documentation](docs/skills.md) for full details and installation instructions.
-----
## π License
MIT β [LICENSE](https://opensource.org/licenses/MIT)