5
5
6
6
import argparse
7
7
import collections .abc
8
+ import contextlib
8
9
import copy
9
10
import dataclasses
10
11
import enum
33
34
from typing import TextIO
34
35
from typing import Type
35
36
from typing import TYPE_CHECKING
37
+ from typing import TypeVar
36
38
import warnings
37
39
38
40
import pluggy
73
75
from _pytest .cacheprovider import Cache
74
76
from _pytest .terminal import TerminalReporter
75
77
78
+ _T_callback = TypeVar ("_T_callback" , bound = Callable [[], None ])
79
+
76
80
77
81
_PluggyPlugin = object
78
82
"""A type to represent plugin objects.
@@ -1085,6 +1089,7 @@ def __init__(
1085
1089
)
1086
1090
self .args_source = Config .ArgsSource .ARGS
1087
1091
self .args : list [str ] = []
1092
+ self ._exit_stack = contextlib .ExitStack ()
1088
1093
1089
1094
@property
1090
1095
def rootpath (self ) -> pathlib .Path :
@@ -1104,10 +1109,11 @@ def inipath(self) -> pathlib.Path | None:
1104
1109
"""
1105
1110
return self ._inipath
1106
1111
1107
- def add_cleanup (self , func : Callable [[], None ] ) -> None :
1112
+ def add_cleanup (self , func : _T_callback ) -> _T_callback :
1108
1113
"""Add a function to be called when the config object gets out of
1109
1114
use (usually coinciding with pytest_unconfigure)."""
1110
- self ._cleanup .append (func )
1115
+ self ._exit_stack .callback (func )
1116
+ return func
1111
1117
1112
1118
def _do_configure (self ) -> None :
1113
1119
assert not self ._configured
@@ -1117,13 +1123,18 @@ def _do_configure(self) -> None:
1117
1123
self .hook .pytest_configure .call_historic (kwargs = dict (config = self ))
1118
1124
1119
1125
def _ensure_unconfigure (self ) -> None :
1120
- if self ._configured :
1121
- self ._configured = False
1122
- self .hook .pytest_unconfigure (config = self )
1123
- self .hook .pytest_configure ._call_history = []
1124
- while self ._cleanup :
1125
- fin = self ._cleanup .pop ()
1126
- fin ()
1126
+ try :
1127
+ if self ._configured :
1128
+ self ._configured = False
1129
+ try :
1130
+ self .hook .pytest_unconfigure (config = self )
1131
+ finally :
1132
+ self .hook .pytest_configure ._call_history = []
1133
+ finally :
1134
+ try :
1135
+ self ._exit_stack .close ()
1136
+ finally :
1137
+ self ._exit_stack = contextlib .ExitStack ()
1127
1138
1128
1139
def get_terminal_writer (self ) -> TerminalWriter :
1129
1140
terminalreporter : TerminalReporter | None = self .pluginmanager .get_plugin (
0 commit comments