17
17
PostgresConfig ,
18
18
)
19
19
from pytest_mock_resources .fixture .base import asyncio_fixture , generate_fixture_id , Scope
20
+ from pytest_mock_resources .hooks import should_cleanup
20
21
from pytest_mock_resources .sqlalchemy import (
21
22
bifurcate_actions ,
22
23
EngineManager ,
@@ -114,6 +115,7 @@ def create_postgres_fixture(
114
115
engine_kwargs = None ,
115
116
template_database = True ,
116
117
actions_share_transaction = None ,
118
+ cleanup_database : Optional [bool ] = None ,
117
119
):
118
120
"""Produce a Postgres fixture.
119
121
@@ -141,6 +143,10 @@ def create_postgres_fixture(
141
143
fixtures for backwards compatibility; and disabled by default for
142
144
asynchronous fixtures (the way v2-style/async features work in SQLAlchemy can lead
143
145
to bad default behavior).
146
+ cleanup_database: Whether to clean up the database after the test completes. Defaults to `None`,
147
+ which defers the decision to the pmr_cleanup/--pmr-cleanup pytest options (which default to True).
148
+ Note this does not currently clean up any "template" databases produced in service
149
+ of the fixture.
144
150
"""
145
151
fixture_id = generate_fixture_id (enabled = template_database , name = "pg" )
146
152
@@ -155,13 +161,23 @@ def create_postgres_fixture(
155
161
}
156
162
157
163
@pytest .fixture (scope = scope )
158
- def _sync (* _ , pmr_postgres_container , pmr_postgres_config ):
159
- fixture = _sync_fixture (pmr_postgres_config , engine_manager_kwargs , engine_kwargs_ )
164
+ def _sync (* _ , pmr_postgres_container , pmr_postgres_config , pytestconfig ):
165
+ fixture = _sync_fixture (
166
+ pmr_postgres_config ,
167
+ engine_manager_kwargs ,
168
+ engine_kwargs_ ,
169
+ cleanup_database = should_cleanup (pytestconfig , cleanup_database ),
170
+ )
160
171
for _ , conn in fixture :
161
172
yield conn
162
173
163
- async def _async (* _ , pmr_postgres_container , pmr_postgres_config ):
164
- fixture = _async_fixture (pmr_postgres_config , engine_manager_kwargs , engine_kwargs_ )
174
+ async def _async (* _ , pmr_postgres_container , pmr_postgres_config , pytestconfig ):
175
+ fixture = _async_fixture (
176
+ pmr_postgres_config ,
177
+ engine_manager_kwargs ,
178
+ engine_kwargs_ ,
179
+ cleanup_database = should_cleanup (pytestconfig , cleanup_database ),
180
+ )
165
181
async for _ , conn in fixture :
166
182
yield conn
167
183
@@ -170,7 +186,14 @@ async def _async(*_, pmr_postgres_container, pmr_postgres_config):
170
186
return _sync
171
187
172
188
173
- def _sync_fixture (pmr_config , engine_manager_kwargs , engine_kwargs , * , fixture = "postgres" ):
189
+ def _sync_fixture (
190
+ pmr_config ,
191
+ engine_manager_kwargs ,
192
+ engine_kwargs ,
193
+ * ,
194
+ fixture = "postgres" ,
195
+ cleanup_database : bool = True ,
196
+ ):
174
197
root_engine = cast (Engine , get_sqlalchemy_engine (pmr_config , pmr_config .root_database ))
175
198
conn = retry (root_engine .connect , retries = DEFAULT_RETRIES )
176
199
conn .close ()
@@ -216,10 +239,27 @@ def _sync_fixture(pmr_config, engine_manager_kwargs, engine_kwargs, *, fixture="
216
239
engine = get_sqlalchemy_engine (pmr_config , database_name , ** engine_kwargs )
217
240
yield from engine_manager .manage_sync (engine )
218
241
242
+ if cleanup_database :
243
+ with root_engine .connect () as root_conn :
244
+ with root_conn .begin () as trans :
245
+ _drop_database (root_conn , database_name )
246
+ trans .commit ()
247
+ root_engine .dispose ()
248
+
249
+
250
+ async def _async_fixture (
251
+ pmr_config ,
252
+ engine_manager_kwargs ,
253
+ engine_kwargs ,
254
+ * ,
255
+ fixture = "postgres" ,
256
+ cleanup_database : bool = True ,
257
+ ):
258
+ from sqlalchemy .ext .asyncio import AsyncEngine
219
259
220
- async def _async_fixture ( pmr_config , engine_manager_kwargs , engine_kwargs , * , fixture = "postgres" ):
221
- root_engine = get_sqlalchemy_engine (
222
- pmr_config , pmr_config .root_database , async_ = True , autocommit = True
260
+ root_engine = cast (
261
+ AsyncEngine ,
262
+ get_sqlalchemy_engine ( pmr_config , pmr_config .root_database , async_ = True , autocommit = True ),
223
263
)
224
264
225
265
root_conn = await async_retry (root_engine .connect , retries = DEFAULT_RETRIES )
@@ -239,7 +279,10 @@ async def _async_fixture(pmr_config, engine_manager_kwargs, engine_kwargs, *, fi
239
279
if template_manager :
240
280
assert template_database
241
281
242
- engine = get_sqlalchemy_engine (pmr_config , template_database , ** engine_kwargs , async_ = True )
282
+ engine = cast (
283
+ AsyncEngine ,
284
+ get_sqlalchemy_engine (pmr_config , template_database , ** engine_kwargs , async_ = True ),
285
+ )
243
286
async with engine .begin () as conn :
244
287
await conn .run_sync (template_manager .run_static_actions )
245
288
await conn .commit ()
@@ -260,6 +303,13 @@ async def _async_fixture(pmr_config, engine_manager_kwargs, engine_kwargs, *, fi
260
303
async for engine , conn in engine_manager .manage_async (engine ):
261
304
yield engine , conn
262
305
306
+ if cleanup_database :
307
+ async with root_engine .connect () as root_conn :
308
+ async with root_conn .begin () as trans :
309
+ await root_conn .run_sync (_drop_database , database_name )
310
+ await trans .commit ()
311
+ await root_engine .dispose ()
312
+
263
313
264
314
def create_engine_manager (
265
315
root_connection ,
@@ -356,5 +406,15 @@ def _generate_database_name(conn):
356
406
return f"pytest_mock_resource_db_{ id_ } "
357
407
358
408
409
+ def _drop_database (root_conn : Connection , database_name : str ):
410
+ with_force = ""
411
+
412
+ assert root_conn .dialect .server_version_info
413
+ if root_conn .dialect .server_version_info >= (13 , 0 ):
414
+ with_force = " WITH FORCE"
415
+
416
+ root_conn .execute (text (f"DROP DATABASE { database_name } { with_force } " ))
417
+
418
+
359
419
pmr_postgres_config = create_postgres_config_fixture ()
360
420
pmr_postgres_container = create_postgres_container_fixture ()
0 commit comments