diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2008-02-11 12:53:42 +0000 |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2008-02-11 12:53:42 +0000 |
commit | 5ca1cba2523645b6043adf5c59bb448b8d22d816 (patch) | |
tree | 20f3738823b386f8e5bb5f11a94b096231818f8d | |
parent | 0b5c17a9c3055491b654bca482e3b1805610ac3d (diff) | |
download | cpython-git-5ca1cba2523645b6043adf5c59bb448b8d22d816.tar.gz |
Backport relevant part of issue 2021 fix (r60695): Support with statement properly in tempfile.NamedTemporaryFile
-rw-r--r-- | Lib/tempfile.py | 18 | ||||
-rw-r--r-- | Lib/test/test_tempfile.py | 15 | ||||
-rw-r--r-- | Misc/NEWS | 3 |
3 files changed, 32 insertions, 4 deletions
diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 2e8cd6d7d5..045e230424 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -378,17 +378,25 @@ class _TemporaryFileWrapper: self.close_called = False def __getattr__(self, name): + # Attribute lookups are delegated to the underlying file + # and cached for non-numeric results + # (i.e. methods are cached, closed and friends are not) file = self.__dict__['file'] a = getattr(file, name) if type(a) != type(0): setattr(self, name, a) return a + # The underlying __enter__ method returns the wrong object + # (self.file) so override it to return the wrapper + def __enter__(self): + self.file.__enter__() + return self + # NT provides delete-on-close as a primitive, so we don't need # the wrapper to do anything special. We still use it so that # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile. if _os.name != 'nt': - # Cache the unlinker so we don't get spurious errors at # shutdown when the module-level "os" is None'd out. Note # that this must be referenced as self.unlink, because the @@ -405,6 +413,14 @@ class _TemporaryFileWrapper: def __del__(self): self.close() + # Need to trap __exit__ as well to ensure the file gets + # deleted when used in a with statement + def __exit__(self, exc, value, tb): + result = self.file.__exit__(exc, value, tb) + self.close() + return result + + def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="", prefix=template, dir=None): """Create and return a temporary file. diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 2047a6364e..cd7ff4e1b5 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -1,5 +1,5 @@ # tempfile.py unit tests. - +from __future__ import with_statement import tempfile import os import sys @@ -298,7 +298,7 @@ class test__mkstemp_inner(TC): # On Windows a spawn* /path/ with embedded spaces shouldn't be quoted, # but an arg with embedded spaces should be decorated with double # quotes on each end - if sys.platform in ('win32'): + if sys.platform in ('win32',): decorated = '"%s"' % sys.executable tester = '"%s"' % tester else: @@ -601,7 +601,6 @@ class test_NamedTemporaryFile(TC): def test_multiple_close(self): # A NamedTemporaryFile can be closed many times without error - f = tempfile.NamedTemporaryFile() f.write('abc\n') f.close() @@ -611,6 +610,16 @@ class test_NamedTemporaryFile(TC): except: self.failOnException("close") + def test_context_manager(self): + # A NamedTemporaryFile can be used as a context manager + with tempfile.NamedTemporaryFile() as f: + self.failUnless(os.path.exists(f.name)) + self.failIf(os.path.exists(f.name)) + def use_closed(): + with f: + pass + self.failUnlessRaises(ValueError, use_closed) + # How to test the mode and bufsize parameters? test_classes.append(test_NamedTemporaryFile) @@ -83,6 +83,9 @@ Core and builtins Library ------- +- #2021: Allow tempfile.NamedTemporaryFile to be used in with statements + by correctly supporting the context management protocol. + - Fixed _ctypes.COMError so that it must be called with exactly three arguments, instances now have the hresult, text, and details instance variables. |