Commit 5ca1cba2 authored by Nick Coghlan's avatar Nick Coghlan

Backport relevant part of issue 2021 fix (r60695): Support with statement...

Backport relevant part of issue 2021 fix (r60695): Support with statement properly in tempfile.NamedTemporaryFile
parent 0b5c17a9
...@@ -378,17 +378,25 @@ class _TemporaryFileWrapper: ...@@ -378,17 +378,25 @@ class _TemporaryFileWrapper:
self.close_called = False self.close_called = False
def __getattr__(self, name): 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'] file = self.__dict__['file']
a = getattr(file, name) a = getattr(file, name)
if type(a) != type(0): if type(a) != type(0):
setattr(self, name, a) setattr(self, name, a)
return 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 # 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 # the wrapper to do anything special. We still use it so that
# file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile. # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile.
if _os.name != 'nt': if _os.name != 'nt':
# Cache the unlinker so we don't get spurious errors at # Cache the unlinker so we don't get spurious errors at
# shutdown when the module-level "os" is None'd out. Note # shutdown when the module-level "os" is None'd out. Note
# that this must be referenced as self.unlink, because the # that this must be referenced as self.unlink, because the
...@@ -405,6 +413,14 @@ class _TemporaryFileWrapper: ...@@ -405,6 +413,14 @@ class _TemporaryFileWrapper:
def __del__(self): def __del__(self):
self.close() 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="", def NamedTemporaryFile(mode='w+b', bufsize=-1, suffix="",
prefix=template, dir=None): prefix=template, dir=None):
"""Create and return a temporary file. """Create and return a temporary file.
......
# tempfile.py unit tests. # tempfile.py unit tests.
from __future__ import with_statement
import tempfile import tempfile
import os import os
import sys import sys
...@@ -298,7 +298,7 @@ class test__mkstemp_inner(TC): ...@@ -298,7 +298,7 @@ class test__mkstemp_inner(TC):
# On Windows a spawn* /path/ with embedded spaces shouldn't be quoted, # On Windows a spawn* /path/ with embedded spaces shouldn't be quoted,
# but an arg with embedded spaces should be decorated with double # but an arg with embedded spaces should be decorated with double
# quotes on each end # quotes on each end
if sys.platform in ('win32'): if sys.platform in ('win32',):
decorated = '"%s"' % sys.executable decorated = '"%s"' % sys.executable
tester = '"%s"' % tester tester = '"%s"' % tester
else: else:
...@@ -601,7 +601,6 @@ class test_NamedTemporaryFile(TC): ...@@ -601,7 +601,6 @@ class test_NamedTemporaryFile(TC):
def test_multiple_close(self): def test_multiple_close(self):
# A NamedTemporaryFile can be closed many times without error # A NamedTemporaryFile can be closed many times without error
f = tempfile.NamedTemporaryFile() f = tempfile.NamedTemporaryFile()
f.write('abc\n') f.write('abc\n')
f.close() f.close()
...@@ -611,6 +610,16 @@ class test_NamedTemporaryFile(TC): ...@@ -611,6 +610,16 @@ class test_NamedTemporaryFile(TC):
except: except:
self.failOnException("close") 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? # How to test the mode and bufsize parameters?
test_classes.append(test_NamedTemporaryFile) test_classes.append(test_NamedTemporaryFile)
......
...@@ -83,6 +83,9 @@ Core and builtins ...@@ -83,6 +83,9 @@ Core and builtins
Library 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 - Fixed _ctypes.COMError so that it must be called with exactly three
arguments, instances now have the hresult, text, and details arguments, instances now have the hresult, text, and details
instance variables. instance variables.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment