← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:py3-bytes-formatting into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:py3-bytes-formatting into launchpad:master.

Commit message:
Avoid b"%s" % str constructions

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

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

On Python 3, %s in a bytes format string requires bytes.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:py3-bytes-formatting into launchpad:master.
diff --git a/lib/lp/app/browser/doc/launchpad-search-pages.txt b/lib/lp/app/browser/doc/launchpad-search-pages.txt
index ded7f0d..abc6e37 100644
--- a/lib/lp/app/browser/doc/launchpad-search-pages.txt
+++ b/lib/lp/app/browser/doc/launchpad-search-pages.txt
@@ -39,11 +39,10 @@ When text is not None, the title indicates what was searched.
     ...     search_param_list = []
     ...     for name in sorted(form):
     ...         value = form[name]
-    ...         if isinstance(value, six.text_type):
-    ...             value = wsgi_native_string(value)
-    ...         search_param_list.append(b'%s=%s' % (
-    ...             wsgi_native_string(name), value))
-    ...     query_string = b'&'.join(search_param_list)
+    ...         search_param_list.append(
+    ...             wsgi_native_string(name) + wsgi_native_string('=') +
+    ...             wsgi_native_string(value))
+    ...     query_string = wsgi_native_string('&').join(search_param_list)
     ...     request = LaunchpadTestRequest(
     ...         SERVER_URL='https://launchpad.test/+search',
     ...         QUERY_STRING=query_string, form=form, PATH_INFO='/+search')
@@ -129,7 +128,7 @@ created because they are the owner.
     ...     owner=sample_person, information_type=InformationType.USERDATA)
 
     >>> search_view = getSearchView(
-    ...     form={'field.text': private_bug.id})
+    ...     form={'field.text': str(private_bug.id)})
     >>> search_view.bug.private
     True
 
@@ -137,7 +136,7 @@ But anonymous and unprivileged users cannot see the private bug.
 
     >>> login(ANONYMOUS)
     >>> search_view = getSearchView(
-    ...     form={'field.text': private_bug.id})
+    ...     form={'field.text': str(private_bug.id)})
     >>> print(search_view.bug)
     None
 
diff --git a/lib/lp/archivepublisher/tests/test_sync_signingkeys.py b/lib/lp/archivepublisher/tests/test_sync_signingkeys.py
index 7c54063..9e4189c 100644
--- a/lib/lp/archivepublisher/tests/test_sync_signingkeys.py
+++ b/lib/lp/archivepublisher/tests/test_sync_signingkeys.py
@@ -209,20 +209,20 @@ class TestSyncSigningKeysScript(TestCaseWithFactory):
 
         # Create fake UEFI keys for the root
         for filename in ("uefi.key", "uefi.crt"):
-            with open(os.path.join(archive_root, filename), 'wb') as fd:
-                fd.write(b"Root %s" % filename)
+            with open(os.path.join(archive_root, filename), 'w') as fd:
+                fd.write("Root %s" % filename)
 
         # Create fake OPAL and Kmod keys for series1
         for filename in ("opal.pem", "opal.x509", "kmod.pem", "kmod.x509"):
-            with open(os.path.join(key_dirs[series1], filename), 'wb') as fd:
-                fd.write(b"Series 1 %s" % filename)
+            with open(os.path.join(key_dirs[series1], filename), 'w') as fd:
+                fd.write("Series 1 %s" % filename)
 
         # Create fake FIT keys for series1
         os.makedirs(os.path.join(key_dirs[series1], "fit"))
         for filename in ("fit.key", "fit.crt"):
             with open(os.path.join(key_dirs[series1], "fit", filename),
-                      'wb') as fd:
-                fd.write(b"Series 1 %s" % filename)
+                      'w') as fd:
+                fd.write("Series 1 %s" % filename)
 
         script = self.makeScript(["--archive", archive.reference])
         script.inject = mock.Mock()
@@ -304,20 +304,20 @@ class TestSyncSigningKeysScript(TestCaseWithFactory):
 
         # Create fake UEFI keys for the root
         for filename in ("uefi.key", "uefi.crt"):
-            with open(os.path.join(archive_root, filename), 'wb') as fd:
-                fd.write(b"Root %s" % filename)
+            with open(os.path.join(archive_root, filename), 'w') as fd:
+                fd.write("Root %s" % filename)
 
         # Create fake OPAL and Kmod keys for series1
         for filename in ("opal.pem", "opal.x509", "kmod.pem", "kmod.x509"):
-            with open(os.path.join(key_dirs[series1], filename), 'wb') as fd:
-                fd.write(b"Series 1 %s" % filename)
+            with open(os.path.join(key_dirs[series1], filename), 'w') as fd:
+                fd.write("Series 1 %s" % filename)
 
         # Create fake FIT keys for series1
         os.makedirs(os.path.join(key_dirs[series1], "fit"))
         for filename in ("fit.key", "fit.crt"):
             with open(os.path.join(key_dirs[series1], "fit", filename),
-                      'wb') as fd:
-                fd.write(b"Series 1 %s" % filename)
+                      'w') as fd:
+                fd.write("Series 1 %s" % filename)
 
         script = self.makeScript(
             ["--archive", archive.reference, "--overwrite", "--dry-run"])
@@ -385,8 +385,8 @@ class TestSyncSigningKeysScript(TestCaseWithFactory):
         gpgkey = self.factory.makeGPGKey(archive.owner)
         secret_key_path = os.path.join(
             self.signing_root_dir, "%s.gpg" % gpgkey.fingerprint)
-        with open(secret_key_path, "wb") as fd:
-            fd.write(b"Private key %s" % gpgkey.fingerprint)
+        with open(secret_key_path, "w") as fd:
+            fd.write("Private key %s" % gpgkey.fingerprint)
         archive.signing_key_owner = archive.owner
         archive.signing_key_fingerprint = gpgkey.fingerprint
 
diff --git a/lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-tools.txt b/lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-tools.txt
index 1647a69..ba8dda6 100644
--- a/lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-tools.txt
+++ b/lib/lp/bugs/stories/guided-filebug/xx-bug-reporting-tools.txt
@@ -66,10 +66,10 @@ The most common case will be that the user is sent to the guided
     >>> filebug_path = (
     ...    '/ubuntu/+source/mozilla-firefox/+filebug/%s' % blob_token)
     >>> filebug_url = 'http://%s%s' % (filebug_host, filebug_path)
-    >>> contents = str(http(
-    ...     b"GET %s HTTP/1.1\nHostname: %s\n"
-    ...     b"Authorization: Basic test@xxxxxxxxxxxxx:test\n\n"
-    ...     % (filebug_path, filebug_host)))
+    >>> contents = str(http(six.ensure_binary(
+    ...     "GET %s HTTP/1.1\nHostname: %s\n"
+    ...     "Authorization: Basic test@xxxxxxxxxxxxx:test\n\n"
+    ...     % (filebug_path, filebug_host))))
 
 At first, the user will be shown a message telling them that the extra
 data is being processed.
diff --git a/lib/lp/buildmaster/tests/mock_slaves.py b/lib/lp/buildmaster/tests/mock_slaves.py
index 6fb0049..7e19f5b 100644
--- a/lib/lp/buildmaster/tests/mock_slaves.py
+++ b/lib/lp/buildmaster/tests/mock_slaves.py
@@ -217,7 +217,7 @@ class WaitingSlave(OkSlave):
             if isinstance(file_to_write, six.string_types):
                 file_to_write = open(file_to_write, 'wb')
             if not self.valid_files[hash]:
-                content = b"This is a %s" % hash
+                content = ("This is a %s" % hash).encode("ASCII")
             else:
                 with open(self.valid_files[hash], 'rb') as source:
                     content = source.read()
diff --git a/lib/lp/services/daemons/tests/test_tachandler.py b/lib/lp/services/daemons/tests/test_tachandler.py
index 75d45a7..0b01898 100644
--- a/lib/lp/services/daemons/tests/test_tachandler.py
+++ b/lib/lp/services/daemons/tests/test_tachandler.py
@@ -169,7 +169,7 @@ class TacTestSetupTestCase(testtools.TestCase):
         with open(fixture.logfile, "wb") as logfile:
             logfile.write(b"One\n")
             logfile.write(b"Two\n")
-            logfile.write(b"Three, %s\n" % LOG_MAGIC.encode("UTF-8"))
+            logfile.write(("Three, %s\n" % LOG_MAGIC).encode("UTF-8"))
             logfile.write(b"Four\n")
 
         # Truncating the log leaves everything up to and including the line
@@ -177,5 +177,5 @@ class TacTestSetupTestCase(testtools.TestCase):
         fixture.truncateLog()
         with open(fixture.logfile, "rb") as logfile:
             self.assertEqual(
-                b"One\nTwo\nThree, %s\n" % LOG_MAGIC.encode("UTF-8"),
+                ("One\nTwo\nThree, %s\n" % LOG_MAGIC).encode("UTF-8"),
                 logfile.read())
diff --git a/lib/lp/services/librarianserver/doc/upload.txt b/lib/lp/services/librarianserver/doc/upload.txt
index ca8c26a..595b0b7 100644
--- a/lib/lp/services/librarianserver/doc/upload.txt
+++ b/lib/lp/services/librarianserver/doc/upload.txt
@@ -108,13 +108,13 @@ Filename with spaces work.
 
 Unicode filenames work, but must be encoded as UTF-8 on the socket.
 
-    >>> filename = 'Yow\N{INTERROBANG}'.encode('utf-8')
-    >>> upload_request(b"""STORE 14 %s
+    >>> filename = 'Yow\N{INTERROBANG}'
+    >>> upload_request(("""STORE 14 %s
     ... Content-Type: text/plain
     ... File-Content-ID: 123
     ... File-Alias-ID: 456
     ... Database-Name: right_database
     ...
-    ... Cats and dogs.""" % filename)
+    ... Cats and dogs.""" % filename).encode('UTF-8'))
     reply: '200'
     file 'Yow‽' stored as text/plain, contents: 'Cats and dogs.'
diff --git a/lib/lp/soyuz/scripts/tests/test_copypackage.py b/lib/lp/soyuz/scripts/tests/test_copypackage.py
index 8fdf14e..1bce73c 100644
--- a/lib/lp/soyuz/scripts/tests/test_copypackage.py
+++ b/lib/lp/soyuz/scripts/tests/test_copypackage.py
@@ -2068,9 +2068,9 @@ class TestCopyClosesBugs(TestCaseWithFactory):
 
     def createSource(self, version, archive, pocket, bug_id):
         changes_template = (
-            b"Format: 1.7\n"
-            b"Launchpad-bugs-fixed: %s\n")
-        changes_file_content = changes_template % bug_id
+            "Format: 1.7\n"
+            "Launchpad-bugs-fixed: %s\n")
+        changes_file_content = (changes_template % bug_id).encode("UTF-8")
         source = self.test_publisher.getPubSource(
             sourcename='buggy-source', version=version,
             distroseries=self.hoary_test, archive=archive, pocket=pocket,
diff --git a/lib/lp/soyuz/stories/ppa/xx-ppa-files.txt b/lib/lp/soyuz/stories/ppa/xx-ppa-files.txt
index f4ad646..ca2e9a1 100644
--- a/lib/lp/soyuz/stories/ppa/xx-ppa-files.txt
+++ b/lib/lp/soyuz/stories/ppa/xx-ppa-files.txt
@@ -251,10 +251,10 @@ Sample Person can't access the file.
 
 The 'No Privileges' user, the PPA owner, can download the DSC file.
 
-    >>> print(http(br"""
+    >>> print(http(six.ensure_binary(r"""
     ... GET %s HTTP/1.1
     ... Authorization: Basic no-priv@xxxxxxxxxxxxx:test
-    ... """ % (dsc_file_lp_url.replace('http://launchpad.test', ''))))
+    ... """ % (dsc_file_lp_url.replace('http://launchpad.test', '')))))
     HTTP/1.1 303 See Other
     ...
     Location: https://...restricted.../test-pkg_1.0.dsc?token=...
@@ -272,10 +272,10 @@ Binary files are served via '+files' rather than '+sourcefiles'.
     Traceback (most recent call last):
     ...
     zope.security.interfaces.Unauthorized
-    >>> print(http(br"""
+    >>> print(http(six.ensure_binary(r"""
     ... GET %s HTTP/1.1
     ... Authorization: Basic no-priv@xxxxxxxxxxxxx:test
-    ... """ % (deb_file_lp_url.replace('http://launchpad.test', ''))))
+    ... """ % (deb_file_lp_url.replace('http://launchpad.test', '')))))
     HTTP/1.1 303 See Other
     ...
     Location: https://...restricted.../test-bin_1.0_all.deb?token=...
@@ -314,9 +314,9 @@ binaries across to no-priv's public ppa.
     >>> print(file_librarian_url)
     http://.../test-pkg_1.0.dsc
 
-    >>> print(http(br"""
+    >>> print(http(six.ensure_binary(r"""
     ... GET %s HTTP/1.1
-    ... """ % file_lp_url.replace('http://launchpad.test', '')))
+    ... """ % file_lp_url.replace('http://launchpad.test', ''))))
     HTTP/1.1 303 See Other
     ...
     Location: http://.../test-pkg_1.0.dsc
@@ -341,10 +341,10 @@ redirect to the files for the default named PPA.
     >>> file_lp_url_without_ppa_name = (
     ...     'http://launchpad.test/~no-priv/+archive/+files/test-pkg_1.0.dsc')
 
-    >>> print(http(br"""
+    >>> print(http(six.ensure_binary(r"""
     ... GET %s HTTP/1.1
     ... """ % file_lp_url_without_ppa_name.replace(
-    ...     'http://launchpad.test', '')))
+    ...     'http://launchpad.test', ''))))
     HTTP/1.1 301 Moved Permanently
     ...
     Location: http://localhost/~no-priv/+archive/ubuntu/ppa/+files/test-pkg_1.0.dsc
@@ -354,10 +354,10 @@ The same redirection happens for +archive/+build/blah urls:
 
     >>> buildlog_lp_url_without_ppa_name = (
     ...     'http://launchpad.test/~no-priv/+archive/+build/1/+files/foo')
-    >>> print(http(br"""
+    >>> print(http(six.ensure_binary(r"""
     ... GET %s HTTP/1.1
     ... """ % buildlog_lp_url_without_ppa_name.replace(
-    ...     'http://launchpad.test', '')))
+    ...     'http://launchpad.test', ''))))
     HTTP/1.1 301 Moved Permanently
     ...
     Location: http://.../~no-priv/+archive/ubuntu/ppa/+build/1/+files/...
@@ -411,9 +411,9 @@ LP proxy URL a proper NotFound error is raised.
     >>> print(file_lp_url)
     http://launchpad.test/~no-priv/+archive/ubuntu/ppa/+sourcefiles/test-pkg/1.0/test-pkg_1.0.dsc
 
-    >>> not_found_file = http(br"""
+    >>> not_found_file = http(six.ensure_binary(r"""
     ... GET %s HTTP/1.1
-    ... """ % file_lp_url.replace('http://launchpad.test', ''))
+    ... """ % file_lp_url.replace('http://launchpad.test', '')))
 
 It results in a 404 response.
 
diff --git a/lib/lp/translations/doc/poimport-pofile-old-po-imported.txt b/lib/lp/translations/doc/poimport-pofile-old-po-imported.txt
index b49a677..d9a96cc 100644
--- a/lib/lp/translations/doc/poimport-pofile-old-po-imported.txt
+++ b/lib/lp/translations/doc/poimport-pofile-old-po-imported.txt
@@ -62,7 +62,7 @@ We create the POFile object where we are going to attach the .po file.
 
 First, we do a valid import.
 
-    >>> pofile_contents = br'''
+    >>> pofile_contents = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "PO-Revision-Date: 2005-05-03 20:41+0100\n"
@@ -74,7 +74,7 @@ First, we do a valid import.
     ...
     ... msgid "foo"
     ... msgstr "blah"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
     >>> by_maintainer = False
     >>> entry = translation_import_queue.addOrUpdateEntry(
     ...     pofile.path, pofile_contents, by_maintainer, person,
@@ -110,7 +110,7 @@ file we just imported.
 Now, we are going to import a .po file that has a 'PO-Revision-Date'
 field with a date older than a previous .po import.
 
-    >>> pofile_contents = br'''
+    >>> pofile_contents = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "PO-Revision-Date: 2005-05-03 19:41+0100\n"
@@ -122,7 +122,7 @@ field with a date older than a previous .po import.
     ...
     ... msgid "foo"
     ... msgstr "blah"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
     >>> by_maintainer = False
     >>> entry = translation_import_queue.addOrUpdateEntry(
     ...     pofile.path, pofile_contents, by_maintainer, person,
diff --git a/lib/lp/translations/doc/poimport-pofile-syntax-error.txt b/lib/lp/translations/doc/poimport-pofile-syntax-error.txt
index 44ce5f5..bc89865 100644
--- a/lib/lp/translations/doc/poimport-pofile-syntax-error.txt
+++ b/lib/lp/translations/doc/poimport-pofile-syntax-error.txt
@@ -58,7 +58,7 @@ We create the POFile object where we are going to attach the .po file.
 Let's import a .po file that misses the '"' char after msgstr. That's a
 syntax error.
 
-    >>> pofile_contents = br'''
+    >>> pofile_contents = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "PO-Revision-Date: 2005-06-03 20:41+0100\n"
@@ -70,7 +70,7 @@ syntax error.
     ... 
     ... msgid "foo"
     ... msgstr blah"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
     >>> by_maintainer = False
     >>> entry = translation_import_queue.addOrUpdateEntry(
     ...     pofile.path, pofile_contents, by_maintainer, person,
@@ -194,7 +194,7 @@ In his rush to be the first Sumerian translator for Firefox, Mark
 submits a translation with a nonsensical plurals definition.
 
     >>> pofile = potemplate.newPOFile('sux')
-    >>> pofile_contents = br'''
+    >>> pofile_contents = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "PO-Revision-Date: 2005-06-29 11:44+0100\n"
@@ -205,7 +205,7 @@ submits a translation with a nonsensical plurals definition.
     ... 
     ... msgid "foo"
     ... msgstr "bar"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
     >>> entry = translation_import_queue.addOrUpdateEntry(
     ...     pofile.path, pofile_contents, False, person,
     ...     productseries=series, potemplate=potemplate, pofile=pofile)
@@ -238,7 +238,7 @@ Not enough forms
 Mark mistakenly attempts to import a translation with "zero" plural
 forms.  He receives an email notifying him of a syntax error.
 
-    >>> pofile_contents = br'''
+    >>> pofile_contents = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "PO-Revision-Date: 2005-06-14 18:33+0100\n"
@@ -249,7 +249,7 @@ forms.  He receives an email notifying him of a syntax error.
     ... 
     ... msgid "foo"
     ... msgstr "bar"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
     >>> entry = translation_import_queue.addOrUpdateEntry(
     ...     pofile.path, pofile_contents, False, person,
     ...     productseries=series, potemplate=potemplate, pofile=pofile)
@@ -276,7 +276,7 @@ forms.  He receives an email notifying him of a syntax error.
 On his next attempt, Mark accidentally types a negative number of plural
 forms.  The same error is given.
 
-    >>> pofile_contents = br'''
+    >>> pofile_contents = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "PO-Revision-Date: 2005-06-15 19:04+0100\n"
@@ -287,7 +287,7 @@ forms.  The same error is given.
     ... 
     ... msgid "foo"
     ... msgstr "bar"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
     >>> entry = translation_import_queue.addOrUpdateEntry(
     ...     pofile.path, pofile_contents, False, person,
     ...     productseries=series, potemplate=potemplate, pofile=pofile)
@@ -325,7 +325,7 @@ to get that information corrected if need be.
     >>> pofile = potemplate.newPOFile('ar')
 
     # PO file with nplurals=7, a value we can't handle.
-    >>> pofile_contents = br'''
+    >>> pofile_contents = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "PO-Revision-Date: 2005-07-01 08:35+0100\n"
@@ -343,7 +343,7 @@ to get that information corrected if need be.
     ... msgstr[4] "baros %%d"
     ... msgstr[5] "barorum %%d"
     ... msgstr[6] "barim %%d"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
     >>> entry = translation_import_queue.addOrUpdateEntry(
     ...     pofile.path, pofile_contents, False, person,
     ...     productseries=series, potemplate=potemplate, pofile=pofile)
@@ -389,7 +389,7 @@ Once Mark has checked the language page and corrected the number of
 plural forms, the file imports just fine.
 
     # Same PO file as before, but with nplurals=6.
-    >>> pofile_contents = br'''
+    >>> pofile_contents = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "PO-Revision-Date: 2005-07-01 08:35+0100\n"
@@ -406,7 +406,7 @@ plural forms, the file imports just fine.
     ... msgstr[3] "baribus %%d"
     ... msgstr[4] "baros %%d"
     ... msgstr[5] "barorum %%d"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
     >>> entry = translation_import_queue.addOrUpdateEntry(
     ...     pofile.path, pofile_contents, False, person,
     ...     productseries=series, potemplate=potemplate, pofile=pofile)
diff --git a/lib/lp/translations/doc/poimport.txt b/lib/lp/translations/doc/poimport.txt
index 1c49a97..5b07995 100644
--- a/lib/lp/translations/doc/poimport.txt
+++ b/lib/lp/translations/doc/poimport.txt
@@ -56,7 +56,7 @@ And this is the POTemplate where the import will be done.
 
 This is the file that'll get imported.
 
-    >>> potemplate_contents = br'''
+    >>> potemplate_contents = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "POT-Creation-Date: 2004-07-11 16:16+0900\n"
@@ -86,7 +86,7 @@ This is the file that'll get imported.
     ...
     ... msgid "translator-credits"
     ... msgstr ""
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
 
 We sometimes saw deadlocks as POFile statistics were updated after
 importing a template.  The operation would read all translation messages
@@ -226,7 +226,7 @@ Import With Errors
 Here are the contents of the file we'll be importing. It has some
 validation errors.
 
-    >>> pofile_with_errors = br'''
+    >>> pofile_with_errors = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "PO-Revision-Date: 2005-06-03 19:41+0100\n"
@@ -257,7 +257,7 @@ validation errors.
     ... msgstr[1] "Bars %%d"
     ... msgstr[2] "Welsh power! %%d"
     ... msgstr[3] "We have four! %%d"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
 
 This is the dbschema that controls the validation of a translation.
 
@@ -423,7 +423,7 @@ instance) and they don't mean that any messages failed to import.
 
 For example, here's a gettext PO file with two headers.
 
-    >>> pofile_with_warning = br'''
+    >>> pofile_with_warning = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "Content-Type: text/plain; charset=UTF-8\n"
@@ -439,7 +439,7 @@ For example, here's a gettext PO file with two headers.
     ...
     ... msgid "a"
     ... msgstr "b"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
     >>> eo_pofile = potemplate.newPOFile('eo')
     >>> warning_entry = translation_import_queue.addOrUpdateEntry(
     ...     'eo.po', pofile_with_warning, False, potemplate.owner,
@@ -484,7 +484,7 @@ Import Without Errors
 Now, let's import one without errors. This file changes one translation
 and adds another one.
 
-    >>> pofile_without_errors = br'''
+    >>> pofile_without_errors = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "PO-Revision-Date: 2005-06-03 20:41+0100\n"
@@ -502,7 +502,7 @@ and adds another one.
     ...
     ... msgid "translator-credits"
     ... msgstr "helpful@xxxxxxxxxxx"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
     >>> entry = translation_import_queue.addOrUpdateEntry(
     ...     pofile.path, pofile_without_errors, True, rosetta_experts,
     ...     distroseries=distroseries, sourcepackagename=sourcepackagename,
@@ -645,7 +645,7 @@ plural forms).
 
 We'll import a POFile with 3 plural forms into this POFile:
 
-    >>> pofile_with_plurals = br'''
+    >>> pofile_with_plurals = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "PO-Revision-Date: 2005-06-03 19:41+0100\n"
@@ -660,7 +660,7 @@ We'll import a POFile with 3 plural forms into this POFile:
     ... msgstr[0] "First form %%d"
     ... msgstr[1] "Second form %%d"
     ... msgstr[2] "Third form %%d"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
 
 We now import this POFile as this language's translation for the soure
 package:
diff --git a/lib/lp/translations/doc/rosetta-karma.txt b/lib/lp/translations/doc/rosetta-karma.txt
index f5bda21..caad946 100644
--- a/lib/lp/translations/doc/rosetta-karma.txt
+++ b/lib/lp/translations/doc/rosetta-karma.txt
@@ -121,7 +121,7 @@ Let's say that we have this .po file to import:
     >>> import datetime
     >>> import pytz
     >>> UTC = pytz.timezone('UTC')
-    >>> pofile_contents = br'''
+    >>> pofile_contents = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "Content-Type: text/plain; charset=UTF-8\n"
@@ -129,7 +129,7 @@ Let's say that we have this .po file to import:
     ...
     ... msgid "foo"
     ... msgstr "bar"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
     >>> potemplate = POTemplate.get(1)
     >>> pofile = potemplate.getPOFileByLang('es')
 
@@ -193,7 +193,7 @@ Tell the PO file to import from the file data it has.
 Now, the user is going to upload a local edition of the .po file. In this
 case, we will give karma *only* because the translation change.
 
-    >>> pofile_contents = br'''
+    >>> pofile_contents = six.ensure_binary(r'''
     ... msgid ""
     ... msgstr ""
     ... "Content-Type: text/plain; charset=UTF-8\n"
@@ -201,7 +201,7 @@ case, we will give karma *only* because the translation change.
     ...
     ... msgid "foo"
     ... msgstr "bars"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
 
 We attach the new file as not comming from upstream.
 
diff --git a/lib/lp/translations/doc/rosetta-poimport-script.txt b/lib/lp/translations/doc/rosetta-poimport-script.txt
index 8866db1..680c6a5 100644
--- a/lib/lp/translations/doc/rosetta-poimport-script.txt
+++ b/lib/lp/translations/doc/rosetta-poimport-script.txt
@@ -32,17 +32,17 @@ the sampledata.
     None
 
     >>> pofile = potemplate.newPOFile('sr')
-    >>> pofile_content = br'''
+    >>> pofile_content = six.ensure_binary('''
     ... msgid ""
     ... msgstr ""
-    ... "PO-Revision-Date: 2005-06-04 20:41+0100\n"
-    ... "Last-Translator: Danilo Šegan <danilo@xxxxxxxxxxxxx>\n"
-    ... "Content-Type: text/plain; charset=UTF-8\n"
-    ... "X-Rosetta-Export-Date: %s\n"
+    ... "PO-Revision-Date: 2005-06-04 20:41+0100\\n"
+    ... "Last-Translator: Danilo \u0160egan <danilo@xxxxxxxxxxxxx>\\n"
+    ... "Content-Type: text/plain; charset=UTF-8\\n"
+    ... "X-Rosetta-Export-Date: %s\\n"
     ...
     ... msgid "Foo %%s"
     ... msgstr "Bar"
-    ... ''' % datetime.datetime.now(UTC).isoformat()
+    ... ''' % datetime.datetime.now(UTC).isoformat())
 
 We clean the import queue.
 
diff --git a/lib/lp/translations/utilities/tests/test_translation_importer.py b/lib/lp/translations/utilities/tests/test_translation_importer.py
index 106ca2d..624b84b 100644
--- a/lib/lp/translations/utilities/tests/test_translation_importer.py
+++ b/lib/lp/translations/utilities/tests/test_translation_importer.py
@@ -235,7 +235,7 @@ class TranslationImporterTestCase(TestCaseWithFactory):
         existing_translation = self.factory.makeCurrentTranslationMessage(
             pofile=pofile, potmsgset=potmsgset1)
 
-        text = b"""
+        text = six.ensure_binary("""
             msgid ""
             msgstr ""
             "MIME-Version: 1.0\\n"
@@ -245,7 +245,7 @@ class TranslationImporterTestCase(TestCaseWithFactory):
 
             msgid "%s"
             msgstr "A translation."
-        """ % potmsgset2.msgid_singular.msgid
+        """ % potmsgset2.msgid_singular.msgid)
 
         entry = self.factory.makeTranslationImportQueueEntry(
             'foo.po', potemplate=template, pofile=pofile,