Index: Lib/distutils/tests/test_dist.py =================================================================== --- Lib/distutils/tests/test_dist.py (révision 68535) +++ Lib/distutils/tests/test_dist.py (copie de travail) @@ -155,6 +155,18 @@ self.assertEquals(len(warns), 0) +WANTED_DESC = """\ +`SomePackage` is a package that does nothing. + +Examples +======== + +An example:: + + >>> 1 + 1 + 2 +""" + class MetadataTestCase(unittest.TestCase): def test_simple_metadata(self): @@ -282,7 +294,28 @@ continue os.environ[key] = value os.remove(user_filename) + + def test_reading_file(self): + pkg_file = os.path.join(os.path.dirname(__file__), 'some.egg-info') + + # now let's try to read it + metadata = distutils.dist.DistributionMetadata(pkg_file) + self.assertEquals(metadata.name, 'SomePackage') + self.assertEquals(metadata.version, '0.52') + self.assertEquals(metadata.summary, 'Very cool') + self.assertEquals(metadata.author, 'SomeGuy') + self.assertEquals(metadata.author_email, 'some.guy@example.com') + self.assertEquals(metadata.url, 'http://example.com') + self.assertEquals(metadata.long_description, WANTED_DESC) + self.assertEquals(metadata.keywords, ['one', 'two', 'three']) + + classifiers = ['Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Programming Language :: Python'] + + self.assertEquals(metadata.classifiers, classifiers) + def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(DistributionTestCase)) Index: Lib/distutils/util.py =================================================================== --- Lib/distutils/util.py (révision 68535) +++ Lib/distutils/util.py (copie de travail) @@ -547,3 +547,8 @@ lines = map(string.strip, lines) header = string.join(lines, '\n' + 8*' ') return header + +def rfc822_unescape(header): + """Removes the 8 spaces space after each newline in a RFC-822 header""" + return '\n'.join(header.split('\n' + 8*' ')) + Index: Lib/distutils/dist.py =================================================================== --- Lib/distutils/dist.py (révision 68535) +++ Lib/distutils/dist.py (copie de travail) @@ -19,7 +19,8 @@ from distutils.errors import * from distutils.fancy_getopt import FancyGetopt, translate_longopt -from distutils.util import check_environ, strtobool, rfc822_escape +from distutils.util import (check_environ, strtobool, rfc822_escape, + rfc822_unescape) from distutils import log from distutils.debug import DEBUG @@ -1050,25 +1051,28 @@ "provides", "requires", "obsoletes", ) - def __init__ (self): - 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 - self.download_url = None - # PEP 314 - self.provides = None - self.requires = None - self.obsoletes = None + def __init__ (self, file=None): + if file is not None: + self.read_pkg_file(file) + else: + 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 + self.download_url = None + # PEP 314 + self.provides = None + self.requires = None + self.obsoletes = None def write_pkg_info (self, base_dir): """Write the PKG-INFO file into the release tree. @@ -1081,6 +1085,56 @@ # write_pkg_info () + def read_pkg_file(self, file): + """Reads from a PKG-INFO file object and initialize the instance. + """ + if isinstance(file, str): + file = open(file, 'rU') + + pkg_info = file.read() + re_options = re.I|re.DOTALL|re.M + + def _extract(fieldname): + if fieldname == 'Description': + # crappy + pattern = r'^Description: (.*)' + res = re.findall(pattern, pkg_info , re_options) + if len(res) == 0: + return 'UNKNOWN' + else: + res = res[0].split('\n' + 8*' ') + res = [r for r in res if not r.startswith('\n')] + return '\n'.join(res) + '\n' + + pattern = r'^%s: (.*?)$' % fieldname + res = re.findall(pattern, pkg_info , re_options) + if fieldname in ('Classifier', 'Requires', 'Provides', + 'Obsolete'): + return res + if len(res) == 0: + return 'UNKNOWN' + return res[0] + + version = _extract('Metadata-Version') + self.name = _extract('Name') + self.version = _extract('Version') + self.summary = _extract('Summary') + self.url = _extract('Home-page') + self.author = _extract('Author') + self.author_email = _extract('Author-email') + self.license = _extract('License') + self.download_url = _extract('Download-URL') + self.long_description = _extract('Description') + self.keywords = _extract('Keywords').split(',') + self.classifiers = _extract('Classifier') + self.platform = _extract('Platform') + + # PEP 314 + if version == '1.1': + self.requires = _extract('Requires') + self.provides = _extract('Provides') + self.obsoletes = _extract('Obsoletes') + def write_pkg_file (self, file): """Write the PKG-INFO format data to a file object. """ Index: Lib/test/test_pkgutil.py =================================================================== --- Lib/test/test_pkgutil.py (révision 68535) +++ Lib/test/test_pkgutil.py (copie de travail) @@ -9,6 +9,7 @@ import shutil import zipfile +from pkgutil import get_metadata class PkgutilTests(unittest.TestCase): @@ -78,6 +79,14 @@ del sys.modules[pkg] + def test_get_metadata(self): + + # wsgiref has an .egg-info in Python + metadata = get_metadata('wsgiref') + self.assertEquals(metadata.name, 'wsgiref') + self.assertEquals(metadata.author, 'Phillip J. Eby') + self.assertEquals(metadata.version, '0.1.2') + class PkgutilPEP302Tests(unittest.TestCase): class MyTestLoader(object): Index: Lib/pkgutil.py =================================================================== --- Lib/pkgutil.py (révision 68535) +++ Lib/pkgutil.py (copie de travail) @@ -8,6 +8,7 @@ import imp import os.path from types import ModuleType +from distutils.dist import DistributionMetadata __all__ = [ 'get_importer', 'iter_importers', 'get_loader', 'find_loader', @@ -581,3 +582,37 @@ parts.insert(0, os.path.dirname(mod.__file__)) resource_name = os.path.join(*parts) return loader.get_data(resource_name) + +_metadata = {} + +def get_metadata(package, paths=sys.path): + """Returns the metadata of a package. + + And stores in an internal cache founded metadata. + + If path_item is given, it's a list of paths to look in.""" + if package in _metadata: + return _metadata[package] + + # scan for .egg-info file in directories + for path in paths: + if not os.path.isdir(path): + continue + for entry in os.listdir(path): + lower = entry.lower() + if lower.endswith('.egg-info'): + fullpath = os.path.join(path, entry) + if not os.path.isfile(fullpath): + continue + # egg-info file + metadata = DistributionMetadata(fullpath) + + # adding the DistributionMetadata instance + # into the cache + _metadata[metadata.name] = metadata + + if metadata.name == package: + return metadata + + return None +