launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #19084
[Merge] lp:~wgrant/launchpad/maintainably-fix-safe-fix-maintainer into lp:launchpad
William Grant has proposed merging lp:~wgrant/launchpad/maintainably-fix-safe-fix-maintainer into lp:launchpad.
Commit message:
Split fix_maintainer into parse_maintainer and rfc(822|2047)_encode_address. Fixes Unicode handling in some callsites like SignableTagFile.parseAddress's creation case.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1479160 in Launchpad itself: "SignableTagFile.parseAddress fails to create a person with a non-ASCII name"
https://bugs.launchpad.net/launchpad/+bug/1479160
For more details, see:
https://code.launchpad.net/~wgrant/launchpad/maintainably-fix-safe-fix-maintainer/+merge/266185
Split fix_maintainer up into parse_maintainer and rfc(822|2047)_encode_address. parse_maintainer now returns Unicode, fixing SignableTagFile.parseAddress when it attempts to create a person with a non-ASCII displayname.
The RFC2047-encoded address no longer respects the address's original encoding, but that actually didn't happen anyway, since everything used safe_fix_maintainer which converts everything to UTF-8 first.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/launchpad/maintainably-fix-safe-fix-maintainer into lp:launchpad.
=== modified file 'lib/lp/archiveuploader/changesfile.py'
--- lib/lp/archiveuploader/changesfile.py 2015-04-21 10:03:15 +0000
+++ lib/lp/archiveuploader/changesfile.py 2015-07-29 07:00:05 +0000
@@ -37,6 +37,7 @@
re_changes_file_name,
re_isadeb,
re_issource,
+ rfc822_encode_address,
UploadError,
UploadWarning,
)
@@ -355,10 +356,10 @@
-- <CHANGED-BY> <DATE>
}}}
"""
- changes_author = (
- '\n\n -- %s %s' %
- (self.changed_by['rfc822'], self.date))
- return self.changes_comment + changes_author
+ changes_author = rfc822_encode_address(
+ self.changed_by['name'], self.changed_by['email'])
+ return '%s\n\n -- %s %s' % (
+ self.changes_comment, changes_author.encode('utf-8'), self.date)
def determine_file_class_and_name(filename):
=== modified file 'lib/lp/archiveuploader/dscfile.py'
--- lib/lp/archiveuploader/dscfile.py 2014-07-23 05:53:56 +0000
+++ lib/lp/archiveuploader/dscfile.py 2015-07-29 07:00:05 +0000
@@ -44,12 +44,12 @@
extract_dpkg_source,
get_source_file_extension,
parse_and_merge_file_lists,
+ parse_maintainer_bytes,
ParseMaintError,
re_is_component_orig_tar_ext,
re_issource,
re_valid_pkg_name,
re_valid_version,
- safe_fix_maintainer,
UploadError,
UploadWarning,
)
@@ -189,13 +189,11 @@
for any reason, or if the email address then cannot be found within
the launchpad database.
- Return a dict containing the rfc822 and rfc2047 formatted forms of
- the address, the person's name, email address and person record within
- the launchpad database.
+ Return a dict containing the person's name, email address and
+ person record within the launchpad database.
"""
try:
- (rfc822, rfc2047, name, email) = safe_fix_maintainer(
- addr, fieldname)
+ (name, email) = parse_maintainer_bytes(addr, fieldname)
except ParseMaintError as error:
raise UploadError(str(error))
@@ -226,8 +224,6 @@
% (name, email))
return {
- "rfc822": rfc822,
- "rfc2047": rfc2047,
"name": name,
"email": email,
"person": person,
=== modified file 'lib/lp/archiveuploader/tests/nascentuploadfile.txt'
--- lib/lp/archiveuploader/tests/nascentuploadfile.txt 2015-01-28 17:54:06 +0000
+++ lib/lp/archiveuploader/tests/nascentuploadfile.txt 2015-07-29 07:00:05 +0000
@@ -298,16 +298,14 @@
The built address_structure contains values that will be used during
the upload processing:
- >>> ed_binary_changes.maintainer['rfc822']
- 'James Troup <james@xxxxxxxxxx>'
- >>> ed_binary_changes.maintainer['rfc2047']
- 'James Troup <james@xxxxxxxxxx>'
>>> ed_binary_changes.maintainer['name']
- 'James Troup'
+ u'James Troup'
>>> ed_binary_changes.maintainer['email']
- 'james@xxxxxxxxxx'
+ u'james@xxxxxxxxxx'
>>> ed_binary_changes.maintainer['person']
<Person ...>
+ >>> ed_binary_changes.maintainer['person'].displayname
+ u'James Troup'
Signature Traces
@@ -372,8 +370,8 @@
the author. The DSCFile class implements the same address parsing
methods found in ChangesFile:
- >>> ed_source_dsc.maintainer['rfc822']
- 'James Troup <james@xxxxxxxxxx>'
+ >>> ed_source_dsc.maintainer['person'].displayname
+ u'James Troup'
The DSC signer IPerson:
=== removed file 'lib/lp/archiveuploader/tests/safe_fix_maintainer.txt'
--- lib/lp/archiveuploader/tests/safe_fix_maintainer.txt 2015-07-07 12:48:40 +0000
+++ lib/lp/archiveuploader/tests/safe_fix_maintainer.txt 1970-01-01 00:00:00 +0000
@@ -1,43 +0,0 @@
-Test some utils method inherited from DAK:
-
-safe_fix_maintainer() is a function used to sanitise the
-identification fields coming from the Debian control files (changes
-and dsc). It allows safe unicode and non-unicode inputs.
-
- >>> from lp.archiveuploader.utils import safe_fix_maintainer
-
- >>> maintainer_field = 'maintainer'
- >>> changer_field = 'changed-by'
-
-Pure ASCII content using the two available fieldname (pretty much the same)
-
- >>> content = 'Hello World <hello@xxxxxxxxx>'
- >>> safe_fix_maintainer(content, maintainer_field)
- ('Hello World <hello@xxxxxxxxx>', 'Hello World <hello@xxxxxxxxx>',
- 'Hello World', 'hello@xxxxxxxxx')
-
- >>> content = 'Hello World <hello@xxxxxxxxx>'
- >>> safe_fix_maintainer(content, changer_field)
- ('Hello World <hello@xxxxxxxxx>', 'Hello World <hello@xxxxxxxxx>',
- 'Hello World', 'hello@xxxxxxxxx')
-
-
-Passing Unicode:
-
- # XXX cprov 2006-02-20 bug=32148: Not sure if it is working properly,
- # at least doesn't raise any exception like in bug #32148.
-
- >>> content = u'Rapha\xc3l Pinson <raphink@xxxxxxxxxx>'
- >>> safe_fix_maintainer(content, maintainer_field)
- ('Rapha\xc3\x83l Pinson <raphink@xxxxxxxxxx>',
- '=?utf-8?q?Rapha=C3=83l_Pinson?= <raphink@xxxxxxxxxx>',
- 'Rapha\xc3\x83l Pinson', 'raphink@xxxxxxxxxx')
-
-
-Passing latin encoded string:
-
- >>> content = 'Rapha\xebl Pinson <raphink@xxxxxxxxxx>'
- >>> safe_fix_maintainer(content, maintainer_field)
- ('Rapha\xc3\xabl Pinson <raphink@xxxxxxxxxx>',
- '=?utf-8?q?Rapha=C3=ABl_Pinson?= <raphink@xxxxxxxxxx>',
- 'Rapha\xc3\xabl Pinson', 'raphink@xxxxxxxxxx')
=== modified file 'lib/lp/archiveuploader/tests/test_changesfile.py'
--- lib/lp/archiveuploader/tests/test_changesfile.py 2015-04-21 10:03:15 +0000
+++ lib/lp/archiveuploader/tests/test_changesfile.py 2015-07-29 07:00:05 +0000
@@ -8,7 +8,11 @@
import os
from debian.deb822 import Changes
-from testtools.matchers import MatchesStructure
+from testtools.matchers import (
+ Equals,
+ MatchesDict,
+ MatchesStructure,
+ )
from zope.component import getUtility
from lp.archiveuploader.changesfile import (
@@ -252,8 +256,13 @@
self.assertEquals(None, changes.changed_by)
errors = list(changes.processAddresses())
self.assertEquals(0, len(errors), "Errors: %r" % errors)
- self.assertEquals(
- "Somebody <somebody@xxxxxxxxxx>", changes.changed_by['rfc822'])
+ self.assertThat(
+ changes.changed_by,
+ MatchesDict({
+ "name": Equals(u"Somebody"),
+ "email": Equals(u"somebody@xxxxxxxxxx"),
+ "person": MatchesStructure.byEquality(displayname=u"Somebody"),
+ }))
def test_simulated_changelog(self):
# The simulated_changelog property returns a changelog entry based on
=== modified file 'lib/lp/archiveuploader/tests/test_dscfile.py'
--- lib/lp/archiveuploader/tests/test_dscfile.py 2014-06-11 08:29:09 +0000
+++ lib/lp/archiveuploader/tests/test_dscfile.py 2015-07-29 07:00:05 +0000
@@ -187,6 +187,16 @@
UploadError,
self.makeSignableTagFile().parseAddress, "invalid@bad-address")
+ def test_parseAddress_decodes_utf8(self):
+ name = u'B\u0105r'
+ email = u'bar@xxxxxxxxxxx'
+ results = self.makeSignableTagFile().parseAddress(
+ '%s <%s>' % (name.encode('utf-8'), email.encode('utf-8')))
+ self.assertEqual(email, results['email'])
+ self.assertEqual(name, results['name'])
+ self.assertEqual(name, results['person'].displayname)
+ self.assertEqual(email, results['person'].guessedemails[0].email)
+
class TestDscFileLibrarian(TestCaseWithFactory):
"""Tests for DscFile that may use the Librarian."""
=== modified file 'lib/lp/archiveuploader/tests/test_utils.py'
--- lib/lp/archiveuploader/tests/test_utils.py 2011-03-21 12:55:50 +0000
+++ lib/lp/archiveuploader/tests/test_utils.py 2015-07-29 07:00:05 +0000
@@ -6,6 +6,9 @@
# arch-tag: 90e6eb79-83a2-47e8-9f8b-3c687079c923
import os
+import re
+
+from testtools.testcase import ExpectedException
from lp.archiveuploader.tests import datadir
from lp.archiveuploader.utils import (
@@ -139,94 +142,99 @@
self.assertEquals(sect, "libs")
self.assertEquals(comp, "restricted")
- def testFixMaintainerOkay(self):
- """lp.archiveuploader.utils.fix_maintainer should parse correct values
+ def testParseMaintainerOkay(self):
+ """lp.archiveuploader.utils.parse_maintainer should parse correctly
"""
- from lp.archiveuploader.utils import fix_maintainer
+ from lp.archiveuploader.utils import (
+ parse_maintainer_bytes,
+ rfc2047_encode_address,
+ rfc822_encode_address,
+ )
cases = (
("No\xc3\xa8l K\xc3\xb6the <noel@xxxxxxxxxx>",
- "No\xc3\xa8l K\xc3\xb6the <noel@xxxxxxxxxx>",
- "=?utf-8?b?Tm/DqGwgS8O2dGhl?= <noel@xxxxxxxxxx>",
- "No\xc3\xa8l K\xc3\xb6the",
- "noel@xxxxxxxxxx"),
+ u"No\xe8l K\xf6the <noel@xxxxxxxxxx>",
+ u"=?utf-8?b?Tm/DqGwgS8O2dGhl?= <noel@xxxxxxxxxx>",
+ u"No\xe8l K\xf6the",
+ u"noel@xxxxxxxxxx"),
("No\xe8l K\xf6the <noel@xxxxxxxxxx>",
- "No\xc3\xa8l K\xc3\xb6the <noel@xxxxxxxxxx>",
- "=?iso-8859-1?q?No=E8l_K=F6the?= <noel@xxxxxxxxxx>",
- "No\xc3\xa8l K\xc3\xb6the",
- "noel@xxxxxxxxxx"),
+ u"No\xe8l K\xf6the <noel@xxxxxxxxxx>",
+ u"=?utf-8?b?Tm/DqGwgS8O2dGhl?= <noel@xxxxxxxxxx>",
+ u"No\xe8l K\xf6the",
+ u"noel@xxxxxxxxxx"),
("James Troup <james@xxxxxxxxxx>",
- "James Troup <james@xxxxxxxxxx>",
- "James Troup <james@xxxxxxxxxx>",
- "James Troup",
- "james@xxxxxxxxxx"),
+ u"James Troup <james@xxxxxxxxxx>",
+ u"James Troup <james@xxxxxxxxxx>",
+ u"James Troup",
+ u"james@xxxxxxxxxx"),
("James J. Troup <james@xxxxxxxxxx>",
- "james@xxxxxxxxxx (James J. Troup)",
- "james@xxxxxxxxxx (James J. Troup)",
- "James J. Troup",
- "james@xxxxxxxxxx"),
+ u"james@xxxxxxxxxx (James J. Troup)",
+ u"james@xxxxxxxxxx (James J. Troup)",
+ u"James J. Troup",
+ u"james@xxxxxxxxxx"),
("James J, Troup <james@xxxxxxxxxx>",
- "james@xxxxxxxxxx (James J, Troup)",
- "james@xxxxxxxxxx (James J, Troup)",
- "James J, Troup",
- "james@xxxxxxxxxx"),
+ u"james@xxxxxxxxxx (James J, Troup)",
+ u"james@xxxxxxxxxx (James J, Troup)",
+ u"James J, Troup",
+ u"james@xxxxxxxxxx"),
("james@xxxxxxxxxx",
- " <james@xxxxxxxxxx>",
- " <james@xxxxxxxxxx>",
- "",
- "james@xxxxxxxxxx"),
+ u" <james@xxxxxxxxxx>",
+ u" <james@xxxxxxxxxx>",
+ u"",
+ u"james@xxxxxxxxxx"),
("<james@xxxxxxxxxx>",
- " <james@xxxxxxxxxx>",
- " <james@xxxxxxxxxx>",
- "",
- "james@xxxxxxxxxx"),
+ u" <james@xxxxxxxxxx>",
+ u" <james@xxxxxxxxxx>",
+ u"",
+ u"james@xxxxxxxxxx"),
("Cris van Pelt <\"Cris van Pelt\"@tribe.eu.org>",
- "Cris van Pelt <\"Cris van Pelt\"@tribe.eu.org>",
- "Cris van Pelt <\"Cris van Pelt\"@tribe.eu.org>",
- "Cris van Pelt",
- "\"Cris van Pelt\"@tribe.eu.org"),
+ u"Cris van Pelt <\"Cris van Pelt\"@tribe.eu.org>",
+ u"Cris van Pelt <\"Cris van Pelt\"@tribe.eu.org>",
+ u"Cris van Pelt",
+ u"\"Cris van Pelt\"@tribe.eu.org"),
("Zak B. Elep <zakame@xxxxxxxxxx>",
- "zakame@xxxxxxxxxx (Zak B. Elep)",
- "zakame@xxxxxxxxxx (Zak B. Elep)",
- "Zak B. Elep",
- "zakame@xxxxxxxxxx"),
+ u"zakame@xxxxxxxxxx (Zak B. Elep)",
+ u"zakame@xxxxxxxxxx (Zak B. Elep)",
+ u"Zak B. Elep",
+ u"zakame@xxxxxxxxxx"),
("zakame@xxxxxxxxxx (Zak B. Elep)",
- " <zakame@xxxxxxxxxx (Zak B. Elep)>",
- " <zakame@xxxxxxxxxx (Zak B. Elep)>",
- "",
- "zakame@xxxxxxxxxx (Zak B. Elep)"),
+ u" <zakame@xxxxxxxxxx (Zak B. Elep)>",
+ u" <zakame@xxxxxxxxxx (Zak B. Elep)>",
+ u"",
+ u"zakame@xxxxxxxxxx (Zak B. Elep)"),
)
for case in cases:
- (a, b, c, d) = fix_maintainer(case[0])
- self.assertEquals(case[1], a)
- self.assertEquals(case[2], b)
- self.assertEquals(case[3], c)
- self.assertEquals(case[4], d)
+ (name, email) = parse_maintainer_bytes(case[0], 'Maintainer')
+ self.assertEquals(case[3], name)
+ self.assertEquals(case[4], email)
+ self.assertEquals(case[1], rfc822_encode_address(name, email))
+ self.assertEquals(case[2], rfc2047_encode_address(name, email))
- def testFixMaintainerRaises(self):
- """lp.archiveuploader.utils.fix_maintainer should raise on incorrect
+ def testParseMaintainerRaises(self):
+ """lp.archiveuploader.utils.parse_maintainer should raise on incorrect
values
"""
- from lp.archiveuploader.utils import fix_maintainer, ParseMaintError
+ from lp.archiveuploader.utils import (
+ parse_maintainer_bytes,
+ ParseMaintError,
+ )
cases = (
"James Troup",
"James Troup <james>",
- "James Troup <james@xxxxxxxxxx")
+ "James Troup <james@xxxxxxxxxx",
+ "No\xc3\xa8l K\xc3\xb6the")
for case in cases:
- try:
- fix_maintainer(case)
- self.assertNotReached()
- except ParseMaintError:
- pass
+ with ExpectedException(ParseMaintError, '^%s: ' % re.escape(case)):
+ parse_maintainer_bytes(case, 'Maintainer')
class TestFilenameRegularExpressions(TestCase):
=== modified file 'lib/lp/archiveuploader/utils.py'
--- lib/lp/archiveuploader/utils.py 2015-07-07 12:46:26 +0000
+++ lib/lp/archiveuploader/utils.py 2015-07-29 07:00:05 +0000
@@ -12,6 +12,7 @@
'extract_dpkg_source',
'get_source_file_extension',
'parse_and_merge_file_lists',
+ 'parse_maintainer_bytes',
'ParseMaintError',
'prefix_multi_line_string',
're_taint_free',
@@ -24,14 +25,15 @@
're_valid_pkg_name',
're_changes_file_name',
're_extract_src_version',
- 'safe_fix_maintainer',
+ 'rfc2047_encode_address',
+ 'rfc822_encode_address',
'UploadError',
'UploadWarning',
]
from collections import defaultdict
-import email.header
+from email.header import Header
import os
import re
import signal
@@ -157,42 +159,6 @@
return (section, component)
-def force_to_utf8(s):
- """Forces a string to UTF-8.
-
- If the string isn't already UTF-8, it's assumed to be ISO-8859-1.
- """
- try:
- unicode(s, 'utf-8')
- return s
- except UnicodeError:
- latin1_s = unicode(s, 'iso8859-1')
- return latin1_s.encode('utf-8')
-
-
-def rfc2047_encode(s):
- """Encodes a (header) string per RFC2047 if necessary.
-
- If the string is neither ASCII nor UTF-8, it's assumed to be ISO-8859-1.
- """
- if not s:
- return ''
- try:
- s.decode('us-ascii')
- #encodings.ascii.Codec().decode(s)
- return s
- except UnicodeError:
- pass
- try:
- s.decode('utf8')
- #encodings.utf_8.Codec().decode(s)
- h = email.header.Header(s, 'utf-8', 998)
- return str(h)
- except UnicodeError:
- h = email.header.Header(s, 'iso-8859-1', 998)
- return str(h)
-
-
class ParseMaintError(Exception):
"""Exception raised for errors in parsing a maintainer field.
@@ -206,73 +172,85 @@
self.message = message
-def fix_maintainer(maintainer, field_name="Maintainer"):
- """Parses a Maintainer or Changed-By field and returns:
-
- (1) an RFC822 compatible version,
- (2) an RFC2047 compatible version,
- (3) the name
- (4) the email
-
- The name is forced to UTF-8 for both (1) and (3). If the name field
- contains '.' or ',', (1) and (2) are switched to 'email (name)' format.
+def parse_maintainer(maintainer, field_name="Maintainer"):
+ """Parses a Maintainer or Changed-By field into the name and address.
+
+ maintainer, name and address are all Unicode.
"""
maintainer = maintainer.strip()
if not maintainer:
- return ('', '', '', '')
+ return (u'', u'')
- if maintainer.find("<") == -1:
+ if maintainer.find(u"<") == -1:
email = maintainer
- name = ""
- elif (maintainer[0] == "<" and maintainer[-1:] == ">"):
+ name = u""
+ elif (maintainer[0] == u"<" and maintainer[-1:] == u">"):
email = maintainer[1:-1]
- name = ""
+ name = u""
else:
m = re_parse_maintainer.match(maintainer)
if not m:
raise ParseMaintError(
"%s: doesn't parse as a valid %s field."
- % (maintainer, field_name))
+ % (maintainer.encode("utf-8"), field_name))
name = m.group(1)
email = m.group(2)
# Just in case the maintainer ended up with nested angles; check...
- while email.startswith("<"):
+ while email.startswith(u"<"):
email = email[1:]
- # Get an RFC2047 compliant version of the name
- rfc2047_name = rfc2047_encode(name)
-
- # Force the name to be UTF-8
- name = force_to_utf8(name)
-
+ if email.find(u"@") == -1 and email.find(u"buildd_") != 0:
+ raise ParseMaintError(
+ "%s: no @ found in email address part." %
+ maintainer.encode("utf-8"))
+
+ return (name, email)
+
+
+def parse_maintainer_bytes(content, fieldname):
+ """Wrapper for parse_maintainer to handle both Unicode and bytestrings.
+
+ It verifies the content type and transforms it to a unicode with
+ guess(). Then we can safely call parse_maintainer().
+ """
+ if type(content) != unicode:
+ content = guess_encoding(content)
+ return parse_maintainer(content, fieldname)
+
+
+def rfc822_encode_address(name, email):
+ """Return a Unicode RFC822 encoding of a name and an email address.
+
+ name and email must be Unicode. If they contain non-ASCII
+ characters, the result is not RFC822-compliant and you should use
+ rfc2047_encode_address instead.
+
+ If the name field contains '.' or ',' the 'email (name)' format is used.
+ """
# If the maintainer's name contains a full stop then the whole field will
# not work directly as an email address due to a misfeature in the syntax
# specified in RFC822; see Debian policy 5.6.2 (Maintainer field syntax)
# for details.
- if name.find(',') != -1 or name.find('.') != -1:
- rfc822_maint = "%s (%s)" % (email, name)
- rfc2047_maint = "%s (%s)" % (email, rfc2047_name)
+ if name.find(u',') != -1 or name.find(u'.') != -1:
+ return u"%s (%s)" % (email, name)
else:
- rfc822_maint = "%s <%s>" % (name, email)
- rfc2047_maint = "%s <%s>" % (rfc2047_name, email)
-
- if email.find("@") == -1 and email.find("buildd_") != 0:
- raise ParseMaintError(
- "%s: no @ found in email address part." % maintainer)
-
- return (rfc822_maint, rfc2047_maint, name, email)
-
-
-def safe_fix_maintainer(content, fieldname):
- """Wrapper for fix_maintainer() to handle unicode and string argument.
-
- It verifies the content type and transforms it to a unicode with
- guess(). Then we can safely call fix_maintainer().
+ return u"%s <%s>" % (name, email)
+
+
+def rfc2047_encode_address(name, email):
+ """Return an RFC2047 encoding of a name and an email address.
+
+ name and email must be Unicode strings, and email must be
+ ASCII-only.
+
+ If the name field contains '.' or ',' the 'email (name)' format is used.
"""
- if type(content) != unicode:
- content = guess_encoding(content)
-
- return fix_maintainer(content.encode("utf-8"), fieldname)
+ try:
+ email.encode('ascii')
+ except UnicodeDecodeError:
+ raise AssertionError("Email addresses must be ASCII.")
+ return rfc822_encode_address(
+ Header(name, 'utf-8', 998).encode().decode('ascii'), email)
def extract_dpkg_source(dsc_filepath, target, vendor=None):
=== modified file 'lib/lp/soyuz/adapters/notification.py'
--- lib/lp/soyuz/adapters/notification.py 2015-07-21 09:04:01 +0000
+++ lib/lp/soyuz/adapters/notification.py 2015-07-29 07:00:05 +0000
@@ -21,8 +21,10 @@
from lp.archivepublisher.utils import get_ppa_reference
from lp.archiveuploader.changesfile import ChangesFile
from lp.archiveuploader.utils import (
+ parse_maintainer_bytes,
ParseMaintError,
- safe_fix_maintainer,
+ rfc2047_encode_address,
+ rfc822_encode_address,
)
from lp.registry.interfaces.person import IPersonSet
from lp.registry.interfaces.pocket import PackagePublishingPocket
@@ -577,7 +579,7 @@
def fix_email(fullemail, field_name):
"""Turn an email address from .changes into various useful forms.
- The input address may be None, or anything that `fix_maintainer`
+ The input address may be None, or anything that `parse_maintainer_bytes`
understands.
:return: A tuple of (RFC2047-compatible address, Unicode
@@ -587,8 +589,11 @@
return None, None, None
try:
- rfc822, rfc2047, _, email = safe_fix_maintainer(fullemail, field_name)
- return rfc2047, rfc822.decode('utf-8'), email
+ name, email = parse_maintainer_bytes(fullemail, field_name)
+ return (
+ rfc2047_encode_address(name, email).encode('utf-8'),
+ rfc822_encode_address(name, email),
+ email.encode('ascii'))
except ParseMaintError:
return None, None, None
Follow ups