You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
All errors raised by the framework use the built-in RuntimeError. This forces users to either catch the very broad RuntimeError (which also matches unrelated runtime issues) or rely on string matching to distinguish failure modes.
These cover several semantically distinct conditions, but downstream code can't tell them apart programmatically.
Proposed Solution
Introduce a small exception hierarchy in modern_di/errors.py (or a new modern_di/exceptions.py), all rooted at a base ModernDIError(RuntimeError) so existing user code that catches RuntimeError keeps working.
A first-pass mapping that aligns with the existing error templates:
Each exception type would carry the structured fields it currently formats into a string (e.g. ArgumentResolutionError(arg_name, arg_type, bound_type)), making programmatic introspection possible.
Impact
Users can write narrow except CircularDependencyError: / except ProviderNotRegisteredError: blocks instead of matching on RuntimeError message strings.
Tests in this repo currently rely on pytest.raises(RuntimeError, match=...) — they can migrate to typed assertions, which are stricter and don't break when wording is improved.
Inheriting from RuntimeError preserves backwards compatibility for anyone catching the broad type today.
Problem
All errors raised by the framework use the built-in
RuntimeError. This forces users to either catch the very broadRuntimeError(which also matches unrelated runtime issues) or rely on string matching to distinguish failure modes.Current call sites:
modern_di/container.py— scope-mismatch, max-scope-reached, missing-provider, skipped-scope, circular-dependencymodern_di/providers/factory.py— argument-resolution failuresmodern_di/registries/providers_registry.py— duplicate provider typemodern_di/registries/cache_registry.py— finalizer cleanup errors (sync + async)modern_di/group.py—Groupinstantiation attemptThese cover several semantically distinct conditions, but downstream code can't tell them apart programmatically.
Proposed Solution
Introduce a small exception hierarchy in
modern_di/errors.py(or a newmodern_di/exceptions.py), all rooted at a baseModernDIError(RuntimeError)so existing user code that catchesRuntimeErrorkeeps working.A first-pass mapping that aligns with the existing error templates:
Each exception type would carry the structured fields it currently formats into a string (e.g.
ArgumentResolutionError(arg_name, arg_type, bound_type)), making programmatic introspection possible.Impact
except CircularDependencyError:/except ProviderNotRegisteredError:blocks instead of matching onRuntimeErrormessage strings.pytest.raises(RuntimeError, match=...)— they can migrate to typed assertions, which are stricter and don't break when wording is improved.RuntimeErrorpreserves backwards compatibility for anyone catching the broad type today.Complexity
Low–medium. Mechanical change: define classes, swap
raise RuntimeError(...)sites, update tests. No behavior change beyond exception type.