9
9
import contextlib
10
10
import sys
11
11
from typing import Generator
12
+ import warnings
12
13
13
14
if sys .version_info >= (3 , 11 ):
14
15
from typing import assert_type
26
27
"""Beginning text of USE_SHELL deprecation warnings when USE_SHELL is set True."""
27
28
28
29
30
+ @contextlib .contextmanager
31
+ def _suppress_deprecation_warning () -> Generator [None , None , None ]:
32
+ with warnings .catch_warnings ():
33
+ warnings .filterwarnings ("ignore" , category = DeprecationWarning )
34
+ yield
35
+
36
+
29
37
@pytest .fixture
30
- def reset_backing_attribute () -> Generator [None , None , None ]:
31
- """Fixture to reset the private ``_USE_SHELL `` attribute.
38
+ def try_restore_use_shell_state () -> Generator [None , None , None ]:
39
+ """Fixture to attempt to restore state associated with the ``USE_SHELL `` attribute.
32
40
33
41
This is used to decrease the likelihood of state changes leaking out and affecting
34
42
other tests. But the goal is not to assert that ``_USE_SHELL`` is used, nor anything
@@ -38,18 +46,27 @@ def reset_backing_attribute() -> Generator[None, None, None]:
38
46
restores attributes that it has previously been used to change, create, or remove.
39
47
"""
40
48
no_value = object ()
49
+
41
50
try :
42
- old_value = Git ._USE_SHELL
51
+ old_backing_value = Git ._USE_SHELL
43
52
except AttributeError :
44
- old_value = no_value
53
+ old_backing_value = no_value
54
+ try :
55
+ with _suppress_deprecation_warning ():
56
+ old_public_value = Git .USE_SHELL
45
57
46
- yield
58
+ # This doesn't have its own try-finally because pytest catches exceptions raised
59
+ # during the yield. (The outer try-finally catches exceptions in this fixture.)
60
+ yield
47
61
48
- if old_value is no_value :
49
- with contextlib .suppress (AttributeError ):
50
- del Git ._USE_SHELL
51
- else :
52
- Git ._USE_SHELL = old_value
62
+ with _suppress_deprecation_warning ():
63
+ Git .USE_SHELL = old_public_value
64
+ finally :
65
+ if old_backing_value is no_value :
66
+ with contextlib .suppress (AttributeError ):
67
+ del Git ._USE_SHELL
68
+ else :
69
+ Git ._USE_SHELL = old_backing_value
53
70
54
71
55
72
def test_cannot_access_undefined_on_git_class () -> None :
@@ -76,23 +93,26 @@ def test_get_use_shell_on_class_default() -> None:
76
93
assert not use_shell
77
94
78
95
79
- # FIXME: More robustly check that each operation really issues exactly one deprecation
80
- # warning, even if this requires relying more on reset_backing_attribute doing its job.
81
- def test_use_shell_on_class (reset_backing_attribute ) -> None :
96
+ def test_use_shell_on_class (try_restore_use_shell_state ) -> None :
82
97
"""USE_SHELL can be written and re-read as a class attribute, always warning."""
83
- # We assert in a "safe" order, using reset_backing_attribute only as a backstop.
84
- with pytest .deprecated_call () as ctx :
98
+ with pytest .deprecated_call () as setting :
85
99
Git .USE_SHELL = True
100
+ with pytest .deprecated_call () as checking :
86
101
set_value = Git .USE_SHELL
102
+ with pytest .deprecated_call () as resetting :
87
103
Git .USE_SHELL = False
104
+ with pytest .deprecated_call () as rechecking :
88
105
reset_value = Git .USE_SHELL
89
106
90
107
# The attribute should take on the values set to it.
91
108
assert set_value is True
92
109
assert reset_value is False
93
110
94
- messages = [str (entry .message ) for entry in ctx ]
95
- set_message , check_message , reset_message , recheck_message = messages
111
+ # Each access should warn exactly once.
112
+ (set_message ,) = [str (entry .message ) for entry in setting ]
113
+ (check_message ,) = [str (entry .message ) for entry in checking ]
114
+ (reset_message ,) = [str (entry .message ) for entry in resetting ]
115
+ (recheck_message ,) = [str (entry .message ) for entry in rechecking ]
96
116
97
117
# Setting it to True should produce the special warning for that.
98
118
assert _USE_SHELL_DEPRECATED_FRAGMENT in set_message
0 commit comments