[3.6] bpo-30197: Enhance functions swap_attr() and swap_item() in test.support. (GH-1341) (#1345)
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 d1a1def7bf221b04dcf3fc3a67aa19aa2f622f83)
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 2d60adc..f8d1779 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2105,12 +2105,15 @@
restoring the old value at the end of the block. If `attr` doesn't
exist on `obj`, it will be created and then deleted at the end of the
block.
+
+ The old value (or None if it doesn't exist) will be assigned to the
+ target of the "as" clause, if there is one.
"""
if hasattr(obj, attr):
real_val = getattr(obj, attr)
setattr(obj, attr, new_val)
try:
- yield
+ yield real_val
finally:
setattr(obj, attr, real_val)
else:
@@ -2118,7 +2121,8 @@
try:
yield
finally:
- delattr(obj, attr)
+ if hasattr(obj, attr):
+ delattr(obj, attr)
@contextlib.contextmanager
def swap_item(obj, item, new_val):
@@ -2132,12 +2136,15 @@
restoring the old value at the end of the block. If `item` doesn't
exist on `obj`, it will be created and then deleted at the end of the
block.
+
+ The old value (or None if it doesn't exist) will be assigned to the
+ target of the "as" clause, if there is one.
"""
if item in obj:
real_val = obj[item]
obj[item] = new_val
try:
- yield
+ yield real_val
finally:
obj[item] = real_val
else:
@@ -2145,7 +2152,8 @@
try:
yield
finally:
- del obj[item]
+ if item in obj:
+ del obj[item]
def strip_python_stderr(stderr):
"""Strip the stderr of a Python process from potential debug output
diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py
index e83a4d6..ddd6509 100644
--- a/Lib/test/test_support.py
+++ b/Lib/test/test_support.py
@@ -282,17 +282,34 @@
def test_swap_attr(self):
class Obj:
- x = 1
+ pass
obj = Obj()
- with support.swap_attr(obj, "x", 5):
+ obj.x = 1
+ with support.swap_attr(obj, "x", 5) as x:
self.assertEqual(obj.x, 5)
+ self.assertEqual(x, 1)
self.assertEqual(obj.x, 1)
+ with support.swap_attr(obj, "y", 5) as y:
+ self.assertEqual(obj.y, 5)
+ self.assertIsNone(y)
+ self.assertFalse(hasattr(obj, 'y'))
+ with support.swap_attr(obj, "y", 5):
+ del obj.y
+ self.assertFalse(hasattr(obj, 'y'))
def test_swap_item(self):
- D = {"item":1}
- with support.swap_item(D, "item", 5):
- self.assertEqual(D["item"], 5)
- self.assertEqual(D["item"], 1)
+ D = {"x":1}
+ with support.swap_item(D, "x", 5) as x:
+ self.assertEqual(D["x"], 5)
+ self.assertEqual(x, 1)
+ self.assertEqual(D["x"], 1)
+ with support.swap_item(D, "y", 5) as y:
+ self.assertEqual(D["y"], 5)
+ self.assertIsNone(y)
+ self.assertNotIn("y", D)
+ with support.swap_item(D, "y", 5):
+ del D["y"]
+ self.assertNotIn("y", D)
class RefClass:
attribute1 = None
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index 51df1ec..d0cf04b 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -273,13 +273,12 @@
tempfile._get_default_tempdir()
self.assertEqual(os.listdir(our_temp_directory), [])
- open = io.open
def bad_writer(*args, **kwargs):
- fp = open(*args, **kwargs)
+ fp = orig_open(*args, **kwargs)
fp.write = raise_OSError
return fp
- with support.swap_attr(io, "open", bad_writer):
+ with support.swap_attr(io, "open", bad_writer) as orig_open:
# test again with failing write()
with self.assertRaises(FileNotFoundError):
tempfile._get_default_tempdir()