← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:py3-binary-files into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:py3-binary-files into launchpad:master.

Commit message:
Open files in binary mode where needed

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/398084

Python 3 is stricter about this.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:py3-binary-files into launchpad:master.
diff --git a/lib/launchpad_loggerhead/tests.py b/lib/launchpad_loggerhead/tests.py
index c4ebbe0..42a0632 100644
--- a/lib/launchpad_loggerhead/tests.py
+++ b/lib/launchpad_loggerhead/tests.py
@@ -34,7 +34,7 @@ SESSION_VAR = 'lh.session'
 
 # See lib/launchpad_loggerhead/wsgi.py for the production mechanism for
 # getting the secret.
-SECRET = 'secret'
+SECRET = b'secret'
 
 
 def session_scribbler(app, test):
diff --git a/lib/launchpad_loggerhead/wsgi.py b/lib/launchpad_loggerhead/wsgi.py
index be5601b..f4a9773 100644
--- a/lib/launchpad_loggerhead/wsgi.py
+++ b/lib/launchpad_loggerhead/wsgi.py
@@ -161,7 +161,8 @@ class LoggerheadApplication(Application):
         self._load_brz_plugins()
 
         with open(os.path.join(
-                config.root, config.codebrowse.secret_path)) as secret_file:
+                config.root, config.codebrowse.secret_path),
+                "rb") as secret_file:
             secret = secret_file.read()
 
         app = RootApp(SESSION_VAR)
diff --git a/lib/lp/archivepublisher/publishing.py b/lib/lp/archivepublisher/publishing.py
index 2069eb1..55614f9 100644
--- a/lib/lp/archivepublisher/publishing.py
+++ b/lib/lp/archivepublisher/publishing.py
@@ -1168,7 +1168,7 @@ class Publisher(object):
         """
         release_path = os.path.join(
             self._config.distsroot, suite, "Release.new")
-        with open_for_writing(release_path, "w") as release_file:
+        with open_for_writing(release_path, "wb") as release_file:
             release_data.dump(release_file, "utf-8")
 
     def _syncTimestamps(self, suite, all_files):
@@ -1337,7 +1337,7 @@ class Publisher(object):
         release_file["Architecture"] = arch_name
 
         release_path = os.path.join(suite_dir, component, arch_path, "Release")
-        with open_for_writing(release_path, "w") as f:
+        with open_for_writing(release_path, "wb") as f:
             release_file.dump(f, "utf-8")
 
     def _writeSuiteSource(self, distroseries, pocket, component,
@@ -1402,7 +1402,7 @@ class Publisher(object):
             # Schedule i18n files for inclusion in the Release file.
             all_series_files.add(os.path.join(i18n_subpath, i18n_file))
 
-        with open(os.path.join(i18n_dir, "Index"), "w") as f:
+        with open(os.path.join(i18n_dir, "Index"), "wb") as f:
             i18n_index.dump(f, "utf-8")
 
         # Schedule this for inclusion in the Release file.
diff --git a/lib/lp/archivepublisher/tests/test_customupload.py b/lib/lp/archivepublisher/tests/test_customupload.py
index a9b1173..476ff95 100644
--- a/lib/lp/archivepublisher/tests/test_customupload.py
+++ b/lib/lp/archivepublisher/tests/test_customupload.py
@@ -266,9 +266,9 @@ class TestSigning(TestCaseWithFactory, RunPartsMixin):
         self.assertIsNotNone(self.archive.signing_key)
         custom_processor = CustomUpload()
         custom_processor.sign(self.archive, "suite", filename)
-        with open(filename) as cleartext_file:
+        with open(filename, "rb") as cleartext_file:
             cleartext = cleartext_file.read()
-            with open("%s.gpg" % filename) as signature_file:
+            with open("%s.gpg" % filename, "rb") as signature_file:
                 signature = getUtility(IGPGHandler).getVerifiedSignature(
                     cleartext, signature_file.read())
         self.assertEqual(
diff --git a/lib/lp/archivepublisher/tests/test_ftparchive.py b/lib/lp/archivepublisher/tests/test_ftparchive.py
index 52c41b9..7209f53 100755
--- a/lib/lp/archivepublisher/tests/test_ftparchive.py
+++ b/lib/lp/archivepublisher/tests/test_ftparchive.py
@@ -8,6 +8,7 @@ from __future__ import absolute_import, print_function, unicode_literals
 __metaclass__ = type
 
 import difflib
+from functools import partial
 import gzip
 import os
 import re
@@ -141,10 +142,10 @@ class TestFTPArchive(TestCaseWithFactory):
         self.assertThat(
             result, MatchesListwise([Equals(stanza) for stanza in sample]))
 
-    def _verifyEmpty(self, path, open_func=open):
+    def _verifyEmpty(self, path, open_func=partial(open, mode="rb")):
         """Assert that the given file is empty."""
         with open_func(path) as result_file:
-            self.assertEqual("", result_file.read())
+            self.assertEqual(b"", result_file.read())
 
     def _addRepositoryFile(self, component, sourcename, leafname,
                            samplename=None):
@@ -156,9 +157,9 @@ class TestFTPArchive(TestCaseWithFactory):
         if samplename is None:
             samplename = leafname
         leaf = os.path.join(self._sampledir, samplename)
-        with open(leaf) as leaf_file:
+        with open(leaf, "rb") as leaf_file:
             leafcontent = leaf_file.read()
-        with open(fullpath, "w") as f:
+        with open(fullpath, "wb") as f:
             f.write(leafcontent)
 
     def _setUpFTPArchiveHandler(self):
diff --git a/lib/lp/archivepublisher/tests/test_indices.py b/lib/lp/archivepublisher/tests/test_indices.py
index b5e68f5..3a39e58 100644
--- a/lib/lp/archivepublisher/tests/test_indices.py
+++ b/lib/lp/archivepublisher/tests/test_indices.py
@@ -343,9 +343,8 @@ class TestNativeArchiveIndexesReparsing(TestNativePublishingBase):
     def write_stanza_and_reparse(self, stanza):
         """Helper method to return the apt_pkg parser for the stanza."""
         index_filename = tempfile.mktemp()
-        index_file = open(index_filename, 'w')
-        index_file.write(stanza.makeOutput().encode('utf-8'))
-        index_file.close()
+        with open(index_filename, 'wb') as index_file:
+            index_file.write(stanza.makeOutput().encode('utf-8'))
 
         parser = apt_pkg.TagFile(open(index_filename))
 
diff --git a/lib/lp/archiveuploader/dscfile.py b/lib/lp/archiveuploader/dscfile.py
index 9e174c4..3ae5496 100644
--- a/lib/lp/archiveuploader/dscfile.py
+++ b/lib/lp/archiveuploader/dscfile.py
@@ -726,12 +726,13 @@ class DSCFile(SourceUploadFile, SignableTagFile):
         # SourcePackageFiles should contain also the DSC
         source_files = self.files + [self]
         for uploaded_file in source_files:
-            library_file = self.librarian.create(
-                uploaded_file.filename,
-                uploaded_file.size,
-                open(uploaded_file.filepath, "rb"),
-                uploaded_file.content_type,
-                restricted=self.policy.archive.private)
+            with open(uploaded_file.filepath, "rb") as uploaded_file_obj:
+                library_file = self.librarian.create(
+                    uploaded_file.filename,
+                    uploaded_file.size,
+                    uploaded_file_obj,
+                    uploaded_file.content_type,
+                    restricted=self.policy.archive.private)
             release.addFile(library_file)
 
         return release
@@ -805,7 +806,7 @@ def find_copyright(source_dir, logger):
         raise UploadWarning("No copyright file found.")
 
     logger.debug("Copying copyright contents.")
-    with open(copyright_file) as f:
+    with open(copyright_file, "rb") as f:
         return f.read().strip()
 
 
diff --git a/lib/lp/archiveuploader/tests/test_changesfile.py b/lib/lp/archiveuploader/tests/test_changesfile.py
index b599019..60c8646 100644
--- a/lib/lp/archiveuploader/tests/test_changesfile.py
+++ b/lib/lp/archiveuploader/tests/test_changesfile.py
@@ -179,11 +179,8 @@ class ChangesFileTests(TestCase):
     def createChangesFile(self, filename, changes):
         tempdir = self.makeTemporaryDirectory()
         path = os.path.join(tempdir, filename)
-        changes_fd = open(path, "w")
-        try:
+        with open(path, "wb") as changes_fd:
             changes.dump(changes_fd)
-        finally:
-            changes_fd.close()
         changesfile = ChangesFile(path, self.policy, self.logger)
         for error in changesfile.parseChanges():
             raise error
diff --git a/lib/lp/archiveuploader/tests/test_dscfile.py b/lib/lp/archiveuploader/tests/test_dscfile.py
index 1e8bf36..3414a40 100644
--- a/lib/lp/archiveuploader/tests/test_dscfile.py
+++ b/lib/lp/archiveuploader/tests/test_dscfile.py
@@ -73,10 +73,9 @@ class TestDscFile(TestCase):
 
     def testGoodDebianCopyright(self):
         """Test that a proper copyright file will be accepted"""
-        copyright = "copyright for dummies"
-        file = open(self.copyright_path, "w")
-        file.write(copyright)
-        file.close()
+        copyright = b"copyright for dummies"
+        with open(self.copyright_path, "wb") as f:
+            f.write(copyright)
 
         self.assertEqual(
             copyright, find_copyright(self.tmpdir, DevNullLogger()))
@@ -95,10 +94,9 @@ class TestDscFile(TestCase):
 
     def testGoodDebianChangelog(self):
         """Test that a proper changelog file will be accepted"""
-        changelog = "changelog for dummies"
-        file = open(self.changelog_path, "w")
-        file.write(changelog)
-        file.close()
+        changelog = b"changelog for dummies"
+        with open(self.changelog_path, "wb") as f:
+            f.write(changelog)
 
         self.assertEqual(
             changelog, find_changelog(self.tmpdir, DevNullLogger()))
diff --git a/lib/lp/archiveuploader/tests/test_nascentuploadfile.py b/lib/lp/archiveuploader/tests/test_nascentuploadfile.py
index 66770e4..eac0c5b 100644
--- a/lib/lp/archiveuploader/tests/test_nascentuploadfile.py
+++ b/lib/lp/archiveuploader/tests/test_nascentuploadfile.py
@@ -221,7 +221,7 @@ class PackageUploadFileTestCase(NascentUploadFileTestCase):
     def createChangesFile(self, filename, changes):
         tempdir = self.makeTemporaryDirectory()
         path = os.path.join(tempdir, filename)
-        with open(path, "w") as changes_fd:
+        with open(path, "wb") as changes_fd:
             changes.dump(changes_fd)
         changesfile = ChangesFile(path, self.policy, self.logger)
         self.assertEqual([], list(changesfile.parseChanges()))
diff --git a/lib/lp/archiveuploader/tests/test_uploadprocessor.py b/lib/lp/archiveuploader/tests/test_uploadprocessor.py
index 91ec622..7c7c2bc 100644
--- a/lib/lp/archiveuploader/tests/test_uploadprocessor.py
+++ b/lib/lp/archiveuploader/tests/test_uploadprocessor.py
@@ -2139,7 +2139,8 @@ class TestUploadProcessor(TestUploadProcessorBase):
         # A buildinfo file is attached to the SPR.
         uploadprocessor = self.setupBreezyAndGetUploadProcessor()
         upload_dir = self.queueUpload("bar_1.0-1_buildinfo")
-        with open(os.path.join(upload_dir, "bar_1.0-1_source.buildinfo")) as f:
+        with open(os.path.join(upload_dir, "bar_1.0-1_source.buildinfo"),
+                  "rb") as f:
             buildinfo_contents = f.read()
         self.processUpload(uploadprocessor, upload_dir)
         source_pub = self.publishPackage("bar", "1.0-1")
@@ -2169,7 +2170,8 @@ class TestUploadProcessor(TestUploadProcessorBase):
         leaf_name = behaviour.getUploadDirLeaf(build.build_cookie)
         upload_dir = self.queueUpload(
             "bar_1.0-1_binary_buildinfo", queue_entry=leaf_name)
-        with open(os.path.join(upload_dir, "bar_1.0-1_i386.buildinfo")) as f:
+        with open(os.path.join(upload_dir, "bar_1.0-1_i386.buildinfo"),
+                  "rb") as f:
             buildinfo_contents = f.read()
         self.options.context = "buildd"
         self.options.builds = True
@@ -2200,7 +2202,8 @@ class TestUploadProcessor(TestUploadProcessorBase):
         leaf_name = behaviour.getUploadDirLeaf(build.build_cookie)
         upload_dir = self.queueUpload(
             "bar_1.0-1_binary_buildinfo_indep", queue_entry=leaf_name)
-        with open(os.path.join(upload_dir, "bar_1.0-1_i386.buildinfo")) as f:
+        with open(os.path.join(upload_dir, "bar_1.0-1_i386.buildinfo"),
+                  "rb") as f:
             buildinfo_contents = f.read()
         self.options.context = "buildd"
         self.options.builds = True
diff --git a/lib/lp/buildmaster/model/buildfarmjobbehaviour.py b/lib/lp/buildmaster/model/buildfarmjobbehaviour.py
index 13a38d7..007a54a 100644
--- a/lib/lp/buildmaster/model/buildfarmjobbehaviour.py
+++ b/lib/lp/buildmaster/model/buildfarmjobbehaviour.py
@@ -192,7 +192,7 @@ class BuildFarmJobBehaviourBase:
                 # If the requested file is the 'buildlog' compress it
                 # using gzip before storing in Librarian.
                 if file_sha1 == 'buildlog':
-                    out_file = open(out_file_name)
+                    out_file = open(out_file_name, 'rb')
                     filename += '.gz'
                     out_file_name += '.gz'
                     gz_file = gzip.GzipFile(out_file_name, mode='wb')
@@ -201,7 +201,7 @@ class BuildFarmJobBehaviourBase:
 
                 # Open the file, seek to its end position, count and seek to
                 # beginning, ready for adding to the Librarian.
-                out_file = open(out_file_name)
+                out_file = open(out_file_name, 'rb')
                 out_file.seek(0, 2)
                 bytes_written = out_file.tell()
                 out_file.seek(0)
diff --git a/lib/lp/buildmaster/tests/test_interactor.py b/lib/lp/buildmaster/tests/test_interactor.py
index 3352036..00bd8ff 100644
--- a/lib/lp/buildmaster/tests/test_interactor.py
+++ b/lib/lp/buildmaster/tests/test_interactor.py
@@ -806,7 +806,7 @@ class TestSlaveWithLibrarian(TestCaseWithFactory):
         # filename made from the sha1 of the content underneath the
         # 'filecache' directory.
         from twisted.internet import reactor
-        content = "Hello World"
+        content = b"Hello World"
         lf = self.factory.makeLibraryFileAlias(
             'HelloWorld.txt', content=content)
         self.layer.txn.commit()
@@ -911,5 +911,5 @@ class TestSlaveWithLibrarian(TestCaseWithFactory):
         empty_sha1 = hashlib.sha1(b'').hexdigest()
         self.slave_helper.makeCacheFile(tachandler, empty_sha1, contents=b'')
         yield slave.getFiles([(empty_sha1, temp_name)])
-        with open(temp_name) as f:
+        with open(temp_name, 'rb') as f:
             self.assertEqual(b'', f.read())
diff --git a/lib/lp/services/twistedsupport/loggingsupport.py b/lib/lp/services/twistedsupport/loggingsupport.py
index 759d5c4..70be91c 100644
--- a/lib/lp/services/twistedsupport/loggingsupport.py
+++ b/lib/lp/services/twistedsupport/loggingsupport.py
@@ -94,7 +94,7 @@ class LaunchpadLogFile(DailyLogFile):
         :return: the path to the compressed file.
         """
         bz2_path = '%s.bz2' % path
-        copy_and_close(open(path), bz2.BZ2File(bz2_path, mode='w'))
+        copy_and_close(open(path, 'rb'), bz2.BZ2File(bz2_path, mode='w'))
         os.remove(path)
         return bz2_path
 
diff --git a/lib/lp/services/webservice/stories/xx-hostedfile.txt b/lib/lp/services/webservice/stories/xx-hostedfile.txt
index a318435..78dba32 100644
--- a/lib/lp/services/webservice/stories/xx-hostedfile.txt
+++ b/lib/lp/services/webservice/stories/xx-hostedfile.txt
@@ -37,7 +37,8 @@ We can upload branding images with PUT.
     ...     image_file = os.path.join(
     ...         os.path.dirname(canonical.launchpad.__file__),
     ...         'images', filename)
-    ...     return open(image_file).read()
+    ...     with open(image_file, 'rb') as f:
+    ...         return f.read()
 
     >>> print(webservice.put(project['icon_link'], 'image/png',
     ...                      load_image('team.png')))
diff --git a/lib/lp/soyuz/adapters/tests/test_archivedependencies.py b/lib/lp/soyuz/adapters/tests/test_archivedependencies.py
index d5a2068..1945a52 100644
--- a/lib/lp/soyuz/adapters/tests/test_archivedependencies.py
+++ b/lib/lp/soyuz/adapters/tests/test_archivedependencies.py
@@ -529,7 +529,7 @@ class TestSourcesList(TestCaseWithFactory):
         # Upload the tools archive key to the keyserver.
         tools_key_name = "ppa-sample-4096@xxxxxxxxxxxxx"
         tools_key_path = os.path.join(gpgkeysdir, "%s.sec" % tools_key_name)
-        with open(tools_key_path) as tools_key_file:
+        with open(tools_key_path, "rb") as tools_key_file:
             secret_key_export = tools_key_file.read()
         # Remove security proxy to avoid problems with running in a thread.
         gpghandler = removeSecurityProxy(getUtility(IGPGHandler))
diff --git a/lib/lp/soyuz/doc/fakepackager.txt b/lib/lp/soyuz/doc/fakepackager.txt
index a4b4eb6..4e8f0e5 100644
--- a/lib/lp/soyuz/doc/fakepackager.txt
+++ b/lib/lp/soyuz/doc/fakepackager.txt
@@ -91,8 +91,8 @@ Now we can build the source package using the generated tarball.
     /tmp/fakepackager-.../biscuit_1.0-1_source.changes
 
     >>> changesfile_path = packager.listAvailableUploads()[0]
-    >>> changesfile = open(changesfile_path)
-    >>> print(changesfile.read())
+    >>> with open(changesfile_path) as changesfile:
+    ...     print(changesfile.read())
     Format: ...
     Date: ...
     Source: biscuit
@@ -167,7 +167,8 @@ basically checking we pass the right arguments to it.
     >>> print(os.path.basename(changesfile_path))
     biscuit_1.0-3_source.changes
 
-    >>> content = open(changesfile_path).read()
+    >>> with open(changesfile_path, 'rb') as changesfile:
+    ...     content = changesfile.read()
 
     >>> from zope.component import getUtility
     >>> from lp.services.gpg.interfaces import IGPGHandler
diff --git a/lib/lp/soyuz/doc/package-diff.txt b/lib/lp/soyuz/doc/package-diff.txt
index 520b12c..dc4830b 100644
--- a/lib/lp/soyuz/doc/package-diff.txt
+++ b/lib/lp/soyuz/doc/package-diff.txt
@@ -290,7 +290,7 @@ The auxiliary function below will facilitate the viewing of diff results.
     ...     jail = tempfile.mkdtemp()
     ...     local = os.path.abspath('')
     ...     jail = tempfile.mkdtemp()
-    ...     fhandle = open(os.path.join(jail, "the.diff.gz"), 'w')
+    ...     fhandle = open(os.path.join(jail, "the.diff.gz"), 'wb')
     ...     copy_and_close(lfa, fhandle)
     ...     os.chdir(jail)
     ...     p = subprocess.Popen(
diff --git a/lib/lp/soyuz/model/packagediff.py b/lib/lp/soyuz/model/packagediff.py
index 12437cd..323f8f2 100644
--- a/lib/lp/soyuz/model/packagediff.py
+++ b/lib/lp/soyuz/model/packagediff.py
@@ -91,7 +91,7 @@ def perform_deb_diff(tmp_dir, out_filename, from_files, to_files):
     full_path = os.path.join(tmp_dir, out_filename)
     out_file = None
     try:
-        out_file = open(full_path, 'w')
+        out_file = open(full_path, 'wb')
         process = subprocess.Popen(
             args, stdout=out_file, stderr=subprocess.PIPE,
             preexec_fn=partial(
@@ -115,7 +115,7 @@ def download_file(destination_path, libraryfile):
     :type libraryfile: ``LibraryFileAlias``
     """
     libraryfile.open()
-    destination_file = open(destination_path, 'w')
+    destination_file = open(destination_path, 'wb')
     copy_and_close(libraryfile, destination_file)
 
 
@@ -251,7 +251,7 @@ class PackageDiff(SQLBase):
                 return
 
             # Compress the generated diff.
-            out_file = open(os.path.join(tmp_dir, result_filename))
+            out_file = open(os.path.join(tmp_dir, result_filename), 'rb')
             gzip_result_filename = result_filename + '.gz'
             gzip_file_path = os.path.join(tmp_dir, gzip_result_filename)
             gzip_file = gzip.GzipFile(gzip_file_path, mode='wb')
@@ -262,7 +262,7 @@ class PackageDiff(SQLBase):
 
             # Upload the compressed diff to librarian and update
             # the package diff request.
-            gzip_file = open(gzip_file_path)
+            gzip_file = open(gzip_file_path, 'rb')
             try:
                 librarian_set = getUtility(ILibraryFileAliasSet)
                 self.diff_content = librarian_set.create(
diff --git a/lib/lp/soyuz/model/queue.py b/lib/lp/soyuz/model/queue.py
index e14e56a..9fdfb5f 100644
--- a/lib/lp/soyuz/model/queue.py
+++ b/lib/lp/soyuz/model/queue.py
@@ -537,7 +537,7 @@ class PackageUpload(SQLBase):
         [pub_source] = self.realiseUpload()
         builds = pub_source.createMissingBuilds(logger=logger)
         self._validateBuildsForSource(pub_source.sourcepackagerelease, builds)
-        with open(changesfile_path, 'r') as changesfile_object:
+        with open(changesfile_path, 'rb') as changesfile_object:
             close_bugs_for_queue_item(
                 self, changesfile_object=changesfile_object)
         self._giveKarma()
diff --git a/lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py b/lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py
index deea061..23aaf6e 100644
--- a/lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py
+++ b/lib/lp/soyuz/tests/test_binarypackagebuildbehaviour.py
@@ -584,7 +584,7 @@ class TestBinaryBuildPackageBehaviourBuildCollection(TestCaseWithFactory):
             # Check that the original file from the slave matches the
             # uncompressed file in the librarian.
             def got_orig_log(ignored):
-                orig_file_content = open(tmp_orig_file_name).read()
+                orig_file_content = open(tmp_orig_file_name, 'rb').read()
                 self.assertEqual(orig_file_content, uncompressed_file)
 
             d = removeSecurityProxy(slave).getFile(
diff --git a/lib/lp/soyuz/tests/test_packagediff.py b/lib/lp/soyuz/tests/test_packagediff.py
index 3579a76..97ddaab 100644
--- a/lib/lp/soyuz/tests/test_packagediff.py
+++ b/lib/lp/soyuz/tests/test_packagediff.py
@@ -43,7 +43,7 @@ def create_proper_job(factory, sourcepackagename=None):
         '%s/foo_1.0-1.5/foo_1.0-1.5.dsc' % suite_dir: None}
     for name in files:
         filename = os.path.split(name)[-1]
-        with open(name, 'r') as content:
+        with open(name, 'rb') as content:
             files[name] = factory.makeLibraryFileAlias(
                 filename=filename, content=content.read())
     transaction.commit()
diff --git a/lib/lp/translations/doc/sourcepackagerelease-translations.txt b/lib/lp/translations/doc/sourcepackagerelease-translations.txt
index ac783b8..42459a1 100644
--- a/lib/lp/translations/doc/sourcepackagerelease-translations.txt
+++ b/lib/lp/translations/doc/sourcepackagerelease-translations.txt
@@ -12,7 +12,7 @@ upload the same sampledata tarball twice, one public and one restricted
     >>> tarball_path = os.path.join(
     ...     os.path.dirname(lp.translations.__file__),
     ...     'doc/sourcepackagerelease-translations.tar.gz')
-    >>> tarball = open(tarball_path)
+    >>> tarball = open(tarball_path, 'rb')
     >>> tarball_size = len(tarball.read())
     >>> _ = tarball.seek(0)
 
@@ -32,6 +32,8 @@ upload the same sampledata tarball twice, one public and one restricted
     ...     contentType='application/x-gtar',
     ...     restricted=True)
 
+    >>> tarball.close()
+
 Commit, so uploaded contents are available in the current test.
 
     >>> transaction.commit()
diff --git a/lib/lp/translations/model/translationtemplatesbuildbehaviour.py b/lib/lp/translations/model/translationtemplatesbuildbehaviour.py
index 5258c1c..2bc523f 100644
--- a/lib/lp/translations/model/translationtemplatesbuildbehaviour.py
+++ b/lib/lp/translations/model/translationtemplatesbuildbehaviour.py
@@ -123,7 +123,7 @@ class TranslationTemplatesBuildBehaviour(BuildFarmJobBehaviourBase):
         if filename is None:
             logger.error("Build produced no tarball.")
         else:
-            tarball_file = open(filename)
+            tarball_file = open(filename, "rb")
             try:
                 logger.debug("Uploading translation templates tarball.")
                 self._uploadTarball(
diff --git a/lib/lp/translations/scripts/tests/test_validate_translations_file.py b/lib/lp/translations/scripts/tests/test_validate_translations_file.py
index 1becde5..c441c54 100644
--- a/lib/lp/translations/scripts/tests/test_validate_translations_file.py
+++ b/lib/lp/translations/scripts/tests/test_validate_translations_file.py
@@ -40,7 +40,7 @@ class TestValidateTranslationsFile(TestCase):
         # Unknown filename extensions result in UnknownFileType.
         validator = self._makeValidator()
         self.assertRaises(
-            UnknownFileType, validator._validateContent, 'foo.bar', 'content')
+            UnknownFileType, validator._validateContent, 'foo.bar', b'content')
 
     def test_validate_po_good(self):
         validator = self._makeValidator()
@@ -53,7 +53,7 @@ class TestValidateTranslationsFile(TestCase):
 
             msgid "foo"
             msgstr "bar"
-            """))
+            """).encode("UTF-8"))
         self.assertTrue(result)
 
     def test_validate_po_bad(self):
@@ -61,7 +61,7 @@ class TestValidateTranslationsFile(TestCase):
         result = validator._validateContent('nl.po', self._strip("""
             msgid "no header here"
             msgstr "hier geen kopje"
-            """))
+            """).encode("UTF-8"))
         self.assertFalse(result)
 
     def test_validate_pot_good(self):
@@ -75,12 +75,12 @@ class TestValidateTranslationsFile(TestCase):
 
             msgid "foo"
             msgstr ""
-            """))
+            """).encode("UTF-8"))
         self.assertTrue(result)
 
     def test_validate_pot_bad(self):
         validator = self._makeValidator()
-        result = validator._validateContent('test.pot', 'garble')
+        result = validator._validateContent('test.pot', b'garble')
         self.assertFalse(result)
 
     def test_script(self):
diff --git a/lib/lp/translations/scripts/validate_translations_file.py b/lib/lp/translations/scripts/validate_translations_file.py
index 84781e9..2ed241f 100644
--- a/lib/lp/translations/scripts/validate_translations_file.py
+++ b/lib/lp/translations/scripts/validate_translations_file.py
@@ -104,6 +104,6 @@ class ValidateTranslationsFile:
         :param filename: Name of a file to read.
         :return: Whether the file was parsed successfully.
         """
-        with open(filename) as f:
+        with open(filename, "rb") as f:
             content = f.read()
         return self._validateContent(filename, content)
diff --git a/lib/lp/translations/tests/test_translationtemplatesbuildbehaviour.py b/lib/lp/translations/tests/test_translationtemplatesbuildbehaviour.py
index 975c787..e2b15a5 100644
--- a/lib/lp/translations/tests/test_translationtemplatesbuildbehaviour.py
+++ b/lib/lp/translations/tests/test_translationtemplatesbuildbehaviour.py
@@ -298,7 +298,7 @@ class TestTTBuildBehaviourTranslationsQueue(
     def test_uploadTarball(self):
         # Files from the tarball end up in the import queue.
         behaviour = self.makeBehaviour()
-        with open(self.dummy_tar) as f:
+        with open(self.dummy_tar, 'rb') as f:
             behaviour._uploadTarball(self.branch, f.read(), None)
 
         entries = self.queue.getAllEntries(target=self.productseries)
@@ -314,7 +314,7 @@ class TestTTBuildBehaviourTranslationsQueue(
     def test_uploadTarball_approved(self):
         # Uploaded template files are automatically approved.
         behaviour = self.makeBehaviour()
-        with open(self.dummy_tar) as f:
+        with open(self.dummy_tar, 'rb') as f:
             behaviour._uploadTarball(self.branch, f.read(), None)
 
         entries = self.queue.getAllEntries(target=self.productseries)
@@ -325,7 +325,7 @@ class TestTTBuildBehaviourTranslationsQueue(
     def test_uploadTarball_importer(self):
         # Files from the tarball are owned by the branch owner.
         behaviour = self.makeBehaviour()
-        with open(self.dummy_tar) as f:
+        with open(self.dummy_tar, 'rb') as f:
             behaviour._uploadTarball(self.branch, f.read(), None)
 
         entries = self.queue.getAllEntries(target=self.productseries)