Index: Lib/distutils/tests/test_dist.py =================================================================== --- Lib/distutils/tests/test_dist.py (revision 62180) +++ Lib/distutils/tests/test_dist.py (working copy) @@ -1,5 +1,5 @@ """Tests for distutils.dist.""" - +# -*- coding: utf-8 -*- import distutils.cmd import distutils.dist import os @@ -179,7 +179,63 @@ dist.metadata.write_pkg_file(sio) return sio.getvalue() + def test_write_pkg_file(self): + # DistributionMetadata now stores some fields + # in Unicode : + # - author + # - maintainer + # - description + # - long_description + my_file = os.path.join(os.path.dirname(__file__), 'f') + klass = distutils.dist.Distribution + + dist = klass(attrs={'author': u'Mister Café', + 'name': 'my.package', + 'maintainer': u'Café Junior', + 'description': u'Café torréfié', + 'long_description': u'Héhéhé'}) + + + # let's make sure the file can be written + # with Unicode fields. they are encoded with + # dist.metadata.encoding (defaults to utf8) + try: + dist.metadata.write_pkg_file(open(my_file, 'w')) + finally: + if os.path.exists(my_file): + os.remove(my_file) + # we can also add an encoding field into the meta-data + # to specify the encoding in usage + dist = klass(attrs={'author': u'Mister Café', + 'name': 'my.package', + 'maintainer': u'Café Junior', + 'description': u'Café torréfié', + 'long_description': u'Héhéhé', + 'encoding': 'iso8859-15'}) + + try: + dist.metadata.write_pkg_file(open(my_file, 'w')) + finally: + if os.path.exists(my_file): + os.remove(my_file) + + # using the wrong encoding should brake + dist = klass(attrs={'author': u'Mister Café', + 'name': 'my.package', + 'maintainer': u'Café Junior', + 'description': u'Café torréfié', + 'long_description': u'Héhéhé', + 'encoding': 'ascii'}) + + try: + f = open(my_file, 'w') + self.assertRaises(UnicodeEncodeError, + dist.metadata.write_pkg_file, f) + finally: + if os.path.exists(my_file): + os.remove(my_file) + def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(DistributionTestCase)) Index: Lib/distutils/dist.py =================================================================== --- Lib/distutils/dist.py (revision 62180) +++ Lib/distutils/dist.py (working copy) @@ -250,7 +250,7 @@ # Now work on the rest of the attributes. Any attribute that's # not already defined is invalid! - for (key,val) in attrs.items(): + for key, val in attrs.items(): if hasattr(self.metadata, "set_" + key): getattr(self.metadata, "set_" + key)(val) elif hasattr(self.metadata, key): @@ -1043,22 +1043,28 @@ "license", "description", "long_description", "keywords", "platforms", "fullname", "contact", "contact_email", "license", "classifiers", - "download_url", + "download_url", "encoding", # PEP 314 "provides", "requires", "obsoletes", ) def __init__ (self): + # encoding + self.encoding = None + + # Unicode strings + self.author = None + self.maintainer = None + self.description = None + self.long_description = None + + # ASCII strings self.name = None self.version = None - self.author = None self.author_email = None - self.maintainer = None self.maintainer_email = None self.url = None self.license = None - self.description = None - self.long_description = None self.keywords = None self.platforms = None self.classifiers = None @@ -1078,6 +1084,10 @@ pkg_info.close() # write_pkg_info () + + def _encode_field(self, value): + """Will encode the value""" + return value.encode(self.get_encoding()) def write_pkg_file (self, file): """Write the PKG-INFO format data to a file object. @@ -1089,15 +1099,22 @@ file.write('Metadata-Version: %s\n' % version) file.write('Name: %s\n' % self.get_name() ) file.write('Version: %s\n' % self.get_version() ) - file.write('Summary: %s\n' % self.get_description() ) + + desc = self._encode_field(self.get_description()) + file.write('Summary: %s\n' % desc) + file.write('Home-page: %s\n' % self.get_url() ) - file.write('Author: %s\n' % self.get_contact() ) + + contact = self._encode_field(self.get_contact()) + file.write('Author: %s\n' % contact ) + file.write('Author-email: %s\n' % self.get_contact_email() ) file.write('License: %s\n' % self.get_license() ) if self.download_url: file.write('Download-URL: %s\n' % self.download_url) - long_desc = rfc822_escape( self.get_long_description() ) + long_desc = self._encode_field(self.get_long_description()) + long_desc = rfc822_escape(long_desc) file.write('Description: %s\n' % long_desc) keywords = string.join( self.get_keywords(), ',') @@ -1117,7 +1134,6 @@ file.write('%s: %s\n' % (name, value)) # -- Metadata query methods ---------------------------------------- - def get_name (self): return self.name or "UNKNOWN" @@ -1128,13 +1144,13 @@ return "%s-%s" % (self.get_name(), self.get_version()) def get_author(self): - return self.author or "UNKNOWN" + return self.author or u"UNKNOWN" # Unicode field def get_author_email(self): return self.author_email or "UNKNOWN" def get_maintainer(self): - return self.maintainer or "UNKNOWN" + return self.maintainer or u"UNKNOWN" # Unicode field def get_maintainer_email(self): return self.maintainer_email or "UNKNOWN" @@ -1142,7 +1158,7 @@ def get_contact(self): return (self.maintainer or self.author or - "UNKNOWN") + u"UNKNOWN") # Unicode field def get_contact_email(self): return (self.maintainer_email or @@ -1157,10 +1173,10 @@ get_licence = get_license def get_description(self): - return self.description or "UNKNOWN" + return self.description or u"UNKNOWN" # Unicode field def get_long_description(self): - return self.long_description or "UNKNOWN" + return self.long_description or u"UNKNOWN" # Unicode field def get_keywords(self): return self.keywords or [] @@ -1174,6 +1190,9 @@ def get_download_url(self): return self.download_url or "UNKNOWN" + def get_encoding(self): + return self.encoding or "utf8" + # PEP 314 def get_requires(self):