Commits

ta...@MacZiade  committed db53b5a

added zip support

  • Participants
  • Parent commits a7dde27

Comments (0)

Files changed (3)

 import sys
 import re
 import threading
+from zipfile import is_zipfile, ZipFile
 
 from distutils.dist  import  DistributionMetadata
 from distutils.errors import DistutilsError
         self.container = os.path.split(path)[0]
         self.pkg_info_path = join(path, 'PKG-INFO')
         self.record_path = join(path, 'RECORD')
-        self.metadata = _DistributionMetadata(self.pkg_info_path)
+        pkginfo = self._open_pkginfo()
+        self.metadata = _DistributionMetadata(pkginfo)
         self.name = self.metadata.name
         self._files = None
 
         if self._files is None:
             self._files = self._read_record()
 
+    def _open_pkginfo(self):
+        return open(self.pkg_info_path)
+
+    def _open_record(self):
+        return open(self.record_path)
+
     def _read_record(self):
         """Reads RECORD."""
         files = []
-        for row in csv.reader(open(self.record_path)):
+        for row in csv.reader(self._open_record()):
             if row == []:
                 continue
             location = row[0]
                                      (path, self.info_path))
         return open(local_path, binary and 'rb' or 'r')
 
+class ZippedDistribution(Distribution):
+
+    def __init__(self, zipfile, path):
+        self.zipfile = zipfile
+        super(ZippedDistribution, self).__init__(path)
+        self.container = self.zipfile.filename
+
+    def _open_pkginfo(self):
+        return self.zipfile.open(self.pkg_info_path)
+
+    def _open_record(self):
+        return self.zipfile.open(self.record_path)
+
 #
 # DistributionDirectory represents a directory that contains egg-info files
 #
             return users[0]
         return None
 
+class ZippedDistributionDirectory(DistributionDirectory):
+
+    def __init__(self, path):
+        if not is_zipfile(path):
+            raise TypeError('%s path is not a zipfile' % path)
+        self.path = path
+        self._zip_file = ZipFile(path)
+        egg_infos = []
+        # scanning the zip content
+        for element in self._zip_file.filelist:
+            paths = os.path.split(element.filename)
+            if len(paths) < 2:
+                continue
+            if splitext(paths[0])[-1].lower() == '.egg-info':
+                if paths[0] not in egg_infos:
+                    self.add(ZippedDistribution(self._zip_file, paths[0]))
+                    egg_infos.append(paths[0])
+
+    def __repr__(self):
+        return 'ZippedDistributionDirectory("%s")' % self.path
+
+    def add(self, dist):
+        """Makes sure only Distribution instances are added."""
+        if not isinstance(dist, ZippedDistribution):
+            raise TypeError('ZippedDistributionDirectory manage only '
+                            'ZippedDistribution instances')
+        super(ZippedDistributionDirectory, self).add(dist)
+
+
 #
 # Directories is a collection of directories, initialized with a
 # list of paths.
         """Controls the mapping deals only with path/DistributionDirectory"""
         if not isinstance(path, str):
             raise TypeError('The key needs to be a path')
-        if not isinstance(dir, DistributionDirectory):
+        if not isinstance(dir, (ZippedDistributionDirectory,
+                                DistributionDirectory)):
             raise TypeError('The value needs to be a DistributionDirectory '
-                            'instance')
+                            'or a ZippedDistributionDirectory instance')
         super(DistributionDirectories, self).__setitem__(path, dir)
 
     #
         if self.use_cache and path in _CACHED_DIRS:
             dist_dir = _CACHED_DIRS[path]
         else:
-            dist_dir = DistributionDirectory(path)
+            if is_zipfile(path):
+                dist_dir = ZippedDistributionDirectory(path)
+            else:
+                dist_dir = DistributionDirectory(path)
             if self.use_cache:
                 _CACHED_DIRS[path] = dist_dir
 
     def load(self, paths):
         """Loads the paths."""
         for path in paths:
-            if path in self or not os.path.isdir(path):
+            if path in self or not (os.path.isdir(path) or
+                                    is_zipfile(path)):
                 continue
             self.append(path)
 

File site-packages.zip

Binary file added.

File test_pkgutil.py

     assert egginfo_dirname('python-ldap', '2.5'), 'python_ldap-2.5.egg-info'
     assert egginfo_dirname('python-ldap', '2.5 a---5'), 'python_ldap-2.5.a_5.egg-info'
 
+
+def test_zipped_directory():
+    dir = ZippedDistributionDirectory(SITE_PKG+'.zip')
+
+    dist = dir.owner('mercurial/filelog.pyc')
+    assert dist.name == 'mercurial'
+    assert dir.owner('mercurial/filelog.py') is None
+
+def setup_zip():
+    sys.old = sys.path
+    sys.path = [SITE_PKG+'.zip']
+    pkgutil.purge_cache()
+    pkgutil._dist_dirs = DistributionDirectories()
+    pkgutil._dist_dirs.load([SITE_PKG+'.zip'])
+
+@with_setup(setup_zip, teardown)
+def test_zipped_distribution():
+    assert_equals(get_distribution('xxx'), None)
+
+    project = get_distribution('mercurial')
+    assert_equals(project.name, 'mercurial')
+
+    project = get_distribution('processing')
+    assert_equals(project.name, 'processing')
+
+    dist = get_distribution('mercurial')
+    assert_equals(str(dist), "Distribution('mercurial')")
+
+    files = list(dist.get_installed_files())
+    assert_equals(len(files), 4)
+    assert_equals(files[0], ('mercurial/filelog.py', '98676876876876', '12'))
+
+    files = list(dist.get_installed_files(local=True))
+
+    site_packages = os.path.split(dist.info_path)[0]
+    location = os.path.join(site_packages, 'mercurial', 'filelog.py')
+    assert_equals(files[0], (location, '98676876876876', '12'))
+
+    f = dist.get_egginfo_file('RECORD')
+    record = os.path.join(SITE_PKG, 'mercurial-1.0.1.egg-info', 'RECORD')
+    assert_equals(open(record).read(), f.read())
+
+    assert dist.uses('mercurial/filelog.py')
+    assert not dist.uses('mercurial/filelog.sasasasa')
+
+    assert_equals(list(dist.get_egginfo_files()),
+                  ['mercurial-1.0.1.egg-info/PKG_INFO',
+                   'mercurial-1.0.1.egg-info/RECORD'])
+
+    assert_equals(list(dist.get_egginfo_files(local=True)),
+                  [os.path.join(SITE_PKG, 'mercurial-1.0.1.egg-info/PKG_INFO'),
+                   os.path.join(SITE_PKG, 'mercurial-1.0.1.egg-info/RECORD')])
+
+