Skip to content

Commit 39883fe

Browse files
committed
Add context manager support to Resource provider
1 parent 4b3476c commit 39883fe

File tree

6 files changed

+261
-193
lines changed

6 files changed

+261
-193
lines changed

docs/providers/resource.rst

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,12 @@ When you call ``.shutdown()`` method on a resource provider, it will remove the
6161
if any, and switch to uninitialized state. Some of resource initializer types support specifying custom
6262
resource shutdown.
6363

64-
Resource provider supports 3 types of initializers:
64+
Resource provider supports 4 types of initializers:
6565

6666
- Function
67-
- Generator
68-
- Subclass of ``resources.Resource``
67+
- Context Manager
68+
- Generator (legacy)
69+
- Subclass of ``resources.Resource`` (legacy)
6970

7071
Function initializer
7172
--------------------
@@ -103,8 +104,44 @@ you configure global resource:
103104
104105
Function initializer does not provide a way to specify custom resource shutdown.
105106

106-
Generator initializer
107-
---------------------
107+
Context manager initializer
108+
---------------------------
109+
110+
This is an extension to the Function initializer. Resource provider automatically detects if the initializer returns a
111+
context manager and uses it to manage the resource lifecycle.
112+
113+
.. code-block:: python
114+
115+
from dependency_injector import containers, providers
116+
117+
class DatabaseConnection:
118+
def __init__(self, host, port, user, password):
119+
self.host = host
120+
self.port = port
121+
self.user = user
122+
self.password = password
123+
124+
def __enter__(self):
125+
print(f"Connecting to {self.host}:{self.port} as {self.user}")
126+
return self
127+
128+
def __exit__(self, exc_type, exc_val, exc_tb):
129+
print("Closing connection")
130+
131+
132+
class Container(containers.DeclarativeContainer):
133+
134+
config = providers.Configuration()
135+
db = providers.Resource(
136+
DatabaseConnection,
137+
host=config.db.host,
138+
port=config.db.port,
139+
user=config.db.user,
140+
password=config.db.password,
141+
)
142+
143+
Generator initializer (legacy)
144+
------------------------------
108145

109146
Resource provider can use 2-step generators:
110147

@@ -154,8 +191,13 @@ object is not mandatory. You can leave ``yield`` statement empty:
154191
argument2=...,
155192
)
156193
157-
Subclass initializer
158-
--------------------
194+
.. note::
195+
196+
Generator initializers are automatically wrapped with ``contextmanager`` or ``asynccontextmanager`` decorator when
197+
provided to a ``Resource`` provider.
198+
199+
Subclass initializer (legacy)
200+
-----------------------------
159201

160202
You can create resource initializer by implementing a subclass of the ``resources.Resource``:
161203

@@ -263,10 +305,11 @@ Asynchronous function initializer:
263305
argument2=...,
264306
)
265307
266-
Asynchronous generator initializer:
308+
Asynchronous Context Manager initializer:
267309

268310
.. code-block:: python
269311
312+
@asynccontextmanager
270313
async def init_async_resource(argument1=..., argument2=...):
271314
connection = await connect()
272315
yield connection

examples/providers/resource.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import sys
44
import logging
55
from concurrent.futures import ThreadPoolExecutor
6+
from contextlib import contextmanager
67

78
from dependency_injector import containers, providers
89

910

11+
@contextmanager
1012
def init_thread_pool(max_workers: int):
1113
thread_pool = ThreadPoolExecutor(max_workers=max_workers)
1214
yield thread_pool

0 commit comments

Comments
 (0)