Skip to content

Commit d1a1def

Browse files
serhiy-storchakavstinner
authored andcommitted
bpo-30197: Enhance functions swap_attr() and swap_item() in test.support. (python#1341)
* bpo-30197: Enhance functions swap_attr() and swap_item() in test.support. They now work when delete replaced attribute or item inside the with statement. The old value of the attribute or item (or None if it doesn't exist) now will be assigned to the target of the "as" clause, if there is one. * Update docstrings.
1 parent 80a3da4 commit d1a1def

File tree

4 files changed

+43
-13
lines changed

4 files changed

+43
-13
lines changed

Lib/test/support/__init__.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,20 +2119,24 @@ def swap_attr(obj, attr, new_val):
21192119
restoring the old value at the end of the block. If `attr` doesn't
21202120
exist on `obj`, it will be created and then deleted at the end of the
21212121
block.
2122+
2123+
The old value (or None if it doesn't exist) will be assigned to the
2124+
target of the "as" clause, if there is one.
21222125
"""
21232126
if hasattr(obj, attr):
21242127
real_val = getattr(obj, attr)
21252128
setattr(obj, attr, new_val)
21262129
try:
2127-
yield
2130+
yield real_val
21282131
finally:
21292132
setattr(obj, attr, real_val)
21302133
else:
21312134
setattr(obj, attr, new_val)
21322135
try:
21332136
yield
21342137
finally:
2135-
delattr(obj, attr)
2138+
if hasattr(obj, attr):
2139+
delattr(obj, attr)
21362140

21372141
@contextlib.contextmanager
21382142
def swap_item(obj, item, new_val):
@@ -2146,20 +2150,24 @@ def swap_item(obj, item, new_val):
21462150
restoring the old value at the end of the block. If `item` doesn't
21472151
exist on `obj`, it will be created and then deleted at the end of the
21482152
block.
2153+
2154+
The old value (or None if it doesn't exist) will be assigned to the
2155+
target of the "as" clause, if there is one.
21492156
"""
21502157
if item in obj:
21512158
real_val = obj[item]
21522159
obj[item] = new_val
21532160
try:
2154-
yield
2161+
yield real_val
21552162
finally:
21562163
obj[item] = real_val
21572164
else:
21582165
obj[item] = new_val
21592166
try:
21602167
yield
21612168
finally:
2162-
del obj[item]
2169+
if item in obj:
2170+
del obj[item]
21632171

21642172
def strip_python_stderr(stderr):
21652173
"""Strip the stderr of a Python process from potential debug output

Lib/test/test_support.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -295,17 +295,34 @@ def test_python_is_optimized(self):
295295

296296
def test_swap_attr(self):
297297
class Obj:
298-
x = 1
298+
pass
299299
obj = Obj()
300-
with support.swap_attr(obj, "x", 5):
300+
obj.x = 1
301+
with support.swap_attr(obj, "x", 5) as x:
301302
self.assertEqual(obj.x, 5)
303+
self.assertEqual(x, 1)
302304
self.assertEqual(obj.x, 1)
305+
with support.swap_attr(obj, "y", 5) as y:
306+
self.assertEqual(obj.y, 5)
307+
self.assertIsNone(y)
308+
self.assertFalse(hasattr(obj, 'y'))
309+
with support.swap_attr(obj, "y", 5):
310+
del obj.y
311+
self.assertFalse(hasattr(obj, 'y'))
303312

304313
def test_swap_item(self):
305-
D = {"item":1}
306-
with support.swap_item(D, "item", 5):
307-
self.assertEqual(D["item"], 5)
308-
self.assertEqual(D["item"], 1)
314+
D = {"x":1}
315+
with support.swap_item(D, "x", 5) as x:
316+
self.assertEqual(D["x"], 5)
317+
self.assertEqual(x, 1)
318+
self.assertEqual(D["x"], 1)
319+
with support.swap_item(D, "y", 5) as y:
320+
self.assertEqual(D["y"], 5)
321+
self.assertIsNone(y)
322+
self.assertNotIn("y", D)
323+
with support.swap_item(D, "y", 5):
324+
del D["y"]
325+
self.assertNotIn("y", D)
309326

310327
class RefClass:
311328
attribute1 = None

Lib/test/test_tempfile.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,13 +273,12 @@ def raise_OSError(*args, **kwargs):
273273
tempfile._get_default_tempdir()
274274
self.assertEqual(os.listdir(our_temp_directory), [])
275275

276-
open = io.open
277276
def bad_writer(*args, **kwargs):
278-
fp = open(*args, **kwargs)
277+
fp = orig_open(*args, **kwargs)
279278
fp.write = raise_OSError
280279
return fp
281280

282-
with support.swap_attr(io, "open", bad_writer):
281+
with support.swap_attr(io, "open", bad_writer) as orig_open:
283282
# test again with failing write()
284283
with self.assertRaises(FileNotFoundError):
285284
tempfile._get_default_tempdir()

Misc/NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,12 @@ Tools/Demos
11071107
Tests
11081108
-----
11091109

1110+
- bpo-30197: Enhanced functions swap_attr() and swap_item() in the
1111+
test.support module. They now work when delete replaced attribute or item
1112+
inside the with statement. The old value of the attribute or item (or None
1113+
if it doesn't exist) now will be assigned to the target of the "as" clause,
1114+
if there is one.
1115+
11101116
- Issue #24932: Use proper command line parsing in _testembed
11111117

11121118
- Issue #28950: Disallow -j0 to be combined with -T/-l in regrtest

0 commit comments

Comments
 (0)