Commit 1690ef36 authored by Fred Drake's avatar Fred Drake

PEP 314 implementation (client side):

added support for the provides, requires, and obsoletes metadata fields
parent 5a3290c3
...@@ -231,7 +231,13 @@ Your selection [default 1]: ''', ...@@ -231,7 +231,13 @@ Your selection [default 1]: ''',
'platform': meta.get_platforms(), 'platform': meta.get_platforms(),
'classifiers': meta.get_classifiers(), 'classifiers': meta.get_classifiers(),
'download_url': meta.get_download_url(), 'download_url': meta.get_download_url(),
# PEP 314
'provides': meta.get_provides(),
'requires': meta.get_requires(),
'obsoletes': meta.get_obsoletes(),
} }
if data['provides'] or data['requires'] or data['obsoletes']:
data['metadata_version'] = '1.1'
return data return data
def post_to_server(self, data, auth=None): def post_to_server(self, data, auth=None):
......
...@@ -47,7 +47,9 @@ setup_keywords = ('distclass', 'script_name', 'script_args', 'options', ...@@ -47,7 +47,9 @@ setup_keywords = ('distclass', 'script_name', 'script_args', 'options',
'name', 'version', 'author', 'author_email', 'name', 'version', 'author', 'author_email',
'maintainer', 'maintainer_email', 'url', 'license', 'maintainer', 'maintainer_email', 'url', 'license',
'description', 'long_description', 'keywords', 'description', 'long_description', 'keywords',
'platforms', 'classifiers', 'download_url',) 'platforms', 'classifiers', 'download_url',
'requires', 'provides', 'obsoletes',
)
# Legal keyword arguments for the Extension constructor # Legal keyword arguments for the Extension constructor
extension_keywords = ('name', 'sources', 'include_dirs', extension_keywords = ('name', 'sources', 'include_dirs',
......
...@@ -106,6 +106,12 @@ Common commands: (see '--help-commands' for more) ...@@ -106,6 +106,12 @@ Common commands: (see '--help-commands' for more)
"print the list of classifiers"), "print the list of classifiers"),
('keywords', None, ('keywords', None,
"print the list of keywords"), "print the list of keywords"),
('provides', None,
"print the list of packages/modules provided"),
('requires', None,
"print the list of packages/modules required"),
('obsoletes', None,
"print the list of packages/modules made obsolete")
] ]
display_option_names = map(lambda x: translate_longopt(x[0]), display_option_names = map(lambda x: translate_longopt(x[0]),
display_options) display_options)
...@@ -210,7 +216,6 @@ Common commands: (see '--help-commands' for more) ...@@ -210,7 +216,6 @@ Common commands: (see '--help-commands' for more)
# distribution options. # distribution options.
if attrs: if attrs:
# Pull out the set of command options and work on them # Pull out the set of command options and work on them
# specifically. Note that this order guarantees that aliased # specifically. Note that this order guarantees that aliased
# command options will override any supplied redundantly # command options will override any supplied redundantly
...@@ -235,7 +240,9 @@ Common commands: (see '--help-commands' for more) ...@@ -235,7 +240,9 @@ Common commands: (see '--help-commands' for more)
# Now work on the rest of the attributes. Any attribute that's # Now work on the rest of the attributes. Any attribute that's
# not already defined is invalid! # not already defined is invalid!
for (key,val) in attrs.items(): for (key,val) in attrs.items():
if hasattr(self.metadata, key): if hasattr(self.metadata, "set_" + key):
getattr(self.metadata, "set_" + key)(val)
elif hasattr(self.metadata, key):
setattr(self.metadata, key, val) setattr(self.metadata, key, val)
elif hasattr(self, key): elif hasattr(self, key):
setattr(self, key, val) setattr(self, key, val)
...@@ -678,7 +685,8 @@ Common commands: (see '--help-commands' for more) ...@@ -678,7 +685,8 @@ Common commands: (see '--help-commands' for more)
value = getattr(self.metadata, "get_"+opt)() value = getattr(self.metadata, "get_"+opt)()
if opt in ['keywords', 'platforms']: if opt in ['keywords', 'platforms']:
print string.join(value, ',') print string.join(value, ',')
elif opt == 'classifiers': elif opt in ('classifiers', 'provides', 'requires',
'obsoletes'):
print string.join(value, '\n') print string.join(value, '\n')
else: else:
print value print value
...@@ -1024,7 +1032,10 @@ class DistributionMetadata: ...@@ -1024,7 +1032,10 @@ class DistributionMetadata:
"license", "description", "long_description", "license", "description", "long_description",
"keywords", "platforms", "fullname", "contact", "keywords", "platforms", "fullname", "contact",
"contact_email", "license", "classifiers", "contact_email", "license", "classifiers",
"download_url") "download_url",
# PEP 314
"provides", "requires", "obsoletes",
)
def __init__ (self): def __init__ (self):
self.name = None self.name = None
...@@ -1041,40 +1052,58 @@ class DistributionMetadata: ...@@ -1041,40 +1052,58 @@ class DistributionMetadata:
self.platforms = None self.platforms = None
self.classifiers = None self.classifiers = None
self.download_url = None self.download_url = None
# PEP 314
self.provides = None
self.requires = None
self.obsoletes = None
def write_pkg_info (self, base_dir): def write_pkg_info (self, base_dir):
"""Write the PKG-INFO file into the release tree. """Write the PKG-INFO file into the release tree.
""" """
pkg_info = open( os.path.join(base_dir, 'PKG-INFO'), 'w') pkg_info = open( os.path.join(base_dir, 'PKG-INFO'), 'w')
pkg_info.write('Metadata-Version: 1.0\n') self.write_pkg_file(pkg_info)
pkg_info.write('Name: %s\n' % self.get_name() )
pkg_info.write('Version: %s\n' % self.get_version() ) pkg_info.close()
pkg_info.write('Summary: %s\n' % self.get_description() )
pkg_info.write('Home-page: %s\n' % self.get_url() ) # write_pkg_info ()
pkg_info.write('Author: %s\n' % self.get_contact() )
pkg_info.write('Author-email: %s\n' % self.get_contact_email() ) def write_pkg_file (self, file):
pkg_info.write('License: %s\n' % self.get_license() ) """Write the PKG-INFO format data to a file object.
"""
version = '1.0'
if self.provides or self.requires or self.obsoletes:
version = '1.1'
file.write('Metadata-Version: %s\n' % version)
file.write('Name: %s\n' % self.get_name() )
file.write('Version: %s\n' % self.get_version() )
file.write('Summary: %s\n' % self.get_description() )
file.write('Home-page: %s\n' % self.get_url() )
file.write('Author: %s\n' % self.get_contact() )
file.write('Author-email: %s\n' % self.get_contact_email() )
file.write('License: %s\n' % self.get_license() )
if self.download_url: if self.download_url:
pkg_info.write('Download-URL: %s\n' % self.download_url) file.write('Download-URL: %s\n' % self.download_url)
long_desc = rfc822_escape( self.get_long_description() ) long_desc = rfc822_escape( self.get_long_description() )
pkg_info.write('Description: %s\n' % long_desc) file.write('Description: %s\n' % long_desc)
keywords = string.join( self.get_keywords(), ',') keywords = string.join( self.get_keywords(), ',')
if keywords: if keywords:
pkg_info.write('Keywords: %s\n' % keywords ) file.write('Keywords: %s\n' % keywords )
for platform in self.get_platforms():
pkg_info.write('Platform: %s\n' % platform )
for classifier in self.get_classifiers(): self._write_list(file, 'Platform', self.get_platforms())
pkg_info.write('Classifier: %s\n' % classifier ) self._write_list(file, 'Classifier', self.get_classifiers())
pkg_info.close() # PEP 314
self._write_list(file, 'Requires', self.get_requires())
self._write_list(file, 'Provides', self.get_provides())
self._write_list(file, 'Obsoletes', self.get_obsoletes())
# write_pkg_info () def _write_list (self, file, name, values):
for value in values:
file.write('%s: %s\n' % (name, value))
# -- Metadata query methods ---------------------------------------- # -- Metadata query methods ----------------------------------------
...@@ -1134,6 +1163,40 @@ class DistributionMetadata: ...@@ -1134,6 +1163,40 @@ class DistributionMetadata:
def get_download_url(self): def get_download_url(self):
return self.download_url or "UNKNOWN" return self.download_url or "UNKNOWN"
# PEP 314
def get_requires(self):
return self.requires or []
def set_requires(self, value):
import distutils.versionpredicate
for v in value:
distutils.versionpredicate.VersionPredicate(v)
self.requires = value
def get_provides(self):
return self.provides or []
def set_provides(self, value):
value = [v.strip() for v in value]
for v in value:
import distutils.versionpredicate
ver = distutils.versionpredicate.check_provision(v)
if ver:
import distutils.version
sv = distutils.version.StrictVersion()
sv.parse(ver.strip()[1:-1])
self.provides = value
def get_obsoletes(self):
return self.obsoletes or []
def set_obsoletes(self, value):
import distutils.versionpredicate
for v in value:
distutils.versionpredicate.VersionPredicate(v)
self.obsoletes = value
# class DistributionMetadata # class DistributionMetadata
......
...@@ -4,6 +4,7 @@ import distutils.cmd ...@@ -4,6 +4,7 @@ import distutils.cmd
import distutils.dist import distutils.dist
import os import os
import shutil import shutil
import StringIO
import sys import sys
import tempfile import tempfile
import unittest import unittest
...@@ -96,5 +97,93 @@ class DistributionTestCase(unittest.TestCase): ...@@ -96,5 +97,93 @@ class DistributionTestCase(unittest.TestCase):
os.unlink(TESTFN) os.unlink(TESTFN)
class MetadataTestCase(unittest.TestCase):
def test_simple_metadata(self):
attrs = {"name": "package",
"version": "1.0"}
dist = distutils.dist.Distribution(attrs)
meta = self.format_metadata(dist)
self.assert_("Metadata-Version: 1.0" in meta)
self.assert_("provides:" not in meta.lower())
self.assert_("requires:" not in meta.lower())
self.assert_("obsoletes:" not in meta.lower())
def test_provides(self):
attrs = {"name": "package",
"version": "1.0",
"provides": ["package", "package.sub"]}
dist = distutils.dist.Distribution(attrs)
self.assertEqual(dist.metadata.get_provides(),
["package", "package.sub"])
self.assertEqual(dist.get_provides(),
["package", "package.sub"])
meta = self.format_metadata(dist)
self.assert_("Metadata-Version: 1.1" in meta)
self.assert_("requires:" not in meta.lower())
self.assert_("obsoletes:" not in meta.lower())
def test_provides_illegal(self):
self.assertRaises(ValueError,
distutils.dist.Distribution,
{"name": "package",
"version": "1.0",
"provides": ["my.pkg (splat)"]})
def test_requires(self):
attrs = {"name": "package",
"version": "1.0",
"requires": ["other", "another (==1.0)"]}
dist = distutils.dist.Distribution(attrs)
self.assertEqual(dist.metadata.get_requires(),
["other", "another (==1.0)"])
self.assertEqual(dist.get_requires(),
["other", "another (==1.0)"])
meta = self.format_metadata(dist)
self.assert_("Metadata-Version: 1.1" in meta)
self.assert_("provides:" not in meta.lower())
self.assert_("Requires: other" in meta)
self.assert_("Requires: another (==1.0)" in meta)
self.assert_("obsoletes:" not in meta.lower())
def test_requires_illegal(self):
self.assertRaises(ValueError,
distutils.dist.Distribution,
{"name": "package",
"version": "1.0",
"requires": ["my.pkg (splat)"]})
def test_obsoletes(self):
attrs = {"name": "package",
"version": "1.0",
"obsoletes": ["other", "another (<1.0)"]}
dist = distutils.dist.Distribution(attrs)
self.assertEqual(dist.metadata.get_obsoletes(),
["other", "another (<1.0)"])
self.assertEqual(dist.get_obsoletes(),
["other", "another (<1.0)"])
meta = self.format_metadata(dist)
self.assert_("Metadata-Version: 1.1" in meta)
self.assert_("provides:" not in meta.lower())
self.assert_("requires:" not in meta.lower())
self.assert_("Obsoletes: other" in meta)
self.assert_("Obsoletes: another (<1.0)" in meta)
def test_obsoletes_illegal(self):
self.assertRaises(ValueError,
distutils.dist.Distribution,
{"name": "package",
"version": "1.0",
"obsoletes": ["my.pkg (splat)"]})
def format_metadata(self, dist):
sio = StringIO.StringIO()
dist.metadata.write_pkg_file(sio)
return sio.getvalue()
def test_suite(): def test_suite():
return unittest.makeSuite(DistributionTestCase) suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(DistributionTestCase))
suite.addTest(unittest.makeSuite(MetadataTestCase))
return suite
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment