0
# Error Handling
1
2
Comprehensive error system providing clear, actionable feedback for dependency injection issues, from binding conflicts to circular dependencies. All errors inherit from the base `Error` class.
3
4
## Capabilities
5
6
### Base Error Class
7
8
Base exception class for all Pinject-related errors.
9
10
```python { .api }
11
class Error(Exception):
12
"""Base exception class for all Pinject errors."""
13
```
14
15
### Binding Resolution Errors
16
17
Errors related to resolving dependencies and finding appropriate bindings.
18
19
```python { .api }
20
class AmbiguousArgNameError(Error):
21
"""Multiple bindings match the same argument name, creating ambiguity."""
22
23
class MissingRequiredBindingError(Error):
24
"""Required binding not found during dependency resolution."""
25
26
class NothingInjectableForArgError(Error):
27
"""No injectable found for a required argument."""
28
29
class OnlyInstantiableViaProviderFunctionError(Error):
30
"""Class can only be instantiated through a provider function."""
31
32
class NonExplicitlyBoundClassError(Error):
33
"""Class not explicitly bound when only_use_explicit_bindings=True."""
34
```
35
36
### Binding Configuration Errors
37
38
Errors that occur during binding specification and configuration.
39
40
```python { .api }
41
class ConflictingExplicitBindingsError(Error):
42
"""Multiple explicit bindings defined for the same key."""
43
44
class ConflictingRequiredBindingError(Error):
45
"""Conflicting implicit bindings for the same requirement."""
46
47
class InvalidBindingTargetError(Error):
48
"""Binding target has wrong type for the binding."""
49
50
class MultipleBindingTargetArgsError(Error):
51
"""Multiple binding targets specified for the same key."""
52
53
class NoBindingTargetArgsError(Error):
54
"""No binding target specified when required."""
55
56
class EmptyBindingSpecError(Error):
57
"""BindingSpec has neither configure() method nor provider methods."""
58
```
59
60
### Decorator Usage Errors
61
62
Errors related to incorrect usage of Pinject decorators.
63
64
```python { .api }
65
class DecoratorAppliedToNonInitError(Error):
66
"""Decorator applied to non-__init__ method."""
67
68
class DuplicateDecoratorError(Error):
69
"""Same decorator applied twice to the same method."""
70
71
class EmptyProvidesDecoratorError(Error):
72
"""@provides() decorator used without arguments."""
73
74
class TooManyArgsToInjectDecoratorError(Error):
75
"""Both arg_names and all_except specified in @inject decorator."""
76
77
class NoRemainingArgsToInjectError(Error):
78
"""All arguments marked as directly passed, leaving none to inject."""
79
80
class PargsDisallowedWhenCopyingArgsError(Error):
81
"""*args not allowed with copy_args decorators."""
82
```
83
84
### Argument and Annotation Errors
85
86
Errors related to argument specification and annotation handling.
87
88
```python { .api }
89
class NoSuchArgError(Error):
90
"""Reference to non-existent argument."""
91
92
class NoSuchArgToInjectError(Error):
93
"""Cannot inject into non-existent argument."""
94
95
class MultipleAnnotationsForSameArgError(Error):
96
"""Same argument annotated multiple times."""
97
98
class DirectlyPassingInjectedArgsError(Error):
99
"""Injected arguments passed directly to provider function."""
100
101
class WrongArgTypeError(Error):
102
"""Argument has wrong type."""
103
104
class WrongArgElementTypeError(Error):
105
"""Array/sequence element has wrong type."""
106
107
class EmptySequenceArgError(Error):
108
"""Empty sequence provided where non-empty sequence expected."""
109
```
110
111
### Scoping Errors
112
113
Errors related to object scope configuration and usage.
114
115
```python { .api }
116
class BadDependencyScopeError(Error):
117
"""Invalid dependency relationship between scopes."""
118
119
class UnknownScopeError(Error):
120
"""Reference to unknown scope identifier."""
121
122
class OverridingDefaultScopeError(Error):
123
"""Attempt to override built-in scope (SINGLETON, PROTOTYPE)."""
124
```
125
126
### Circular Dependency Errors
127
128
Errors related to circular dependency detection.
129
130
```python { .api }
131
class CyclicInjectionError(Error):
132
"""Circular dependency detected in object graph."""
133
```
134
135
### Method Configuration Errors
136
137
Errors related to BindingSpec method configuration.
138
139
```python { .api }
140
class ConfigureMethodMissingArgsError(Error):
141
"""BindingSpec configure method missing required arguments."""
142
```
143
144
### Injection Policy Errors
145
146
Errors related to injection policies and restrictions.
147
148
```python { .api }
149
class InjectingNoneDisallowedError(Error):
150
"""None injection attempted when allow_injecting_none=False."""
151
```
152
153
## Usage Examples
154
155
### Handling Ambiguous Bindings
156
157
```python
158
import pinject
159
160
class DatabaseService(object):
161
def __init__(self):
162
pass
163
164
class MockDatabaseService(object):
165
def __init__(self):
166
pass
167
168
# This will cause AmbiguousArgNameError
169
class UserService(object):
170
def __init__(self, database_service): # Ambiguous: which DatabaseService?
171
self.db = database_service
172
173
try:
174
obj_graph = pinject.new_object_graph(classes=[DatabaseService, MockDatabaseService])
175
user_service = obj_graph.provide(UserService)
176
except pinject.AmbiguousArgNameError as e:
177
print(f"Ambiguous binding: {e}")
178
179
# Solution: Use explicit bindings or annotations
180
class MyBindingSpec(pinject.BindingSpec):
181
def configure(self, bind):
182
bind('database_service').to_class(DatabaseService)
183
184
obj_graph = pinject.new_object_graph(
185
classes=[DatabaseService, MockDatabaseService],
186
binding_specs=[MyBindingSpec()]
187
)
188
user_service = obj_graph.provide(UserService) # Success
189
```
190
191
### Handling Missing Bindings
192
193
```python
194
import pinject
195
196
class UserService(object):
197
def __init__(self, database_service): # database_service not available
198
self.db = database_service
199
200
try:
201
obj_graph = pinject.new_object_graph()
202
user_service = obj_graph.provide(UserService)
203
except pinject.MissingRequiredBindingError as e:
204
print(f"Missing binding: {e}")
205
print("Solution: Provide the required class or binding")
206
207
# Solution: Add the missing class
208
class DatabaseService(object):
209
def __init__(self):
210
pass
211
212
obj_graph = pinject.new_object_graph(classes=[DatabaseService])
213
user_service = obj_graph.provide(UserService) # Success
214
```
215
216
### Handling Circular Dependencies
217
218
```python
219
import pinject
220
221
class ServiceA(object):
222
def __init__(self, service_b):
223
self.service_b = service_b
224
225
class ServiceB(object):
226
def __init__(self, service_a):
227
self.service_a = service_a
228
229
try:
230
obj_graph = pinject.new_object_graph()
231
service_a = obj_graph.provide(ServiceA)
232
except pinject.CyclicInjectionError as e:
233
print(f"Circular dependency: {e}")
234
235
# Solution: Break the cycle with lazy injection or redesign
236
class ServiceA(object):
237
def __init__(self, service_b):
238
self.service_b = service_b
239
240
class ServiceB(object):
241
def __init__(self):
242
self.service_a = None # Set later to break cycle
243
244
def set_service_a(self, service_a):
245
self.service_a = service_a
246
247
obj_graph = pinject.new_object_graph()
248
service_a = obj_graph.provide(ServiceA)
249
service_b = obj_graph.provide(ServiceB)
250
service_b.set_service_a(service_a) # Manual resolution
251
```
252
253
### Handling Decorator Errors
254
255
```python
256
import pinject
257
258
class InvalidService(object):
259
@pinject.inject(['nonexistent_arg'])
260
def __init__(self, real_arg):
261
self.arg = real_arg
262
263
try:
264
obj_graph = pinject.new_object_graph()
265
service = obj_graph.provide(InvalidService)
266
except pinject.NoSuchArgToInjectError as e:
267
print(f"Invalid injection specification: {e}")
268
269
# Solution: Fix the decorator
270
class ValidService(object):
271
@pinject.inject(['real_arg'])
272
def __init__(self, real_arg):
273
self.arg = real_arg
274
```
275
276
### Handling Scope Errors
277
278
```python
279
import pinject
280
281
class MyBindingSpec(pinject.BindingSpec):
282
def configure(self, bind):
283
# This will cause UnknownScopeError
284
bind('service').to_class(object, in_scope='unknown_scope')
285
286
try:
287
obj_graph = pinject.new_object_graph(binding_specs=[MyBindingSpec()])
288
except pinject.UnknownScopeError as e:
289
print(f"Unknown scope: {e}")
290
291
# Solution: Use valid scope or define custom scope
292
class ValidBindingSpec(pinject.BindingSpec):
293
def configure(self, bind):
294
bind('service').to_class(object, in_scope=pinject.SINGLETON)
295
```
296
297
### Error Context and Debugging
298
299
```python
300
import pinject
301
302
# Enable detailed error reporting
303
obj_graph = pinject.new_object_graph(use_short_stack_traces=False)
304
305
class ComplexService(object):
306
def __init__(self, dep1, dep2, dep3):
307
pass
308
309
try:
310
service = obj_graph.provide(ComplexService)
311
except pinject.Error as e:
312
# All Pinject errors provide detailed context
313
print(f"Error type: {type(e).__name__}")
314
print(f"Error message: {e}")
315
print(f"Error occurred during: ComplexService instantiation")
316
317
# Errors include location information and context
318
# to help identify the exact source of the problem
319
```