[Python-checkins] distutils2: Added support for zipped eggs
tarek.ziade
python-checkins at python.org
Sun Jun 20 23:04:52 CEST 2010
tarek.ziade pushed ce6942d3c4f2 to distutils2:
http://hg.python.org/distutils2/rev/ce6942d3c4f2
changeset: 199:ce6942d3c4f2
parent: 187:48f3b9a445da
user: Josip Djolonga
date: Sat Jun 05 16:59:49 2010 +0200
summary: Added support for zipped eggs
files: src/distutils2/_backport/pkgutil.py, src/distutils2/_backport/tests/fake_dists/bacon-0.1.egg-info/PKG-INFO, src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/METADATA, src/distutils2/depgraph.py, src/distutils2/metadata.py
diff --git a/src/distutils2/_backport/pkgutil.py b/src/distutils2/_backport/pkgutil.py
--- a/src/distutils2/_backport/pkgutil.py
+++ b/src/distutils2/_backport/pkgutil.py
@@ -12,6 +12,13 @@
from distutils2.errors import DistutilsError
from distutils2.metadata import DistributionMetadata
from distutils2.version import suggest_normalized_version, VersionPredicate
+import zipimport
+try:
+ import cStringIO as StringIO
+except ImportError:
+ import StringIO
+import re
+import warnings
__all__ = [
'get_importer', 'iter_importers', 'get_loader', 'find_loader',
@@ -726,12 +733,96 @@
metadata = None
"""A :class:`distutils2.metadata.DistributionMetadata` instance loaded with
the distribution's METADATA file."""
+ _REQUIREMENT = re.compile( \
+ r'(?P<name>[-A-Za-z0-9_.]+)\s*' \
+ r'(?P<first>(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)?\s*' \
+ r'(?P<rest>(?:\s*,\s*(?:<|<=|!=|==|>=|>)[-A-Za-z0-9_.]+)*)\s*' \
+ r'(?P<extras>\[.*\])?')
def __init__(self, path):
- if os.path.isdir(path):
- path = os.path.join(path, 'PKG-INFO')
- self.metadata = DistributionMetadata(path=path)
- self.name = self.metadata['name']
+
+ # reused from Distribute's pkg_resources
+ def yield_lines(strs):
+ """Yield non-empty/non-comment lines of a ``basestring`` or sequence"""
+ if isinstance(strs, basestring):
+ for s in strs.splitlines():
+ s = s.strip()
+ if s and not s.startswith('#'): # skip blank lines/comments
+ yield s
+ else:
+ for ss in strs:
+ for s in yield_lines(ss):
+ yield s
+
+ requires = None
+ if path.endswith('.egg'):
+ if os.path.isdir(path):
+ path = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
+ self.metadata = DistributionMetadata(path=path)
+ try:
+ req_path = os.path.join(path, 'EGG_INFO', 'requires.txt')
+ requires = open(req_path, 'r').read()
+ except IOError:
+ requires = None
+ else:
+ zipf = zipimport.zipimporter(path)
+ fileobj = StringIO.StringIO(zipf.get_data('EGG-INFO/PKG-INFO'))
+ self.metadata = DistributionMetadata(fileobj=fileobj)
+ try:
+ requires = zipf.get_data('EGG-INFO/requires.txt')
+ except IOError:
+ requires = None
+ elif path.endswith('.egg-info'):
+ if os.path.isdir(path):
+ path = os.path.join(path, 'PKG-INFO')
+ try:
+ req_f = open(os.path.join(path, 'requires.txt'), 'r')
+ requires = req_f.read()
+ except IOError:
+ requires = None
+ self.metadata = DistributionMetadata(path=path)
+ self.name = self.metadata['name']
+ else:
+ raise ValueError('The path must end with .egg-info or .egg')
+
+ provides = "%s (%s)" % (self.metadata['name'],
+ self.metadata['version'])
+ if self.metadata['Metadata-Version'] == '1.2':
+ self.metadata['Provides-Dist'] += (provides,)
+ else:
+ self.metadata['Provides'] += (provides,)
+ reqs = []
+ if requires is not None:
+ for line in yield_lines(requires):
+ if line[0] == '[':
+ warnings.warn('distutils2 does not support extensions in requires.txt')
+ break
+ else:
+ match = _REQUIREMENT.match(line.strip())
+ if not match:
+ raise ValueError('Distribution %s has ill formed '
+ 'requires.txt file (%s)' %
+ (self.name, line))
+ else:
+ if match.group('extra'):
+ s = 'Distribution %s uses extra requirements which'\
+ ' are not supported in distutils' % (self.name)
+ warnings.warn(s)
+ name = match.group('name')
+ version = None
+ if match.group('first'):
+ version = match.group('first')
+ if match.group('rest'):
+ version += match.group('rest')
+ version = version.replace(' ', '') # trim spaces
+ if version is None:
+ reqs.append(name)
+ else:
+ reqs.append('%s (%s)' % (name, version))
+ if self.metadata['Metadata-Version'] == '1.2':
+ self.metadata['Requires-Dist'] += reqs
+ else:
+ self.metadata['Requires'] += reqs
def get_installed_files(self, local=False):
return []
@@ -792,7 +883,8 @@
if dir.endswith('.dist-info'):
dist = Distribution(os.path.join(realpath, dir))
yield dist
- elif use_egg_info and dir.endswith('.egg-info'):
+ elif use_egg_info and (dir.endswith('.egg-info') or
+ dir.endswith('.egg')):
dist = EggInfoDistribution(os.path.join(realpath, dir))
yield dist
@@ -887,7 +979,7 @@
provided = dist.metadata['Provides-Dist'] + dist.metadata['Provides']
for p in provided:
- p_components = p.split(' ', 1)
+ p_components = p.rsplit(' ', 1)
if len(p_components) == 1 or predicate is None:
if name == p_components[0]:
yield dist
@@ -896,7 +988,7 @@
p_name, p_ver = p_components
if len(p_ver) < 2 or p_ver[0] != '(' or p_ver[-1] != ')':
raise DistutilsError(('Distribution %s has invalid ' +
- 'provides field') % (dist.name,))
+ 'provides field: %s') % (dist.name,p))
p_ver = p_ver[1:-1] # trim off the parenthesis
if p_name == name and predicate.match(p_ver):
yield dist
diff --git a/src/distutils2/_backport/tests/fake_dists/bacon-0.1.egg-info/PKG-INFO b/src/distutils2/_backport/tests/fake_dists/bacon-0.1.egg-info/PKG-INFO
--- a/src/distutils2/_backport/tests/fake_dists/bacon-0.1.egg-info/PKG-INFO
+++ b/src/distutils2/_backport/tests/fake_dists/bacon-0.1.egg-info/PKG-INFO
@@ -2,4 +2,5 @@
Name: bacon
Version: 0.1
Provides-Dist: truffles (2.0)
+Provides-Dist: bacon (0.1)
Obsoletes-Dist: truffles (>=0.9,<=1.5)
diff --git a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/METADATA b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/METADATA
--- a/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/METADATA
+++ b/src/distutils2/_backport/tests/fake_dists/towel_stuff-0.1.dist-info/METADATA
@@ -2,4 +2,6 @@
Name: towel-stuff
Version: 0.1
Provides-Dist: truffles (1.1.2)
+Provides-Dist: towel-stuff (0.1)
Obsoletes-Dist: truffles (!=0.8,<1.0)
+Requires-Dist: bacon (<=0.2)
diff --git a/src/distutils2/depgraph.py b/src/distutils2/depgraph.py
--- a/src/distutils2/depgraph.py
+++ b/src/distutils2/depgraph.py
@@ -60,40 +60,41 @@
"""
self.missing[distribution].append(requirement)
- def to_dot(self, f, skip_disconnected=True):
- """
- Writes a DOT output for the graph to the provided *file*.
- If *skip_disconnected* is set to ``True``, then all distributions
- that are not dependent on any other distributions are skipped.
- :type f: ``file``
- ;type skip_disconnected: ``bool``
- """
- if not isinstance(f, file):
- raise TypeError('the argument has to be of type file')
+def graph_to_dot(graph, f, skip_disconnected=True):
+ """
+ Writes a DOT output for the graph to the provided *file*.
+ If *skip_disconnected* is set to ``True``, then all distributions
+ that are not dependent on any other distributions are skipped.
- disconnected = []
+ :type f: ``file``
+ ;type skip_disconnected: ``bool``
+ """
+ if not isinstance(f, file):
+ raise TypeError('the argument has to be of type file')
- f.write("digraph dependencies {\n")
- for dist, adjs in self.adjacency_list.iteritems():
- if len(adjs) == 0 and not skip_disconnected:
- disconnected.append(dist)
- for (other, label) in adjs:
- if not label is None:
- f.write('"%s" -> "%s" [label="%s"]\n' %
- (dist.name, other.name, label))
- else:
- f.write('"%s" -> "%s"\n' % (dist.name, other.name))
- if not skip_disconnected and len(disconnected) > 0:
- f.write('subgraph disconnected {\n')
- f.write('label = "Disconnected"\n')
- f.write('bgcolor = red\n')
+ disconnected = []
- for dist in disconnected:
- f.write('"%s"' % dist.name)
- f.write('\n')
- f.write('}\n')
+ f.write("digraph dependencies {\n")
+ for dist, adjs in graph.adjacency_list.iteritems():
+ if len(adjs) == 0 and not skip_disconnected:
+ disconnected.append(dist)
+ for (other, label) in adjs:
+ if not label is None:
+ f.write('"%s" -> "%s" [label="%s"]\n' %
+ (dist.name, other.name, label))
+ else:
+ f.write('"%s" -> "%s"\n' % (dist.name, other.name))
+ if not skip_disconnected and len(disconnected) > 0:
+ f.write('subgraph disconnected {\n')
+ f.write('label = "Disconnected"\n')
+ f.write('bgcolor = red\n')
+
+ for dist in disconnected:
+ f.write('"%s"' % dist.name)
+ f.write('\n')
f.write('}\n')
+ f.write('}\n')
def generate_graph(dists):
diff --git a/src/distutils2/metadata.py b/src/distutils2/metadata.py
--- a/src/distutils2/metadata.py
+++ b/src/distutils2/metadata.py
@@ -186,13 +186,15 @@
"""Distribution meta-data class (1.0 or 1.2).
"""
def __init__(self, path=None, platform_dependant=False,
- execution_context=None):
+ execution_context=None, fileobj=None):
self._fields = {}
self.version = None
self.docutils_support = _HAS_DOCUTILS
self.platform_dependant = platform_dependant
if path is not None:
self.read(path)
+ elif fileobj is not None:
+ self.read_file(fileobj)
self.execution_context = execution_context
def _set_best_version(self):
--
Repository URL: http://hg.python.org/distutils2
More information about the Python-checkins
mailing list