]> granicus.if.org Git - python/commitdiff
[2.7] bpo-30197: Enhance swap_attr() and backport swap_item() in test.test_support...
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 28 Apr 2017 17:06:30 +0000 (20:06 +0300)
committerGitHub <noreply@github.com>
Fri, 28 Apr 2017 17:06:30 +0000 (20:06 +0300)
(cherry picked from commit d1a1def7bf221b04dcf3fc3a67aa19aa2f622f83)

Lib/test/test_support.py
Lib/test/test_tempfile.py
Misc/NEWS

index e339da5ff4d1d38b21e038e8c69368d55878666c..976f301c0a9144d9b32e21b7b99d5ee7c4c823c8 100644 (file)
@@ -1647,12 +1647,15 @@ def swap_attr(obj, attr, new_val):
         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:
@@ -1660,7 +1663,39 @@ def swap_attr(obj, attr, new_val):
         try:
             yield
         finally:
-            delattr(obj, attr)
+            if hasattr(obj, attr):
+                delattr(obj, attr)
+
+@contextlib.contextmanager
+def swap_item(obj, item, new_val):
+    """Temporary swap out an item with a new object.
+
+    Usage:
+        with swap_item(obj, "item", 5):
+            ...
+
+        This will set obj["item"] to 5 for the duration of the with: block,
+        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 real_val
+        finally:
+            obj[item] = real_val
+    else:
+        obj[item] = new_val
+        try:
+            yield
+        finally:
+            if item in obj:
+                del obj[item]
 
 def py3k_bytes(b):
     """Emulate the py3k bytes() constructor.
index 078e4a9a2d06a92187055ffc8380f5e7634ff204..5c85cc9bd306d4d16abcb24fb5c7f6a421f10468 100644 (file)
@@ -235,13 +235,12 @@ class TestGetDefaultTempdir(TC):
                     self.assertEqual(cm.exception.errno, errno.ENOENT)
                     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(IOError) as cm:
                         tempfile._get_default_tempdir()
index 657b2fb84e130515646649da1a18150b2f5d301c..8ec9f2a0eb167b2b95a7cb1f7d3d8b629a1fcc6f 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -144,6 +144,12 @@ Build
 Tests
 -----
 
+- bpo-30197: Enhanced function swap_attr() in the test.test_support module.
+  It now works when delete replaced attribute inside the with statement.  The
+  old value of the attribute (or None if it doesn't exist) now will be
+  assigned to the target of the "as" clause, if there is one.
+  Also backported function swap_item().
+
 - bpo-28087: Skip test_asyncore and test_eintr poll failures on macOS.
   Skip some tests of select.poll when running on macOS due to unresolved
   issues with the underlying system poll function on some macOS versions.