Circular Dependencies¶
When two modules depend on each other, Python's import system will fail before spryx-di even runs. forward_ref solves this.
The Problem¶
# identity/module.py
from billing.module import billing_module # ImportError: circular
identity_module = Module(
name="identity",
imports=[billing_module],
)
The Solution: forward_ref¶
from spryx_di import Module, forward_ref
# identity/module.py — does NOT import billing
identity_module = Module(
name="identity",
providers=[...],
exports=[UserReader],
imports=[forward_ref("billing")],
)
# billing/module.py — does NOT import identity
billing_module = Module(
name="billing",
providers=[...],
exports=[BillingGateway],
imports=[forward_ref("identity")],
)
forward_ref("billing") is a string reference resolved by ApplicationContext at boot time, after all modules are loaded.
What Happens at Boot¶
ApplicationContextresolves all forward_refs to real modules- Circular via
forward_refis allowed, with a WARNING log: - Circular via direct references still raises
CircularModuleError
Alternatives¶
If forward_ref is spreading across many modules, consider:
- Extract a shared module — move common types to a third module both can import
- Domain events — decouple with async event bus instead of direct dependency
- Rethink boundaries — maybe the two modules should be one