[Python-checkins] distutils2: fix for 14294

tarek.ziade python-checkins at python.org
Wed Mar 14 04:32:20 CET 2012


http://hg.python.org/distutils2/rev/f453054a7d8b
changeset:   1307:f453054a7d8b
parent:      1304:932b3cea4285
user:        Preston Holmes <preston at ptone.com>
date:        Tue Mar 13 20:26:28 2012 -0700
summary:
  fix for 14294

files:
  distutils2/database.py        |  76 ++--------------------
  distutils2/tests/requires.txt |  15 ++++
  distutils2/tests/test_util.py |  12 +++-
  distutils2/util.py            |  77 +++++++++++++++++++++++
  4 files changed, 111 insertions(+), 69 deletions(-)


diff --git a/distutils2/database.py b/distutils2/database.py
--- a/distutils2/database.py
+++ b/distutils2/database.py
@@ -15,6 +15,7 @@
 from distutils2.errors import PackagingError
 from distutils2.version import suggest_normalized_version, VersionPredicate
 from distutils2.metadata import Metadata
+from distutils2.util import parse_requires
 
 
 __all__ = [
@@ -300,11 +301,6 @@
     """A :class:`distutils2.metadata.Metadata` 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):
         self.path = path
@@ -314,20 +310,7 @@
             self.version = self.metadata['Version']
             return
 
-        # 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()
-                    # skip blank lines/comments
-                    if s and not s.startswith('#'):
-                        yield s
-            else:
-                for ss in strs:
-                    for s in yield_lines(ss):
-                        yield s
+
 
         requires = None
 
@@ -335,15 +318,8 @@
             if os.path.isdir(path):
                 meta_path = os.path.join(path, 'EGG-INFO', 'PKG-INFO')
                 self.metadata = Metadata(path=meta_path)
-                try:
-                    req_path = os.path.join(path, 'EGG-INFO', 'requires.txt')
-                    fp = open(req_path, 'r')
-                    try:
-                        requires = fp.read()
-                    finally:
-                        fp.close()
-                except IOError:
-                    requires = None
+                req_path = os.path.join(path, 'EGG-INFO', 'requires.txt')
+                requires = parse_requires(req_path)
             else:
                 # FIXME handle the case where zipfile is not available
                 zipf = zipimport.zipimporter(path)
@@ -360,14 +336,8 @@
         elif path.endswith('.egg-info'):
             if os.path.isdir(path):
                 path = os.path.join(path, 'PKG-INFO')
-                try:
-                    fp = open(os.path.join(path, 'requires.txt'), 'r')
-                    try:
-                        requires = fp.read()
-                    finally:
-                        fp.close()
-                except IOError:
-                    requires = None
+                req_path = os.path.join(path, 'requires.txt')
+                requires = parse_requires(req_path)
             self.metadata = Metadata(path=path)
             self.name = self.metadata['Name']
             self.version = self.metadata['Version']
@@ -383,40 +353,10 @@
                     if field in self.metadata:
                         del self.metadata[field]
 
-        reqs = []
 
-        if requires is not None:
-            for line in yield_lines(requires):
-                if line.startswith('['):
-                    logger.warning(
-                        'extensions in requires.txt are not supported '
-                        '(used by %r %s)', self.name, self.version)
-                    break
-                else:
-                    match = self._REQUIREMENT.match(line.strip())
-                    if not match:
-                        # this happens when we encounter extras; since they
-                        # are written at the end of the file we just exit
-                        break
-                    else:
-                        if match.group('extras'):
-                            msg = ('extra requirements are not supported '
-                                   '(used by %r %s)', self.name, self.version)
-                            logger.warning(msg, self.name)
-                        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 len(reqs) > 0:
-                self.metadata['Requires-Dist'] += reqs
+        if requires is not None and len(requires)>0:
+            self.metadata['Requires-Dist'] += requires
 
         if _cache_enabled:
             _cache_path_egg[self.path] = self
diff --git a/distutils2/tests/requires.txt b/distutils2/tests/requires.txt
new file mode 100644
--- /dev/null
+++ b/distutils2/tests/requires.txt
@@ -0,0 +1,15 @@
+setuptools
+zope.browser
+zope.component
+zope.configuration
+zope.contenttype >= 3.5
+zope.event
+zope.exceptions
+zope.i18n
+zope.interface
+zope.location
+zope.proxy
+zope.security
+
+[test]
+zope.testing
\ No newline at end of file
diff --git a/distutils2/tests/test_util.py b/distutils2/tests/test_util.py
--- a/distutils2/tests/test_util.py
+++ b/distutils2/tests/test_util.py
@@ -18,7 +18,8 @@
     get_compiler_versions, _MAC_OS_X_LD_VERSION, byte_compile, find_packages,
     spawn, get_pypirc_path, generate_pypirc, read_pypirc, resolve_name, iglob,
     RICH_GLOB, egginfo_to_distinfo, is_setuptools, is_distutils, is_packaging,
-    get_install_method, cfg_to_args, generate_setup_py, encode_multipart)
+    get_install_method, cfg_to_args, generate_setup_py, encode_multipart,
+    parse_requires)
 
 from distutils2.tests import support, unittest
 from distutils2.tests.test_config import SETUP_CFG
@@ -378,6 +379,15 @@
         self.assertEqual(sorted(res),
                          ['pkg1', 'pkg1.pkg3', 'pkg1.pkg3.pkg6', 'pkg5'])
 
+    def test_parse_requires(self):
+        req_file = os.path.join(os.path.dirname(__file__), 'requires.txt')
+        expected_requires = ['setuptools', 'zope.browser', 'zope.component',
+                'zope.configuration', 'zope.contenttype', 'zope.event',
+                'zope.exceptions', 'zope.i18n', 'zope.interface',
+                'zope.location', 'zope.proxy', 'zope.security']
+        requires = parse_requires(req_file)
+        self.assertEqual(requires, expected_requires)
+
     def test_resolve_name(self):
         # test raw module name
         tmpdir = self.mkdtemp()
diff --git a/distutils2/util.py b/distutils2/util.py
--- a/distutils2/util.py
+++ b/distutils2/util.py
@@ -25,6 +25,7 @@
 from distutils2.errors import (PackagingPlatformError, PackagingFileError,
                                PackagingExecError, InstallationException,
                                PackagingInternalError)
+from distutils2.metadata import Metadata
 from distutils2._backport import shutil, sysconfig
 
 __all__ = [
@@ -1172,6 +1173,71 @@
         f.close()
     return record_path
 
+def parse_requires(req_path):
+    """Takes the raw content of a requires.txt file and returns a list of requirements"""
+
+    # 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()
+                # skip blank lines/comments
+                if s and not s.startswith('#'):
+                    yield s
+        else:
+            for ss in strs:
+                for s in yield_lines(ss):
+                    yield s
+
+    _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>\[.*\])?')
+
+    reqs = []
+    try:
+        fp = open(req_path, 'r')
+        try:
+            requires = fp.read()
+        finally:
+            fp.close()
+    except IOError:
+        return None
+
+    for line in yield_lines(requires):
+                if line.startswith('['):
+                    logger.warning('extensions in requires.txt are not supported')
+                    break
+                else:
+                    match = _REQUIREMENT.match(line.strip())
+                    if not match:
+                        # this happens when we encounter extras; since they
+                        # are written at the end of the file we just exit
+                        break
+                    else:
+                        if match.group('extras'):
+                            # msg = ('extra requirements are not supported '
+                                   # '(used by %r %s)', self.name, self.version)
+                            msg = 'extra requirements are not supported'
+                            logger.warning(msg)
+                        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))
+    return reqs
+
+
+
 
 def egginfo_to_distinfo(record_file, installer=_DEFAULT_INSTALLER,
                         requested=False, remove_egginfo=False):
@@ -1201,6 +1267,17 @@
     metadata_path = distinfo['metadata_path']
     logger.info('creating %s', metadata_path)
     shutil.copy2(distinfo['metadata'], metadata_path)
+    # add requirements and output metadata
+    requires = None
+    req_path = os.path.join(distinfo_dir, 'requires.txt')
+    requires = parse_requires(req_path)
+    if requires is not None:
+        # create a metadata instance to handle the reqs injection
+        metadata = Metadata(path=metadata_path)
+        metadata['Requires-Dist'] = requires
+        metadata.write(metadata_path)
+
+
 
     installer_path = distinfo['installer_path']
     logger.info('creating %s', installer_path)

-- 
Repository URL: http://hg.python.org/distutils2


More information about the Python-checkins mailing list