0
# Provider System
1
2
Modular provider classes and dependency registration functions for creating reusable dependency factories. Providers organize related dependencies and can be combined to build complex dependency graphs.
3
4
## Capabilities
5
6
### Provider Class
7
8
Main provider class for organizing and registering dependency factories with flexible configuration options.
9
10
```python { .api }
11
class Provider(BaseProvider):
12
def __init__(
13
self,
14
scope: BaseScope | None = None,
15
component: Component | None = None
16
):
17
"""
18
Create a new provider.
19
20
Parameters:
21
- scope: Default scope for dependencies registered in this provider
22
- component: Default component for dependencies in this provider
23
"""
24
25
def provide(
26
self,
27
source: Any,
28
*,
29
scope: BaseScope | None = None,
30
provides: Any | None = None,
31
cache: bool = True,
32
recursive: bool = False,
33
override: bool = False
34
) -> None:
35
"""
36
Register a dependency factory.
37
38
Parameters:
39
- source: Class or factory function to provide the dependency
40
- scope: Lifecycle scope (overrides provider default)
41
- provides: Type to provide (inferred from source if not specified)
42
- cache: Whether to cache instances within scope
43
- recursive: Whether to recursively provide parent types
44
- override: Whether to override existing registrations
45
"""
46
47
def provide_all(
48
self,
49
*provides: Any,
50
scope: BaseScope | None = None,
51
cache: bool = True,
52
recursive: bool = False,
53
override: bool = False
54
) -> Callable[[Any], Any]:
55
"""
56
Register multiple types from a single source.
57
58
Parameters:
59
- provides: Types to provide from the decorated source
60
- scope: Lifecycle scope (overrides provider default)
61
- cache: Whether to cache instances within scope
62
- recursive: Whether to recursively provide parent types
63
- override: Whether to override existing registrations
64
65
Returns:
66
Decorator function
67
"""
68
69
def alias(
70
self,
71
source: Any,
72
*,
73
provides: Any | None = None,
74
cache: bool = True,
75
component: Component | None = None,
76
override: bool = False
77
) -> None:
78
"""
79
Create an alias for an existing dependency.
80
81
Parameters:
82
- source: Type of the existing dependency to alias
83
- provides: Type to provide as alias (inferred if not specified)
84
- cache: Whether to cache the alias
85
- component: Component to look for source in
86
- override: Whether to override existing registrations
87
"""
88
89
def decorate(
90
self,
91
source: Any,
92
*,
93
provides: Any | None = None
94
) -> None:
95
"""
96
Register a decorator for dependency modification.
97
98
Parameters:
99
- source: Decorator function that modifies the dependency
100
- provides: Type to decorate (inferred if not specified)
101
"""
102
103
def from_context(
104
self,
105
provides: Any,
106
*,
107
scope: BaseScope | None = None,
108
override: bool = False
109
) -> None:
110
"""
111
Register a context variable as a dependency.
112
113
Parameters:
114
- provides: Type to provide from context
115
- scope: Lifecycle scope (overrides provider default)
116
- override: Whether to override existing registrations
117
"""
118
119
def to_component(self, component: Component) -> ProviderWrapper:
120
"""
121
Create a wrapper that registers all dependencies in a specific component.
122
123
Parameters:
124
- component: Component identifier
125
126
Returns:
127
ProviderWrapper for the specified component
128
"""
129
```
130
131
**Usage Example:**
132
133
```python
134
from dishka import Provider, Scope
135
from typing import Protocol
136
137
class Database(Protocol):
138
def query(self, sql: str) -> list: ...
139
140
class PostgreSQLDB:
141
def __init__(self, connection_string: str):
142
self.connection_string = connection_string
143
144
def query(self, sql: str) -> list:
145
return []
146
147
class UserService:
148
def __init__(self, db: Database):
149
self.db = db
150
151
# Create provider
152
provider = Provider(scope=Scope.REQUEST)
153
154
# Register dependencies
155
provider.provide(PostgreSQLDB, provides=Database, scope=Scope.APP)
156
provider.provide(UserService)
157
158
# Register with alias
159
provider.alias(Database, provides=Protocol)
160
```
161
162
### Provide Decorator
163
164
Function and decorator for registering dependency factories with flexible configuration.
165
166
```python { .api }
167
def provide(
168
source: Any = None,
169
*,
170
scope: BaseScope | None = None,
171
provides: Any | None = None,
172
cache: bool = True,
173
recursive: bool = False,
174
override: bool = False
175
) -> Any:
176
"""
177
Register a dependency factory (can be used as decorator or direct call).
178
179
Parameters:
180
- source: Class or factory function (when used directly)
181
- scope: Lifecycle scope for the dependency
182
- provides: Type to provide (inferred from source if not specified)
183
- cache: Whether to cache instances within scope
184
- recursive: Whether to recursively provide parent types
185
- override: Whether to override existing registrations
186
187
Returns:
188
When used as decorator: decorator function
189
When used directly: CompositeDependencySource
190
"""
191
```
192
193
**Usage Examples:**
194
195
```python
196
# As a decorator
197
@provide(scope=Scope.APP, provides=Database)
198
def create_database() -> PostgreSQLDB:
199
return PostgreSQLDB("postgresql://localhost/db")
200
201
# On a class
202
@provide(scope=Scope.REQUEST)
203
class UserService:
204
def __init__(self, db: Database):
205
self.db = db
206
207
# Direct usage
208
provide(PostgreSQLDB, provides=Database, scope=Scope.APP)
209
210
# In a provider class
211
class DatabaseProvider(Provider):
212
@provide(scope=Scope.APP)
213
def connection_string(self) -> str:
214
return "postgresql://localhost/db"
215
216
@provide(scope=Scope.APP, provides=Database)
217
def database(self, conn_str: str) -> PostgreSQLDB:
218
return PostgreSQLDB(conn_str)
219
```
220
221
### Provide All Decorator
222
223
Decorator for registering multiple types from a single source.
224
225
```python { .api }
226
def provide_all(
227
*provides: Any,
228
scope: BaseScope | None = None,
229
cache: bool = True,
230
recursive: bool = False,
231
override: bool = False
232
) -> Callable[[Any], CompositeDependencySource]:
233
"""
234
Register multiple types from a single source.
235
236
Parameters:
237
- provides: Types to provide from the decorated source
238
- scope: Lifecycle scope for all provided types
239
- cache: Whether to cache instances within scope
240
- recursive: Whether to recursively provide parent types
241
- override: Whether to override existing registrations
242
243
Returns:
244
Decorator function
245
"""
246
```
247
248
**Usage Example:**
249
250
```python
251
from typing import Protocol
252
253
class Readable(Protocol):
254
def read(self) -> str: ...
255
256
class Writable(Protocol):
257
def write(self, data: str) -> None: ...
258
259
@provide_all(Readable, Writable, scope=Scope.REQUEST)
260
class FileHandler:
261
def __init__(self, filename: str):
262
self.filename = filename
263
264
def read(self) -> str:
265
return "file contents"
266
267
def write(self, data: str) -> None:
268
pass
269
```
270
271
### Alias Function
272
273
Function for creating dependency aliases to map interfaces to implementations.
274
275
```python { .api }
276
def alias(
277
source: Any,
278
*,
279
provides: Any | None = None,
280
cache: bool = True,
281
component: Component | None = None,
282
override: bool = False
283
) -> CompositeDependencySource:
284
"""
285
Create an alias for an existing dependency.
286
287
Parameters:
288
- source: Type of the existing dependency to alias
289
- provides: Type to provide as alias (inferred if not specified)
290
- cache: Whether to cache the alias
291
- component: Component to look for source in
292
- override: Whether to override existing registrations
293
294
Returns:
295
CompositeDependencySource for the alias
296
"""
297
```
298
299
**Usage Example:**
300
301
```python
302
# Direct usage
303
alias(PostgreSQLDB, provides=Database)
304
305
# In a provider
306
provider = Provider()
307
provider.provide(PostgreSQLDB, scope=Scope.APP)
308
provider.alias(PostgreSQLDB, provides=Database)
309
310
# In a provider class
311
class DatabaseProvider(Provider):
312
postgres_db = provide(PostgreSQLDB, scope=Scope.APP)
313
database = alias(PostgreSQLDB, provides=Database)
314
```
315
316
### Decorate Function
317
318
Function and decorator for registering dependency decorators that modify existing dependencies.
319
320
```python { .api }
321
def decorate(
322
source: Any = None,
323
*,
324
provides: Any | None = None
325
) -> Any:
326
"""
327
Register a decorator for dependency modification.
328
329
Parameters:
330
- source: Decorator function (when used directly)
331
- provides: Type to decorate (inferred if not specified)
332
333
Returns:
334
When used as decorator: decorator function
335
When used directly: CompositeDependencySource
336
"""
337
```
338
339
**Usage Example:**
340
341
```python
342
# As a decorator
343
@decorate(provides=Database)
344
def add_logging(db: Database) -> Database:
345
class LoggingDatabase:
346
def __init__(self, wrapped_db: Database):
347
self.db = wrapped_db
348
349
def query(self, sql: str) -> list:
350
print(f"Executing: {sql}")
351
return self.db.query(sql)
352
353
return LoggingDatabase(db)
354
355
# In a provider class
356
class DatabaseProvider(Provider):
357
@decorate(provides=Database)
358
def add_metrics(self, db: Database) -> Database:
359
# Add metrics collection
360
return MetricsDatabase(db)
361
```
362
363
### Context Variable Registration
364
365
Function for registering context variables as injectable dependencies.
366
367
```python { .api }
368
def from_context(
369
provides: Any,
370
*,
371
scope: BaseScope | None = None,
372
override: bool = False
373
) -> CompositeDependencySource:
374
"""
375
Register a context variable as a dependency.
376
377
Parameters:
378
- provides: Type to provide from context
379
- scope: Lifecycle scope for the context variable
380
- override: Whether to override existing registrations
381
382
Returns:
383
CompositeDependencySource for the context variable
384
"""
385
```
386
387
**Usage Example:**
388
389
```python
390
# Register context variables
391
from_context(str, scope=Scope.REQUEST) # Get string from context
392
from_context(UserID, scope=Scope.REQUEST) # Get UserID from context
393
394
# In a provider
395
provider = Provider()
396
provider.from_context(str, scope=Scope.REQUEST)
397
398
# In a provider class
399
class ContextProvider(Provider):
400
user_id = from_context(UserID, scope=Scope.REQUEST)
401
request_id = from_context(RequestID, scope=Scope.REQUEST)
402
```
403
404
### Base Provider Interface
405
406
Base interface that all providers implement.
407
408
```python { .api }
409
class BaseProvider:
410
"""Base interface for dependency providers"""
411
412
def get_dependencies(self) -> dict[DependencyKey, DependencySource]:
413
"""Get all dependencies registered in this provider"""
414
415
class ProviderWrapper(BaseProvider):
416
"""Wrapper that applies component to all dependencies"""
417
418
def __init__(self, provider: BaseProvider, component: Component): ...
419
```
420
421
### Factory Functions
422
423
Helper functions for creating root context providers.
424
425
```python { .api }
426
def make_root_context_provider(
427
context: dict[DependencyKey, Any]
428
) -> BaseProvider:
429
"""
430
Create a provider that supplies values from a context dictionary.
431
432
Parameters:
433
- context: Dictionary mapping dependency keys to values
434
435
Returns:
436
BaseProvider that provides the context values
437
"""
438
```