Skip to content

Commit ee65393

Browse files
committed
de-emphasize request.addfinalizer
1 parent 2c402f4 commit ee65393

File tree

1 file changed

+50
-18
lines changed

1 file changed

+50
-18
lines changed

doc/en/fixture.rst

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,35 @@ The ``smtp_connection`` connection will be closed after the test finished
400400
execution because the ``smtp_connection`` object automatically closes when
401401
the ``with`` statement ends.
402402

403+
Using the contextlib.ExitStack context manager finalizers will always be called
404+
regardless if the fixture *setup* code raises an exception. This is handy to properly
405+
close all resources created by a fixture even if one of them fails to be created/acquired:
406+
407+
.. code-block:: python
408+
409+
# content of test_yield3.py
410+
411+
import contextlib
412+
413+
import pytest
414+
415+
from .utils import connect
416+
417+
418+
@pytest.fixture
419+
def equipments():
420+
with contextlib.ExitStack():
421+
r = []
422+
for port in ('C1', 'C3', 'C28'):
423+
equip = connect(port)
424+
stack.callback(equip.disconnect)
425+
r.append(equip)
426+
yield r
427+
428+
In the example above, if ``"C28"`` fails with an exception, ``"C1"`` and ``"C3"`` will still
429+
be properly closed. Of course, if an exception happens before the finalize function is
430+
registered then it will not be executed.
431+
403432
Note that if an exception happens during the *setup* code (before the ``yield`` keyword), the
404433
*teardown* code (after the ``yield``) will not be called.
405434

@@ -428,29 +457,32 @@ Here's the ``smtp_connection`` fixture changed to use ``addfinalizer`` for clean
428457
return smtp_connection # provide the fixture value
429458
430459
431-
Both ``yield`` and ``addfinalizer`` methods work similarly by calling their code after the test
432-
ends, but ``addfinalizer`` has two key differences over ``yield``:
460+
Here's the ``equipments`` fixture changed to use ``addfinalizer`` for cleanup:
433461

434-
1. It is possible to register multiple finalizer functions.
462+
.. code-block:: python
435463
436-
2. Finalizers will always be called regardless if the fixture *setup* code raises an exception.
437-
This is handy to properly close all resources created by a fixture even if one of them
438-
fails to be created/acquired::
464+
# content of test_yield3.py
439465
440-
@pytest.fixture
441-
def equipments(request):
442-
r = []
443-
for port in ('C1', 'C3', 'C28'):
444-
equip = connect(port)
445-
request.addfinalizer(equip.disconnect)
446-
r.append(equip)
447-
return r
448-
449-
In the example above, if ``"C28"`` fails with an exception, ``"C1"`` and ``"C3"`` will still
450-
be properly closed. Of course, if an exception happens before the finalize function is
451-
registered then it will not be executed.
466+
import contextlib
467+
468+
import pytest
469+
470+
from .utils import connect
452471
453472
473+
@pytest.fixture
474+
def equipments(request):
475+
r = []
476+
for port in ('C1', 'C3', 'C28'):
477+
equip = connect(port)
478+
request.addfinalizer(equip.disconnect)
479+
r.append(equip)
480+
return r
481+
482+
483+
Both ``yield`` and ``addfinalizer`` methods work similarly by calling their code after the test
484+
ends.
485+
454486
.. _`request-context`:
455487

456488
Fixtures can introspect the requesting test context

0 commit comments

Comments
 (0)