[Python-checkins] distutils2: now checking Requires-Python and Name

tarek.ziade python-checkins at python.org
Fri Mar 12 19:32:53 CET 2010


tarek.ziade pushed 29e64afc676d to distutils2:

http://hg.python.org/distutils2/rev/29e64afc676d
changeset:   73:29e64afc676d
tag:         tip
user:        Tarek Ziade <tarek at ziade.org>
date:        Fri Mar 12 13:26:01 2010 -0500
summary:     now checking Requires-Python and Name
files:       src/distutils2/metadata.py, src/distutils2/tests/test_metadata.py, src/distutils2/version.py

diff --git a/src/distutils2/metadata.py b/src/distutils2/metadata.py
--- a/src/distutils2/metadata.py
+++ b/src/distutils2/metadata.py
@@ -1,55 +1,9 @@
 """
-==================================================
 Implementation of the Metadata for Python packages
-==================================================
 
-The file format is RFC 822 and there are currently three implementations.
-We only support reading/writing Metadata v1.0 or v1.2. If 1.1 is encountered
-1.1 extra fields will be ignored.
+Supports all Metadata formats (1.0, 1.1, 1.2).
+"""
 
-PEP 241 - Metadata v1.0
-=======================
-
-- Metadata-Version
-- Name
-- Version
-- Platform (multiple)
-- Summary
-- Description (optional)
-- Keywords (optional)
-- Home-page (optional)
-- Author  (optional)
-- Author-email (optional)
-- License (optional)
-
-PEP 345 - Metadata v1.2
-=======================
-
-# XXX adding codename ? multiple email rfc232 ?
-
-- Metadata-Version
-- Name
-- Version
-- Platform (multiple)
-- Supported-Platform (multiple)
-- Summary
-- Description (optional) -- changed format
-- Keywords (optional)
-- Home-page (optional)
-- Download-URL
-- Author  (optional)
-- Author-email (optional)
-- Maintainer (optional)
-- Maintainer-email (optional)
-- License (optional)
-- Classifier (multiple) -- see PEP 241
-- Requires-Python
-- Requires-External (multiple)
-- Requires-Dist (multiple)
-- Provides-Dist (multiple)
-- Obsoletes-Dist (multiple)
-
-"""
 import re
 import os
 import sys
@@ -60,7 +14,8 @@
 
 from distutils2.log import warn
 from distutils2.util import rfc822_escape
-from distutils2.version import is_valid_predicate
+from distutils2.version import (is_valid_predicate, is_valid_version,
+                                is_valid_versions)
 from distutils2.errors import (MetadataConflictError,
                                MetadataUnrecognizedVersionError)
 
@@ -122,10 +77,11 @@
                'Requires-External')
 
 _345_MARKERS = ('Provides-Dist', 'Requires-Dist', 'Requires-Python',
-                'Obsoletes-Dist', 'Requires-External', 'Maintainer',
-                'Maintainer-email')
+        'Obsoletes-Dist', 'Requires-External', 'Maintainer',
+        'Maintainer-email')
 
 _ALL_FIELDS = []
+
 for field in _241_FIELDS + _314_FIELDS + _345_FIELDS:
     if field in _ALL_FIELDS:
         continue
@@ -164,37 +120,37 @@
     return '1.2'
 
 _ATTR2FIELD = {'metadata_version': 'Metadata-Version',
-               'name': 'Name',
-               'version': 'Version',
-               'platform': 'Platform',
-               'supported_platform': 'Supported-Platform',
-               'description': 'Summary',
-               'long_description': 'Description',
-               'keywords': 'Keywords',
-               'url': 'Home-page',
-               'author': 'Author',
-               'author_email': 'Author-email',
-               'maintainer': 'Maintainer',
-               'maintainer_email': 'Maintainer-email',
-               'licence': 'License',
-               'classifier': 'Classifier',
-               'download_url': 'Download-URL',
-               'obsoletes_dist': 'Obsoletes-Dist',
-               'provides_dist': 'Provides-Dist',
-               'requires_dist': 'Requires-Dist',
-               'requires_python': 'Requires-Python',
-               'requires_external': 'Requires-External',
-               'requires': 'Requires',
-               'provides': 'Provides',
-               'obsoletes': 'Obsoletes',
-               }
+        'name': 'Name',
+        'version': 'Version',
+        'platform': 'Platform',
+        'supported_platform': 'Supported-Platform',
+        'description': 'Summary',
+        'long_description': 'Description',
+        'keywords': 'Keywords',
+        'url': 'Home-page',
+        'author': 'Author',
+        'author_email': 'Author-email',
+        'maintainer': 'Maintainer',
+        'maintainer_email': 'Maintainer-email',
+        'licence': 'License',
+        'classifier': 'Classifier',
+        'download_url': 'Download-URL',
+        'obsoletes_dist': 'Obsoletes-Dist',
+        'provides_dist': 'Provides-Dist',
+        'requires_dist': 'Requires-Dist',
+        'requires_python': 'Requires-Python',
+        'requires_external': 'Requires-External',
+        'requires': 'Requires',
+        'provides': 'Provides',
+        'obsoletes': 'Obsoletes',
+        }
 
 _PREDICATE_FIELDS = ('Requires-Dist', 'Obsoletes-Dist', 'Provides-Dist')
-
+_VERSIONS_FIELDS = ('Requires-Python',)
+_VERSION_FIELDS = ('Version',)
 _LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes',
-               'Requires', 'Provides', 'Obsoletes-Dist',
-               'Provides-Dist', 'Requires-Dist', 'Requires-Python',
-               'Requires-External')
+        'Requires', 'Provides', 'Obsoletes-Dist',
+        'Provides-Dist', 'Requires-Dist', 'Requires-External')
 
 _ELEMENTSFIELD = ('Keywords',)
 
@@ -347,23 +303,37 @@
         """Controls then sets a metadata field"""
         name = self._convert_name(name)
 
-        # XXX need to parse the Requires-Python value
-        #
+        if (name in _ELEMENTSFIELD + ('Platform',) and
+            not isinstance(value, (list, tuple))):
+            if isinstance(value, str):
+                value = value.split(',')
+            else:
+                value = []
+        elif (name in _LISTFIELDS and
+            not isinstance(value, (list, tuple))):
+            if isinstance(value, str):
+                value = [value]
+            else:
+                value = None
+
         if name in _PREDICATE_FIELDS and value is not None:
             for v in value:
                 # check that the values are valid predicates
                 if not is_valid_predicate(v.split(';')[0]):
                     warn('"%s" is not a valid predicate' % v)
-        if name in _LISTFIELDS + _ELEMENTSFIELD:
-            if isinstance(value, str):
-                value = value.split(',')
-        elif name in _UNICODEFIELDS:
+        elif name in _VERSIONS_FIELDS and value is not None:
+            if not is_valid_versions(value):
+                warn('"%s" is not a valid predicate' % value)
+        elif name in _VERSION_FIELDS and value is not None:
+            if not is_valid_version(value):
+                warn('"%s" is not a valid version' % value)
+
+        if name in _UNICODEFIELDS:
             value = self._encode_field(value)
             if name == 'Description':
                 value = self._remove_line_prefix(value)
+
         self._fields[name] = value
-        # will trigger an error in case the user
-        # tries to set incompatible versions fields
         self._set_best_version()
 
     def get(self, name):
diff --git a/src/distutils2/tests/test_metadata.py b/src/distutils2/tests/test_metadata.py
--- a/src/distutils2/tests/test_metadata.py
+++ b/src/distutils2/tests/test_metadata.py
@@ -137,11 +137,53 @@
     def test_warnings(self):
         metadata = DistributionMetadata()
 
-        # this should raise a warning
-        # XXX how to test this on 2.4 ?
-        metadata['Requires-Dist'] = ['Funky (Groovie)']
+        # these should raise a warning
+        values = (('Requires-Dist', 'Funky (Groovie)'),
+                  ('Requires-Python', '1-4'))
 
+        from distutils2 import metadata as m
+        old = m.warn
+        m.warns = 0
 
+        def _warn(*args):
+            m.warns += 1
+
+        m.warn = _warn
+
+        try:
+            for name, value in values:
+                metadata.set(name, value)
+        finally:
+            m.warn = old
+            res = m.warns
+            del m.warns
+
+        # we should have a certain amount of warnings
+        num_wanted = len(values)
+        self.assertEquals(num_wanted, res)
+
+    def test_multiple_predicates(self):
+        metadata = DistributionMetadata()
+
+        from distutils2 import metadata as m
+        old = m.warn
+        m.warns = 0
+
+        def _warn(*args):
+            m.warns += 1
+
+        # see for "3" instead of "3.0"  ???
+        # its seems like the MINOR VERSION can be omitted
+        m.warn = _warn
+        try:
+            metadata['Requires-Python'] = '>=2.6, <3.0'
+            metadata['Requires-Dist'] = ['Foo (>=2.6, <3.0)']
+        finally:
+            m.warn = old
+            res = m.warns
+            del m.warns
+
+        self.assertEquals(res, 0)
 
 def test_suite():
     return unittest2.makeSuite(DistributionMetadataTestCase)
diff --git a/src/distutils2/version.py b/src/distutils2/version.py
--- a/src/distutils2/version.py
+++ b/src/distutils2/version.py
@@ -312,6 +312,7 @@
 
 _PREDICATE = re.compile(r"(?i)^\s*([a-z_]\w*(?:\.[a-z_]\w*)*)(.*)")
 _VERSIONS = re.compile(r"^\s*\((.*)\)\s*$")
+_PLAIN_VERSIONS = re.compile(r"^\s*(.*)\s*$")
 _SPLIT_CMP = re.compile(r"^\s*(<=|>=|<|>|!=|==)\s*([^\s,]+)\s*$")
 
 def _split_predicate(predicate):
@@ -323,6 +324,7 @@
         comp, version = match.groups()
     return comp, NormalizedVersion(version)
 
+
 class VersionPredicate(object):
     """Defines a predicate: ProjectName (>ver1,ver2, ..)"""
 
@@ -341,7 +343,6 @@
 
         self.name, predicates = match.groups()
         predicates = predicates.strip()
-
         predicates = _VERSIONS.match(predicates)
         if predicates is not None:
             predicates = predicates.groups()[0]
@@ -359,6 +360,26 @@
                 return False
         return True
 
+class Versions(VersionPredicate):
+    def __init__(self, predicate):
+        predicate = predicate.strip()
+        match = _PLAIN_VERSIONS.match(predicate)
+        if match is None:
+            raise ValueError('Bad predicate "%s"' % predicate)
+        self.name = None
+        predicates = match.groups()[0]
+        self.predicates = [_split_predicate(pred.strip())
+                           for pred in predicates.split(',')]
+
+class Version(VersionPredicate):
+    def __init__(self, predicate):
+        predicate = predicate.strip()
+        match = _PLAIN_VERSIONS.match(predicate)
+        if match is None:
+            raise ValueError('Bad predicate "%s"' % predicate)
+        self.name = None
+        self.predicates = _split_predicate(match.groups()[0])
+
 def is_valid_predicate(predicate):
     try:
         VersionPredicate(predicate)
@@ -367,3 +388,19 @@
     else:
         return True
 
+def is_valid_versions(predicate):
+    try:
+        Versions(predicate)
+    except (ValueError, IrrationalVersionError):
+        return False
+    else:
+        return True
+
+def is_valid_version(predicate):
+    try:
+        Version(predicate)
+    except (ValueError, IrrationalVersionError):
+        return False
+    else:
+        return True
+

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


More information about the Python-checkins mailing list