← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:unsixify-email-payload into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:unsixify-email-payload into launchpad:master.

Commit message:
Remove six from email message payload handling

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

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

On Python 3, `email.message.Message.get_payload(decode=True)` always returns bytes (confusingly - the decoding in this case is according to the message's `Content-Transfer-Encoding`, rather than from bytes to text), so we don't need `six.ensure_text` to convert it to text; `.decode()` will do.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:unsixify-email-payload into launchpad:master.
diff --git a/lib/lp/bugs/doc/bugnotification-sending.rst b/lib/lp/bugs/doc/bugnotification-sending.rst
index 721b359..bd7df75 100644
--- a/lib/lp/bugs/doc/bugnotification-sending.rst
+++ b/lib/lp/bugs/doc/bugnotification-sending.rst
@@ -31,7 +31,7 @@ easier.
     ...     print_notification_headers(
     ...         email_notification, extra_headers=extra_headers)
     ...     print()
-    ...     print(six.ensure_str(email_notification.get_payload(decode=True)))
+    ...     print(email_notification.get_payload(decode=True).decode())
     ...     print("-" * 70)
 
 We'll also import a helper function to help us with database users.
@@ -273,7 +273,7 @@ lp/bugs/tests/test_bugnotification.py), and not demonstrated here.
 Another thing worth noting is that there's a blank line before the
 signature, and the signature marker has a trailing space.
 
-    >>> six.ensure_str(message.get_payload(decode=True)).splitlines()  # noqa
+    >>> message.get_payload(decode=True).decode().splitlines()  # noqa
     [...,
      '',
      '-- ',
@@ -1063,7 +1063,7 @@ It's important to note that the bug title and description are wrapped
 and indented correctly in verbose notifications.
 
     >>> message = collated_messages['conciseteam@xxxxxxxxxxx'][0]
-    >>> payload = six.ensure_str(message.get_payload(decode=True))
+    >>> payload = message.get_payload(decode=True).decode()
     >>> print(payload.splitlines())
     [...
      'Title:',
@@ -1077,7 +1077,7 @@ and indented correctly in verbose notifications.
 The title is also wrapped and indented in normal notifications.
 
     >>> message = collated_messages['verboseteam@xxxxxxxxxxx'][0]
-    >>> payload = six.ensure_str(message.get_payload(decode=True))
+    >>> payload = message.get_payload(decode=True).decode()
     >>> print(payload.strip().splitlines())
     [...
      'Title:',
diff --git a/lib/lp/bugs/doc/externalbugtracker-debbugs.rst b/lib/lp/bugs/doc/externalbugtracker-debbugs.rst
index e418ae2..b2bd92e 100644
--- a/lib/lp/bugs/doc/externalbugtracker-debbugs.rst
+++ b/lib/lp/bugs/doc/externalbugtracker-debbugs.rst
@@ -317,7 +317,7 @@ description as the description.
     >>> print(report['Subject'])
     evolution: Multiple format string vulnerabilities in Evolution
 
-    >>> print(six.ensure_text(report.get_payload(decode=True)))
+    >>> print(report.get_payload(decode=True).decode())
     Package: evolution
     Severity: grave
     Tags: security
diff --git a/lib/lp/bugs/doc/initial-bug-contacts.rst b/lib/lp/bugs/doc/initial-bug-contacts.rst
index 7161f17..2985ec4 100644
--- a/lib/lp/bugs/doc/initial-bug-contacts.rst
+++ b/lib/lp/bugs/doc/initial-bug-contacts.rst
@@ -196,7 +196,7 @@ of the email with the bug title and URL.
     >>> msg['Subject']
     '[Bug 1] [NEW] Firefox does not support SVG'
 
-    >>> print(six.ensure_text(msg.get_payload(decode=True)))
+    >>> print(msg.get_payload(decode=True).decode())
     You have been subscribed to a public bug:
     <BLANKLINE>
     Firefox needs to support embedded SVG images, now that the standard has
diff --git a/lib/lp/charms/tests/test_charmrecipebuild.py b/lib/lp/charms/tests/test_charmrecipebuild.py
index a1739c2..1e7b069 100644
--- a/lib/lp/charms/tests/test_charmrecipebuild.py
+++ b/lib/lp/charms/tests/test_charmrecipebuild.py
@@ -8,7 +8,6 @@ from datetime import datetime, timedelta
 from urllib.request import urlopen
 
 import pytz
-import six
 from fixtures import FakeLogger
 from nacl.public import PrivateKey
 from pymacaroons import Macaroon
@@ -531,9 +530,9 @@ class TestCharmRecipeBuild(TestCaseWithFactory):
         self.assertEqual(
             "FAILEDTOBUILD", notification["X-Launchpad-Build-State"]
         )
-        body, footer = six.ensure_text(
-            notification.get_payload(decode=True)
-        ).split("\n-- \n")
+        body, footer = (
+            notification.get_payload(decode=True).decode().split("\n-- \n")
+        )
         self.assertEqual(expected_body % (build.log_url, ""), body)
         self.assertEqual(
             "http://launchpad.test/~person/charm-project/+charm/charm-1/";
diff --git a/lib/lp/charms/tests/test_charmrecipejob.py b/lib/lp/charms/tests/test_charmrecipejob.py
index 0a45645..53e4bca 100644
--- a/lib/lp/charms/tests/test_charmrecipejob.py
+++ b/lib/lp/charms/tests/test_charmrecipejob.py
@@ -5,7 +5,6 @@
 
 from textwrap import dedent
 
-import six
 from testtools.matchers import (
     AfterPreprocessing,
     ContainsDict,
@@ -265,7 +264,7 @@ class TestCharmRecipeRequestBuildsJob(TestCaseWithFactory):
         self.assertEqual(
             "Launchpad encountered an error during the following operation: "
             "requesting builds of %s.  Nonsense on stilts" % recipe.name,
-            six.ensure_text(notification.get_payload(decode=True)),
+            notification.get_payload(decode=True).decode(),
         )
         self.assertThat(
             job,
diff --git a/lib/lp/code/doc/branch-merge-proposal-notifications.rst b/lib/lp/code/doc/branch-merge-proposal-notifications.rst
index d9b8dde..6d27d37 100644
--- a/lib/lp/code/doc/branch-merge-proposal-notifications.rst
+++ b/lib/lp/code/doc/branch-merge-proposal-notifications.rst
@@ -147,7 +147,7 @@ An email is sent to subscribers of either branch and the default reviewer.
     Subscriber
     >>> print(notification['X-Launchpad-Message-For'])
     source-subscriber
-    >>> print(six.ensure_text(notification.get_payload(decode=True)))
+    >>> print(notification.get_payload(decode=True).decode())
     Eric has proposed merging
     lp://dev/~person-name...into lp://dev/~person-name...
     --
@@ -196,8 +196,7 @@ Fake the update preview diff as done.
     source@xxxxxxxxxxx, Subscriber, source-subscriber
     target@xxxxxxxxxxx, Subscriber, target-subscriber
     >>> notification = notifications[0]
-    >>> print(six.ensure_text(
-    ...     notification.get_payload()[0].get_payload(decode=True)))
+    >>> print(notification.get_payload()[0].get_payload(decode=True).decode())
     Eric has proposed merging
     lp://dev/~person-name...into lp://dev/~person-name...
     <BLANKLINE>
diff --git a/lib/lp/code/doc/branch-notifications.rst b/lib/lp/code/doc/branch-notifications.rst
index 7d73eeb..51a1ad0 100644
--- a/lib/lp/code/doc/branch-notifications.rst
+++ b/lib/lp/code/doc/branch-notifications.rst
@@ -64,8 +64,8 @@ also sends the email to the list of recipients.
     Subscriber
     >>> print(branch_notification['X-Launchpad-Message-For'])
     name12
-    >>> notification_body = six.ensure_text(
-    ...     branch_notification.get_payload(decode=True))
+    >>> notification_body = (
+    ...     branch_notification.get_payload(decode=True).decode())
     >>> print(notification_body)
     ... # noqa
     ... # doctest: -NORMALIZE_WHITESPACE
@@ -212,8 +212,7 @@ Limiting the size of diff received by email
     ...     else:
     ...         body = email.get_payload(decode=True)
     ...     print('To: %s\n%s%s' % (
-    ...         email['To'], six.ensure_text(body),
-    ...         six.ensure_text(attachment)))
+    ...         email['To'], body.decode(), attachment.decode()))
 
 We need to create some sufficiently large diffs to compare against.
 
diff --git a/lib/lp/code/doc/codeimport.rst b/lib/lp/code/doc/codeimport.rst
index 840388a..7ee6e91 100644
--- a/lib/lp/code/doc/codeimport.rst
+++ b/lib/lp/code/doc/codeimport.rst
@@ -111,7 +111,7 @@ three members of the vcs-imports team.
     Operator @vcs-imports
     >>> print(message['X-Launchpad-Message-For'])
     vcs-imports
-    >>> print(six.ensure_text(message.get_payload(decode=True)))
+    >>> print(message.get_payload(decode=True).decode())
     A new CVS code import has been requested by Code Import Person:
         http://code.launchpad.test/~import-person/widget/trunk-cvs
     from
diff --git a/lib/lp/code/mail/tests/test_branchmergeproposal.py b/lib/lp/code/mail/tests/test_branchmergeproposal.py
index 151f3a3..3da9c85 100644
--- a/lib/lp/code/mail/tests/test_branchmergeproposal.py
+++ b/lib/lp/code/mail/tests/test_branchmergeproposal.py
@@ -8,7 +8,6 @@ import re
 from difflib import unified_diff
 from textwrap import dedent
 
-import six
 import transaction
 from lazr.lifecycle.event import ObjectModifiedEvent
 from lazr.lifecycle.snapshot import Snapshot
@@ -641,9 +640,7 @@ class TestMergeProposalMailing(TestCaseWithFactory):
                 "bmp": canonical_url(bmp),
             }
         )
-        self.assertEqual(
-            expected, six.ensure_text(email.get_payload(decode=True))
-        )
+        self.assertEqual(expected, email.get_payload(decode=True).decode())
 
     def assertRecipientsMatches(self, recipients, mailer):
         """Assert that `mailer` will send to the people in `recipients`."""
@@ -794,9 +791,7 @@ class TestBranchMergeProposalRequestReview(TestCaseWithFactory):
                 "bmp": canonical_url(bmp),
             }
         )
-        self.assertEqual(
-            expected, six.ensure_text(sent_mail.get_payload(decode=True))
-        )
+        self.assertEqual(expected, sent_mail.get_payload(decode=True).decode())
 
     def test_nominateReview_emails_team_address(self):
         # If a review request is made for a team, the members of the team are
diff --git a/lib/lp/code/mail/tests/test_codeimport.py b/lib/lp/code/mail/tests/test_codeimport.py
index 622a51e..c27904a 100644
--- a/lib/lp/code/mail/tests/test_codeimport.py
+++ b/lib/lp/code/mail/tests/test_codeimport.py
@@ -6,7 +6,6 @@
 import email
 import textwrap
 
-import six
 import transaction
 
 from lp.code.enums import (
@@ -50,7 +49,7 @@ class TestNewCodeImports(TestCaseWithFactory):
             "\n"
             "-- \nYou are getting this email because you are a member of the "
             "vcs-imports team.\n",
-            six.ensure_text(msg.get_payload(decode=True)),
+            msg.get_payload(decode=True).decode(),
         )
 
     def test_svn_to_bzr_import(self):
@@ -78,7 +77,7 @@ class TestNewCodeImports(TestCaseWithFactory):
             "\n"
             "-- \nYou are getting this email because you are a member of the "
             "vcs-imports team.\n",
-            six.ensure_text(msg.get_payload(decode=True)),
+            msg.get_payload(decode=True).decode(),
         )
 
     def test_git_to_bzr_import(self):
@@ -106,7 +105,7 @@ class TestNewCodeImports(TestCaseWithFactory):
             "\n"
             "-- \nYou are getting this email because you are a member of the "
             "vcs-imports team.\n",
-            six.ensure_text(msg.get_payload(decode=True)),
+            msg.get_payload(decode=True).decode(),
         )
 
     def test_git_to_git_import(self):
@@ -136,7 +135,7 @@ class TestNewCodeImports(TestCaseWithFactory):
             "\n"
             "-- \nYou are getting this email because you are a member of the "
             "vcs-imports team.\n",
-            six.ensure_text(msg.get_payload(decode=True)),
+            msg.get_payload(decode=True).decode(),
         )
 
     def test_new_source_package_import(self):
@@ -173,7 +172,7 @@ class TestNewCodeImports(TestCaseWithFactory):
             "\n"
             "-- \nYou are getting this email because you are a member of the "
             "vcs-imports team.\n",
-            six.ensure_text(msg.get_payload(decode=True)),
+            msg.get_payload(decode=True).decode(),
         )
 
 
@@ -200,7 +199,7 @@ class TestUpdatedCodeImports(TestCaseWithFactory):
                 "details": details,
                 "unique_name": unique_name,
             },
-            six.ensure_text(msg.get_payload(decode=True)),
+            msg.get_payload(decode=True).decode(),
         )
 
     def assertDifferentDetailsEmail(
@@ -229,7 +228,7 @@ class TestUpdatedCodeImports(TestCaseWithFactory):
                 "new_details": new_details,
                 "unique_name": unique_name,
             },
-            six.ensure_text(msg.get_payload(decode=True)),
+            msg.get_payload(decode=True).decode(),
         )
 
     def test_cvs_to_bzr_import_same_details(self):
diff --git a/lib/lp/code/model/tests/test_branchjob.py b/lib/lp/code/model/tests/test_branchjob.py
index f9ce151..be039b5 100644
--- a/lib/lp/code/model/tests/test_branchjob.py
+++ b/lib/lp/code/model/tests/test_branchjob.py
@@ -335,9 +335,7 @@ class TestBranchUpgradeJob(TestCaseWithFactory):
         self.assertEqual(
             "Launchpad error while upgrading a branch", mail["subject"]
         )
-        self.assertIn(
-            "Not a branch", six.ensure_text(mail.get_payload(decode=True))
-        )
+        self.assertIn("Not a branch", mail.get_payload(decode=True).decode())
 
 
 class TestRevisionMailJob(TestCaseWithFactory):
@@ -395,7 +393,7 @@ class TestRevisionMailJob(TestCaseWithFactory):
                 "url": canonical_url(branch),
                 "identity": branch.bzr_identity,
             },
-            six.ensure_text(mail.get_payload(decode=True)),
+            mail.get_payload(decode=True).decode(),
         )
 
     def test_revno_string(self):
diff --git a/lib/lp/code/model/tests/test_branchmergeproposaljobs.py b/lib/lp/code/model/tests/test_branchmergeproposaljobs.py
index 9438d99..dd9a6e9 100644
--- a/lib/lp/code/model/tests/test_branchmergeproposaljobs.py
+++ b/lib/lp/code/model/tests/test_branchmergeproposaljobs.py
@@ -349,7 +349,7 @@ class TestUpdatePreviewDiffJob(DiffTestCase):
             "The source branch of http://code.launchpad.test/~%s/%s/%s/";
             "+merge/%d has no revisions."
             % (branch.owner.name, branch.target.name, branch.name, bmp.id),
-            six.ensure_text(email.get_payload(decode=True)),
+            email.get_payload(decode=True).decode(),
         )
 
     def test_run_branches_pending_writes(self):
@@ -771,7 +771,7 @@ class TestReviewRequestedEmailJob(TestCaseWithFactory):
         (notification,) = pop_notifications()
         self.assertIn(
             "You have been requested to review the proposed merge",
-            six.ensure_text(notification.get_payload(decode=True)),
+            notification.get_payload(decode=True).decode(),
         )
 
 
diff --git a/lib/lp/code/model/tests/test_gitrepository.py b/lib/lp/code/model/tests/test_gitrepository.py
index 4d26c93..670b4d6 100644
--- a/lib/lp/code/model/tests/test_gitrepository.py
+++ b/lib/lp/code/model/tests/test_gitrepository.py
@@ -11,7 +11,6 @@ from functools import partial
 from textwrap import dedent
 
 import pytz
-import six
 import transaction
 from breezy import urlutils
 from fixtures import MockPatch
@@ -1851,9 +1850,13 @@ class TestGitRepositoryModificationNotifications(TestCaseWithFactory):
             ).runAll()
         bodies_by_recipient = {}
         for from_addr, to_addrs, message in stub.test_emails:
-            body = email.message_from_bytes(message).get_payload(decode=True)
+            body = (
+                email.message_from_bytes(message)
+                .get_payload(decode=True)
+                .decode()
+            )
             for to_addr in to_addrs:
-                bodies_by_recipient[to_addr] = six.ensure_text(body)
+                bodies_by_recipient[to_addr] = body
         # Both the owner and the unprivileged subscriber receive email.
         self.assertContentEqual(
             [owner_address, subscriber_address], bodies_by_recipient.keys()
diff --git a/lib/lp/codehosting/scanner/tests/test_mergedetection.py b/lib/lp/codehosting/scanner/tests/test_mergedetection.py
index def12d1..b37b585 100644
--- a/lib/lp/codehosting/scanner/tests/test_mergedetection.py
+++ b/lib/lp/codehosting/scanner/tests/test_mergedetection.py
@@ -333,7 +333,7 @@ class TestBranchMergeDetectionHandler(TestCaseWithFactory):
         notifications = pop_notifications()
         self.assertIn(
             "Work in progress => Merged",
-            six.ensure_text(notifications[0].get_payload(decode=True)),
+            notifications[0].get_payload(decode=True).decode(),
         )
         self.assertEqual(proposal.address, notifications[0]["From"])
         recipients = {msg["x-envelope-to"] for msg in notifications}
diff --git a/lib/lp/registry/stories/gpg-coc/xx-gpg-coc.rst b/lib/lp/registry/stories/gpg-coc/xx-gpg-coc.rst
index d9c465e..6761538 100644
--- a/lib/lp/registry/stories/gpg-coc/xx-gpg-coc.rst
+++ b/lib/lp/registry/stories/gpg-coc/xx-gpg-coc.rst
@@ -65,7 +65,7 @@ followed by ASCII armored encrypted confirmation instructions.  Ensure that
 the clear text instructions contain the expected URLs pointing to more help.
 
     >>> cipher_body = msg.get_payload(decode=True)
-    >>> print(six.ensure_text(cipher_body))  # noqa
+    >>> print(cipher_body.decode())  # noqa
     Hello,
     <BLANKLINE>
     This message contains the instructions for confirming registration of an
@@ -192,7 +192,7 @@ ability to decrypt text with this key.
 The email does contain some information about the key, and a token URL
 Sample Person should visit to verify their ownership of the key.
 
-    >>> print(six.ensure_text(body))
+    >>> print(body.decode())
     <BLANKLINE>
     Hello,
     ...
@@ -629,7 +629,7 @@ Test if the advertisement email was sent:
     >>> from lp.services.mail import stub
     >>> from_addr, to_addrs, raw_msg = stub.test_emails.pop()
     >>> msg = email.message_from_bytes(raw_msg)
-    >>> print(six.ensure_text(msg.get_payload(decode=True)))
+    >>> print(msg.get_payload(decode=True).decode())
     <BLANKLINE>
     ...
     User: 'Mark Shuttleworth'
diff --git a/lib/lp/services/mail/doc/sending-mail.rst b/lib/lp/services/mail/doc/sending-mail.rst
index b520983..4d0047e 100644
--- a/lib/lp/services/mail/doc/sending-mail.rst
+++ b/lib/lp/services/mail/doc/sending-mail.rst
@@ -27,7 +27,7 @@ Now let's look at the sent email:
     'foo.bar@xxxxxxxxxxxxx'
     >>> msg['Subject']
     'Subject'
-    >>> print(six.ensure_text(msg.get_payload(decode=True)))
+    >>> print(msg.get_payload(decode=True).decode())
     Content
 
 Make sure bulk headers are set for vacation programs.
@@ -59,7 +59,7 @@ the person's name is encoded properly.
     'Foo Bar <foo.bar@xxxxxxxxxxxxx>'
     >>> msg['Subject']
     'Subject'
-    >>> print(six.ensure_text(msg.get_payload(decode=True)))
+    >>> print(msg.get_payload(decode=True).decode())
     Content
     >>> msg['Precedence']
     'bulk'
@@ -251,7 +251,7 @@ that the precedence header was not added.
     'feedback@xxxxxxxxxxxxx'
     >>> msg['Subject']
     'Forgot password'
-    >>> print(six.ensure_text(msg.get_payload(decode=True)))
+    >>> print(msg.get_payload(decode=True).decode())
     Content
     >>> print(msg['Precedence'])
     None
diff --git a/lib/lp/services/mail/tests/test_incoming.py b/lib/lp/services/mail/tests/test_incoming.py
index cb85217..3925782 100644
--- a/lib/lp/services/mail/tests/test_incoming.py
+++ b/lib/lp/services/mail/tests/test_incoming.py
@@ -10,7 +10,6 @@ from email.mime.multipart import MIMEMultipart
 from email.utils import parseaddr
 from textwrap import dedent
 
-import six
 import transaction
 from testtools.matchers import Equals, Is
 from zope.interface import implementer
@@ -110,9 +109,7 @@ class IncomingTestCase(TestCaseWithFactory):
         handleMail()
         self.assertEqual([], self.oopses)
         [notification] = pop_notifications()
-        body = six.ensure_text(
-            notification.get_payload()[0].get_payload(decode=True)
-        )
+        body = notification.get_payload()[0].get_payload(decode=True).decode()
         self.assertIn(
             "An error occurred while processing a mail you sent to "
             "Launchpad's email\ninterface.\n\n\n"
@@ -152,9 +149,7 @@ class IncomingTestCase(TestCaseWithFactory):
         handleMail()
         self.assertEqual([], self.oopses)
         [notification] = pop_notifications()
-        body = six.ensure_text(
-            notification.get_payload()[0].get_payload(decode=True)
-        )
+        body = notification.get_payload()[0].get_payload(decode=True).decode()
         self.assertIn(
             "An error occurred while processing a mail you sent to "
             "Launchpad's email\ninterface.\n\n\n"
@@ -196,9 +191,7 @@ class IncomingTestCase(TestCaseWithFactory):
         handleMail()
         self.assertEqual([], self.oopses)
         [notification] = pop_notifications()
-        body = six.ensure_text(
-            notification.get_payload()[0].get_payload(decode=True)
-        )
+        body = notification.get_payload()[0].get_payload(decode=True).decode()
         self.assertIn(
             "An error occurred while processing a mail you sent to "
             "Launchpad's email\ninterface.\n\n\n"
@@ -226,9 +219,7 @@ class IncomingTestCase(TestCaseWithFactory):
         handleMail()
         self.assertEqual([], self.oopses)
         [notification] = pop_notifications()
-        body = six.ensure_text(
-            notification.get_payload()[0].get_payload(decode=True)
-        )
+        body = notification.get_payload()[0].get_payload(decode=True).decode()
         self.assertIn("The mail you sent to Launchpad is too long.", body)
         self.assertIn("was 55 MB and the limit is 10 MB.", body)
 
diff --git a/lib/lp/services/verification/tests/test_logintoken.py b/lib/lp/services/verification/tests/test_logintoken.py
index 61f7534..cd70cb3 100644
--- a/lib/lp/services/verification/tests/test_logintoken.py
+++ b/lib/lp/services/verification/tests/test_logintoken.py
@@ -6,7 +6,6 @@
 import doctest
 from textwrap import dedent
 
-import six
 from testtools.matchers import DocTestMatches
 from zope.component import getUtility
 
@@ -81,5 +80,5 @@ class TestLoginToken(TestCaseWithFactory):
             expected_message, doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE
         )
         self.assertThat(
-            six.ensure_text(message.get_payload(decode=True)), expected_matcher
+            message.get_payload(decode=True).decode(), expected_matcher
         )
diff --git a/lib/lp/snappy/tests/test_snapbuild.py b/lib/lp/snappy/tests/test_snapbuild.py
index 9949862..c1e0378 100644
--- a/lib/lp/snappy/tests/test_snapbuild.py
+++ b/lib/lp/snappy/tests/test_snapbuild.py
@@ -7,7 +7,6 @@ from datetime import datetime, timedelta
 from urllib.request import urlopen
 
 import pytz
-import six
 from fixtures import FakeLogger
 from pymacaroons import Macaroon
 from testtools.matchers import (
@@ -533,9 +532,9 @@ class TestSnapBuild(TestCaseWithFactory):
         self.assertEqual(
             "FAILEDTOBUILD", notification["X-Launchpad-Build-State"]
         )
-        body, footer = six.ensure_text(
-            notification.get_payload(decode=True)
-        ).split("\n-- \n")
+        body, footer = (
+            notification.get_payload(decode=True).decode().split("\n-- \n")
+        )
         self.assertEqual(expected_body % (build.log_url, ""), body)
         self.assertEqual(
             "http://launchpad.test/~person/+snap/snap-1/+build/%d\n";
diff --git a/lib/lp/snappy/tests/test_snapbuildjob.py b/lib/lp/snappy/tests/test_snapbuildjob.py
index c145fdb..9c2ad2a 100644
--- a/lib/lp/snappy/tests/test_snapbuildjob.py
+++ b/lib/lp/snappy/tests/test_snapbuildjob.py
@@ -5,7 +5,6 @@
 
 from datetime import timedelta
 
-import six
 import transaction
 from fixtures import FakeLogger
 from testtools.matchers import (
@@ -312,9 +311,9 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
             "snap-build-upload-unauthorized",
             notification["X-Launchpad-Notification-Type"],
         )
-        body, footer = six.ensure_text(
-            notification.get_payload(decode=True)
-        ).split("\n-- \n")
+        body, footer = (
+            notification.get_payload(decode=True).decode().split("\n-- \n")
+        )
         self.assertIn(
             "http://launchpad.test/~requester-team/+snap/test-snap/+authorize";,
             body,
@@ -440,9 +439,9 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
             "snap-build-upload-refresh-failed",
             notification["X-Launchpad-Notification-Type"],
         )
-        body, footer = six.ensure_text(
-            notification.get_payload(decode=True)
-        ).split("\n-- \n")
+        body, footer = (
+            notification.get_payload(decode=True).decode().split("\n-- \n")
+        )
         self.assertIn(
             "http://launchpad.test/~requester-team/+snap/test-snap/+authorize";,
             body,
@@ -510,9 +509,9 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
             "snap-build-upload-failed",
             notification["X-Launchpad-Notification-Type"],
         )
-        body, footer = six.ensure_text(
-            notification.get_payload(decode=True)
-        ).split("\n-- \n")
+        body, footer = (
+            notification.get_payload(decode=True).decode().split("\n-- \n")
+        )
         self.assertIn("Failed to upload", body)
         build_url = (
             "http://launchpad.test/~requester-team/+snap/test-snap/+build/%d";
@@ -653,9 +652,9 @@ class TestSnapStoreUploadJob(TestCaseWithFactory):
             "snap-build-upload-scan-failed",
             notification["X-Launchpad-Notification-Type"],
         )
-        body, footer = six.ensure_text(
-            notification.get_payload(decode=True)
-        ).split("\n-- \n")
+        body, footer = (
+            notification.get_payload(decode=True).decode().split("\n-- \n")
+        )
         self.assertIn("Scan failed.", body)
         self.assertEqual(
             "http://launchpad.test/~requester-team/+snap/test-snap/+build/%d\n";
diff --git a/lib/lp/snappy/tests/test_snapjob.py b/lib/lp/snappy/tests/test_snapjob.py
index 77d0acd..0fb2ba9 100644
--- a/lib/lp/snappy/tests/test_snapjob.py
+++ b/lib/lp/snappy/tests/test_snapjob.py
@@ -5,7 +5,6 @@
 
 from textwrap import dedent
 
-import six
 from testtools.matchers import (
     AfterPreprocessing,
     ContainsDict,
@@ -264,7 +263,7 @@ class TestSnapRequestBuildsJob(TestCaseWithFactory):
         self.assertEqual(
             "Launchpad encountered an error during the following operation: "
             "requesting builds of %s.  Nonsense on stilts" % snap.name,
-            six.ensure_text(notification.get_payload(decode=True)),
+            notification.get_payload(decode=True).decode(),
         )
         self.assertThat(
             job,
@@ -315,7 +314,7 @@ class TestSnapRequestBuildsJob(TestCaseWithFactory):
             "Launchpad encountered an error during the following operation: "
             "requesting builds of %s.  No such base: "
             "'nonexistent'." % snap.name,
-            six.ensure_text(notification.get_payload(decode=True)),
+            notification.get_payload(decode=True).decode(),
         )
         self.assertThat(
             job,
diff --git a/lib/lp/soyuz/doc/build-failedtoupload-workflow.rst b/lib/lp/soyuz/doc/build-failedtoupload-workflow.rst
index bc241b5..1e6a93a 100644
--- a/lib/lp/soyuz/doc/build-failedtoupload-workflow.rst
+++ b/lib/lp/soyuz/doc/build-failedtoupload-workflow.rst
@@ -81,8 +81,8 @@ Note that the generated notification contain the 'extra_info' content:
     >>> build_notification['X-Creator-Recipient']
     'mark@xxxxxxxxxxx'
 
-    >>> notification_body = six.ensure_text(
-    ...     build_notification.get_payload(decode=True))
+    >>> notification_body = (
+    ...     build_notification.get_payload(decode=True).decode())
     >>> print(notification_body)  # noqa  # doctest: -NORMALIZE_WHITESPACE
     <BLANKLINE>
      * Source Package: cdrkit
diff --git a/lib/lp/soyuz/mail/tests/test_packageupload.py b/lib/lp/soyuz/mail/tests/test_packageupload.py
index ffb89af..d9200c9 100644
--- a/lib/lp/soyuz/mail/tests/test_packageupload.py
+++ b/lib/lp/soyuz/mail/tests/test_packageupload.py
@@ -3,7 +3,6 @@
 
 from textwrap import dedent
 
-import six
 from testtools.matchers import Contains, ContainsDict, Equals
 from zope.component import getUtility
 from zope.security.proxy import removeSecurityProxy
@@ -50,7 +49,7 @@ class TestNotificationRequiringLibrarian(TestCaseWithFactory):
         notifications = pop_notifications()
         self.assertEqual(2, len(notifications))
         msg = notifications[1].get_payload(0)
-        body = six.ensure_text(msg.get_payload(decode=True))
+        body = msg.get_payload(decode=True).decode()
         self.assertIn("Changed-By: Loïc", body)
         self.assertIn("Signed-By: Stéphane", body)
 
@@ -263,7 +262,7 @@ class TestNotificationRequiringLibrarian(TestCaseWithFactory):
         )
         mailer.sendAll()
         [notification] = pop_notifications()
-        body = six.ensure_text(notification.get_payload(decode=True))
+        body = notification.get_payload(decode=True).decode()
         self.assertEqual("Blamer <blamer@xxxxxxxxxxx>", notification["To"])
         expected_body = dedent(
             """\
diff --git a/lib/lp/soyuz/scripts/tests/test_copypackage.py b/lib/lp/soyuz/scripts/tests/test_copypackage.py
index 3186237..66ff8b7 100644
--- a/lib/lp/soyuz/scripts/tests/test_copypackage.py
+++ b/lib/lp/soyuz/scripts/tests/test_copypackage.py
@@ -5,7 +5,6 @@ import datetime
 from textwrap import dedent
 
 import pytz
-import six
 import transaction
 from testtools.content import text_content
 from testtools.matchers import (
@@ -1731,7 +1730,7 @@ class TestDoDirectCopy(BaseDoCopyTests, TestCaseWithFactory):
         self.assertEqual(
             target_archive.reference, notification["X-Launchpad-Archive"]
         )
-        body = six.ensure_text(notification.get_payload(decode=True))
+        body = notification.get_payload(decode=True).decode()
         expected = dedent(
             """\
             Accepted: