| commit 24: | db53b5a1ecf6 |
| parent 23: | a7dde278d993 |
| branch: | default |
added zip support
9 months ago
Changed (Δ8.7 KB):
raw changeset »
pkgutil.py (61 lines added, 6 lines removed)
site-packages.zip (binary file changed)
test_pkgutil.py (54 lines added, 0 lines removed)
| … | … | @@ -10,6 +10,7 @@ import csv |
10 |
10 |
import sys |
11 |
11 |
import re |
12 |
12 |
import threading |
13 |
from zipfile import is_zipfile, ZipFile |
|
13 |
14 |
|
14 |
15 |
from distutils.dist import DistributionMetadata |
15 |
16 |
from distutils.errors import DistutilsError |
| … | … | @@ -150,7 +151,8 @@ class Distribution(object): |
150 |
151 |
self.container = os.path.split(path)[0] |
151 |
152 |
self.pkg_info_path = join(path, 'PKG-INFO') |
152 |
153 |
self.record_path = join(path, 'RECORD') |
153 |
|
|
154 |
pkginfo = self._open_pkginfo() |
|
155 |
self.metadata = _DistributionMetadata(pkginfo) |
|
154 |
156 |
self.name = self.metadata.name |
155 |
157 |
self._files = None |
156 |
158 |
|
| … | … | @@ -162,10 +164,16 @@ class Distribution(object): |
162 |
164 |
if self._files is None: |
163 |
165 |
self._files = self._read_record() |
164 |
166 |
|
167 |
def _open_pkginfo(self): |
|
168 |
return open(self.pkg_info_path) |
|
169 |
||
170 |
def _open_record(self): |
|
171 |
return open(self.record_path) |
|
172 |
||
165 |
173 |
def _read_record(self): |
166 |
174 |
"""Reads RECORD.""" |
167 |
175 |
files = [] |
168 |
for row in csv.reader( |
|
176 |
for row in csv.reader(self._open_record()): |
|
169 |
177 |
if row == []: |
170 |
178 |
continue |
171 |
179 |
location = row[0] |
| … | … | @@ -242,6 +250,19 @@ class Distribution(object): |
242 |
250 |
(path, self.info_path)) |
243 |
251 |
return open(local_path, binary and 'rb' or 'r') |
244 |
252 |
|
253 |
class ZippedDistribution(Distribution): |
|
254 |
||
255 |
def __init__(self, zipfile, path): |
|
256 |
self.zipfile = zipfile |
|
257 |
super(ZippedDistribution, self).__init__(path) |
|
258 |
self.container = self.zipfile.filename |
|
259 |
||
260 |
def _open_pkginfo(self): |
|
261 |
return self.zipfile.open(self.pkg_info_path) |
|
262 |
||
263 |
def _open_record(self): |
|
264 |
return self.zipfile.open(self.record_path) |
|
265 |
||
245 |
266 |
# |
246 |
267 |
# DistributionDirectory represents a directory that contains egg-info files |
247 |
268 |
# |
| … | … | @@ -283,6 +304,35 @@ class DistributionDirectory(set): |
283 |
304 |
return users[0] |
284 |
305 |
return None |
285 |
306 |
|
307 |
class ZippedDistributionDirectory(DistributionDirectory): |
|
308 |
||
309 |
def __init__(self, path): |
|
310 |
if not is_zipfile(path): |
|
311 |
raise TypeError('%s path is not a zipfile' % path) |
|
312 |
self.path = path |
|
313 |
self._zip_file = ZipFile(path) |
|
314 |
egg_infos = [] |
|
315 |
# scanning the zip content |
|
316 |
for element in self._zip_file.filelist: |
|
317 |
paths = os.path.split(element.filename) |
|
318 |
if len(paths) < 2: |
|
319 |
continue |
|
320 |
if splitext(paths[0])[-1].lower() == '.egg-info': |
|
321 |
if paths[0] not in egg_infos: |
|
322 |
self.add(ZippedDistribution(self._zip_file, paths[0])) |
|
323 |
egg_infos.append(paths[0]) |
|
324 |
||
325 |
def __repr__(self): |
|
326 |
return 'ZippedDistributionDirectory("%s")' % self.path |
|
327 |
||
328 |
def add(self, dist): |
|
329 |
"""Makes sure only Distribution instances are added.""" |
|
330 |
if not isinstance(dist, ZippedDistribution): |
|
331 |
raise TypeError('ZippedDistributionDirectory manage only ' |
|
332 |
'ZippedDistribution instances') |
|
333 |
super(ZippedDistributionDirectory, self).add(dist) |
|
334 |
||
335 |
||
286 |
336 |
# |
287 |
337 |
# Directories is a collection of directories, initialized with a |
288 |
338 |
# list of paths. |
| … | … | @@ -307,9 +357,10 @@ class DistributionDirectories(dict): |
307 |
357 |
"""Controls the mapping deals only with path/DistributionDirectory""" |
308 |
358 |
if not isinstance(path, str): |
309 |
359 |
raise TypeError('The key needs to be a path') |
310 |
if not isinstance(dir, |
|
360 |
if not isinstance(dir, (ZippedDistributionDirectory, |
|
361 |
DistributionDirectory)): |
|
311 |
362 |
raise TypeError('The value needs to be a DistributionDirectory ' |
312 |
' |
|
363 |
'or a ZippedDistributionDirectory instance') |
|
313 |
364 |
super(DistributionDirectories, self).__setitem__(path, dir) |
314 |
365 |
|
315 |
366 |
# |
| … | … | @@ -320,7 +371,10 @@ class DistributionDirectories(dict): |
320 |
371 |
if self.use_cache and path in _CACHED_DIRS: |
321 |
372 |
dist_dir = _CACHED_DIRS[path] |
322 |
373 |
else: |
323 |
|
|
374 |
if is_zipfile(path): |
|
375 |
dist_dir = ZippedDistributionDirectory(path) |
|
376 |
else: |
|
377 |
dist_dir = DistributionDirectory(path) |
|
324 |
378 |
if self.use_cache: |
325 |
379 |
_CACHED_DIRS[path] = dist_dir |
326 |
380 |
|
| … | … | @@ -329,7 +383,8 @@ class DistributionDirectories(dict): |
329 |
383 |
def load(self, paths): |
330 |
384 |
"""Loads the paths.""" |
331 |
385 |
for path in paths: |
332 |
if path in self or not |
|
386 |
if path in self or not (os.path.isdir(path) or |
|
387 |
is_zipfile(path)): |
|
333 |
388 |
continue |
334 |
389 |
self.append(path) |
335 |
390 |
Up to file-list site-packages.zip:
Up to file-list test_pkgutil.py:
| … | … | @@ -75,3 +75,57 @@ def test_egginfo_dirname(): |
75 |
75 |
assert egginfo_dirname('python-ldap', '2.5'), 'python_ldap-2.5.egg-info' |
76 |
76 |
assert egginfo_dirname('python-ldap', '2.5 a---5'), 'python_ldap-2.5.a_5.egg-info' |
77 |
77 |
|
78 |
||
79 |
def test_zipped_directory(): |
|
80 |
dir = ZippedDistributionDirectory(SITE_PKG+'.zip') |
|
81 |
||
82 |
dist = dir.owner('mercurial/filelog.pyc') |
|
83 |
assert dist.name == 'mercurial' |
|
84 |
assert dir.owner('mercurial/filelog.py') is None |
|
85 |
||
86 |
def setup_zip(): |
|
87 |
sys.old = sys.path |
|
88 |
sys.path = [SITE_PKG+'.zip'] |
|
89 |
pkgutil.purge_cache() |
|
90 |
pkgutil._dist_dirs = DistributionDirectories() |
|
91 |
pkgutil._dist_dirs.load([SITE_PKG+'.zip']) |
|
92 |
||
93 |
@with_setup(setup_zip, teardown) |
|
94 |
def test_zipped_distribution(): |
|
95 |
assert_equals(get_distribution('xxx'), None) |
|
96 |
||
97 |
project = get_distribution('mercurial') |
|
98 |
assert_equals(project.name, 'mercurial') |
|
99 |
||
100 |
project = get_distribution('processing') |
|
101 |
assert_equals(project.name, 'processing') |
|
102 |
||
103 |
dist = get_distribution('mercurial') |
|
104 |
assert_equals(str(dist), "Distribution('mercurial')") |
|
105 |
||
106 |
files = list(dist.get_installed_files()) |
|
107 |
assert_equals(len(files), 4) |
|
108 |
assert_equals(files[0], ('mercurial/filelog.py', '98676876876876', '12')) |
|
109 |
||
110 |
files = list(dist.get_installed_files(local=True)) |
|
111 |
||
112 |
site_packages = os.path.split(dist.info_path)[0] |
|
113 |
location = os.path.join(site_packages, 'mercurial', 'filelog.py') |
|
114 |
assert_equals(files[0], (location, '98676876876876', '12')) |
|
115 |
||
116 |
f = dist.get_egginfo_file('RECORD') |
|
117 |
record = os.path.join(SITE_PKG, 'mercurial-1.0.1.egg-info', 'RECORD') |
|
118 |
assert_equals(open(record).read(), f.read()) |
|
119 |
||
120 |
assert dist.uses('mercurial/filelog.py') |
|
121 |
assert not dist.uses('mercurial/filelog.sasasasa') |
|
122 |
||
123 |
assert_equals(list(dist.get_egginfo_files()), |
|
124 |
['mercurial-1.0.1.egg-info/PKG_INFO', |
|
125 |
'mercurial-1.0.1.egg-info/RECORD']) |
|
126 |
||
127 |
assert_equals(list(dist.get_egginfo_files(local=True)), |
|
128 |
[os.path.join(SITE_PKG, 'mercurial-1.0.1.egg-info/PKG_INFO'), |
|
129 |
os.path.join(SITE_PKG, 'mercurial-1.0.1.egg-info/RECORD')]) |
|
130 |
||
131 |
