[issue22831] Use "with" to avoid possible fd leaks

Serhiy Storchaka report at bugs.python.org
Fri Mar 20 14:39:53 CET 2015


Serhiy Storchaka added the comment:

п'ятниця, 20-бер-2015 12:36:25 ви написали:
> Martin Panter added the comment:
> 
> There were a couple mistakes I found; see Reitveld. I was going to say to
> leave the open(mode="r") parameter as it is, since an explicit "r" is more
> readable, but since you already took some out, I’m not going to complain.
> 
> While many of the changes look worthwhile, I do worry that some of them will
> never be tested (at least until say Python 3.14 or something). E.g. I just
> tried running Tools/scripts/dutree.py cos it looked interesting, but was
> confronted with the “unorderable types: int() < NoneType()” Python 2-ism.
> 
> ----------
> 
> _______________________________________
> Python tracker <report at bugs.python.org>
> <http://bugs.python.org/issue22831>
> _______________________________________

----------
Added file: http://bugs.python.org/file38601/fd_leaks_tests1_2.patch
Added file: http://bugs.python.org/file38602/fd_leaks_tools1_2.patch
Added file: http://bugs.python.org/file38603/fd_leaks_tools2_2.patch

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue22831>
_______________________________________
-------------- next part --------------
diff -r d478a2a5738a Lib/test/test_dbm_dumb.py
--- a/Lib/test/test_dbm_dumb.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Lib/test/test_dbm_dumb.py	Fri Mar 20 14:17:30 2015 +0200
@@ -2,6 +2,7 @@
    Original by Roger E. Masse
 """
 
+import contextlib
 import io
 import operator
 import os
@@ -31,12 +32,11 @@ class DumbDBMTestCase(unittest.TestCase)
              }
 
     def test_dumbdbm_creation(self):
-        f = dumbdbm.open(_fname, 'c')
-        self.assertEqual(list(f.keys()), [])
-        for key in self._dict:
-            f[key] = self._dict[key]
-        self.read_helper(f)
-        f.close()
+        with contextlib.closing(dumbdbm.open(_fname, 'c')) as f:
+            self.assertEqual(list(f.keys()), [])
+            for key in self._dict:
+                f[key] = self._dict[key]
+            self.read_helper(f)
 
     @unittest.skipUnless(hasattr(os, 'umask'), 'test needs os.umask()')
     @unittest.skipUnless(hasattr(os, 'chmod'), 'test needs os.chmod()')
@@ -69,63 +69,55 @@ class DumbDBMTestCase(unittest.TestCase)
 
     def test_dumbdbm_modification(self):
         self.init_db()
-        f = dumbdbm.open(_fname, 'w')
-        self._dict[b'g'] = f[b'g'] = b"indented"
-        self.read_helper(f)
-        f.close()
+        with contextlib.closing(dumbdbm.open(_fname, 'w')) as f:
+            self._dict[b'g'] = f[b'g'] = b"indented"
+            self.read_helper(f)
 
     def test_dumbdbm_read(self):
         self.init_db()
-        f = dumbdbm.open(_fname, 'r')
-        self.read_helper(f)
-        f.close()
+        with contextlib.closing(dumbdbm.open(_fname, 'r')) as f:
+            self.read_helper(f)
 
     def test_dumbdbm_keys(self):
         self.init_db()
-        f = dumbdbm.open(_fname)
-        keys = self.keys_helper(f)
-        f.close()
+        with contextlib.closing(dumbdbm.open(_fname)) as f:
+            keys = self.keys_helper(f)
 
     def test_write_contains(self):
-        f = dumbdbm.open(_fname)
-        f[b'1'] = b'hello'
-        self.assertIn(b'1', f)
-        f.close()
+        with contextlib.closing(dumbdbm.open(_fname)) as f:
+            f[b'1'] = b'hello'
+            self.assertIn(b'1', f)
 
     def test_write_write_read(self):
         # test for bug #482460
-        f = dumbdbm.open(_fname)
-        f[b'1'] = b'hello'
-        f[b'1'] = b'hello2'
-        f.close()
-        f = dumbdbm.open(_fname)
-        self.assertEqual(f[b'1'], b'hello2')
-        f.close()
+        with contextlib.closing(dumbdbm.open(_fname)) as f:
+            f[b'1'] = b'hello'
+            f[b'1'] = b'hello2'
+        with contextlib.closing(dumbdbm.open(_fname)) as f:
+            self.assertEqual(f[b'1'], b'hello2')
 
     def test_str_read(self):
         self.init_db()
-        f = dumbdbm.open(_fname, 'r')
-        self.assertEqual(f['\u00fc'], self._dict['\u00fc'.encode('utf-8')])
+        with contextlib.closing(dumbdbm.open(_fname, 'r')) as f:
+            self.assertEqual(f['\u00fc'], self._dict['\u00fc'.encode('utf-8')])
 
     def test_str_write_contains(self):
         self.init_db()
-        f = dumbdbm.open(_fname)
-        f['\u00fc'] = b'!'
-        f['1'] = 'a'
-        f.close()
-        f = dumbdbm.open(_fname, 'r')
-        self.assertIn('\u00fc', f)
-        self.assertEqual(f['\u00fc'.encode('utf-8')],
-                         self._dict['\u00fc'.encode('utf-8')])
-        self.assertEqual(f[b'1'], b'a')
+        with contextlib.closing(dumbdbm.open(_fname)) as f:
+            f['\u00fc'] = b'!'
+            f['1'] = 'a'
+        with contextlib.closing(dumbdbm.open(_fname, 'r')) as f:
+            self.assertIn('\u00fc', f)
+            self.assertEqual(f['\u00fc'.encode('utf-8')],
+                             self._dict['\u00fc'.encode('utf-8')])
+            self.assertEqual(f[b'1'], b'a')
 
     def test_line_endings(self):
         # test for bug #1172763: dumbdbm would die if the line endings
         # weren't what was expected.
-        f = dumbdbm.open(_fname)
-        f[b'1'] = b'hello'
-        f[b'2'] = b'hello2'
-        f.close()
+        with contextlib.closing(dumbdbm.open(_fname)) as f:
+            f[b'1'] = b'hello'
+            f[b'2'] = b'hello2'
 
         # Mangle the file by changing the line separator to Windows or Unix
         with io.open(_fname + '.dir', 'rb') as file:
@@ -148,10 +140,9 @@ class DumbDBMTestCase(unittest.TestCase)
             self.assertEqual(self._dict[key], f[key])
 
     def init_db(self):
-        f = dumbdbm.open(_fname, 'w')
-        for k in self._dict:
-            f[k] = self._dict[k]
-        f.close()
+        with contextlib.closing(dumbdbm.open(_fname, 'w')) as f:
+            for k in self._dict:
+                f[k] = self._dict[k]
 
     def keys_helper(self, f):
         keys = sorted(f.keys())
@@ -165,25 +156,23 @@ class DumbDBMTestCase(unittest.TestCase)
         import random
         d = {}  # mirror the database
         for dummy in range(5):
-            f = dumbdbm.open(_fname)
-            for dummy in range(100):
-                k = random.choice('abcdefghijklm')
-                if random.random() < 0.2:
-                    if k in d:
-                        del d[k]
-                        del f[k]
-                else:
-                    v = random.choice((b'a', b'b', b'c')) * random.randrange(10000)
-                    d[k] = v
-                    f[k] = v
-                    self.assertEqual(f[k], v)
-            f.close()
+            with contextlib.closing(dumbdbm.open(_fname)) as f:
+                for dummy in range(100):
+                    k = random.choice('abcdefghijklm')
+                    if random.random() < 0.2:
+                        if k in d:
+                            del d[k]
+                            del f[k]
+                    else:
+                        v = random.choice((b'a', b'b', b'c')) * random.randrange(10000)
+                        d[k] = v
+                        f[k] = v
+                        self.assertEqual(f[k], v)
 
-            f = dumbdbm.open(_fname)
-            expected = sorted((k.encode("latin-1"), v) for k, v in d.items())
-            got = sorted(f.items())
-            self.assertEqual(expected, got)
-            f.close()
+            with contextlib.closing(dumbdbm.open(_fname)) as f:
+                expected = sorted((k.encode("latin-1"), v) for k, v in d.items())
+                got = sorted(f.items())
+                self.assertEqual(expected, got)
 
     def test_context_manager(self):
         with dumbdbm.open(_fname, 'c') as db:
diff -r d478a2a5738a Lib/test/test_mmap.py
--- a/Lib/test/test_mmap.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Lib/test/test_mmap.py	Fri Mar 20 14:17:30 2015 +0200
@@ -268,13 +268,12 @@ class MmapTests(unittest.TestCase):
 
     def test_find_end(self):
         # test the new 'end' parameter works as expected
-        f = open(TESTFN, 'wb+')
-        data = b'one two ones'
-        n = len(data)
-        f.write(data)
-        f.flush()
-        m = mmap.mmap(f.fileno(), n)
-        f.close()
+        with open(TESTFN, 'wb+') as f:
+            data = b'one two ones'
+            n = len(data)
+            f.write(data)
+            f.flush()
+            m = mmap.mmap(f.fileno(), n)
 
         self.assertEqual(m.find(b'one'), 0)
         self.assertEqual(m.find(b'ones'), 8)
@@ -287,13 +286,12 @@ class MmapTests(unittest.TestCase):
 
     def test_rfind(self):
         # test the new 'end' parameter works as expected
-        f = open(TESTFN, 'wb+')
-        data = b'one two ones'
-        n = len(data)
-        f.write(data)
-        f.flush()
-        m = mmap.mmap(f.fileno(), n)
-        f.close()
+        with open(TESTFN, 'wb+') as f:
+            data = b'one two ones'
+            n = len(data)
+            f.write(data)
+            f.flush()
+            m = mmap.mmap(f.fileno(), n)
 
         self.assertEqual(m.rfind(b'one'), 8)
         self.assertEqual(m.rfind(b'one '), 0)
@@ -306,31 +304,24 @@ class MmapTests(unittest.TestCase):
 
     def test_double_close(self):
         # make sure a double close doesn't crash on Solaris (Bug# 665913)
-        f = open(TESTFN, 'wb+')
+        with open(TESTFN, 'wb+') as f:
+            f.write(2**16 * b'a') # Arbitrary character
 
-        f.write(2**16 * b'a') # Arbitrary character
-        f.close()
-
-        f = open(TESTFN, 'rb')
-        mf = mmap.mmap(f.fileno(), 2**16, access=mmap.ACCESS_READ)
-        mf.close()
-        mf.close()
-        f.close()
+        with open(TESTFN, 'rb') as f:
+            mf = mmap.mmap(f.fileno(), 2**16, access=mmap.ACCESS_READ)
+            mf.close()
+            mf.close()
 
     @unittest.skipUnless(hasattr(os, "stat"), "needs os.stat()")
     def test_entire_file(self):
         # test mapping of entire file by passing 0 for map length
-        f = open(TESTFN, "wb+")
+        with open(TESTFN, "wb+") as f:
+            f.write(2**16 * b'm') # Arbitrary character
 
-        f.write(2**16 * b'm') # Arbitrary character
-        f.close()
-
-        f = open(TESTFN, "rb+")
-        mf = mmap.mmap(f.fileno(), 0)
-        self.assertEqual(len(mf), 2**16, "Map size should equal file size.")
-        self.assertEqual(mf.read(2**16), 2**16 * b"m")
-        mf.close()
-        f.close()
+        with open(TESTFN, "rb+") as f, \
+             mmap.mmap(f.fileno(), 0) as mf:
+                self.assertEqual(len(mf), 2**16, "Map size should equal file size.")
+                self.assertEqual(mf.read(2**16), 2**16 * b"m")
 
     @unittest.skipUnless(hasattr(os, "stat"), "needs os.stat()")
     def test_length_0_offset(self):
@@ -358,16 +349,15 @@ class MmapTests(unittest.TestCase):
 
     def test_move(self):
         # make move works everywhere (64-bit format problem earlier)
-        f = open(TESTFN, 'wb+')
+        with open(TESTFN, 'wb+') as f:
 
-        f.write(b"ABCDEabcde") # Arbitrary character
-        f.flush()
+            f.write(b"ABCDEabcde") # Arbitrary character
+            f.flush()
 
-        mf = mmap.mmap(f.fileno(), 10)
-        mf.move(5, 0, 5)
-        self.assertEqual(mf[:], b"ABCDEABCDE", "Map move should have duplicated front 5")
-        mf.close()
-        f.close()
+            mf = mmap.mmap(f.fileno(), 10)
+            mf.move(5, 0, 5)
+            self.assertEqual(mf[:], b"ABCDEABCDE", "Map move should have duplicated front 5")
+            mf.close()
 
         # more excessive test
         data = b"0123456789"
@@ -565,10 +555,9 @@ class MmapTests(unittest.TestCase):
         mapsize = 10
         with open(TESTFN, "wb") as fp:
             fp.write(b"a"*mapsize)
-        f = open(TESTFN, "rb")
-        m = mmap.mmap(f.fileno(), mapsize, prot=mmap.PROT_READ)
-        self.assertRaises(TypeError, m.write, "foo")
-        f.close()
+        with open(TESTFN, "rb") as f:
+            m = mmap.mmap(f.fileno(), mapsize, prot=mmap.PROT_READ)
+            self.assertRaises(TypeError, m.write, "foo")
 
     def test_error(self):
         self.assertIs(mmap.error, OSError)
@@ -577,9 +566,8 @@ class MmapTests(unittest.TestCase):
         data = b"0123456789"
         with open(TESTFN, "wb") as fp:
             fp.write(b"x"*len(data))
-        f = open(TESTFN, "r+b")
-        m = mmap.mmap(f.fileno(), len(data))
-        f.close()
+        with open(TESTFN, "r+b") as f:
+            m = mmap.mmap(f.fileno(), len(data))
         # Test write_byte()
         for i in range(len(data)):
             self.assertEqual(m.tell(), i)
diff -r d478a2a5738a Lib/test/test_socket.py
--- a/Lib/test/test_socket.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Lib/test/test_socket.py	Fri Mar 20 14:17:30 2015 +0200
@@ -686,10 +686,9 @@ class GeneralModuleTests(unittest.TestCa
         self.assertEqual(repr(s), expected)
 
     def test_weakref(self):
-        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        p = proxy(s)
-        self.assertEqual(p.fileno(), s.fileno())
-        s.close()
+        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
+            p = proxy(s)
+            self.assertEqual(p.fileno(), s.fileno())
         s = None
         try:
             p.fileno()
@@ -933,23 +932,20 @@ class GeneralModuleTests(unittest.TestCa
         # Testing default timeout
         # The default timeout should initially be None
         self.assertEqual(socket.getdefaulttimeout(), None)
-        s = socket.socket()
-        self.assertEqual(s.gettimeout(), None)
-        s.close()
+        with socket.socket() as s:
+            self.assertEqual(s.gettimeout(), None)
 
         # Set the default timeout to 10, and see if it propagates
         socket.setdefaulttimeout(10)
         self.assertEqual(socket.getdefaulttimeout(), 10)
-        s = socket.socket()
-        self.assertEqual(s.gettimeout(), 10)
-        s.close()
+        with socket.socket() as s:
+            self.assertEqual(s.gettimeout(), 10)
 
         # Reset the default timeout to None, and see if it propagates
         socket.setdefaulttimeout(None)
         self.assertEqual(socket.getdefaulttimeout(), None)
-        s = socket.socket()
-        self.assertEqual(s.gettimeout(), None)
-        s.close()
+        with socket.socket() as s:
+            self.assertEqual(s.gettimeout(), None)
 
         # Check that setting it to an invalid value raises ValueError
         self.assertRaises(ValueError, socket.setdefaulttimeout, -1)
@@ -1156,24 +1152,22 @@ class GeneralModuleTests(unittest.TestCa
 
     def testSendAfterClose(self):
         # testing send() after close() with timeout
-        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        sock.settimeout(1)
-        sock.close()
+        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
+            sock.settimeout(1)
         self.assertRaises(OSError, sock.send, b"spam")
 
     def testNewAttributes(self):
         # testing .family, .type and .protocol
 
-        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        self.assertEqual(sock.family, socket.AF_INET)
-        if hasattr(socket, 'SOCK_CLOEXEC'):
-            self.assertIn(sock.type,
-                          (socket.SOCK_STREAM | socket.SOCK_CLOEXEC,
-                           socket.SOCK_STREAM))
-        else:
-            self.assertEqual(sock.type, socket.SOCK_STREAM)
-        self.assertEqual(sock.proto, 0)
-        sock.close()
+        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
+            self.assertEqual(sock.family, socket.AF_INET)
+            if hasattr(socket, 'SOCK_CLOEXEC'):
+                self.assertIn(sock.type,
+                              (socket.SOCK_STREAM | socket.SOCK_CLOEXEC,
+                               socket.SOCK_STREAM))
+            else:
+                self.assertEqual(sock.type, socket.SOCK_STREAM)
+            self.assertEqual(sock.proto, 0)
 
     def test_getsockaddrarg(self):
         sock = socket.socket()
@@ -1400,10 +1394,9 @@ class GeneralModuleTests(unittest.TestCa
     def test_listen_backlog_overflow(self):
         # Issue 15989
         import _testcapi
-        srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        srv.bind((HOST, 0))
-        self.assertRaises(OverflowError, srv.listen, _testcapi.INT_MAX + 1)
-        srv.close()
+        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as srv:
+            srv.bind((HOST, 0))
+            self.assertRaises(OverflowError, srv.listen, _testcapi.INT_MAX + 1)
 
     @unittest.skipUnless(support.IPV6_ENABLED, 'IPv6 required for this test.')
     def test_flowinfo(self):
diff -r d478a2a5738a Lib/test/test_tarfile.py
--- a/Lib/test/test_tarfile.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Lib/test/test_tarfile.py	Fri Mar 20 14:17:30 2015 +0200
@@ -127,49 +127,47 @@ class UstarReadTest(ReadTest, unittest.T
             data = fobj.read()
 
         tarinfo = self.tar.getmember("ustar/regtype")
-        fobj = self.tar.extractfile(tarinfo)
-
-        text = fobj.read()
-        fobj.seek(0)
-        self.assertEqual(0, fobj.tell(),
-                     "seek() to file's start failed")
-        fobj.seek(2048, 0)
-        self.assertEqual(2048, fobj.tell(),
-                     "seek() to absolute position failed")
-        fobj.seek(-1024, 1)
-        self.assertEqual(1024, fobj.tell(),
-                     "seek() to negative relative position failed")
-        fobj.seek(1024, 1)
-        self.assertEqual(2048, fobj.tell(),
-                     "seek() to positive relative position failed")
-        s = fobj.read(10)
-        self.assertEqual(s, data[2048:2058],
-                     "read() after seek failed")
-        fobj.seek(0, 2)
-        self.assertEqual(tarinfo.size, fobj.tell(),
-                     "seek() to file's end failed")
-        self.assertEqual(fobj.read(), b"",
-                     "read() at file's end did not return empty string")
-        fobj.seek(-tarinfo.size, 2)
-        self.assertEqual(0, fobj.tell(),
-                     "relative seek() to file's end failed")
-        fobj.seek(512)
-        s1 = fobj.readlines()
-        fobj.seek(512)
-        s2 = fobj.readlines()
-        self.assertEqual(s1, s2,
-                     "readlines() after seek failed")
-        fobj.seek(0)
-        self.assertEqual(len(fobj.readline()), fobj.tell(),
-                     "tell() after readline() failed")
-        fobj.seek(512)
-        self.assertEqual(len(fobj.readline()) + 512, fobj.tell(),
-                     "tell() after seek() and readline() failed")
-        fobj.seek(0)
-        line = fobj.readline()
-        self.assertEqual(fobj.read(), data[len(line):],
-                     "read() after readline() failed")
-        fobj.close()
+        with self.tar.extractfile(tarinfo) as fobj:
+            text = fobj.read()
+            fobj.seek(0)
+            self.assertEqual(0, fobj.tell(),
+                         "seek() to file's start failed")
+            fobj.seek(2048, 0)
+            self.assertEqual(2048, fobj.tell(),
+                         "seek() to absolute position failed")
+            fobj.seek(-1024, 1)
+            self.assertEqual(1024, fobj.tell(),
+                         "seek() to negative relative position failed")
+            fobj.seek(1024, 1)
+            self.assertEqual(2048, fobj.tell(),
+                         "seek() to positive relative position failed")
+            s = fobj.read(10)
+            self.assertEqual(s, data[2048:2058],
+                         "read() after seek failed")
+            fobj.seek(0, 2)
+            self.assertEqual(tarinfo.size, fobj.tell(),
+                         "seek() to file's end failed")
+            self.assertEqual(fobj.read(), b"",
+                         "read() at file's end did not return empty string")
+            fobj.seek(-tarinfo.size, 2)
+            self.assertEqual(0, fobj.tell(),
+                         "relative seek() to file's end failed")
+            fobj.seek(512)
+            s1 = fobj.readlines()
+            fobj.seek(512)
+            s2 = fobj.readlines()
+            self.assertEqual(s1, s2,
+                         "readlines() after seek failed")
+            fobj.seek(0)
+            self.assertEqual(len(fobj.readline()), fobj.tell(),
+                         "tell() after readline() failed")
+            fobj.seek(512)
+            self.assertEqual(len(fobj.readline()) + 512, fobj.tell(),
+                         "tell() after seek() and readline() failed")
+            fobj.seek(0)
+            line = fobj.readline()
+            self.assertEqual(fobj.read(), data[len(line):],
+                         "read() after readline() failed")
 
     def test_fileobj_text(self):
         with self.tar.extractfile("ustar/regtype") as fobj:
@@ -437,15 +435,14 @@ class MiscReadTestBase(CommonReadTest):
             fobj.seek(offset)
 
             # Test if the tarfile starts with the second member.
-            tar = tar.open(self.tarname, mode="r:", fileobj=fobj)
-            t = tar.next()
-            self.assertEqual(t.name, name)
-            # Read to the end of fileobj and test if seeking back to the
-            # beginning works.
-            tar.getmembers()
-            self.assertEqual(tar.extractfile(t).read(), data,
-                    "seek back did not work")
-            tar.close()
+            with tar.open(self.tarname, mode="r:", fileobj=fobj) as tar:
+                t = tar.next()
+                self.assertEqual(t.name, name)
+                # Read to the end of fileobj and test if seeking back to the
+                # beginning works.
+                tar.getmembers()
+                self.assertEqual(tar.extractfile(t).read(), data,
+                        "seek back did not work")
 
     def test_fail_comp(self):
         # For Gzip and Bz2 Tests: fail with a ReadError on an uncompressed file.
@@ -968,9 +965,8 @@ class WriteTestBase(TarTest):
 
     def test_fileobj_no_close(self):
         fobj = io.BytesIO()
-        tar = tarfile.open(fileobj=fobj, mode=self.mode)
-        tar.addfile(tarfile.TarInfo("foo"))
-        tar.close()
+        with tarfile.open(fileobj=fobj, mode=self.mode) as tar:
+            tar.addfile(tarfile.TarInfo("foo"))
         self.assertFalse(fobj.closed, "external fileobjs must never closed")
         # Issue #20238: Incomplete gzip output with mode="w:gz"
         data = fobj.getvalue()
@@ -1210,19 +1206,16 @@ class WriteTest(WriteTestBase, unittest.
             with open(source_file,'w') as f:
                 f.write('something\n')
             os.symlink(source_file, target_file)
-            tar = tarfile.open(temparchive,'w')
-            tar.add(source_file)
-            tar.add(target_file)
-            tar.close()
+            with tarfile.open(temparchive, 'w') as tar:
+                tar.add(source_file)
+                tar.add(target_file)
             # Let's extract it to the location which contains the symlink
-            tar = tarfile.open(temparchive,'r')
-            # this should not raise OSError: [Errno 17] File exists
-            try:
-                tar.extractall(path=tempdir)
-            except OSError:
-                self.fail("extractall failed with symlinked files")
-            finally:
-                tar.close()
+            with tarfile.open(temparchive) as tar:
+                # this should not raise OSError: [Errno 17] File exists
+                try:
+                    tar.extractall(path=tempdir)
+                except OSError:
+                    self.fail("extractall failed with symlinked files")
         finally:
             support.unlink(temparchive)
             support.rmtree(tempdir)
diff -r d478a2a5738a Lib/test/test_uu.py
--- a/Lib/test/test_uu.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Lib/test/test_uu.py	Fri Mar 20 14:17:30 2015 +0200
@@ -172,26 +172,21 @@ class UUFileTest(unittest.TestCase):
         fin = fout = None
         try:
             support.unlink(self.tmpin)
-            fin = open(self.tmpin, 'wb')
-            fin.write(plaintext)
-            fin.close()
+            with open(self.tmpin, 'wb') as fin:
+                fin.write(plaintext)
 
-            fin = open(self.tmpin, 'rb')
-            fout = open(self.tmpout, 'wb')
-            uu.encode(fin, fout, self.tmpin, mode=0o644)
-            fin.close()
-            fout.close()
+            with open(self.tmpin, 'rb') as fin, \
+                 open(self.tmpout, 'wb') as fout:
+                uu.encode(fin, fout, self.tmpin, mode=0o644)
 
-            fout = open(self.tmpout, 'rb')
-            s = fout.read()
-            fout.close()
+            with open(self.tmpout, 'rb') as fout:
+                s = fout.read()
             self.assertEqual(s, encodedtextwrapped(0o644, self.tmpin))
 
             # in_file and out_file as filenames
             uu.encode(self.tmpin, self.tmpout, self.tmpin, mode=0o644)
-            fout = open(self.tmpout, 'rb')
-            s = fout.read()
-            fout.close()
+            with open(self.tmpout, 'rb') as fout:
+                s = fout.read()
             self.assertEqual(s, encodedtextwrapped(0o644, self.tmpin))
 
         finally:
@@ -202,17 +197,14 @@ class UUFileTest(unittest.TestCase):
         f = None
         try:
             support.unlink(self.tmpin)
-            f = open(self.tmpin, 'wb')
-            f.write(encodedtextwrapped(0o644, self.tmpout))
-            f.close()
+            with open(self.tmpin, 'wb') as f:
+                f.write(encodedtextwrapped(0o644, self.tmpout))
 
-            f = open(self.tmpin, 'rb')
-            uu.decode(f)
-            f.close()
+            with open(self.tmpin, 'rb') as f:
+                uu.decode(f)
 
-            f = open(self.tmpout, 'rb')
-            s = f.read()
-            f.close()
+            with open(self.tmpout, 'rb') as f:
+                s = f.read()
             self.assertEqual(s, plaintext)
             # XXX is there an xp way to verify the mode?
         finally:
@@ -222,15 +214,13 @@ class UUFileTest(unittest.TestCase):
         f = None
         try:
             support.unlink(self.tmpin)
-            f = open(self.tmpin, 'wb')
-            f.write(encodedtextwrapped(0o644, self.tmpout))
-            f.close()
+            with open(self.tmpin, 'wb') as f:
+                f.write(encodedtextwrapped(0o644, self.tmpout))
 
             uu.decode(self.tmpin)
 
-            f = open(self.tmpout, 'rb')
-            s = f.read()
-            f.close()
+            with open(self.tmpout, 'rb') as f:
+                s = f.read()
             self.assertEqual(s, plaintext)
         finally:
             self._kill(f)
@@ -241,13 +231,11 @@ class UUFileTest(unittest.TestCase):
         try:
             f = io.BytesIO(encodedtextwrapped(0o644, self.tmpout))
 
-            f = open(self.tmpin, 'rb')
-            uu.decode(f)
-            f.close()
+            with open(self.tmpin, 'rb') as f:
+                uu.decode(f)
 
-            f = open(self.tmpin, 'rb')
-            self.assertRaises(uu.Error, uu.decode, f)
-            f.close()
+            with open(self.tmpin, 'rb') as f:
+                self.assertRaises(uu.Error, uu.decode, f)
         finally:
             self._kill(f)
 
diff -r d478a2a5738a Lib/test/test_zipfile64.py
--- a/Lib/test/test_zipfile64.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Lib/test/test_zipfile64.py	Fri Mar 20 14:17:30 2015 +0200
@@ -32,42 +32,39 @@ class TestsWithSourceFile(unittest.TestC
         self.data = '\n'.join(line_gen).encode('ascii')
 
         # And write it to a file.
-        fp = open(TESTFN, "wb")
-        fp.write(self.data)
-        fp.close()
+        with open(TESTFN, "wb") as fp:
+            fp.write(self.data)
 
     def zipTest(self, f, compression):
         # Create the ZIP archive.
-        zipfp = zipfile.ZipFile(f, "w", compression)
+        with zipfile.ZipFile(f, "w", compression) as zipfp:
 
-        # It will contain enough copies of self.data to reach about 6GB of
-        # raw data to store.
-        filecount = 6*1024**3 // len(self.data)
+            # It will contain enough copies of self.data to reach about 6GB of
+            # raw data to store.
+            filecount = 6*1024**3 // len(self.data)
 
-        next_time = time.time() + _PRINT_WORKING_MSG_INTERVAL
-        for num in range(filecount):
-            zipfp.writestr("testfn%d" % num, self.data)
-            # Print still working message since this test can be really slow
-            if next_time <= time.time():
-                next_time = time.time() + _PRINT_WORKING_MSG_INTERVAL
-                print((
-                   '  zipTest still writing %d of %d, be patient...' %
-                   (num, filecount)), file=sys.__stdout__)
-                sys.__stdout__.flush()
-        zipfp.close()
+            next_time = time.time() + _PRINT_WORKING_MSG_INTERVAL
+            for num in range(filecount):
+                zipfp.writestr("testfn%d" % num, self.data)
+                # Print still working message since this test can be really slow
+                if next_time <= time.time():
+                    next_time = time.time() + _PRINT_WORKING_MSG_INTERVAL
+                    print((
+                       '  zipTest still writing %d of %d, be patient...' %
+                       (num, filecount)), file=sys.__stdout__)
+                    sys.__stdout__.flush()
 
         # Read the ZIP archive
-        zipfp = zipfile.ZipFile(f, "r", compression)
-        for num in range(filecount):
-            self.assertEqual(zipfp.read("testfn%d" % num), self.data)
-            # Print still working message since this test can be really slow
-            if next_time <= time.time():
-                next_time = time.time() + _PRINT_WORKING_MSG_INTERVAL
-                print((
-                   '  zipTest still reading %d of %d, be patient...' %
-                   (num, filecount)), file=sys.__stdout__)
-                sys.__stdout__.flush()
-        zipfp.close()
+        with zipfile.ZipFile(f, "r", compression) as zipfp:
+            for num in range(filecount):
+                self.assertEqual(zipfp.read("testfn%d" % num), self.data)
+                # Print still working message since this test can be really slow
+                if next_time <= time.time():
+                    next_time = time.time() + _PRINT_WORKING_MSG_INTERVAL
+                    print((
+                       '  zipTest still reading %d of %d, be patient...' %
+                       (num, filecount)), file=sys.__stdout__)
+                    sys.__stdout__.flush()
 
     def testStored(self):
         # Try the temp file first.  If we do TESTFN2 first, then it hogs
@@ -92,56 +89,50 @@ class OtherTests(unittest.TestCase):
     def testMoreThan64kFiles(self):
         # This test checks that more than 64k files can be added to an archive,
         # and that the resulting archive can be read properly by ZipFile
-        zipf = zipfile.ZipFile(TESTFN, mode="w", allowZip64=True)
-        zipf.debug = 100
-        numfiles = (1 << 16) * 3//2
-        for i in range(numfiles):
-            zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
-        self.assertEqual(len(zipf.namelist()), numfiles)
-        zipf.close()
+        with zipfile.ZipFile(TESTFN, mode="w", allowZip64=True) as zipf:
+            zipf.debug = 100
+            numfiles = (1 << 16) * 3//2
+            for i in range(numfiles):
+                zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
+            self.assertEqual(len(zipf.namelist()), numfiles)
 
-        zipf2 = zipfile.ZipFile(TESTFN, mode="r")
-        self.assertEqual(len(zipf2.namelist()), numfiles)
-        for i in range(numfiles):
-            content = zipf2.read("foo%08d" % i).decode('ascii')
-            self.assertEqual(content, "%d" % (i**3 % 57))
-        zipf2.close()
+        with zipfile.ZipFile(TESTFN, mode="r") as zipf2:
+            self.assertEqual(len(zipf2.namelist()), numfiles)
+            for i in range(numfiles):
+                content = zipf2.read("foo%08d" % i).decode('ascii')
+                self.assertEqual(content, "%d" % (i**3 % 57))
 
     def testMoreThan64kFilesAppend(self):
-        zipf = zipfile.ZipFile(TESTFN, mode="w", allowZip64=False)
-        zipf.debug = 100
-        numfiles = (1 << 16) - 1
-        for i in range(numfiles):
-            zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
-        self.assertEqual(len(zipf.namelist()), numfiles)
-        with self.assertRaises(zipfile.LargeZipFile):
-            zipf.writestr("foo%08d" % numfiles, b'')
-        self.assertEqual(len(zipf.namelist()), numfiles)
-        zipf.close()
+        with zipfile.ZipFile(TESTFN, mode="w", allowZip64=False) as zipf:
+            zipf.debug = 100
+            numfiles = (1 << 16) - 1
+            for i in range(numfiles):
+                zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
+            self.assertEqual(len(zipf.namelist()), numfiles)
+            with self.assertRaises(zipfile.LargeZipFile):
+                zipf.writestr("foo%08d" % numfiles, b'')
+            self.assertEqual(len(zipf.namelist()), numfiles)
 
-        zipf = zipfile.ZipFile(TESTFN, mode="a", allowZip64=False)
-        zipf.debug = 100
-        self.assertEqual(len(zipf.namelist()), numfiles)
-        with self.assertRaises(zipfile.LargeZipFile):
-            zipf.writestr("foo%08d" % numfiles, b'')
-        self.assertEqual(len(zipf.namelist()), numfiles)
-        zipf.close()
+        with zipfile.ZipFile(TESTFN, mode="a", allowZip64=False) as zipf:
+            zipf.debug = 100
+            self.assertEqual(len(zipf.namelist()), numfiles)
+            with self.assertRaises(zipfile.LargeZipFile):
+                zipf.writestr("foo%08d" % numfiles, b'')
+            self.assertEqual(len(zipf.namelist()), numfiles)
 
-        zipf = zipfile.ZipFile(TESTFN, mode="a", allowZip64=True)
-        zipf.debug = 100
-        self.assertEqual(len(zipf.namelist()), numfiles)
-        numfiles2 = (1 << 16) * 3//2
-        for i in range(numfiles, numfiles2):
-            zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
-        self.assertEqual(len(zipf.namelist()), numfiles2)
-        zipf.close()
+        with zipfile.ZipFile(TESTFN, mode="a", allowZip64=True) as zipf:
+            zipf.debug = 100
+            self.assertEqual(len(zipf.namelist()), numfiles)
+            numfiles2 = (1 << 16) * 3//2
+            for i in range(numfiles, numfiles2):
+                zipf.writestr("foo%08d" % i, "%d" % (i**3 % 57))
+            self.assertEqual(len(zipf.namelist()), numfiles2)
 
-        zipf2 = zipfile.ZipFile(TESTFN, mode="r")
-        self.assertEqual(len(zipf2.namelist()), numfiles2)
-        for i in range(numfiles2):
-            content = zipf2.read("foo%08d" % i).decode('ascii')
-            self.assertEqual(content, "%d" % (i**3 % 57))
-        zipf2.close()
+        with zipfile.ZipFile(TESTFN, mode="r") as zipf2:
+            self.assertEqual(len(zipf2.namelist()), numfiles2)
+            for i in range(numfiles2):
+                content = zipf2.read("foo%08d" % i).decode('ascii')
+                self.assertEqual(content, "%d" % (i**3 % 57))
 
     def tearDown(self):
         support.unlink(TESTFN)
-------------- next part --------------
diff -r d478a2a5738a Parser/asdl_c.py
--- a/Parser/asdl_c.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Parser/asdl_c.py	Fri Mar 20 15:28:09 2015 +0200
@@ -1252,41 +1252,39 @@ def main(srcfile, dump_module=False):
         sys.exit(1)
     if INC_DIR:
         p = "%s/%s-ast.h" % (INC_DIR, mod.name)
-        f = open(p, "w")
-        f.write(auto_gen_msg)
-        f.write('#include "asdl.h"\n\n')
-        c = ChainOfVisitors(TypeDefVisitor(f),
-                            StructVisitor(f),
-                            PrototypeVisitor(f),
-                            )
-        c.visit(mod)
-        f.write("PyObject* PyAST_mod2obj(mod_ty t);\n")
-        f.write("mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);\n")
-        f.write("int PyAST_Check(PyObject* obj);\n")
-        f.close()
+        with open(p, "w") as f:
+            f.write(auto_gen_msg)
+            f.write('#include "asdl.h"\n\n')
+            c = ChainOfVisitors(TypeDefVisitor(f),
+                                StructVisitor(f),
+                                PrototypeVisitor(f),
+                                )
+            c.visit(mod)
+            f.write("PyObject* PyAST_mod2obj(mod_ty t);\n")
+            f.write("mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);\n")
+            f.write("int PyAST_Check(PyObject* obj);\n")
 
     if SRC_DIR:
         p = os.path.join(SRC_DIR, str(mod.name) + "-ast.c")
-        f = open(p, "w")
-        f.write(auto_gen_msg)
-        f.write('#include <stddef.h>\n')
-        f.write('\n')
-        f.write('#include "Python.h"\n')
-        f.write('#include "%s-ast.h"\n' % mod.name)
-        f.write('\n')
-        f.write("static PyTypeObject AST_type;\n")
-        v = ChainOfVisitors(
-            PyTypesDeclareVisitor(f),
-            PyTypesVisitor(f),
-            Obj2ModPrototypeVisitor(f),
-            FunctionVisitor(f),
-            ObjVisitor(f),
-            Obj2ModVisitor(f),
-            ASTModuleVisitor(f),
-            PartingShots(f),
-            )
-        v.visit(mod)
-        f.close()
+        with open(p, "w") as f:
+            f.write(auto_gen_msg)
+            f.write('#include <stddef.h>\n')
+            f.write('\n')
+            f.write('#include "Python.h"\n')
+            f.write('#include "%s-ast.h"\n' % mod.name)
+            f.write('\n')
+            f.write("static PyTypeObject AST_type;\n")
+            v = ChainOfVisitors(
+                PyTypesDeclareVisitor(f),
+                PyTypesVisitor(f),
+                Obj2ModPrototypeVisitor(f),
+                FunctionVisitor(f),
+                ObjVisitor(f),
+                Obj2ModVisitor(f),
+                ASTModuleVisitor(f),
+                PartingShots(f),
+                )
+            v.visit(mod)
 
 if __name__ == "__main__":
     import sys
diff -r d478a2a5738a Tools/scripts/fixcid.py
--- a/Tools/scripts/fixcid.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/fixcid.py	Fri Mar 20 15:28:09 2015 +0200
@@ -279,36 +279,36 @@ def addsubst(substfile):
     except IOError as msg:
         err(substfile + ': cannot read substfile: ' + str(msg) + '\n')
         sys.exit(1)
-    lineno = 0
-    while 1:
-        line = fp.readline()
-        if not line: break
-        lineno = lineno + 1
-        try:
-            i = line.index('#')
-        except ValueError:
-            i = -1          # Happens to delete trailing \n
-        words = line[:i].split()
-        if not words: continue
-        if len(words) == 3 and words[0] == 'struct':
-            words[:2] = [words[0] + ' ' + words[1]]
-        elif len(words) != 2:
-            err(substfile + '%s:%r: warning: bad line: %r' % (substfile, lineno, line))
-            continue
-        if Reverse:
-            [value, key] = words
-        else:
-            [key, value] = words
-        if value[0] == '*':
-            value = value[1:]
-        if key[0] == '*':
-            key = key[1:]
-            NotInComment[key] = value
-        if key in Dict:
-            err('%s:%r: warning: overriding: %r %r\n' % (substfile, lineno, key, value))
-            err('%s:%r: warning: previous: %r\n' % (substfile, lineno, Dict[key]))
-        Dict[key] = value
-    fp.close()
+    with fp:
+        lineno = 0
+        while 1:
+            line = fp.readline()
+            if not line: break
+            lineno = lineno + 1
+            try:
+                i = line.index('#')
+            except ValueError:
+                i = -1          # Happens to delete trailing \n
+            words = line[:i].split()
+            if not words: continue
+            if len(words) == 3 and words[0] == 'struct':
+                words[:2] = [words[0] + ' ' + words[1]]
+            elif len(words) != 2:
+                err(substfile + '%s:%r: warning: bad line: %r' % (substfile, lineno, line))
+                continue
+            if Reverse:
+                [value, key] = words
+            else:
+                [key, value] = words
+            if value[0] == '*':
+                value = value[1:]
+            if key[0] == '*':
+                key = key[1:]
+                NotInComment[key] = value
+            if key in Dict:
+                err('%s:%r: warning: overriding: %r %r\n' % (substfile, lineno, key, value))
+                err('%s:%r: warning: previous: %r\n' % (substfile, lineno, Dict[key]))
+            Dict[key] = value
 
 if __name__ == '__main__':
     main()
diff -r d478a2a5738a Tools/scripts/fixdiv.py
--- a/Tools/scripts/fixdiv.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/fixdiv.py	Fri Mar 20 15:28:09 2015 +0200
@@ -185,21 +185,21 @@ def readwarnings(warningsfile):
         sys.stderr.write("can't open: %s\n" % msg)
         return
     warnings = {}
-    while 1:
-        line = f.readline()
-        if not line:
-            break
-        m = prog.match(line)
-        if not m:
-            if line.find("division") >= 0:
-                sys.stderr.write("Warning: ignored input " + line)
-            continue
-        filename, lineno, what = m.groups()
-        list = warnings.get(filename)
-        if list is None:
-            warnings[filename] = list = []
-        list.append((int(lineno), sys.intern(what)))
-    f.close()
+    with f:
+        while 1:
+            line = f.readline()
+            if not line:
+                break
+            m = prog.match(line)
+            if not m:
+                if line.find("division") >= 0:
+                    sys.stderr.write("Warning: ignored input " + line)
+                continue
+            filename, lineno, what = m.groups()
+            list = warnings.get(filename)
+            if list is None:
+                warnings[filename] = list = []
+            list.append((int(lineno), sys.intern(what)))
     return warnings
 
 def process(filename, list):
@@ -210,84 +210,84 @@ def process(filename, list):
     except IOError as msg:
         sys.stderr.write("can't open: %s\n" % msg)
         return 1
-    print("Index:", filename)
-    f = FileContext(fp)
-    list.sort()
-    index = 0 # list[:index] has been processed, list[index:] is still to do
-    g = tokenize.generate_tokens(f.readline)
-    while 1:
-        startlineno, endlineno, slashes = lineinfo = scanline(g)
-        if startlineno is None:
-            break
-        assert startlineno <= endlineno is not None
-        orphans = []
-        while index < len(list) and list[index][0] < startlineno:
-            orphans.append(list[index])
-            index += 1
-        if orphans:
-            reportphantomwarnings(orphans, f)
-        warnings = []
-        while index < len(list) and list[index][0] <= endlineno:
-            warnings.append(list[index])
-            index += 1
-        if not slashes and not warnings:
-            pass
-        elif slashes and not warnings:
-            report(slashes, "No conclusive evidence")
-        elif warnings and not slashes:
-            reportphantomwarnings(warnings, f)
-        else:
-            if len(slashes) > 1:
-                if not multi_ok:
-                    rows = []
-                    lastrow = None
-                    for (row, col), line in slashes:
-                        if row == lastrow:
-                            continue
-                        rows.append(row)
-                        lastrow = row
-                    assert rows
-                    if len(rows) == 1:
-                        print("*** More than one / operator in line", rows[0])
+    with fp:
+        print("Index:", filename)
+        f = FileContext(fp)
+        list.sort()
+        index = 0 # list[:index] has been processed, list[index:] is still to do
+        g = tokenize.generate_tokens(f.readline)
+        while 1:
+            startlineno, endlineno, slashes = lineinfo = scanline(g)
+            if startlineno is None:
+                break
+            assert startlineno <= endlineno is not None
+            orphans = []
+            while index < len(list) and list[index][0] < startlineno:
+                orphans.append(list[index])
+                index += 1
+            if orphans:
+                reportphantomwarnings(orphans, f)
+            warnings = []
+            while index < len(list) and list[index][0] <= endlineno:
+                warnings.append(list[index])
+                index += 1
+            if not slashes and not warnings:
+                pass
+            elif slashes and not warnings:
+                report(slashes, "No conclusive evidence")
+            elif warnings and not slashes:
+                reportphantomwarnings(warnings, f)
+            else:
+                if len(slashes) > 1:
+                    if not multi_ok:
+                        rows = []
+                        lastrow = None
+                        for (row, col), line in slashes:
+                            if row == lastrow:
+                                continue
+                            rows.append(row)
+                            lastrow = row
+                        assert rows
+                        if len(rows) == 1:
+                            print("*** More than one / operator in line", rows[0])
+                        else:
+                            print("*** More than one / operator per statement", end=' ')
+                            print("in lines %d-%d" % (rows[0], rows[-1]))
+                intlong = []
+                floatcomplex = []
+                bad = []
+                for lineno, what in warnings:
+                    if what in ("int", "long"):
+                        intlong.append(what)
+                    elif what in ("float", "complex"):
+                        floatcomplex.append(what)
                     else:
-                        print("*** More than one / operator per statement", end=' ')
-                        print("in lines %d-%d" % (rows[0], rows[-1]))
-            intlong = []
-            floatcomplex = []
-            bad = []
-            for lineno, what in warnings:
-                if what in ("int", "long"):
-                    intlong.append(what)
-                elif what in ("float", "complex"):
-                    floatcomplex.append(what)
-                else:
-                    bad.append(what)
-            lastrow = None
-            for (row, col), line in slashes:
-                if row == lastrow:
-                    continue
-                lastrow = row
-                line = chop(line)
-                if line[col:col+1] != "/":
-                    print("*** Can't find the / operator in line %d:" % row)
-                    print("*", line)
-                    continue
-                if bad:
-                    print("*** Bad warning for line %d:" % row, bad)
-                    print("*", line)
-                elif intlong and not floatcomplex:
-                    print("%dc%d" % (row, row))
-                    print("<", line)
-                    print("---")
-                    print(">", line[:col] + "/" + line[col:])
-                elif floatcomplex and not intlong:
-                    print("True division / operator at line %d:" % row)
-                    print("=", line)
-                elif intlong and floatcomplex:
-                    print("*** Ambiguous / operator (%s, %s) at line %d:" % (
-                        "|".join(intlong), "|".join(floatcomplex), row))
-                    print("?", line)
-    fp.close()
+                        bad.append(what)
+                lastrow = None
+                for (row, col), line in slashes:
+                    if row == lastrow:
+                        continue
+                    lastrow = row
+                    line = chop(line)
+                    if line[col:col+1] != "/":
+                        print("*** Can't find the / operator in line %d:" % row)
+                        print("*", line)
+                        continue
+                    if bad:
+                        print("*** Bad warning for line %d:" % row, bad)
+                        print("*", line)
+                    elif intlong and not floatcomplex:
+                        print("%dc%d" % (row, row))
+                        print("<", line)
+                        print("---")
+                        print(">", line[:col] + "/" + line[col:])
+                    elif floatcomplex and not intlong:
+                        print("True division / operator at line %d:" % row)
+                        print("=", line)
+                    elif intlong and floatcomplex:
+                        print("*** Ambiguous / operator (%s, %s) at line %d:" %
+                            ("|".join(intlong), "|".join(floatcomplex), row))
+                        print("?", line)
 
 def reportphantomwarnings(warnings, f):
     blocks = []
diff -r d478a2a5738a Tools/scripts/fixheader.py
--- a/Tools/scripts/fixheader.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/fixheader.py	Fri Mar 20 15:28:09 2015 +0200
@@ -15,8 +15,8 @@ def process(filename):
     except IOError as msg:
         sys.stderr.write('%s: can\'t open: %s\n' % (filename, str(msg)))
         return
-    data = f.read()
-    f.close()
+    with f:
+        data = f.read()
     if data[:2] != '/*':
         sys.stderr.write('%s does not begin with C comment\n' % filename)
         return
@@ -31,19 +31,19 @@ def process(filename):
         if ord(c)<=0x80 and c.isalnum():
             magic = magic + c.upper()
         else: magic = magic + '_'
-    sys.stdout = f
-    print('#ifndef', magic)
-    print('#define', magic)
-    print('#ifdef __cplusplus')
-    print('extern "C" {')
-    print('#endif')
-    print()
-    f.write(data)
-    print()
-    print('#ifdef __cplusplus')
-    print('}')
-    print('#endif')
-    print('#endif /*', '!'+magic, '*/')
+    with f:
+        print('#ifndef', magic, file=f)
+        print('#define', magic, file=f)
+        print('#ifdef __cplusplus', file=f)
+        print('extern "C" {', file=f)
+        print('#endif', file=f)
+        print(file=f)
+        f.write(data)
+        print(file=f)
+        print('#ifdef __cplusplus', file=f)
+        print('}', file=f)
+        print('#endif', file=f)
+        print('#endif /*', '!'+magic, '*/', file=f)
 
 if __name__ == '__main__':
     main()
diff -r d478a2a5738a Tools/scripts/gprof2html.py
--- a/Tools/scripts/gprof2html.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/gprof2html.py	Fri Mar 20 15:28:09 2015 +0200
@@ -28,14 +28,7 @@ def add_escapes(filename):
         for line in fp:
             yield html.escape(line)
 
-
-def main():
-    filename = "gprof.out"
-    if sys.argv[1:]:
-        filename = sys.argv[1]
-    outputfilename = filename + ".html"
-    input = add_escapes(filename)
-    output = open(outputfilename, "w")
+def gprof2html(input, output, filename):
     output.write(header % filename)
     for line in input:
         output.write(line)
@@ -78,7 +71,16 @@ def main():
                 part = '<a href="#call:%s">%s</a>' % (part, part)
             output.write(part)
     output.write(trailer)
-    output.close()
+
+
+def main():
+    filename = "gprof.out"
+    if sys.argv[1:]:
+        filename = sys.argv[1]
+    outputfilename = filename + ".html"
+    input = add_escapes(filename)
+    with open(outputfilename, "w") as output:
+        gprof2html(input, output, filename)
     webbrowser.open("file:" + os.path.abspath(outputfilename))
 
 if __name__ == '__main__':
diff -r d478a2a5738a Tools/scripts/texi2html.py
--- a/Tools/scripts/texi2html.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/texi2html.py	Fri Mar 20 15:28:09 2015 +0200
@@ -118,11 +118,10 @@ class HTMLNode:
             self.lines.append(line)
 
     def flush(self):
-        fp = open(self.dirname + '/' + makefile(self.name), 'w')
-        fp.write(self.prologue)
-        fp.write(self.text)
-        fp.write(self.epilogue)
-        fp.close()
+        with open(self.dirname + '/' + makefile(self.name), 'w') as fp:
+            fp.write(self.prologue)
+            fp.write(self.text)
+            fp.write(self.epilogue)
 
     def link(self, label, nodename, rel=None, rev=None):
         if nodename:
@@ -558,14 +557,14 @@ class TexinfoParser:
         except IOError as msg:
             print('*** Can\'t open include file', repr(file))
             return
-        print('!'*self.debugging, '--> file', repr(file))
-        save_done = self.done
-        save_skip = self.skip
-        save_stack = self.stack
-        self.includedepth = self.includedepth + 1
-        self.parserest(fp, 0)
-        self.includedepth = self.includedepth - 1
-        fp.close()
+        with fp:
+            print('!'*self.debugging, '--> file', repr(file))
+            save_done = self.done
+            save_skip = self.skip
+            save_stack = self.stack
+            self.includedepth = self.includedepth + 1
+            self.parserest(fp, 0)
+            self.includedepth = self.includedepth - 1
         self.done = save_done
         self.skip = save_skip
         self.stack = save_stack
@@ -1770,78 +1769,75 @@ class HTMLHelp:
 
         # PROJECT FILE
         try:
-            fp = open(projectfile,'w')
-            print('[OPTIONS]', file=fp)
-            print('Auto Index=Yes', file=fp)
-            print('Binary TOC=No', file=fp)
-            print('Binary Index=Yes', file=fp)
-            print('Compatibility=1.1', file=fp)
-            print('Compiled file=' + resultfile + '', file=fp)
-            print('Contents file=' + contentfile + '', file=fp)
-            print('Default topic=' + defaulttopic + '', file=fp)
-            print('Error log file=ErrorLog.log', file=fp)
-            print('Index file=' + indexfile + '', file=fp)
-            print('Title=' + title + '', file=fp)
-            print('Display compile progress=Yes', file=fp)
-            print('Full-text search=Yes', file=fp)
-            print('Default window=main', file=fp)
-            print('', file=fp)
-            print('[WINDOWS]', file=fp)
-            print('main=,"' + contentfile + '","' + indexfile
-                        + '","","",,,,,0x23520,222,0x1046,[10,10,780,560],'
-                        '0xB0000,,,,,,0', file=fp)
-            print('', file=fp)
-            print('[FILES]', file=fp)
-            print('', file=fp)
-            self.dumpfiles(fp)
-            fp.close()
+            with open(projectfile, 'w') as fp:
+                print('[OPTIONS]', file=fp)
+                print('Auto Index=Yes', file=fp)
+                print('Binary TOC=No', file=fp)
+                print('Binary Index=Yes', file=fp)
+                print('Compatibility=1.1', file=fp)
+                print('Compiled file=' + resultfile + '', file=fp)
+                print('Contents file=' + contentfile + '', file=fp)
+                print('Default topic=' + defaulttopic + '', file=fp)
+                print('Error log file=ErrorLog.log', file=fp)
+                print('Index file=' + indexfile + '', file=fp)
+                print('Title=' + title + '', file=fp)
+                print('Display compile progress=Yes', file=fp)
+                print('Full-text search=Yes', file=fp)
+                print('Default window=main', file=fp)
+                print('', file=fp)
+                print('[WINDOWS]', file=fp)
+                print('main=,"' + contentfile + '","' + indexfile
+                            + '","","",,,,,0x23520,222,0x1046,[10,10,780,560],'
+                            '0xB0000,,,,,,0', file=fp)
+                print('', file=fp)
+                print('[FILES]', file=fp)
+                print('', file=fp)
+                self.dumpfiles(fp)
         except IOError as msg:
             print(projectfile, ':', msg)
             sys.exit(1)
 
         # CONTENT FILE
         try:
-            fp = open(contentfile,'w')
-            print('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">', file=fp)
-            print('<!-- This file defines the table of contents -->', file=fp)
-            print('<HTML>', file=fp)
-            print('<HEAD>', file=fp)
-            print('<meta name="GENERATOR"'
-                        'content="Microsoft® HTML Help Workshop 4.1">', file=fp)
-            print('<!-- Sitemap 1.0 -->', file=fp)
-            print('</HEAD>', file=fp)
-            print('<BODY>', file=fp)
-            print('   <OBJECT type="text/site properties">', file=fp)
-            print('     <param name="Window Styles" value="0x800025">', file=fp)
-            print('     <param name="comment" value="title:">', file=fp)
-            print('     <param name="comment" value="base:">', file=fp)
-            print('   </OBJECT>', file=fp)
-            self.dumpnodes(fp)
-            print('</BODY>', file=fp)
-            print('</HTML>', file=fp)
-            fp.close()
+            with open(contentfile, 'w') as fp:
+                print('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">', file=fp)
+                print('<!-- This file defines the table of contents -->', file=fp)
+                print('<HTML>', file=fp)
+                print('<HEAD>', file=fp)
+                print('<meta name="GENERATOR" '
+                      'content="Microsoft® HTML Help Workshop 4.1">', file=fp)
+                print('<!-- Sitemap 1.0 -->', file=fp)
+                print('</HEAD>', file=fp)
+                print('<BODY>', file=fp)
+                print('   <OBJECT type="text/site properties">', file=fp)
+                print('     <param name="Window Styles" value="0x800025">', file=fp)
+                print('     <param name="comment" value="title:">', file=fp)
+                print('     <param name="comment" value="base:">', file=fp)
+                print('   </OBJECT>', file=fp)
+                self.dumpnodes(fp)
+                print('</BODY>', file=fp)
+                print('</HTML>', file=fp)
         except IOError as msg:
             print(contentfile, ':', msg)
             sys.exit(1)
 
         # INDEX FILE
         try:
-            fp = open(indexfile  ,'w')
-            print('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">', file=fp)
-            print('<!-- This file defines the index -->', file=fp)
-            print('<HTML>', file=fp)
-            print('<HEAD>', file=fp)
-            print('<meta name="GENERATOR"'
-                        'content="Microsoft® HTML Help Workshop 4.1">', file=fp)
-            print('<!-- Sitemap 1.0 -->', file=fp)
-            print('</HEAD>', file=fp)
-            print('<BODY>', file=fp)
-            print('<OBJECT type="text/site properties">', file=fp)
-            print('</OBJECT>', file=fp)
-            self.dumpindex(fp)
-            print('</BODY>', file=fp)
-            print('</HTML>', file=fp)
-            fp.close()
+            with open(indexfile, 'w') as fp:
+                print('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">', file=fp)
+                print('<!-- This file defines the index -->', file=fp)
+                print('<HTML>', file=fp)
+                print('<HEAD>', file=fp)
+                print('<meta name="GENERATOR" '
+                      'content="Microsoft® HTML Help Workshop 4.1">', file=fp)
+                print('<!-- Sitemap 1.0 -->', file=fp)
+                print('</HEAD>', file=fp)
+                print('<BODY>', file=fp)
+                print('<OBJECT type="text/site properties">', file=fp)
+                print('</OBJECT>', file=fp)
+                self.dumpindex(fp)
+                print('</BODY>', file=fp)
+                print('</HTML>', file=fp)
         except IOError as msg:
             print(indexfile  , ':', msg)
             sys.exit(1)
@@ -2064,8 +2060,8 @@ def test():
         print(file, ':', msg)
         sys.exit(1)
 
-    parser.parse(fp)
-    fp.close()
+    with fp:
+        parser.parse(fp)
     parser.report()
 
     htmlhelp.finalize()
-------------- next part --------------
diff -r d478a2a5738a Tools/demo/markov.py
--- a/Tools/demo/markov.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/demo/markov.py	Fri Mar 20 12:55:59 2015 +0200
@@ -79,8 +79,8 @@ def test():
             else:
                 f = open(filename, 'r')
             if debug: print('processing', filename, '...')
-            text = f.read()
-            f.close()
+            with f:
+                text = f.read()
             paralist = text.split('\n\n')
             for para in paralist:
                 if debug > 1: print('feeding ...')
diff -r d478a2a5738a Tools/demo/rpython.py
--- a/Tools/demo/rpython.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/demo/rpython.py	Fri Mar 20 12:55:59 2015 +0200
@@ -22,17 +22,16 @@ def main():
         port = int(port[i+1:])
         host = host[:i]
     command = ' '.join(sys.argv[2:])
-    s = socket(AF_INET, SOCK_STREAM)
-    s.connect((host, port))
-    s.send(command.encode())
-    s.shutdown(SHUT_WR)
-    reply = b''
-    while True:
-        data = s.recv(BUFSIZE)
-        if not data:
-            break
-        reply += data
-    print(reply.decode(), end=' ')
-    s.close()
+    with socket(AF_INET, SOCK_STREAM) as s:
+        s.connect((host, port))
+        s.send(command.encode())
+        s.shutdown(SHUT_WR)
+        reply = b''
+        while True:
+            data = s.recv(BUFSIZE)
+            if not data:
+                break
+            reply += data
+        print(reply.decode(), end=' ')
 
 main()
diff -r d478a2a5738a Tools/demo/rpythond.py
--- a/Tools/demo/rpythond.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/demo/rpythond.py	Fri Mar 20 12:55:59 2015 +0200
@@ -26,16 +26,16 @@ def main():
     s.listen(1)
     while True:
         conn, (remotehost, remoteport) = s.accept()
-        print('connection from', remotehost, remoteport)
-        request = b''
-        while 1:
-            data = conn.recv(BUFSIZE)
-            if not data:
-                break
-            request += data
-        reply = execute(request.decode())
-        conn.send(reply.encode())
-        conn.close()
+        with conn:
+            print('connection from', remotehost, remoteport)
+            request = b''
+            while 1:
+                data = conn.recv(BUFSIZE)
+                if not data:
+                    break
+                request += data
+            reply = execute(request.decode())
+            conn.send(reply.encode())
 
 def execute(request):
     stdout = sys.stdout
diff -r d478a2a5738a Tools/freeze/checkextensions_win32.py
--- a/Tools/freeze/checkextensions_win32.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/freeze/checkextensions_win32.py	Fri Mar 20 12:55:59 2015 +0200
@@ -130,7 +130,8 @@ def parse_dsp(dsp):
     ret = []
     dsp_path, dsp_name = os.path.split(dsp)
     try:
-        lines = open(dsp, "r").readlines()
+        with open(dsp, "r") as fp:
+            lines = fp.readlines()
     except IOError as msg:
         sys.stderr.write("%s: %s\n" % (dsp, msg))
         return None
diff -r d478a2a5738a Tools/freeze/freeze.py
--- a/Tools/freeze/freeze.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/freeze/freeze.py	Fri Mar 20 12:55:59 2015 +0200
@@ -144,7 +144,8 @@ def main():
         # last option can not be "-i", so this ensures "pos+1" is in range!
         if sys.argv[pos] == '-i':
             try:
-                options = open(sys.argv[pos+1]).read().split()
+                with open(sys.argv[pos+1]) as infp:
+                    options = infp.read().split()
             except IOError as why:
                 usage("File name '%s' specified with the -i option "
                       "can not be read - %s" % (sys.argv[pos+1], why) )
diff -r d478a2a5738a Tools/i18n/msgfmt.py
--- a/Tools/i18n/msgfmt.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/i18n/msgfmt.py	Fri Mar 20 12:55:59 2015 +0200
@@ -109,7 +109,8 @@ def make(filename, outfile):
         outfile = os.path.splitext(infile)[0] + '.mo'
 
     try:
-        lines = open(infile, 'rb').readlines()
+        with open(infile, 'rb') as f:
+            lines = f.readlines()
     except IOError as msg:
         print(msg, file=sys.stderr)
         sys.exit(1)
@@ -199,7 +200,8 @@ def make(filename, outfile):
     output = generate()
 
     try:
-        open(outfile,"wb").write(output)
+        with open(outfile,"wb") as f:
+            f.write(output)
     except IOError as msg:
         print(msg, file=sys.stderr)
 
diff -r d478a2a5738a Tools/i18n/pygettext.py
--- a/Tools/i18n/pygettext.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/i18n/pygettext.py	Fri Mar 20 12:55:59 2015 +0200
@@ -595,9 +595,8 @@ def main():
     # initialize list of strings to exclude
     if options.excludefilename:
         try:
-            fp = open(options.excludefilename)
-            options.toexclude = fp.readlines()
-            fp.close()
+            with open(options.excludefilename) as fp:
+                options.toexclude = fp.readlines()
         except IOError:
             print(_(
                 "Can't read --exclude-file: %s") % options.excludefilename, file=sys.stderr)
diff -r d478a2a5738a Tools/pybench/pybench.py
--- a/Tools/pybench/pybench.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/pybench/pybench.py	Fri Mar 20 12:55:59 2015 +0200
@@ -893,10 +893,9 @@ python pybench.py -s p25.pybench -c p21.
 
         if compare_to:
             try:
-                f = open(compare_to,'rb')
-                bench = pickle.load(f)
-                bench.name = compare_to
-                f.close()
+                with open(compare_to,'rb') as f:
+                    bench = pickle.load(f)
+                    bench.name = compare_to
                 compare_to = bench
             except IOError as reason:
                 print('* Error opening/reading file %s: %s' % (
@@ -906,10 +905,9 @@ python pybench.py -s p25.pybench -c p21.
 
         if show_bench:
             try:
-                f = open(show_bench,'rb')
-                bench = pickle.load(f)
-                bench.name = show_bench
-                f.close()
+                with open(show_bench,'rb') as f:
+                    bench = pickle.load(f)
+                    bench.name = show_bench
                 bench.print_header()
                 if compare_to:
                     bench.print_comparison(compare_to,
@@ -960,10 +958,9 @@ python pybench.py -s p25.pybench -c p21.
 
         if reportfile:
             try:
-                f = open(reportfile,'wb')
-                bench.name = reportfile
-                pickle.dump(bench,f)
-                f.close()
+                with open(reportfile,'wb') as f:
+                    bench.name = reportfile
+                    pickle.dump(bench,f)
             except IOError as reason:
                 print('* Error opening/writing reportfile %s: %s' % (
                     reportfile,
diff -r d478a2a5738a Tools/scripts/cleanfuture.py
--- a/Tools/scripts/cleanfuture.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/cleanfuture.py	Fri Mar 20 12:55:59 2015 +0200
@@ -96,11 +96,11 @@ def check(file):
         errprint("%r: I/O Error: %s" % (file, str(msg)))
         return
 
-    ff = FutureFinder(f, file)
-    changed = ff.run()
-    if changed:
-        ff.gettherest()
-    f.close()
+    with f:
+        ff = FutureFinder(f, file)
+        changed = ff.run()
+        if changed:
+            ff.gettherest()
     if changed:
         if verbose:
             print("changed.")
@@ -122,9 +122,8 @@ def check(file):
             os.rename(file, bak)
             if verbose:
                 print("renamed", file, "to", bak)
-            g = open(file, "w")
-            ff.write(g)
-            g.close()
+            with open(file, "w") as g:
+                ff.write(g)
             if verbose:
                 print("wrote new", file)
     else:
diff -r d478a2a5738a Tools/scripts/combinerefs.py
--- a/Tools/scripts/combinerefs.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/combinerefs.py	Fri Mar 20 12:55:59 2015 +0200
@@ -85,9 +85,7 @@ def read(fileiter, pat, whilematch):
         else:
             break
 
-def combine(fname):
-    f = open(fname)
-
+def combinefile(f):
     fi = iter(f)
 
     for line in read(fi, re.compile(r'^Remaining objects:$'), False):
@@ -121,8 +119,11 @@ def combine(fname):
             print('[%s->%s]' % (addr2rc[addr], rc), end=' ')
         print(guts, addr2guts[addr])
 
-    f.close()
     print("%d objects before, %d after" % (before, after))
 
+def combine(fname):
+    with open(fname) as f:
+        combinefile(f)
+
 if __name__ == '__main__':
     combine(sys.argv[1])
diff -r d478a2a5738a Tools/scripts/dutree.py
--- a/Tools/scripts/dutree.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/dutree.py	Fri Mar 20 12:55:59 2015 +0200
@@ -4,18 +4,18 @@
 import os, sys, errno
 
 def main():
-    p = os.popen('du ' + ' '.join(sys.argv[1:]), 'r')
     total, d = None, {}
-    for line in p.readlines():
-        i = 0
-        while line[i] in '0123456789': i = i+1
-        size = eval(line[:i])
-        while line[i] in ' \t': i = i+1
-        filename = line[i:-1]
-        comps = filename.split('/')
-        if comps[0] == '': comps[0] = '/'
-        if comps[len(comps)-1] == '': del comps[len(comps)-1]
-        total, d = store(size, comps, total, d)
+    with os.popen('du ' + ' '.join(sys.argv[1:])) as p:
+        for line in p:
+            i = 0
+            while line[i] in '0123456789': i = i+1
+            size = eval(line[:i])
+            while line[i] in ' \t': i = i+1
+            filename = line[i:-1]
+            comps = filename.split('/')
+            if comps[0] == '': comps[0] = '/'
+            if comps[len(comps)-1] == '': del comps[len(comps)-1]
+            total, d = store(size, comps, total, d)
     try:
         display(total, d)
     except IOError as e:
diff -r d478a2a5738a Tools/scripts/eptags.py
--- a/Tools/scripts/eptags.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/eptags.py	Fri Mar 20 12:55:59 2015 +0200
@@ -28,29 +28,30 @@ def treat_file(filename, outfp):
     except:
         sys.stderr.write('Cannot open %s\n'%filename)
         return
-    charno = 0
-    lineno = 0
-    tags = []
-    size = 0
-    while 1:
-        line = fp.readline()
-        if not line:
-            break
-        lineno = lineno + 1
-        m = matcher.search(line)
-        if m:
-            tag = m.group(0) + '\177%d,%d\n' % (lineno, charno)
-            tags.append(tag)
-            size = size + len(tag)
-        charno = charno + len(line)
+    with fp:
+        charno = 0
+        lineno = 0
+        tags = []
+        size = 0
+        while 1:
+            line = fp.readline()
+            if not line:
+                break
+            lineno = lineno + 1
+            m = matcher.search(line)
+            if m:
+                tag = m.group(0) + '\177%d,%d\n' % (lineno, charno)
+                tags.append(tag)
+                size = size + len(tag)
+            charno = charno + len(line)
     outfp.write('\f\n%s,%d\n' % (filename,size))
     for tag in tags:
         outfp.write(tag)
 
 def main():
-    outfp = open('TAGS', 'w')
-    for filename in sys.argv[1:]:
-        treat_file(filename, outfp)
+    with open('TAGS', 'w') as outfp:
+        for filename in sys.argv[1:]:
+            treat_file(filename, outfp)
 
 if __name__=="__main__":
     main()
diff -r d478a2a5738a Tools/scripts/finddiv.py
--- a/Tools/scripts/finddiv.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/finddiv.py	Fri Mar 20 12:55:59 2015 +0200
@@ -55,17 +55,17 @@ def process(filename, listnames):
     except IOError as msg:
         sys.stderr.write("Can't open: %s\n" % msg)
         return 1
-    g = tokenize.generate_tokens(fp.readline)
-    lastrow = None
-    for type, token, (row, col), end, line in g:
-        if token in ("/", "/="):
-            if listnames:
-                print(filename)
-                break
-            if row != lastrow:
-                lastrow = row
-                print("%s:%d:%s" % (filename, row, line), end=' ')
-    fp.close()
+    with fp:
+        g = tokenize.generate_tokens(fp.readline)
+        lastrow = None
+        for type, token, (row, col), end, line in g:
+            if token in ("/", "/="):
+                if listnames:
+                    print(filename)
+                    break
+                if row != lastrow:
+                    lastrow = row
+                    print("%s:%d:%s" % (filename, row, line), end=' ')
 
 def processdir(dir, listnames):
     try:
diff -r d478a2a5738a Tools/scripts/fixnotice.py
--- a/Tools/scripts/fixnotice.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/fixnotice.py	Fri Mar 20 12:55:59 2015 +0200
@@ -73,22 +73,19 @@ def main():
         elif opt == '--dry-run':
             DRYRUN = 1
         elif opt == '--oldnotice':
-            fp = open(arg)
-            OLD_NOTICE = fp.read()
-            fp.close()
+            with open(arg) as fp:
+                OLD_NOTICE = fp.read()
         elif opt == '--newnotice':
-            fp = open(arg)
-            NEW_NOTICE = fp.read()
-            fp.close()
+            with open(arg) as fp:
+                NEW_NOTICE = fp.read()
 
     for arg in args:
         process(arg)
 
 
 def process(file):
-    f = open(file)
-    data = f.read()
-    f.close()
+    with open(file) as f:
+        data = f.read()
     i = data.find(OLD_NOTICE)
     if i < 0:
         if VERBOSE:
@@ -102,9 +99,8 @@ def process(file):
     data = data[:i] + NEW_NOTICE + data[i+len(OLD_NOTICE):]
     new = file + ".new"
     backup = file + ".bak"
-    f = open(new, "w")
-    f.write(data)
-    f.close()
+    with open(new, "w") as f:
+        f.write(data)
     os.rename(file, backup)
     os.rename(new, file)
 
diff -r d478a2a5738a Tools/scripts/fixps.py
--- a/Tools/scripts/fixps.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/fixps.py	Fri Mar 20 12:55:59 2015 +0200
@@ -14,20 +14,18 @@ def main():
         except IOError as msg:
             print(filename, ': can\'t open :', msg)
             continue
-        line = f.readline()
-        if not re.match('^#! */usr/local/bin/python', line):
-            print(filename, ': not a /usr/local/bin/python script')
-            f.close()
-            continue
-        rest = f.read()
-        f.close()
+        with f:
+            line = f.readline()
+            if not re.match('^#! */usr/local/bin/python', line):
+                print(filename, ': not a /usr/local/bin/python script')
+                continue
+            rest = f.read()
         line = re.sub('/usr/local/bin/python',
                       '/usr/bin/env python', line)
         print(filename, ':', repr(line))
-        f = open(filename, "w")
-        f.write(line)
-        f.write(rest)
-        f.close()
+        with open(filename, "w") as f:
+            f.write(line)
+            f.write(rest)
 
 if __name__ == '__main__':
     main()
diff -r d478a2a5738a Tools/scripts/get-remote-certificate.py
--- a/Tools/scripts/get-remote-certificate.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/get-remote-certificate.py	Fri Mar 20 12:55:59 2015 +0200
@@ -29,9 +29,8 @@ def fetch_server_certificate (host, port
             return None
         else:
             tn = tempfile.mktemp()
-            fp = open(tn, "wb")
-            fp.write(m.group(1) + b"\n")
-            fp.close()
+            with open(tn, "wb") as fp:
+                fp.write(m.group(1) + b"\n")
             try:
                 tn2 = (outfile or tempfile.mktemp())
                 status, output = subproc(r'openssl x509 -in "%s" -out "%s"' %
@@ -39,9 +38,8 @@ def fetch_server_certificate (host, port
                 if status != 0:
                     raise RuntimeError('OpenSSL x509 failed with status %s and '
                                        'output: %r' % (status, output))
-                fp = open(tn2, 'rb')
-                data = fp.read()
-                fp.close()
+                with open(tn2, 'rb') as fp:
+                    data = fp.read()
                 os.unlink(tn2)
                 return data
             finally:
@@ -49,9 +47,8 @@ def fetch_server_certificate (host, port
 
     if sys.platform.startswith("win"):
         tfile = tempfile.mktemp()
-        fp = open(tfile, "w")
-        fp.write("quit\n")
-        fp.close()
+        with open(tfile, "w") as fp:
+            fp.write("quit\n")
         try:
             status, output = subproc(
                 'openssl s_client -connect "%s:%s" -showcerts < "%s"' %
diff -r d478a2a5738a Tools/scripts/h2py.py
--- a/Tools/scripts/h2py.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/h2py.py	Fri Mar 20 12:55:59 2015 +0200
@@ -69,23 +69,21 @@ def main():
             sys.stdout.write('# Generated by h2py from stdin\n')
             process(sys.stdin, sys.stdout)
         else:
-            fp = open(filename, 'r')
-            outfile = os.path.basename(filename)
-            i = outfile.rfind('.')
-            if i > 0: outfile = outfile[:i]
-            modname = outfile.upper()
-            outfile = modname + '.py'
-            outfp = open(outfile, 'w')
-            outfp.write('# Generated by h2py from %s\n' % filename)
-            filedict = {}
-            for dir in searchdirs:
-                if filename[:len(dir)] == dir:
-                    filedict[filename[len(dir)+1:]] = None  # no '/' trailing
-                    importable[filename[len(dir)+1:]] = modname
-                    break
-            process(fp, outfp)
-            outfp.close()
-            fp.close()
+            with open(filename) as fp:
+                outfile = os.path.basename(filename)
+                i = outfile.rfind('.')
+                if i > 0: outfile = outfile[:i]
+                modname = outfile.upper()
+                outfile = modname + '.py'
+                with open(outfile, 'w') as outfp:
+                    outfp.write('# Generated by h2py from %s\n' % filename)
+                    filedict = {}
+                    for dir in searchdirs:
+                        if filename[:len(dir)] == dir:
+                            filedict[filename[len(dir)+1:]] = None  # no '/' trailing
+                            importable[filename[len(dir)+1:]] = modname
+                            break
+                    process(fp, outfp)
 
 def pytify(body):
     # replace ignored patterns by spaces
@@ -161,9 +159,10 @@ def process(fp, outfp, env = {}):
                     except IOError:
                         pass
                 if inclfp:
-                    outfp.write(
-                            '\n# Included from %s\n' % filename)
-                    process(inclfp, outfp, env)
+                    with inclfp:
+                        outfp.write(
+                                '\n# Included from %s\n' % filename)
+                        process(inclfp, outfp, env)
                 else:
                     sys.stderr.write('Warning - could not find file %s\n' %
                                      filename)
diff -r d478a2a5738a Tools/scripts/ifdef.py
--- a/Tools/scripts/ifdef.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/ifdef.py	Fri Mar 20 12:55:59 2015 +0200
@@ -45,9 +45,8 @@ def main():
         if filename == '-':
             process(sys.stdin, sys.stdout)
         else:
-            f = open(filename, 'r')
-            process(f, sys.stdout)
-            f.close()
+            with open(filename) as f:
+                process(f, sys.stdout)
 
 def process(fpi, fpo):
     keywords = ('if', 'ifdef', 'ifndef', 'else', 'endif')
diff -r d478a2a5738a Tools/scripts/md5sum.py
--- a/Tools/scripts/md5sum.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/md5sum.py	Fri Mar 20 12:55:59 2015 +0200
@@ -47,10 +47,10 @@ def printsum(filename, out=sys.stdout):
     except IOError as msg:
         sys.stderr.write('%s: Can\'t open: %s\n' % (filename, msg))
         return 1
-    if fnfilter:
-        filename = fnfilter(filename)
-    sts = printsumfp(fp, filename, out)
-    fp.close()
+    with fp:
+        if fnfilter:
+            filename = fnfilter(filename)
+        sts = printsumfp(fp, filename, out)
     return sts
 
 def printsumfp(fp, filename, out=sys.stdout):
diff -r d478a2a5738a Tools/scripts/mkreal.py
--- a/Tools/scripts/mkreal.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/mkreal.py	Fri Mar 20 12:55:59 2015 +0200
@@ -18,14 +18,13 @@ def mkrealfile(name):
     st = os.stat(name) # Get the mode
     mode = S_IMODE(st[ST_MODE])
     linkto = os.readlink(name) # Make sure again it's a symlink
-    f_in = open(name, 'r') # This ensures it's a file
-    os.unlink(name)
-    f_out = open(name, 'w')
-    while 1:
-        buf = f_in.read(BUFSIZE)
-        if not buf: break
-        f_out.write(buf)
-    del f_out # Flush data to disk before changing mode
+    with open(name, 'rb') as f_in: # This ensures it's a file
+        os.unlink(name)
+        with open(name, 'wb') as f_out:
+            while 1:
+                buf = f_in.read(BUFSIZE)
+                if not buf: break
+                f_out.write(buf)
     os.chmod(name, mode)
 
 def mkrealdir(name):
diff -r d478a2a5738a Tools/scripts/nm2def.py
--- a/Tools/scripts/nm2def.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/nm2def.py	Fri Mar 20 12:55:59 2015 +0200
@@ -42,7 +42,8 @@ NM = 'nm -p -g %s'                      
 
 def symbols(lib=PYTHONLIB,types=('T','C','D')):
 
-    lines = os.popen(NM % lib).readlines()
+    with os.popen(NM % lib) as pipe:
+        lines = pipe.readlines()
     lines = [s.strip() for s in lines]
     symbols = {}
     for line in lines:
@@ -97,7 +98,7 @@ def main():
     exports = export_list(s)
     f = sys.stdout # open('PC/python_nt.def','w')
     f.write(DEF_TEMPLATE % (exports))
-    f.close()
+    # f.close()
 
 if __name__ == '__main__':
     main()
diff -r d478a2a5738a Tools/scripts/objgraph.py
--- a/Tools/scripts/objgraph.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/objgraph.py	Fri Mar 20 12:55:59 2015 +0200
@@ -180,7 +180,8 @@ def main():
         if filename == '-':
             readinput(sys.stdin)
         else:
-            readinput(open(filename, 'r'))
+            with open(filename) as f:
+                readinput(f)
     #
     warndups()
     #
diff -r d478a2a5738a Tools/scripts/parseentities.py
--- a/Tools/scripts/parseentities.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/parseentities.py	Fri Mar 20 12:55:59 2015 +0200
@@ -50,13 +50,15 @@ def writefile(f,defs):
 
 if __name__ == '__main__':
     if len(sys.argv) > 1:
-        infile = open(sys.argv[1])
+        with open(sys.argv[1]) as infile:
+            text = infile.read()
     else:
-        infile = sys.stdin
+        text = sys.stdin.read()
+
+    defs = parse(text)
+
     if len(sys.argv) > 2:
-        outfile = open(sys.argv[2],'w')
+        with open(sys.argv[2],'w') as outfile:
+            writefile(outfile, defs)
     else:
-        outfile = sys.stdout
-    text = infile.read()
-    defs = parse(text)
-    writefile(outfile,defs)
+        writefile(sys.stdout, defs)
diff -r d478a2a5738a Tools/scripts/pathfix.py
--- a/Tools/scripts/pathfix.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/pathfix.py	Fri Mar 20 12:55:59 2015 +0200
@@ -97,29 +97,27 @@ def fix(filename):
     except IOError as msg:
         err('%s: cannot open: %r\n' % (filename, msg))
         return 1
-    line = f.readline()
-    fixed = fixline(line)
-    if line == fixed:
-        rep(filename+': no change\n')
-        f.close()
-        return
-    head, tail = os.path.split(filename)
-    tempname = os.path.join(head, '@' + tail)
-    try:
-        g = open(tempname, 'wb')
-    except IOError as msg:
-        f.close()
-        err('%s: cannot create: %r\n' % (tempname, msg))
-        return 1
-    rep(filename + ': updating\n')
-    g.write(fixed)
-    BUFSIZE = 8*1024
-    while 1:
-        buf = f.read(BUFSIZE)
-        if not buf: break
-        g.write(buf)
-    g.close()
-    f.close()
+    with f:
+        line = f.readline()
+        fixed = fixline(line)
+        if line == fixed:
+            rep(filename+': no change\n')
+            return
+        head, tail = os.path.split(filename)
+        tempname = os.path.join(head, '@' + tail)
+        try:
+            g = open(tempname, 'wb')
+        except IOError as msg:
+            err('%s: cannot create: %r\n' % (tempname, msg))
+            return 1
+        with g:
+            rep(filename + ': updating\n')
+            g.write(fixed)
+            BUFSIZE = 8*1024
+            while 1:
+                buf = f.read(BUFSIZE)
+                if not buf: break
+                g.write(buf)
 
     # Finishing touch -- move files
 
diff -r d478a2a5738a Tools/scripts/pdeps.py
--- a/Tools/scripts/pdeps.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/pdeps.py	Fri Mar 20 12:55:59 2015 +0200
@@ -64,29 +64,28 @@ m_from = re.compile('^[ \t]*import[ \t]+
 # Collect data from one file
 #
 def process(filename, table):
-    fp = open(filename, 'r')
-    mod = os.path.basename(filename)
-    if mod[-3:] == '.py':
-        mod = mod[:-3]
-    table[mod] = list = []
-    while 1:
-        line = fp.readline()
-        if not line: break
-        while line[-1:] == '\\':
-            nextline = fp.readline()
-            if not nextline: break
-            line = line[:-1] + nextline
-        m_found = m_import.match(line) or m_from.match(line)
-        if m_found:
-            (a, b), (a1, b1) = m_found.regs[:2]
-        else: continue
-        words = line[a1:b1].split(',')
-        # print '#', line, words
-        for word in words:
-            word = word.strip()
-            if word not in list:
-                list.append(word)
-    fp.close()
+    with open(filename) as fp:
+        mod = os.path.basename(filename)
+        if mod[-3:] == '.py':
+            mod = mod[:-3]
+        table[mod] = list = []
+        while 1:
+            line = fp.readline()
+            if not line: break
+            while line[-1:] == '\\':
+                nextline = fp.readline()
+                if not nextline: break
+                line = line[:-1] + nextline
+            m_found = m_import.match(line) or m_from.match(line)
+            if m_found:
+                (a, b), (a1, b1) = m_found.regs[:2]
+            else: continue
+            words = line[a1:b1].split(',')
+            # print '#', line, words
+            for word in words:
+                word = word.strip()
+                if word not in list:
+                    list.append(word)
 
 
 # Compute closure (this is in fact totally general)
diff -r d478a2a5738a Tools/scripts/ptags.py
--- a/Tools/scripts/ptags.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/ptags.py	Fri Mar 20 12:55:59 2015 +0200
@@ -19,9 +19,9 @@ def main():
     for filename in args:
         treat_file(filename)
     if tags:
-        fp = open('tags', 'w')
-        tags.sort()
-        for s in tags: fp.write(s)
+        with open('tags', 'w') as fp:
+            tags.sort()
+            for s in tags: fp.write(s)
 
 
 expr = '^[ \t]*(def|class)[ \t]+([a-zA-Z0-9_]+)[ \t]*[:\(]'
@@ -33,21 +33,22 @@ def treat_file(filename):
     except:
         sys.stderr.write('Cannot open %s\n' % filename)
         return
-    base = os.path.basename(filename)
-    if base[-3:] == '.py':
-        base = base[:-3]
-    s = base + '\t' + filename + '\t' + '1\n'
-    tags.append(s)
-    while 1:
-        line = fp.readline()
-        if not line:
-            break
-        m = matcher.match(line)
-        if m:
-            content = m.group(0)
-            name = m.group(2)
-            s = name + '\t' + filename + '\t/^' + content + '/\n'
-            tags.append(s)
+    with fp:
+        base = os.path.basename(filename)
+        if base[-3:] == '.py':
+            base = base[:-3]
+        s = base + '\t' + filename + '\t' + '1\n'
+        tags.append(s)
+        while 1:
+            line = fp.readline()
+            if not line:
+                break
+            m = matcher.match(line)
+            if m:
+                content = m.group(0)
+                name = m.group(2)
+                s = name + '\t' + filename + '\t/^' + content + '/\n'
+                tags.append(s)
 
 if __name__ == '__main__':
     main()
diff -r d478a2a5738a Tools/scripts/rgrep.py
--- a/Tools/scripts/rgrep.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/rgrep.py	Fri Mar 20 12:55:59 2015 +0200
@@ -30,29 +30,30 @@ def main():
         f = open(filename)
     except IOError as msg:
         usage("can't open %r: %s" % (filename, msg), 1)
-    f.seek(0, 2)
-    pos = f.tell()
-    leftover = None
-    while pos > 0:
-        size = min(pos, bufsize)
-        pos = pos - size
-        f.seek(pos)
-        buffer = f.read(size)
-        lines = buffer.split("\n")
-        del buffer
-        if leftover is None:
-            if not lines[-1]:
-                del lines[-1]
-        else:
-            lines[-1] = lines[-1] + leftover
-        if pos > 0:
-            leftover = lines[0]
-            del lines[0]
-        else:
-            leftover = None
-        for line in reversed(lines):
-            if prog.search(line):
-                print(line)
+    with f:
+        f.seek(0, 2)
+        pos = f.tell()
+        leftover = None
+        while pos > 0:
+            size = min(pos, bufsize)
+            pos = pos - size
+            f.seek(pos)
+            buffer = f.read(size)
+            lines = buffer.split("\n")
+            del buffer
+            if leftover is None:
+                if not lines[-1]:
+                    del lines[-1]
+            else:
+                lines[-1] = lines[-1] + leftover
+            if pos > 0:
+                leftover = lines[0]
+                del lines[0]
+            else:
+                leftover = None
+            for line in reversed(lines):
+                if prog.search(line):
+                    print(line)
 
 
 def usage(msg, code=2):
diff -r d478a2a5738a Tools/scripts/svneol.py
--- a/Tools/scripts/svneol.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/scripts/svneol.py	Fri Mar 20 12:55:59 2015 +0200
@@ -39,7 +39,8 @@ import subprocess
 def propfiles(root, fn):
     default = os.path.join(root, ".svn", "props", fn + ".svn-work")
     try:
-        format = int(open(os.path.join(root, ".svn", "format")).read().strip())
+        with open(os.path.join(root, ".svn", "format")) as f:
+            format = int(f.read().strip())
     except IOError:
         return []
     if format in (8, 9):
@@ -60,27 +61,27 @@ def proplist(root, fn):
             # no properties file: not under version control,
             # or no properties set
             continue
-        while True:
-            # key-value pairs, of the form
-            # K <length>
-            # <keyname>NL
-            # V length
-            # <value>NL
-            # END
-            line = f.readline()
-            if line.startswith("END"):
-                break
-            assert line.startswith("K ")
-            L = int(line.split()[1])
-            key = f.read(L)
-            result.append(key)
-            f.readline()
-            line = f.readline()
-            assert line.startswith("V ")
-            L = int(line.split()[1])
-            value = f.read(L)
-            f.readline()
-        f.close()
+        with f:
+            while True:
+                # key-value pairs, of the form
+                # K <length>
+                # <keyname>NL
+                # V length
+                # <value>NL
+                # END
+                line = f.readline()
+                if line.startswith("END"):
+                    break
+                assert line.startswith("K ")
+                L = int(line.split()[1])
+                key = f.read(L)
+                result.append(key)
+                f.readline()
+                line = f.readline()
+                assert line.startswith("V ")
+                L = int(line.split()[1])
+                value = f.read(L)
+                f.readline()
     return result
 
 
diff -r d478a2a5738a Tools/unicode/gencjkcodecs.py
--- a/Tools/unicode/gencjkcodecs.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/unicode/gencjkcodecs.py	Fri Mar 20 12:55:59 2015 +0200
@@ -61,7 +61,8 @@ def gencodecs(prefix):
                                        encoding=enc.lower(),
                                        owner=loc)
             codecpath = os.path.join(prefix, enc + '.py')
-            open(codecpath, 'w').write(code)
+            with open(codecpath, 'w') as f:
+                f.write(code)
 
 if __name__ == '__main__':
     import sys
diff -r d478a2a5738a Tools/unicode/gencodec.py
--- a/Tools/unicode/gencodec.py	Fri Mar 20 10:37:34 2015 +0100
+++ b/Tools/unicode/gencodec.py	Fri Mar 20 12:55:59 2015 +0200
@@ -72,9 +72,8 @@ def parsecodes(codes, len=len, range=ran
 
 def readmap(filename):
 
-    f = open(filename,'r')
-    lines = f.readlines()
-    f.close()
+    with open(filename) as f:
+        lines = f.readlines()
     enc2uni = {}
     identity = []
     unmapped = list(range(256))
@@ -359,18 +358,16 @@ encoding_table = codecs.charmap_build(de
 def pymap(name,map,pyfile,encodingname,comments=1):
 
     code = codegen(name,map,encodingname,comments)
-    f = open(pyfile,'w')
-    f.write(code)
-    f.close()
+    with open(pyfile,'w') as f:
+        f.write(code)
 
 def marshalmap(name,map,marshalfile):
 
     d = {}
     for e,(u,c) in map.items():
         d[e] = (u,c)
-    f = open(marshalfile,'wb')
-    marshal.dump(d,f)
-    f.close()
+    with open(marshalfile,'wb') as f:
+        marshal.dump(d,f)
 
 def convertdir(dir, dirprefix='', nameprefix='', comments=1):
 
@@ -411,8 +408,8 @@ def rewritepythondir(dir, dirprefix='', 
         print('converting %s to %s' % (mapname,
                                        dirprefix + codefile))
         try:
-            map = marshal.load(open(os.path.join(dir,mapname),
-                               'rb'))
+            with open(os.path.join(dir, mapname), 'rb') as f:
+                map = marshal.load(f)
             if not map:
                 print('* map is empty; skipping')
             else:


More information about the Python-bugs-list mailing list