Index: Lib/distutils/tests/test_dist.py =================================================================== --- Lib/distutils/tests/test_dist.py (révision 68609) +++ 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/tests/some.egg-info =================================================================== --- Lib/distutils/tests/some.egg-info (révision 0) +++ Lib/distutils/tests/some.egg-info (révision 0) @@ -0,0 +1,23 @@ +Metadata-Version: 1.0 +Name: SomePackage +Version: 0.52 +Summary: Very cool +Home-page: http://example.com +Author: SomeGuy +Author-email: some.guy@example.com +License: BSD Licence +Description: `SomePackage` is a package that does nothing. + + Examples + ======== + + An example:: + + >>> 1 + 1 + 2 + +Keywords: one,two,three +Platform: Unix and Windows +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: Programming Language :: Python Modification de propriétés sur Lib/distutils/tests/some.egg-info ___________________________________________________________________ Nom : svn:eol-style + native Index: Lib/distutils/dist.py =================================================================== --- Lib/distutils/dist.py (révision 68609) +++ Lib/distutils/dist.py (copie de travail) @@ -19,7 +19,7 @@ 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 from distutils import log from distutils.debug import DEBUG @@ -1050,25 +1050,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 +1084,60 @@ # 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') + else: + self.requires = None + self.provides = None + self.obsoletes = None + 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 68609) +++ Lib/test/test_pkgutil.py (copie de travail) @@ -8,8 +8,15 @@ import tempfile import shutil import zipfile +from site import addsitedir +from pkgutil import get_metadata +PKG_INFO = """\ +Metadata-Version: 1.0 +Name: %s +Version: 1.0 +""" class PkgutilTests(unittest.TestCase): @@ -21,6 +28,11 @@ del sys.path[0] shutil.rmtree(self.dirname) + def _make_test_dir(self, name): + fullname = os.path.join(self.dirname, name) + os.mkdir(fullname) + return fullname + def test_getdata_filesys(self): pkg = 'test_getdata_filesys' @@ -78,6 +90,55 @@ del sys.modules[pkg] + def test_get_metadata(self): + + # different use cases : + # 1/ a simple .egg-info file into the path + # 2/ an .egg dir with EGG-INFO/PKG-INFO + # 3/ a zipped .egg + # what about elements that contains several packages ? + + # 1/ simple .egg-info file + # 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') + + # 2/ .egg-info dir + # never seen that case ... + # need to ask Philip to understand + + # 3/ .egg dir + + # let's create a site-packages folder + base_dir = self._make_test_dir('site-packages') + egg_dir = os.path.join(base_dir, 'package-1.0-py2.5.egg') + os.mkdir(egg_dir) + + # let's build the egg structure + egg_info = os.path.join(egg_dir, 'EGG-INFO') + os.mkdir(egg_info) + target = os.path.join(egg_info, 'PKG-INFO') + open(target, 'w').write(PKG_INFO % 'package') + + # this adds and scans the custom site-packages + addsitedir(base_dir) + + # let's try to get our .egg package now + metadata = get_metadata('package') + self.assertEquals(metadata.name, 'package') + + # 3/ zipped .egg dir + egg_dir = os.path.join(base_dir, 'package2-1.0-py2.5.egg') + zip_file = zipfile.ZipFile(egg_dir, 'w') + zip_file.writestr('EGG-INFO/PKG-INFO', PKG_INFO % 'package2') + zip_file.close() + + # let's try to get our zipped .egg package now + metadata = get_metadata('package2') + self.assertEquals(metadata.name, 'package2') + class PkgutilPEP302Tests(unittest.TestCase): class MyTestLoader(object): Index: Lib/pkgutil.py =================================================================== --- Lib/pkgutil.py (révision 68609) +++ Lib/pkgutil.py (copie de travail) @@ -9,6 +9,11 @@ import os.path from types import ModuleType +from zipimport import zipimporter +from zipimport import ZipImportError +from distutils.dist import DistributionMetadata +from StringIO import StringIO + __all__ = [ 'get_importer', 'iter_importers', 'get_loader', 'find_loader', 'walk_packages', 'iter_modules', @@ -581,3 +586,82 @@ parts.insert(0, os.path.dirname(mod.__file__)) resource_name = os.path.join(*parts) return loader.get_data(resource_name) + +_metadata = {} + +def _get_pkginfo(path): + """Returns the PKG-INFO file, given a directory or + a file + """ + entry = os.path.split(path)[-1] + extension = os.path.splitext(path)[-1].lower() + is_dir = os.path.isdir(path) + + if extension == '.egg-info': + if is_dir: + # egg-info folder with an egg structure ??? + # XXX + return None + # egg-info file + if os.path.exists(path): + return path + elif extension == '.egg': + if is_dir: + pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') + if os.path.exists(pkg_info): + return pkg_info + else: + # let's see if it's a zipped egg + try: + archive = zipimporter(path) + pkg_info = archive.get_data('EGG-INFO/PKG-INFO') + return StringIO(pkg_info) + except (ZipImportError, IOError): + # happens if it's not a zip file + # or if it doesn't contain an EGG-INFO/PKG-INFO file + return None + + return None + +def _get_metadata(pkg_info, pkg_name): + """Returns the metadata, given a pkg_info file, + and put it in the cache""" + metadata = DistributionMetadata(pkg_info) + _metadata[metadata.name] = metadata + if metadata.name == pkg_name: + return metadata + return None + +def get_metadata(pkg_name, 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 pkg_name in _metadata: + return _metadata[pkg_name] + + # look for for metadata files in paths directories and files + for path in paths: + if not os.path.exists(path): + continue + + # to be treated ??? + #if not os.path.isdir(path): + # metadata = _get_metadata(path, package) + # if metadata is not None: + # return metadata + + for entry in os.listdir(path): + fullpath = os.path.join(path, entry) + pkg_info = _get_pkginfo(fullpath) + + if pkg_info is None: + continue + + metadata = _get_metadata(pkg_info, pkg_name) + if metadata is not None: + return metadata + return None +