0
# Dependency Injection Decorators
1
2
Decorators for controlling injection behavior, marking classes as injectable, defining provider methods, and specifying argument annotations for precise dependency resolution.
3
4
## Capabilities
5
6
### Injection Control
7
8
Controls which arguments are injected and which are passed directly, providing fine-grained control over the dependency injection process.
9
10
```python { .api }
11
def inject(arg_names=None, all_except=None):
12
"""
13
Decorator that specifies which arguments to inject for a method.
14
15
Parameters:
16
- arg_names: list of argument names to inject; if None, inject all possible args
17
- all_except: list of argument names NOT to inject; mutually exclusive with arg_names
18
19
Returns:
20
Decorated function with injection specifications
21
"""
22
```
23
24
### Injectable Marking
25
26
Explicitly marks classes as available for dependency injection, required when using `only_use_explicit_bindings=True`.
27
28
```python { .api }
29
def injectable(fn):
30
"""
31
Decorator that explicitly marks a class as injectable.
32
33
Parameters:
34
- fn: class to mark as injectable
35
36
Returns:
37
The class with injectable metadata
38
"""
39
```
40
41
### Provider Methods
42
43
Defines methods that provide instances for dependency injection, typically used within BindingSpec classes.
44
45
```python { .api }
46
def provides(arg_name=None, annotated_with=None, in_scope=None):
47
"""
48
Decorator that marks a method as a provider for dependency injection.
49
50
Parameters:
51
- arg_name: name of the argument this provider serves; if None, inferred from method name
52
- annotated_with: annotation object for disambiguation
53
- in_scope: scope ID for the provided instances
54
55
Returns:
56
Decorated provider method
57
"""
58
```
59
60
### Argument Annotation
61
62
Adds annotations to specific arguments for disambiguation when multiple bindings exist for the same type.
63
64
```python { .api }
65
def annotate_arg(arg_name, with_annotation):
66
"""
67
Adds an annotation to an injected argument for disambiguation.
68
69
Parameters:
70
- arg_name: name of the argument to annotate
71
- with_annotation: annotation object for disambiguation
72
73
Returns:
74
Function decorator that applies the annotation
75
"""
76
```
77
78
## Usage Examples
79
80
### Basic Injection Control
81
82
```python
83
import pinject
84
85
class DatabaseService(object):
86
def __init__(self):
87
self.connected = True
88
89
class UserService(object):
90
@pinject.inject(['database_service'])
91
def __init__(self, database_service, api_key="default_key"):
92
self.db = database_service
93
self.api_key = api_key # api_key has default, not injected
94
95
obj_graph = pinject.new_object_graph()
96
user_service = obj_graph.provide(UserService) # uses default api_key
97
```
98
99
### Excluding Arguments from Injection
100
101
```python
102
import pinject
103
104
class LoggingService(object):
105
def __init__(self):
106
self.logs = []
107
108
class ProcessingService(object):
109
@pinject.inject(all_except=['batch_size'])
110
def __init__(self, logging_service, batch_size=100):
111
self.logger = logging_service
112
self.batch_size = batch_size
113
114
obj_graph = pinject.new_object_graph()
115
service = obj_graph.provide(ProcessingService, batch_size=50)
116
```
117
118
### Explicit Injectable Classes
119
120
```python
121
import pinject
122
123
@pinject.injectable
124
class DatabaseConnection(object):
125
def __init__(self):
126
self.url = "sqlite://memory"
127
128
@pinject.injectable
129
class UserRepository(object):
130
def __init__(self, database_connection):
131
self.db = database_connection
132
133
# Use only explicitly marked classes
134
obj_graph = pinject.new_object_graph(
135
classes=[DatabaseConnection, UserRepository],
136
only_use_explicit_bindings=True
137
)
138
repo = obj_graph.provide(UserRepository)
139
```
140
141
### Provider Methods in Binding Specs
142
143
```python
144
import pinject
145
146
class DatabaseConfig(object):
147
def __init__(self, url, timeout):
148
self.url = url
149
self.timeout = timeout
150
151
class MyBindingSpec(pinject.BindingSpec):
152
@pinject.provides('database_config')
153
def provide_db_config(self):
154
return DatabaseConfig("postgresql://localhost", 30)
155
156
@pinject.provides(in_scope=pinject.SINGLETON)
157
def provide_connection_pool(self, database_config):
158
return ConnectionPool(database_config.url)
159
160
obj_graph = pinject.new_object_graph(binding_specs=[MyBindingSpec()])
161
```
162
163
### Argument Annotations for Disambiguation
164
165
```python
166
import pinject
167
168
class DatabaseConnection(object):
169
def __init__(self, host, port):
170
self.host = host
171
self.port = port
172
173
class CacheConnection(object):
174
def __init__(self, host, port):
175
self.host = host
176
self.port = port
177
178
class AppService(object):
179
@pinject.annotate_arg('database_connection', with_annotation='primary')
180
@pinject.annotate_arg('cache_connection', with_annotation='redis')
181
def __init__(self, database_connection, cache_connection):
182
self.db = database_connection
183
self.cache = cache_connection
184
185
class MyBindingSpec(pinject.BindingSpec):
186
@pinject.provides('database_connection', annotated_with='primary')
187
def provide_primary_db(self):
188
return DatabaseConnection('db.example.com', 5432)
189
190
@pinject.provides('cache_connection', annotated_with='redis')
191
def provide_redis_cache(self):
192
return CacheConnection('cache.example.com', 6379)
193
194
obj_graph = pinject.new_object_graph(binding_specs=[MyBindingSpec()])
195
app = obj_graph.provide(AppService)
196
```