8000 [3.5] bpo-30197: Enhance functions swap_attr() and swap_item() in tes… · serhiy-storchaka/cpython@eed8c51 · GitHub
[go: up one dir, main page]

Skip to content

Commit eed8c51

Browse files
[3.5] bpo-30197: Enhance functions swap_attr() and swap_item() in test.support. (python#1341)
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. (cherry picked from commit d1a1def)
1 parent 98c7a9e commit eed8c51

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
@@ -2073,20 +2073,24 @@ def swap_attr(obj, attr, new_val):
20732073
restoring the old value at the end of the block. If `attr` doesn't
20742074
exist on `obj`, it will be created and then deleted at the end of the
20752075
block.
2076+
2077+
The old value (or None if it doesn't exist) will be assigned to the
2078+
target of the "as" clause, if there is one.
20762079
"""
20772080
if hasattr(obj, attr):
20782081
real_val = getattr(obj, attr)
20792082
setattr(obj, attr, new_val)
20802083
try:
2081-
yield
2084+
yield real_val
20822085
finally:
20832086
setattr(obj, attr, real_val)
20842087
else:
20852088
setattr(obj, attr, new_val)
20862089
try:
20872090
yield
20882091
finally:
2089-
delattr(obj, attr)
2092+
if hasattr(obj, attr):
2093+
delattr(obj, attr)
20902094

20912095
@contextlib.contextmanager
20922096
def swap_item(obj, item, new_val):
@@ -2100,20 +2104,24 @@ def swap_item(obj, item, new_val):
21002104
restoring the old value at the end of the block. If `item` doesn't
21012105
exist on `obj`, it will be created and then deleted at the end of the
21022106
block.
2107+
2108+
The old value (or None if it doesn't exist) will be assigned to the
2109+
target of the "as" clause, if there is one.
21032110
"""
21042111
if item in obj:
21052112
real_val = obj[item]
21062113
obj[item] = new_val
21072114
try:
2108-
yield
2115+
yield real_val
21092116
finally:
21102117
obj[item] = real_val
21112118
else:
21122119
obj[item] = new_val
21132120
try:
21142121
yield
21152122
finally:
2116-
del obj[item]
2123+
if item in obj:
2124+
del obj[item]
21172125

21182126
def strip_python_stderr(stderr):
21192127
"""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
@@ -283,17 +283,34 @@ def test_python_is_optimized(self):
283283

284284
def test_swap_attr(self):
285285
class Obj:
286-
x = 1
286+
pass
287287
obj = Obj()
288-
with support.swap_attr(obj, "x", 5):
288+
obj.x = 1
289+
with support.swap_attr(obj, "x", 5) as x:
289290
self.assertEqual(obj.x, 5)
291+
self.assertEqual(x, 1)
290292
self.assertEqual(obj.x, 1)
293+
with support.swap_attr(obj, "y", 5) as y:
294+
self.assertEqual(obj.y, 5)
295+
self.assertIsNone(y)
296+
self.assertFalse(hasattr(obj, 'y'))
297+
with support.swap_attr(obj, "y", 5):
298+
del obj.y
299+
self.assertFalse(hasattr(obj, 'y'))
291300

292301
def test_swap_item(self):
293-
D = {"item":1}
294-
with support.swap_item(D, "item", 5):
295-
self.assertEqual(D["item"], 5)
296-
self.assertEqual(D["item"], 1)
302+
D = {"x":1}
303+
with support.swap_item(D, "x", 5) as x:
304+
self.assertEqual(D["x"], 5)
305+
self.assertEqual(x, 1)
306+
self.assertEqual(D["x"], 1)
307+
with support.swap_item(D, "y", 5) as y:
308+
self.assertEqual(D["y"], 5)
309+
self.assertIsNone(y)
310+
self.assertNotIn("y", D)
311+
with support.swap_item(D, "y", 5):
312+
del D["y"]
313+
self.assertNotIn("y", D)
297314

298315
class RefClass:
299316
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
< 7F9F /div>
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ Build
199199
Tests
200200
-----
201201

202+
- bpo-30197: Enhanced functions swap_attr() and swap_item() in the
203+
test.support module. They now work when delete replaced attribute or item
204+
inside the with statement. The old value of the attribute or item (or None
205+
if it doesn't exist) now will be assigned to the target of the "as" clause,
206+
if there is one.
207+
202208
- Issue #29571: to match the behaviour of the ``re.LOCALE`` flag,
203209
test_re.test_locale_flag now uses ``locale.getpreferredencoding(False)`` to
204210
determine the candidate encoding for the test regex (allowing it to correctly

0 commit comments

Comments
 (0)
0