Make test_zipfile pass.
The zipfile module now does all I/O in binary mode using bytes.
(Maybe we should support wrapping a TextIOWrapper around it
when text mode reading is requested?)
Even the password is a bytes array now.
Had to fix py_compile.py to use bytes while I was at it.
The _struct needed a patch to support bytes, str8 and str
for the 's' and 'p' formats.
diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py
index 172e230..197170a 100644
--- a/Lib/test/test_zipfile.py
+++ b/Lib/test/test_zipfile.py
@@ -3,10 +3,8 @@
     import zlib
 except ImportError:
     zlib = None
+import zipfile, os, unittest, sys, shutil, struct, io
 
-import zipfile, os, unittest, sys, shutil, struct
-
-from StringIO import StringIO
 from tempfile import TemporaryFile
 from random import randint, random
 
@@ -18,9 +16,10 @@
 
 class TestsWithSourceFile(unittest.TestCase):
     def setUp(self):
-        self.line_gen = ("Zipfile test line %d. random float: %f" % (i, random())
-                          for i in range(FIXEDTEST_SIZE))
-        self.data = '\n'.join(self.line_gen) + '\n'
+        self.line_gen = (bytes("Zipfile test line %d. random float: %f" %
+                               (i, random()))
+                         for i in range(FIXEDTEST_SIZE))
+        self.data = b'\n'.join(self.line_gen) + b'\n'
 
         # Make a source file with some lines
         fp = open(TESTFN, "wb")
@@ -45,14 +44,8 @@
         self.assertEqual(zipfp.read("strfile"), self.data)
 
         # Print the ZIP directory
-        fp = StringIO()
-        stdout = sys.stdout
-        try:
-            sys.stdout = fp
-
-            zipfp.printdir()
-        finally:
-            sys.stdout = stdout
+        fp = io.StringIO()
+        zipfp.printdir(file=fp)
 
         directory = fp.getvalue()
         lines = directory.splitlines()
@@ -95,7 +88,7 @@
         zipfp.close()
 
     def testStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.zipTest(f, zipfile.ZIP_STORED)
 
     def zipOpenTest(self, f, compression):
@@ -119,12 +112,12 @@
                 break
             zipdata2.append(read_data)
 
-        self.assertEqual(''.join(zipdata1), self.data)
-        self.assertEqual(''.join(zipdata2), self.data)
+        self.assertEqual(b''.join(zipdata1), self.data)
+        self.assertEqual(b''.join(zipdata2), self.data)
         zipfp.close()
 
     def testOpenStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.zipOpenTest(f, zipfile.ZIP_STORED)
 
     def zipRandomOpenTest(self, f, compression):
@@ -140,11 +133,11 @@
                 break
             zipdata1.append(read_data)
 
-        self.assertEqual(''.join(zipdata1), self.data)
+        self.assertEqual(b''.join(zipdata1), self.data)
         zipfp.close()
 
     def testRandomOpenStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.zipRandomOpenTest(f, zipfile.ZIP_STORED)
 
     def zipReadlineTest(self, f, compression):
@@ -181,40 +174,40 @@
         zipfp.close()
 
     def testReadlineStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.zipReadlineTest(f, zipfile.ZIP_STORED)
 
     def testReadlinesStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.zipReadlinesTest(f, zipfile.ZIP_STORED)
 
     def testIterlinesStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.zipIterlinesTest(f, zipfile.ZIP_STORED)
 
     if zlib:
         def testDeflated(self):
-            for f in (TESTFN2, TemporaryFile(), StringIO()):
+            for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
                 self.zipTest(f, zipfile.ZIP_DEFLATED)
 
         def testOpenDeflated(self):
-            for f in (TESTFN2, TemporaryFile(), StringIO()):
+            for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
                 self.zipOpenTest(f, zipfile.ZIP_DEFLATED)
 
         def testRandomOpenDeflated(self):
-            for f in (TESTFN2, TemporaryFile(), StringIO()):
+            for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
                 self.zipRandomOpenTest(f, zipfile.ZIP_DEFLATED)
 
         def testReadlineDeflated(self):
-            for f in (TESTFN2, TemporaryFile(), StringIO()):
+            for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
                 self.zipReadlineTest(f, zipfile.ZIP_DEFLATED)
 
         def testReadlinesDeflated(self):
-            for f in (TESTFN2, TemporaryFile(), StringIO()):
+            for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
                 self.zipReadlinesTest(f, zipfile.ZIP_DEFLATED)
 
         def testIterlinesDeflated(self):
-            for f in (TESTFN2, TemporaryFile(), StringIO()):
+            for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
                 self.zipIterlinesTest(f, zipfile.ZIP_DEFLATED)
 
         def testLowCompression(self):
@@ -227,8 +220,8 @@
             # Get an open object for strfile
             zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED)
             openobj = zipfp.open("strfile")
-            self.assertEqual(openobj.read(1), '1')
-            self.assertEqual(openobj.read(1), '2')
+            self.assertEqual(openobj.read(1), b'1')
+            self.assertEqual(openobj.read(1), b'2')
 
     def testAbsoluteArcnames(self):
         zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED)
@@ -251,8 +244,9 @@
         self._limit = zipfile.ZIP64_LIMIT
         zipfile.ZIP64_LIMIT = 5
 
-        line_gen = ("Test of zipfile line %d." % i for i in range(0, FIXEDTEST_SIZE))
-        self.data = '\n'.join(line_gen)
+        line_gen = (bytes("Test of zipfile line %d." % i)
+                    for i in range(0, FIXEDTEST_SIZE))
+        self.data = b'\n'.join(line_gen)
 
         # Make a source file with some lines
         fp = open(TESTFN, "wb")
@@ -272,7 +266,7 @@
         zipfp.close()
 
     def testLargeFileException(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.largeFileExceptionTest(f, zipfile.ZIP_STORED)
             self.largeFileExceptionTest2(f, zipfile.ZIP_STORED)
 
@@ -291,14 +285,8 @@
         self.assertEqual(zipfp.read("strfile"), self.data)
 
         # Print the ZIP directory
-        fp = StringIO()
-        stdout = sys.stdout
-        try:
-            sys.stdout = fp
-
-            zipfp.printdir()
-        finally:
-            sys.stdout = stdout
+        fp = io.StringIO()
+        zipfp.printdir(fp)
 
         directory = fp.getvalue()
         lines = directory.splitlines()
@@ -343,13 +331,13 @@
         zipfp.close()
 
     def testStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.zipTest(f, zipfile.ZIP_STORED)
 
 
     if zlib:
         def testDeflated(self):
-            for f in (TESTFN2, TemporaryFile(), StringIO()):
+            for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
                 self.zipTest(f, zipfile.ZIP_DEFLATED)
 
     def testAbsoluteArcnames(self):
@@ -440,7 +428,7 @@
             os.unlink(TESTFN)
 
         filename = 'testfile.txt'
-        content = 'hello, world. this is some content.'
+        content = b'hello, world. this is some content.'
 
         try:
             zf = zipfile.ZipFile(TESTFN, 'a')
@@ -483,7 +471,7 @@
         # This test checks that the is_zipfile function correctly identifies
         # a file that is a zip file
         zipf = zipfile.ZipFile(TESTFN, mode="w")
-        zipf.writestr("foo.txt", "O, for a Muse of Fire!")
+        zipf.writestr("foo.txt", b"O, for a Muse of Fire!")
         zipf.close()
         chk = zipfile.is_zipfile(TESTFN)
         self.assert_(chk is True)
@@ -504,7 +492,7 @@
 
     def testClosedZipRaisesRuntimeError(self):
         # Verify that testzip() doesn't swallow inappropriate exceptions.
-        data = StringIO()
+        data = io.BytesIO()
         zipf = zipfile.ZipFile(data, mode="w")
         zipf.writestr("foo.txt", "O, for a Muse of Fire!")
         zipf.close()
@@ -525,15 +513,15 @@
     # ZIP file
 
     data = (
-    'PK\x03\x04\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00\x1a\x00'
-    '\x00\x00\x08\x00\x00\x00test.txt\xfa\x10\xa0gly|\xfa-\xc5\xc0=\xf9y'
-    '\x18\xe0\xa8r\xb3Z}Lg\xbc\xae\xf9|\x9b\x19\xe4\x8b\xba\xbb)\x8c\xb0\xdbl'
-    'PK\x01\x02\x14\x00\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00'
-    '\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
-    '\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
-    '\x00\x00L\x00\x00\x00\x00\x00' )
+    b'PK\x03\x04\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00\x1a\x00'
+    b'\x00\x00\x08\x00\x00\x00test.txt\xfa\x10\xa0gly|\xfa-\xc5\xc0=\xf9y'
+    b'\x18\xe0\xa8r\xb3Z}Lg\xbc\xae\xf9|\x9b\x19\xe4\x8b\xba\xbb)\x8c\xb0\xdbl'
+    b'PK\x01\x02\x14\x00\x14\x00\x01\x00\x00\x00n\x92i.#y\xef?&\x00\x00\x00'
+    b'\x1a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x01\x00 \x00\xb6\x81'
+    b'\x00\x00\x00\x00test.txtPK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x006\x00'
+    b'\x00\x00L\x00\x00\x00\x00\x00' )
 
-    plain = 'zipfile.py encryption test'
+    plain = b'zipfile.py encryption test'
 
     def setUp(self):
         fp = open(TESTFN, "wb")
@@ -551,18 +539,19 @@
         self.assertRaises(RuntimeError, self.zip.read, "test.txt")
 
     def testBadPassword(self):
-        self.zip.setpassword("perl")
+        self.zip.setpassword(b"perl")
         self.assertRaises(RuntimeError, self.zip.read, "test.txt")
 
     def testGoodPassword(self):
-        self.zip.setpassword("python")
+        self.zip.setpassword(b"python")
         self.assertEquals(self.zip.read("test.txt"), self.plain)
 
 
 class TestsWithRandomBinaryFiles(unittest.TestCase):
     def setUp(self):
         datacount = randint(16, 64)*1024 + randint(1, 1024)
-        self.data = ''.join((struct.pack('<f', random()*randint(-1000, 1000)) for i in range(datacount)))
+        self.data = b''.join(struct.pack('<f', random()*randint(-1000, 1000))
+                             for i in range(datacount))
 
         # Make a source file with some lines
         fp = open(TESTFN, "wb")
@@ -592,7 +581,7 @@
         zipfp.close()
 
     def testStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.zipTest(f, zipfile.ZIP_STORED)
 
     def zipOpenTest(self, f, compression):
@@ -616,17 +605,17 @@
                 break
             zipdata2.append(read_data)
 
-        testdata1 = ''.join(zipdata1)
+        testdata1 = b''.join(zipdata1)
         self.assertEqual(len(testdata1), len(self.data))
         self.assertEqual(testdata1, self.data)
 
-        testdata2 = ''.join(zipdata2)
+        testdata2 = b''.join(zipdata2)
         self.assertEqual(len(testdata1), len(self.data))
         self.assertEqual(testdata1, self.data)
         zipfp.close()
 
     def testOpenStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.zipOpenTest(f, zipfile.ZIP_STORED)
 
     def zipRandomOpenTest(self, f, compression):
@@ -642,13 +631,13 @@
                 break
             zipdata1.append(read_data)
 
-        testdata = ''.join(zipdata1)
+        testdata = b''.join(zipdata1)
         self.assertEqual(len(testdata), len(self.data))
         self.assertEqual(testdata, self.data)
         zipfp.close()
 
     def testRandomOpenStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.zipRandomOpenTest(f, zipfile.ZIP_STORED)
 
 class TestsWithMultipleOpens(unittest.TestCase):
@@ -682,8 +671,8 @@
         data2 = zopen2.read(500)
         data1 += zopen1.read(500)
         data2 += zopen2.read(500)
-        self.assertEqual(data1, '1'*FIXEDTEST_SIZE)
-        self.assertEqual(data2, '2'*FIXEDTEST_SIZE)
+        self.assertEqual(data1, b'1'*FIXEDTEST_SIZE)
+        self.assertEqual(data2, b'2'*FIXEDTEST_SIZE)
         zipf.close()
 
     def testInterleaved(self):
@@ -696,8 +685,8 @@
         data2 = zopen2.read(500)
         data1 += zopen1.read(500)
         data2 += zopen2.read(500)
-        self.assertEqual(data1, '1'*FIXEDTEST_SIZE)
-        self.assertEqual(data2, '2'*FIXEDTEST_SIZE)
+        self.assertEqual(data1, b'1'*FIXEDTEST_SIZE)
+        self.assertEqual(data2, b'2'*FIXEDTEST_SIZE)
         zipf.close()
 
     def tearDown(self):
@@ -706,13 +695,19 @@
 
 class UniversalNewlineTests(unittest.TestCase):
     def setUp(self):
-        self.line_gen = ["Test of zipfile line %d." % i for i in range(FIXEDTEST_SIZE)]
+        self.line_gen = [bytes("Test of zipfile line %d." % i)
+                         for i in range(FIXEDTEST_SIZE)]
         self.seps = ('\r', '\r\n', '\n')
         self.arcdata, self.arcfiles = {}, {}
         for n, s in enumerate(self.seps):
-            self.arcdata[s] = s.join(self.line_gen) + s
+            b = s.encode("ascii")
+            self.arcdata[s] = b.join(self.line_gen) + b
             self.arcfiles[s] = '%s-%d' % (TESTFN, n)
-            file(self.arcfiles[s], "wb").write(self.arcdata[s])
+            f = open(self.arcfiles[s], "wb")
+            try:
+                f.write(self.arcdata[s])
+            finally:
+                f.close()
 
     def makeTestArchive(self, f, compression):
         # Create the ZIP archive
@@ -741,7 +736,7 @@
             zipopen = zipfp.open(fn, "rU")
             for line in self.line_gen:
                 linedata = zipopen.readline()
-                self.assertEqual(linedata, line + '\n')
+                self.assertEqual(linedata, line + b'\n')
 
         zipfp.close()
 
@@ -753,7 +748,7 @@
         for sep, fn in self.arcfiles.items():
             ziplines = zipfp.open(fn, "rU").readlines()
             for line, zipline in zip(self.line_gen, ziplines):
-                self.assertEqual(zipline, line + '\n')
+                self.assertEqual(zipline, line + b'\n')
 
         zipfp.close()
 
@@ -764,41 +759,41 @@
         zipfp = zipfile.ZipFile(f, "r")
         for sep, fn in self.arcfiles.items():
             for line, zipline in zip(self.line_gen, zipfp.open(fn, "rU")):
-                self.assertEqual(zipline, line + '\n')
+                self.assertEqual(zipline, line + b'\n')
 
         zipfp.close()
 
     def testReadStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.readTest(f, zipfile.ZIP_STORED)
 
     def testReadlineStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.readlineTest(f, zipfile.ZIP_STORED)
 
     def testReadlinesStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.readlinesTest(f, zipfile.ZIP_STORED)
 
     def testIterlinesStored(self):
-        for f in (TESTFN2, TemporaryFile(), StringIO()):
+        for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
             self.iterlinesTest(f, zipfile.ZIP_STORED)
 
     if zlib:
         def testReadDeflated(self):
-            for f in (TESTFN2, TemporaryFile(), StringIO()):
+            for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
                 self.readTest(f, zipfile.ZIP_DEFLATED)
 
         def testReadlineDeflated(self):
-            for f in (TESTFN2, TemporaryFile(), StringIO()):
+            for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
                 self.readlineTest(f, zipfile.ZIP_DEFLATED)
 
         def testReadlinesDeflated(self):
-            for f in (TESTFN2, TemporaryFile(), StringIO()):
+            for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
                 self.readlinesTest(f, zipfile.ZIP_DEFLATED)
 
         def testIterlinesDeflated(self):
-            for f in (TESTFN2, TemporaryFile(), StringIO()):
+            for f in (TESTFN2, TemporaryFile(), io.BytesIO()):
                 self.iterlinesTest(f, zipfile.ZIP_DEFLATED)
 
     def tearDown(self):