[Python-checkins] cpython (merge default -> default): Branch merge

eric.araujo python-checkins at python.org
Mon Sep 12 17:42:25 CEST 2011


http://hg.python.org/cpython/rev/ad6b879eab02
changeset: 72359:ad6b879eab02
parent: 72345:c91900e4e805
parent: 72356:df157cb96a99
user: Éric Araujo <merwok at netwok.org>
date: Mon Sep 12 17:34:40 2011 +0200
summary:
 Branch merge
files:
 Doc/install/pysetup.rst | 17 +-
 Lib/distutils/dist.py | 3 +-
 Lib/distutils/tests/test_dist.py | 112 +-
 Lib/packaging/command/bdist_wininst.py | 20 +-
 Lib/packaging/command/build_ext.py | 4 -
 Lib/packaging/command/install_distinfo.py | 80 +-
 Lib/packaging/config.py | 7 +-
 Lib/packaging/metadata.py | 17 +-
 Lib/packaging/pypi/simple.py | 22 +-
 Lib/packaging/run.py | 20 +-
 Lib/packaging/tests/test_command_install_data.py | 1 +
 Lib/packaging/tests/test_dist.py | 252 +-----
 Lib/packaging/tests/test_metadata.py | 390 +++++++--
 Lib/packaging/tests/test_run.py | 23 +-
 Misc/NEWS | 4 +
 15 files changed, 488 insertions(+), 484 deletions(-)
diff --git a/Doc/install/pysetup.rst b/Doc/install/pysetup.rst
--- a/Doc/install/pysetup.rst
+++ b/Doc/install/pysetup.rst
@@ -19,13 +19,12 @@
 
 Pysetup makes it easy to find out what Python packages are installed::
 
- $ pysetup search virtualenv
- virtualenv 1.6 at /opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info
+ $ pysetup list virtualenv
+ 'virtualenv' 1.6 at '/opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info'
 
- $ pysetup search --all
- pyverify 0.8.1 at /opt/python3.3/lib/python3.3/site-packages/pyverify-0.8.1.dist-info
- virtualenv 1.6 at /opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info
- wsgiref 0.1.2 at /opt/python3.3/lib/python3.3/wsgiref.egg-info
+ $ pysetup list
+ 'pyverify' 0.8.1 at '/opt/python3.3/lib/python3.3/site-packages/pyverify-0.8.1.dist-info'
+ 'virtualenv' 1.6 at '/opt/python3.3/lib/python3.3/site-packages/virtualenv-1.6-py3.3.egg-info'
 ...
 
 
@@ -146,9 +145,11 @@
 metadata: Display the metadata of a project
 install: Install a project
 remove: Remove a project
- search: Search for a project
+ search: Search for a project in the indexes
+ list: List installed projects
 graph: Display a graph
- create: Create a Project
+ create: Create a project
+ generate-setup: Generate a backward-comptatible setup.py
 
 To get more help on an action, use:
 
diff --git a/Lib/distutils/dist.py b/Lib/distutils/dist.py
--- a/Lib/distutils/dist.py
+++ b/Lib/distutils/dist.py
@@ -1018,7 +1018,8 @@
 """Write the PKG-INFO format data to a file object.
 """
 version = '1.0'
- if self.provides or self.requires or self.obsoletes:
+ if (self.provides or self.requires or self.obsoletes or
+ self.classifiers or self.download_url):
 version = '1.1'
 
 file.write('Metadata-Version: %s\n' % version)
diff --git a/Lib/distutils/tests/test_dist.py b/Lib/distutils/tests/test_dist.py
--- a/Lib/distutils/tests/test_dist.py
+++ b/Lib/distutils/tests/test_dist.py
@@ -74,7 +74,7 @@
 self.assertEqual(d.get_command_packages(),
 ["distutils.command", "foo.bar", "distutils.tests"])
 cmd = d.get_command_obj("test_dist")
- self.assertTrue(isinstance(cmd, test_dist))
+ self.assertIsInstance(cmd, test_dist)
 self.assertEqual(cmd.sample_option, "sometext")
 
 def test_command_packages_configfile(self):
@@ -106,28 +106,23 @@
 def test_empty_options(self):
 # an empty options dictionary should not stay in the
 # list of attributes
- klass = Distribution
 
 # catching warnings
 warns = []
+
 def _warn(msg):
 warns.append(msg)
 
- old_warn = warnings.warn
+ self.addCleanup(setattr, warnings, 'warn', warnings.warn)
 warnings.warn = _warn
- try:
- dist = klass(attrs={'author': 'xxx',
- 'name': 'xxx',
- 'version': 'xxx',
- 'url': 'xxxx',
- 'options': {}})
- finally:
- warnings.warn = old_warn
+ dist = Distribution(attrs={'author': 'xxx', 'name': 'xxx',
+ 'version': 'xxx', 'url': 'xxxx',
+ 'options': {}})
 
 self.assertEqual(len(warns), 0)
+ self.assertNotIn('options', dir(dist))
 
 def test_finalize_options(self):
-
 attrs = {'keywords': 'one,two',
 'platforms': 'one,two'}
 
@@ -150,7 +145,6 @@
 cmds = dist.get_command_packages()
 self.assertEqual(cmds, ['distutils.command', 'one', 'two'])
 
-
 def test_announce(self):
 # make sure the level is known
 dist = Distribution()
@@ -158,6 +152,7 @@
 kwargs = {'level': 'ok2'}
 self.assertRaises(ValueError, dist.announce, args, kwargs)
 
+
 class MetadataTestCase(support.TempdirManager, support.EnvironGuard,
 unittest.TestCase):
 
@@ -170,15 +165,20 @@
 sys.argv[:] = self.argv[1]
 super(MetadataTestCase, self).tearDown()
 
+ def format_metadata(self, dist):
+ sio = io.StringIO()
+ dist.metadata.write_pkg_file(sio)
+ return sio.getvalue()
+
 def test_simple_metadata(self):
 attrs = {"name": "package",
 "version": "1.0"}
 dist = Distribution(attrs)
 meta = self.format_metadata(dist)
- self.assertTrue("Metadata-Version: 1.0" in meta)
- self.assertTrue("provides:" not in meta.lower())
- self.assertTrue("requires:" not in meta.lower())
- self.assertTrue("obsoletes:" not in meta.lower())
+ self.assertIn("Metadata-Version: 1.0", meta)
+ self.assertNotIn("provides:", meta.lower())
+ self.assertNotIn("requires:", meta.lower())
+ self.assertNotIn("obsoletes:", meta.lower())
 
 def test_provides(self):
 attrs = {"name": "package",
@@ -190,9 +190,9 @@
 self.assertEqual(dist.get_provides(),
 ["package", "package.sub"])
 meta = self.format_metadata(dist)
- self.assertTrue("Metadata-Version: 1.1" in meta)
- self.assertTrue("requires:" not in meta.lower())
- self.assertTrue("obsoletes:" not in meta.lower())
+ self.assertIn("Metadata-Version: 1.1", meta)
+ self.assertNotIn("requires:", meta.lower())
+ self.assertNotIn("obsoletes:", meta.lower())
 
 def test_provides_illegal(self):
 self.assertRaises(ValueError, Distribution,
@@ -210,11 +210,11 @@
 self.assertEqual(dist.get_requires(),
 ["other", "another (==1.0)"])
 meta = self.format_metadata(dist)
- self.assertTrue("Metadata-Version: 1.1" in meta)
- self.assertTrue("provides:" not in meta.lower())
- self.assertTrue("Requires: other" in meta)
- self.assertTrue("Requires: another (==1.0)" in meta)
- self.assertTrue("obsoletes:" not in meta.lower())
+ self.assertIn("Metadata-Version: 1.1", meta)
+ self.assertNotIn("provides:", meta.lower())
+ self.assertIn("Requires: other", meta)
+ self.assertIn("Requires: another (==1.0)", meta)
+ self.assertNotIn("obsoletes:", meta.lower())
 
 def test_requires_illegal(self):
 self.assertRaises(ValueError, Distribution,
@@ -232,11 +232,11 @@
 self.assertEqual(dist.get_obsoletes(),
 ["other", "another (<1.0)"])
 meta = self.format_metadata(dist)
- self.assertTrue("Metadata-Version: 1.1" in meta)
- self.assertTrue("provides:" not in meta.lower())
- self.assertTrue("requires:" not in meta.lower())
- self.assertTrue("Obsoletes: other" in meta)
- self.assertTrue("Obsoletes: another (<1.0)" in meta)
+ self.assertIn("Metadata-Version: 1.1", meta)
+ self.assertNotIn("provides:", meta.lower())
+ self.assertNotIn("requires:", meta.lower())
+ self.assertIn("Obsoletes: other", meta)
+ self.assertIn("Obsoletes: another (<1.0)", meta)
 
 def test_obsoletes_illegal(self):
 self.assertRaises(ValueError, Distribution,
@@ -244,10 +244,34 @@
 "version": "1.0",
 "obsoletes": ["my.pkg (splat)"]})
 
- def format_metadata(self, dist):
- sio = io.StringIO()
- dist.metadata.write_pkg_file(sio)
- return sio.getvalue()
+ def test_classifier(self):
+ attrs = {'name': 'Boa', 'version': '3.0',
+ 'classifiers': ['Programming Language :: Python :: 3']}
+ dist = Distribution(attrs)
+ meta = self.format_metadata(dist)
+ self.assertIn('Metadata-Version: 1.1', meta)
+
+ def test_download_url(self):
+ attrs = {'name': 'Boa', 'version': '3.0',
+ 'download_url': 'http://example.org/boa'}
+ dist = Distribution(attrs)
+ meta = self.format_metadata(dist)
+ self.assertIn('Metadata-Version: 1.1', meta)
+
+ def test_long_description(self):
+ long_desc = textwrap.dedent("""\
+ example::
+ We start here
+ and continue here
+ and end here.""")
+ attrs = {"name": "package",
+ "version": "1.0",
+ "long_description": long_desc}
+
+ dist = Distribution(attrs)
+ meta = self.format_metadata(dist)
+ meta = meta.replace('\n' + 8 * ' ', '\n')
+ self.assertIn(long_desc, meta)
 
 def test_custom_pydistutils(self):
 # fixes #2166
@@ -272,14 +296,14 @@
 if sys.platform in ('linux', 'darwin'):
 os.environ['HOME'] = temp_dir
 files = dist.find_config_files()
- self.assertTrue(user_filename in files)
+ self.assertIn(user_filename, files)
 
 # win32-style
 if sys.platform == 'win32':
 # home drive should be found
 os.environ['HOME'] = temp_dir
 files = dist.find_config_files()
- self.assertTrue(user_filename in files,
+ self.assertIn(user_filename, files,
 '%r not found in %r' % (user_filename, files))
 finally:
 os.remove(user_filename)
@@ -301,22 +325,8 @@
 
 output = [line for line in s.getvalue().split('\n')
 if line.strip() != '']
- self.assertTrue(len(output) > 0)
+ self.assertTrue(output)
 
- def test_long_description(self):
- long_desc = textwrap.dedent("""\
- example::
- We start here
- and continue here
- and end here.""")
- attrs = {"name": "package",
- "version": "1.0",
- "long_description": long_desc}
-
- dist = Distribution(attrs)
- meta = self.format_metadata(dist)
- meta = meta.replace('\n' + 8 * ' ', '\n')
- self.assertTrue(long_desc in meta)
 
 def test_suite():
 suite = unittest.TestSuite()
diff --git a/Lib/packaging/command/bdist_wininst.py b/Lib/packaging/command/bdist_wininst.py
--- a/Lib/packaging/command/bdist_wininst.py
+++ b/Lib/packaging/command/bdist_wininst.py
@@ -1,7 +1,5 @@
 """Create an executable installer for Windows."""
 
-# FIXME synchronize bytes/str use with same file in distutils
-
 import sys
 import os
 
@@ -186,9 +184,8 @@
 os.remove(arcname)
 
 if not self.keep_temp:
- if self.dry_run:
- logger.info('removing %s', self.bdist_dir)
- else:
+ logger.info('removing %s', self.bdist_dir)
+ if not self.dry_run:
 rmtree(self.bdist_dir)
 
 def get_inidata(self):
@@ -265,14 +262,17 @@
 cfgdata = cfgdata.encode("mbcs")
 
 # Append the pre-install script
- cfgdata = cfgdata + "0円"
+ cfgdata = cfgdata + b"0円"
 if self.pre_install_script:
- with open(self.pre_install_script) as fp:
- script_data = fp.read()
- cfgdata = cfgdata + script_data + "\n0円"
+ # We need to normalize newlines, so we open in text mode and
+ # convert back to bytes. "latin-1" simply avoids any possible
+ # failures.
+ with open(self.pre_install_script, encoding="latin-1") as fp:
+ script_data = fp.read().encode("latin-1")
+ cfgdata = cfgdata + script_data + b"\n0円"
 else:
 # empty pre-install script
- cfgdata = cfgdata + "0円"
+ cfgdata = cfgdata + b"0円"
 file.write(cfgdata)
 
 # The 'magic number' 0x1234567B is used to make sure that the
diff --git a/Lib/packaging/command/build_ext.py b/Lib/packaging/command/build_ext.py
--- a/Lib/packaging/command/build_ext.py
+++ b/Lib/packaging/command/build_ext.py
@@ -1,9 +1,5 @@
 """Build extension modules."""
 
-# FIXME Is this module limited to C extensions or do C++ extensions work too?
-# The docstring of this module said that C++ was not supported, but other
-# comments contradict that.
-
 import os
 import re
 import sys
diff --git a/Lib/packaging/command/install_distinfo.py b/Lib/packaging/command/install_distinfo.py
--- a/Lib/packaging/command/install_distinfo.py
+++ b/Lib/packaging/command/install_distinfo.py
@@ -28,7 +28,7 @@
 ('no-record', None,
 "do not generate a RECORD file"),
 ('no-resources', None,
- "do not generate a RESSOURCES list installed file")
+ "do not generate a RESSOURCES list installed file"),
 ]
 
 boolean_options = ['requested', 'no-record', 'no-resources']
@@ -70,56 +70,56 @@
 self.distinfo_dir = os.path.join(self.distinfo_dir, basename)
 
 def run(self):
- # FIXME dry-run should be used at a finer level, so that people get
- # useful logging output and can have an idea of what the command would
- # have done
+ target = self.distinfo_dir
+
+ if os.path.isdir(target) and not os.path.islink(target):
+ if not self.dry_run:
+ rmtree(target)
+ elif os.path.exists(target):
+ self.execute(os.unlink, (self.distinfo_dir,),
+ "removing " + target)
+
+ self.execute(os.makedirs, (target,), "creating " + target)
+
+ metadata_path = os.path.join(self.distinfo_dir, 'METADATA')
+ self.execute(self.distribution.metadata.write, (metadata_path,),
+ "creating " + metadata_path)
+ self.outfiles.append(metadata_path)
+
+ installer_path = os.path.join(self.distinfo_dir, 'INSTALLER')
+ logger.info('creating %s', installer_path)
 if not self.dry_run:
- target = self.distinfo_dir
-
- if os.path.isdir(target) and not os.path.islink(target):
- rmtree(target)
- elif os.path.exists(target):
- self.execute(os.unlink, (self.distinfo_dir,),
- "removing " + target)
-
- self.execute(os.makedirs, (target,), "creating " + target)
-
- metadata_path = os.path.join(self.distinfo_dir, 'METADATA')
- logger.info('creating %s', metadata_path)
- self.distribution.metadata.write(metadata_path)
- self.outfiles.append(metadata_path)
-
- installer_path = os.path.join(self.distinfo_dir, 'INSTALLER')
- logger.info('creating %s', installer_path)
 with open(installer_path, 'w') as f:
 f.write(self.installer)
- self.outfiles.append(installer_path)
+ self.outfiles.append(installer_path)
 
- if self.requested:
- requested_path = os.path.join(self.distinfo_dir, 'REQUESTED')
- logger.info('creating %s', requested_path)
+ if self.requested:
+ requested_path = os.path.join(self.distinfo_dir, 'REQUESTED')
+ logger.info('creating %s', requested_path)
+ if not self.dry_run:
 open(requested_path, 'wb').close()
- self.outfiles.append(requested_path)
+ self.outfiles.append(requested_path)
 
-
- if not self.no_resources:
- install_data = self.get_finalized_command('install_data')
- if install_data.get_resources_out() != []:
- resources_path = os.path.join(self.distinfo_dir,
- 'RESOURCES')
- logger.info('creating %s', resources_path)
+ if not self.no_resources:
+ install_data = self.get_finalized_command('install_data')
+ if install_data.get_resources_out() != []:
+ resources_path = os.path.join(self.distinfo_dir,
+ 'RESOURCES')
+ logger.info('creating %s', resources_path)
+ if not self.dry_run:
 with open(resources_path, 'wb') as f:
 writer = csv.writer(f, delimiter=',',
 lineterminator='\n',
 quotechar='"')
- for tuple in install_data.get_resources_out():
- writer.writerow(tuple)
+ for row in install_data.get_resources_out():
+ writer.writerow(row)
 
- self.outfiles.append(resources_path)
+ self.outfiles.append(resources_path)
 
- if not self.no_record:
- record_path = os.path.join(self.distinfo_dir, 'RECORD')
- logger.info('creating %s', record_path)
+ if not self.no_record:
+ record_path = os.path.join(self.distinfo_dir, 'RECORD')
+ logger.info('creating %s', record_path)
+ if not self.dry_run:
 with open(record_path, 'w', encoding='utf-8') as f:
 writer = csv.writer(f, delimiter=',',
 lineterminator='\n',
@@ -141,7 +141,7 @@
 
 # add the RECORD file itself
 writer.writerow((record_path, '', ''))
- self.outfiles.append(record_path)
+ self.outfiles.append(record_path)
 
 def get_outputs(self):
 return self.outfiles
diff --git a/Lib/packaging/config.py b/Lib/packaging/config.py
--- a/Lib/packaging/config.py
+++ b/Lib/packaging/config.py
@@ -227,10 +227,11 @@
 self.dist.scripts = [self.dist.scripts]
 
 self.dist.package_data = {}
- for data in files.get('package_data', []):
- data = data.split('=')
+ for line in files.get('package_data', []):
+ data = line.split('=')
 if len(data) != 2:
- continue # FIXME errors should never pass silently
+ raise ValueError('invalid line for package_data: %s '
+ '(misses "=")' % line)
 key, value = data
 self.dist.package_data[key.strip()] = value.strip()
 
diff --git a/Lib/packaging/metadata.py b/Lib/packaging/metadata.py
--- a/Lib/packaging/metadata.py
+++ b/Lib/packaging/metadata.py
@@ -61,7 +61,8 @@
 'License', 'Classifier', 'Download-URL', 'Obsoletes',
 'Provides', 'Requires')
 
-_314_MARKERS = ('Obsoletes', 'Provides', 'Requires')
+_314_MARKERS = ('Obsoletes', 'Provides', 'Requires', 'Classifier',
+ 'Download-URL')
 
 _345_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform',
 'Supported-Platform', 'Summary', 'Description',
@@ -354,11 +355,20 @@
 Keys that don't match a metadata field or that have an empty value are
 dropped.
 """
+ # XXX the code should just use self.set, which does tbe same checks and
+ # conversions already, but that would break packaging.pypi: it uses the
+ # update method, which does not call _set_best_version (which set
+ # does), and thus allows having a Metadata object (as long as you don't
+ # modify or write it) with extra fields from PyPI that are not fields
+ # defined in Metadata PEPs. to solve it, the best_version system
+ # should be reworked so that it's called only for writing, or in a new
+ # strict mode, or with a new, more lax Metadata subclass in p7g.pypi
 def _set(key, value):
 if key in _ATTR2FIELD and value:
 self.set(self._convert_name(key), value)
 
- if other is None:
+ if not other:
+ # other is None or empty container
 pass
 elif hasattr(other, 'keys'):
 for k in other.keys():
@@ -368,7 +378,8 @@
 _set(k, v)
 
 if kwargs:
- self.update(kwargs)
+ for k, v in kwargs.items():
+ _set(k, v)
 
 def set(self, name, value):
 """Control then set a metadata field."""
diff --git a/Lib/packaging/pypi/simple.py b/Lib/packaging/pypi/simple.py
--- a/Lib/packaging/pypi/simple.py
+++ b/Lib/packaging/pypi/simple.py
@@ -159,22 +159,20 @@
 
 Return a list of names.
 """
+ if '*' in name:
+ name.replace('*', '.*')
+ else:
+ name = "%s%s%s" % ('*.?', name, '*.?')
+ name = name.replace('*', '[^<]*') # avoid matching end tag
+ pattern = ('<a[^>]*>(%s)</a>' % name).encode('utf-8')
+ projectname = re.compile(pattern, re.I)
+ matching_projects = []
+
 with self._open_url(self.index_url) as index:
- if '*' in name:
- name.replace('*', '.*')
- else:
- name = "%s%s%s" % ('*.?', name, '*.?')
- name = name.replace('*', '[^<]*') # avoid matching end tag
- projectname = re.compile('<a[^>]*>(%s)</a>' % name, re.I)
- matching_projects = []
-
 index_content = index.read()
 
- # FIXME should use bytes I/O and regexes instead of decoding
- index_content = index_content.decode()
-
 for match in projectname.finditer(index_content):
- project_name = match.group(1)
+ project_name = match.group(1).decode('utf-8')
 matching_projects.append(self._get_project(project_name))
 return matching_projects
 
diff --git a/Lib/packaging/run.py b/Lib/packaging/run.py
--- a/Lib/packaging/run.py
+++ b/Lib/packaging/run.py
@@ -290,27 +290,23 @@
 
 
 @action_help("""\
-Usage: pysetup list dist [dist ...]
+Usage: pysetup list [dist ...]
 or: pysetup list --help
- or: pysetup list --all
 
 Print name, version and location for the matching installed distributions.
 
 positional arguments:
- dist installed distribution name
-
-optional arguments:
- --all list all installed distributions
+ dist installed distribution name; omit to get all distributions
 """)
 def _list(dispatcher, args, **kw):
- opts = _parse_args(args[1:], '', ['all'])
+ opts = _parse_args(args[1:], '', [])
 dists = get_distributions(use_egg_info=True)
- if 'all' in opts or opts['args'] == []:
+ if opts['args']:
+ results = (d for d in dists if d.name.lower() in opts['args'])
+ listall = False
+ else:
 results = dists
 listall = True
- else:
- results = (d for d in dists if d.name.lower() in opts['args'])
- listall = False
 
 number = 0
 for dist in results:
@@ -368,7 +364,7 @@
 ('install', 'Install a project', _install),
 ('remove', 'Remove a project', _remove),
 ('search', 'Search for a project in the indexes', _search),
- ('list', 'List installed releases', _list),
+ ('list', 'List installed projects', _list),
 ('graph', 'Display a graph', _graph),
 ('create', 'Create a project', _create),
 ('generate-setup', 'Generate a backward-comptatible setup.py', _generate),
diff --git a/Lib/packaging/tests/test_command_install_data.py b/Lib/packaging/tests/test_command_install_data.py
--- a/Lib/packaging/tests/test_command_install_data.py
+++ b/Lib/packaging/tests/test_command_install_data.py
@@ -35,6 +35,7 @@
 two = os.path.join(pkg_dir, 'two')
 self.write_file(two, 'xxx')
 
+ # FIXME this creates a literal \{inst2\} directory!
 cmd.data_files = {one: '{inst}/one', two: '{inst2}/two'}
 self.assertCountEqual(cmd.get_inputs(), [one, two])
 
diff --git a/Lib/packaging/tests/test_dist.py b/Lib/packaging/tests/test_dist.py
--- a/Lib/packaging/tests/test_dist.py
+++ b/Lib/packaging/tests/test_dist.py
@@ -1,16 +1,13 @@
 """Tests for packaging.dist."""
 import os
-import io
 import sys
 import logging
 import textwrap
-import sysconfig
 import packaging.dist
 
 from packaging.dist import Distribution
 from packaging.command import set_command
 from packaging.command.cmd import Command
-from packaging.metadata import Metadata
 from packaging.errors import PackagingModuleError, PackagingOptionError
 from packaging.tests import TESTFN, captured_stdout
 from packaging.tests import support, unittest
@@ -49,6 +46,7 @@
 sys.argv[:] = self.argv[1]
 super(DistributionTestCase, self).tearDown()
 
+ @unittest.skip('needs to be updated')
 def test_debug_mode(self):
 self.addCleanup(os.unlink, TESTFN)
 with open(TESTFN, "w") as f:
@@ -59,6 +57,8 @@
 sys.argv.append("build")
 __, stdout = captured_stdout(create_distribution, files)
 self.assertEqual(stdout, '')
+ # XXX debug mode does not exist anymore, test logging levels in this
+ # test instead
 packaging.dist.DEBUG = True
 try:
 __, stdout = captured_stdout(create_distribution, files)
@@ -66,34 +66,6 @@
 finally:
 packaging.dist.DEBUG = False
 
- def test_write_pkg_file(self):
- # Check Metadata handling of Unicode fields
- tmp_dir = self.mkdtemp()
- my_file = os.path.join(tmp_dir, 'f')
- cls = Distribution
-
- dist = cls(attrs={'author': 'Mister Café',
- 'name': 'my.package',
- 'maintainer': 'Café Junior',
- 'summary': 'Café torréfié',
- 'description': 'Héhéhé'})
-
- # let's make sure the file can be written
- # with Unicode fields. they are encoded with
- # PKG_INFO_ENCODING
- with open(my_file, 'w', encoding='utf-8') as fp:
- dist.metadata.write_file(fp)
-
- # regular ascii is of course always usable
- dist = cls(attrs={'author': 'Mister Cafe',
- 'name': 'my.package',
- 'maintainer': 'Cafe Junior',
- 'summary': 'Cafe torrefie',
- 'description': 'Hehehe'})
-
- with open(my_file, 'w') as fp:
- dist.metadata.write_file(fp)
-
 def test_bad_attr(self):
 Distribution(attrs={'author': 'xxx',
 'name': 'xxx',
@@ -101,28 +73,18 @@
 'home-page': 'xxxx',
 'badoptname': 'xxx'})
 logs = self.get_logs(logging.WARNING)
- self.assertEqual(1, len(logs))
+ self.assertEqual(len(logs), 1)
 self.assertIn('unknown argument', logs[0])
 
- def test_bad_version(self):
- Distribution(attrs={'author': 'xxx',
- 'name': 'xxx',
- 'version': 'xxx',
- 'home-page': 'xxxx'})
- logs = self.get_logs(logging.WARNING)
- self.assertEqual(1, len(logs))
- self.assertIn('not a valid version', logs[0])
-
 def test_empty_options(self):
 # an empty options dictionary should not stay in the
 # list of attributes
- Distribution(attrs={'author': 'xxx',
- 'name': 'xxx',
- 'version': '1.2',
- 'home-page': 'xxxx',
- 'options': {}})
+ dist = Distribution(attrs={'author': 'xxx', 'name': 'xxx',
+ 'version': '1.2', 'home-page': 'xxxx',
+ 'options': {}})
 
 self.assertEqual([], self.get_logs(logging.WARNING))
+ self.assertNotIn('options', dir(dist))
 
 def test_non_empty_options(self):
 # TODO: how to actually use options is not documented except
@@ -141,7 +103,6 @@
 self.assertIn('owner', dist.get_option_dict('sdist'))
 
 def test_finalize_options(self):
-
 attrs = {'keywords': 'one,two',
 'platform': 'one,two'}
 
@@ -152,6 +113,24 @@
 self.assertEqual(dist.metadata['platform'], ['one', 'two'])
 self.assertEqual(dist.metadata['keywords'], ['one', 'two'])
 
+ def test_custom_pydistutils(self):
+ # Bug #2166: make sure pydistutils.cfg is found
+ if os.name == 'posix':
+ user_filename = ".pydistutils.cfg"
+ else:
+ user_filename = "pydistutils.cfg"
+
+ temp_dir = self.mkdtemp()
+ user_filename = os.path.join(temp_dir, user_filename)
+ with open(user_filename, 'w') as f:
+ f.write('.')
+
+ dist = Distribution()
+
+ os.environ['HOME'] = temp_dir
+ files = dist.find_config_files()
+ self.assertIn(user_filename, files)
+
 def test_find_config_files_disable(self):
 # Bug #1180: Allow users to disable their own config file.
 temp_home = self.mkdtemp()
@@ -270,185 +249,8 @@
 self.assertRaises(PackagingOptionError, d.run_command, 'test_dist')
 
 
-class MetadataTestCase(support.TempdirManager,
- support.LoggingCatcher,
- support.EnvironRestorer,
- unittest.TestCase):
-
- restore_environ = ['HOME']
-
- def setUp(self):
- super(MetadataTestCase, self).setUp()
- self.argv = sys.argv, sys.argv[:]
-
- def tearDown(self):
- sys.argv = self.argv[0]
- sys.argv[:] = self.argv[1]
- super(MetadataTestCase, self).tearDown()
-
- def test_simple_metadata(self):
- attrs = {"name": "package",
- "version": "1.0"}
- dist = Distribution(attrs)
- meta = self.format_metadata(dist)
- self.assertIn("Metadata-Version: 1.0", meta)
- self.assertNotIn("provides:", meta.lower())
- self.assertNotIn("requires:", meta.lower())
- self.assertNotIn("obsoletes:", meta.lower())
-
- def test_provides_dist(self):
- attrs = {"name": "package",
- "version": "1.0",
- "provides_dist": ["package", "package.sub"]}
- dist = Distribution(attrs)
- self.assertEqual(dist.metadata['Provides-Dist'],
- ["package", "package.sub"])
- meta = self.format_metadata(dist)
- self.assertIn("Metadata-Version: 1.2", meta)
- self.assertNotIn("requires:", meta.lower())
- self.assertNotIn("obsoletes:", meta.lower())
-
- def _test_provides_illegal(self):
- # XXX to do: check the versions
- self.assertRaises(ValueError, Distribution,
- {"name": "package",
- "version": "1.0",
- "provides_dist": ["my.pkg (splat)"]})
-
- def test_requires_dist(self):
- attrs = {"name": "package",
- "version": "1.0",
- "requires_dist": ["other", "another (==1.0)"]}
- dist = Distribution(attrs)
- self.assertEqual(dist.metadata['Requires-Dist'],
- ["other", "another (==1.0)"])
- meta = self.format_metadata(dist)
- self.assertIn("Metadata-Version: 1.2", meta)
- self.assertNotIn("provides:", meta.lower())
- self.assertIn("Requires-Dist: other", meta)
- self.assertIn("Requires-Dist: another (==1.0)", meta)
- self.assertNotIn("obsoletes:", meta.lower())
-
- def _test_requires_illegal(self):
- # XXX
- self.assertRaises(ValueError, Distribution,
- {"name": "package",
- "version": "1.0",
- "requires": ["my.pkg (splat)"]})
-
- def test_obsoletes_dist(self):
- attrs = {"name": "package",
- "version": "1.0",
- "obsoletes_dist": ["other", "another (<1.0)"]}
- dist = Distribution(attrs)
- self.assertEqual(dist.metadata['Obsoletes-Dist'],
- ["other", "another (<1.0)"])
- meta = self.format_metadata(dist)
- self.assertIn("Metadata-Version: 1.2", meta)
- self.assertNotIn("provides:", meta.lower())
- self.assertNotIn("requires:", meta.lower())
- self.assertIn("Obsoletes-Dist: other", meta)
- self.assertIn("Obsoletes-Dist: another (<1.0)", meta)
-
- def _test_obsoletes_illegal(self):
- # XXX
- self.assertRaises(ValueError, Distribution,
- {"name": "package",
- "version": "1.0",
- "obsoletes": ["my.pkg (splat)"]})
-
- def format_metadata(self, dist):
- sio = io.StringIO()
- dist.metadata.write_file(sio)
- return sio.getvalue()
-
- def test_custom_pydistutils(self):
- # fixes #2166
- # make sure pydistutils.cfg is found
- if os.name == 'posix':
- user_filename = ".pydistutils.cfg"
- else:
- user_filename = "pydistutils.cfg"
-
- temp_dir = self.mkdtemp()
- user_filename = os.path.join(temp_dir, user_filename)
- with open(user_filename, 'w') as f:
- f.write('.')
-
- dist = Distribution()
-
- # linux-style
- if sys.platform in ('linux', 'darwin'):
- os.environ['HOME'] = temp_dir
- files = dist.find_config_files()
- self.assertIn(user_filename, files)
-
- # win32-style
- if sys.platform == 'win32':
- # home drive should be found
- os.environ['HOME'] = temp_dir
- files = dist.find_config_files()
- self.assertIn(user_filename, files)
-
- def test_show_help(self):
- # smoke test, just makes sure some help is displayed
- dist = Distribution()
- sys.argv = []
- dist.help = True
- dist.script_name = os.path.join(sysconfig.get_path('scripts'),
- 'pysetup')
- __, stdout = captured_stdout(dist.parse_command_line)
- output = [line for line in stdout.split('\n')
- if line.strip() != '']
- self.assertGreater(len(output), 0)
-
- def test_description(self):
- desc = textwrap.dedent("""\
- example::
- We start here
- and continue here
- and end here.""")
- attrs = {"name": "package",
- "version": "1.0",
- "description": desc}
-
- dist = packaging.dist.Distribution(attrs)
- meta = self.format_metadata(dist)
- meta = meta.replace('\n' + 7 * ' ' + '|', '\n')
- self.assertIn(desc, meta)
-
- def test_read_metadata(self):
- attrs = {"name": "package",
- "version": "1.0",
- "description": "desc",
- "summary": "xxx",
- "download_url": "http://example.com",
- "keywords": ['one', 'two'],
- "requires_dist": ['foo']}
-
- dist = Distribution(attrs)
- PKG_INFO = io.StringIO()
- dist.metadata.write_file(PKG_INFO)
- PKG_INFO.seek(0)
-
- metadata = Metadata()
- metadata.read_file(PKG_INFO)
-
- self.assertEqual(metadata['name'], "package")
- self.assertEqual(metadata['version'], "1.0")
- self.assertEqual(metadata['summary'], "xxx")
- self.assertEqual(metadata['download_url'], 'http://example.com')
- self.assertEqual(metadata['keywords'], ['one', 'two'])
- self.assertEqual(metadata['platform'], [])
- self.assertEqual(metadata['obsoletes'], [])
- self.assertEqual(metadata['requires-dist'], ['foo'])
-
-
 def test_suite():
- suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(DistributionTestCase))
- suite.addTest(unittest.makeSuite(MetadataTestCase))
- return suite
+ return unittest.makeSuite(DistributionTestCase)
 
 if __name__ == "__main__":
 unittest.main(defaultTest="test_suite")
diff --git a/Lib/packaging/tests/test_metadata.py b/Lib/packaging/tests/test_metadata.py
--- a/Lib/packaging/tests/test_metadata.py
+++ b/Lib/packaging/tests/test_metadata.py
@@ -2,6 +2,7 @@
 import os
 import sys
 import logging
+from textwrap import dedent
 from io import StringIO
 
 from packaging.errors import (MetadataConflictError, MetadataMissingError,
@@ -9,12 +10,29 @@
 from packaging.metadata import Metadata, PKG_INFO_PREFERRED_VERSION
 
 from packaging.tests import unittest
-from packaging.tests.support import LoggingCatcher
+from packaging.tests.support import (LoggingCatcher, TempdirManager,
+ EnvironRestorer)
 
 
 class MetadataTestCase(LoggingCatcher,
+ TempdirManager,
+ EnvironRestorer,
 unittest.TestCase):
 
+ maxDiff = None
+ restore_environ = ['HOME']
+
+ def setUp(self):
+ super(MetadataTestCase, self).setUp()
+ self.argv = sys.argv, sys.argv[:]
+
+ def tearDown(self):
+ sys.argv = self.argv[0]
+ sys.argv[:] = self.argv[1]
+ super(MetadataTestCase, self).tearDown()
+
+ #### Test various methods of the Metadata class
+
 def test_instantiation(self):
 PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
 with open(PKG_INFO, 'r', encoding='utf-8') as f:
@@ -43,17 +61,6 @@
 self.assertRaises(TypeError, Metadata,
 PKG_INFO, mapping=m, fileobj=fp)
 
- def test_metadata_read_write(self):
- PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
- metadata = Metadata(PKG_INFO)
- out = StringIO()
- metadata.write_file(out)
- out.seek(0)
- res = Metadata()
- res.read_file(out)
- for k in metadata:
- self.assertEqual(metadata[k], res[k])
-
 def test_metadata_markers(self):
 # see if we can be platform-aware
 PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
@@ -70,31 +77,10 @@
 
 # test with context
 context = {'sys.platform': 'okook'}
- metadata = Metadata(platform_dependent=True,
- execution_context=context)
+ metadata = Metadata(platform_dependent=True, execution_context=context)
 metadata.read_file(StringIO(content))
 self.assertEqual(metadata['Requires-Dist'], ['foo'])
 
- def test_description(self):
- PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
- with open(PKG_INFO, 'r', encoding='utf-8') as f:
- content = f.read() % sys.platform
- metadata = Metadata()
- metadata.read_file(StringIO(content))
-
- # see if we can read the description now
- DESC = os.path.join(os.path.dirname(__file__), 'LONG_DESC.txt')
- with open(DESC) as f:
- wanted = f.read()
- self.assertEqual(wanted, metadata['Description'])
-
- # save the file somewhere and make sure we can read it back
- out = StringIO()
- metadata.write_file(out)
- out.seek(0)
- metadata.read_file(out)
- self.assertEqual(wanted, metadata['Description'])
-
 def test_mapping_api(self):
 PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
 with open(PKG_INFO, 'r', encoding='utf-8') as f:
@@ -109,73 +95,86 @@
 metadata.update([('version', '0.7')])
 self.assertEqual(metadata['Version'], '0.7')
 
+ # make sure update method checks values like the set method does
+ metadata.update({'version': '1--2'})
+ self.assertEqual(len(self.get_logs()), 1)
+
+ # XXX caveat: the keys method and friends are not 3.x-style views
+ # should be changed or documented
 self.assertEqual(list(metadata), list(metadata.keys()))
 
- def test_versions(self):
- metadata = Metadata()
- metadata['Obsoletes'] = 'ok'
- self.assertEqual(metadata['Metadata-Version'], '1.1')
+ def test_read_metadata(self):
+ fields = {'name': 'project',
+ 'version': '1.0',
+ 'description': 'desc',
+ 'summary': 'xxx',
+ 'download_url': 'http://example.com',
+ 'keywords': ['one', 'two'],
+ 'requires_dist': ['foo']}
 
- del metadata['Obsoletes']
- metadata['Obsoletes-Dist'] = 'ok'
- self.assertEqual(metadata['Metadata-Version'], '1.2')
+ metadata = Metadata(mapping=fields)
+ PKG_INFO = StringIO()
+ metadata.write_file(PKG_INFO)
+ PKG_INFO.seek(0)
 
- self.assertRaises(MetadataConflictError, metadata.set,
- 'Obsoletes', 'ok')
+ metadata = Metadata(fileobj=PKG_INFO)
 
- del metadata['Obsoletes']
- del metadata['Obsoletes-Dist']
- metadata['Version'] = '1'
- self.assertEqual(metadata['Metadata-Version'], '1.0')
+ self.assertEqual(metadata['name'], 'project')
+ self.assertEqual(metadata['version'], '1.0')
+ self.assertEqual(metadata['summary'], 'xxx')
+ self.assertEqual(metadata['download_url'], 'http://example.com')
+ self.assertEqual(metadata['keywords'], ['one', 'two'])
+ self.assertEqual(metadata['platform'], [])
+ self.assertEqual(metadata['obsoletes'], [])
+ self.assertEqual(metadata['requires-dist'], ['foo'])
 
- PKG_INFO = os.path.join(os.path.dirname(__file__),
- 'SETUPTOOLS-PKG-INFO')
- with open(PKG_INFO, 'r', encoding='utf-8') as f:
- content = f.read()
- metadata.read_file(StringIO(content))
- self.assertEqual(metadata['Metadata-Version'], '1.0')
+ def test_write_metadata(self):
+ # check support of non-ASCII values
+ tmp_dir = self.mkdtemp()
+ my_file = os.path.join(tmp_dir, 'f')
 
- PKG_INFO = os.path.join(os.path.dirname(__file__),
- 'SETUPTOOLS-PKG-INFO2')
- with open(PKG_INFO, 'r', encoding='utf-8') as f:
- content = f.read()
- metadata.read_file(StringIO(content))
- self.assertEqual(metadata['Metadata-Version'], '1.1')
+ metadata = Metadata(mapping={'author': 'Mister Café',
+ 'name': 'my.project',
+ 'author': 'Café Junior',
+ 'summary': 'Café torréfié',
+ 'description': 'Héhéhé',
+ 'keywords': ['café', 'coffee']})
+ metadata.write(my_file)
 
- # Update the _fields dict directly to prevent 'Metadata-Version'
- # from being updated by the _set_best_version() method.
- metadata._fields['Metadata-Version'] = '1.618'
- self.assertRaises(MetadataUnrecognizedVersionError, metadata.keys)
+ # the file should use UTF-8
+ metadata2 = Metadata()
+ with open(my_file, encoding='utf-8') as fp:
+ metadata2.read_file(fp)
 
- def test_warnings(self):
- metadata = Metadata()
+ # XXX when keywords are not defined, metadata will have
+ # 'Keywords': [] but metadata2 will have 'Keywords': ['']
+ # because of a value.split(',') in Metadata.get
+ self.assertEqual(metadata.items(), metadata2.items())
 
- # these should raise a warning
- values = (('Requires-Dist', 'Funky (Groovie)'),
- ('Requires-Python', '1-4'))
+ # ASCII also works, it's a subset of UTF-8
+ metadata = Metadata(mapping={'author': 'Mister Cafe',
+ 'name': 'my.project',
+ 'author': 'Cafe Junior',
+ 'summary': 'Cafe torrefie',
+ 'description': 'Hehehe'})
+ metadata.write(my_file)
 
- for name, value in values:
- metadata.set(name, value)
+ metadata2 = Metadata()
+ with open(my_file, encoding='utf-8') as fp:
+ metadata2.read_file(fp)
 
- # we should have a certain amount of warnings
- self.assertEqual(len(self.get_logs()), 2)
+ def test_metadata_read_write(self):
+ PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
+ metadata = Metadata(PKG_INFO)
+ out = StringIO()
+ metadata.write_file(out)
 
- def test_multiple_predicates(self):
- metadata = Metadata()
+ out.seek(0)
+ res = Metadata()
+ res.read_file(out)
+ self.assertEqual(metadata.values(), res.values())
 
- # see for "3" instead of "3.0" ???
- # its seems like the MINOR VERSION can be omitted
- metadata['Requires-Python'] = '>=2.6, <3.0'
- metadata['Requires-Dist'] = ['Foo (>=2.6, <3.0)']
-
- self.assertEqual([], self.get_logs(logging.WARNING))
-
- def test_project_url(self):
- metadata = Metadata()
- metadata['Project-URL'] = [('one', 'http://ok')]
- self.assertEqual(metadata['Project-URL'],
- [('one', 'http://ok')])
- self.assertEqual(metadata['Metadata-Version'], '1.2')
+ #### Test checks
 
 def test_check_version(self):
 metadata = Metadata()
@@ -238,38 +237,215 @@
 metadata['Requires-dist'] = ['Foo (a)']
 metadata['Obsoletes-dist'] = ['Foo (a)']
 metadata['Provides-dist'] = ['Foo (a)']
- if metadata.docutils_support:
- missing, warnings = metadata.check()
- self.assertEqual(len(warnings), 4)
- metadata.docutils_support = False
 missing, warnings = metadata.check()
 self.assertEqual(len(warnings), 4)
 
- def test_best_choice(self):
- metadata = Metadata()
- metadata['Version'] = '1.0'
+ #### Test fields and metadata versions
+
+ def test_metadata_versions(self):
+ metadata = Metadata(mapping={'name': 'project', 'version': '1.0'})
 self.assertEqual(metadata['Metadata-Version'],
 PKG_INFO_PREFERRED_VERSION)
+ self.assertNotIn('Provides', metadata)
+ self.assertNotIn('Requires', metadata)
+ self.assertNotIn('Obsoletes', metadata)
+
 metadata['Classifier'] = ['ok']
+ self.assertEqual(metadata['Metadata-Version'], '1.1')
+
+ metadata = Metadata()
+ metadata['Download-URL'] = 'ok'
+ self.assertEqual(metadata['Metadata-Version'], '1.1')
+
+ metadata = Metadata()
+ metadata['Obsoletes'] = 'ok'
+ self.assertEqual(metadata['Metadata-Version'], '1.1')
+
+ del metadata['Obsoletes']
+ metadata['Obsoletes-Dist'] = 'ok'
 self.assertEqual(metadata['Metadata-Version'], '1.2')
 
- def test_project_urls(self):
- # project-url is a bit specific, make sure we write it
- # properly in PKG-INFO
+ self.assertRaises(MetadataConflictError, metadata.set,
+ 'Obsoletes', 'ok')
+
+ del metadata['Obsoletes']
+ del metadata['Obsoletes-Dist']
+ metadata['Version'] = '1'
+ self.assertEqual(metadata['Metadata-Version'], '1.0')
+
+ # make sure the _best_version function works okay with
+ # non-conflicting fields from 1.1 and 1.2 (i.e. we want only the
+ # requires/requires-dist and co. pairs to cause a conflict, not all
+ # fields in _314_MARKERS)
 metadata = Metadata()
- metadata['Version'] = '1.0'
- metadata['Project-Url'] = [('one', 'http://ok')]
+ metadata['Requires-Python'] = '3'
+ metadata['Classifier'] = ['Programming language :: Python :: 3']
+ self.assertEqual(metadata['Metadata-Version'], '1.2')
+
+ PKG_INFO = os.path.join(os.path.dirname(__file__),
+ 'SETUPTOOLS-PKG-INFO')
+ metadata = Metadata(PKG_INFO)
+ self.assertEqual(metadata['Metadata-Version'], '1.0')
+
+ PKG_INFO = os.path.join(os.path.dirname(__file__),
+ 'SETUPTOOLS-PKG-INFO2')
+ metadata = Metadata(PKG_INFO)
+ self.assertEqual(metadata['Metadata-Version'], '1.1')
+
+ # Update the _fields dict directly to prevent 'Metadata-Version'
+ # from being updated by the _set_best_version() method.
+ metadata._fields['Metadata-Version'] = '1.618'
+ self.assertRaises(MetadataUnrecognizedVersionError, metadata.keys)
+
+ def test_version(self):
+ Metadata(mapping={'author': 'xxx',
+ 'name': 'xxx',
+ 'version': 'xxx',
+ 'home-page': 'xxxx'})
+ logs = self.get_logs(logging.WARNING)
+ self.assertEqual(1, len(logs))
+ self.assertIn('not a valid version', logs[0])
+
+ def test_description(self):
+ PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO')
+ with open(PKG_INFO, 'r', encoding='utf-8') as f:
+ content = f.read() % sys.platform
+ metadata = Metadata()
+ metadata.read_file(StringIO(content))
+
+ # see if we can read the description now
+ DESC = os.path.join(os.path.dirname(__file__), 'LONG_DESC.txt')
+ with open(DESC) as f:
+ wanted = f.read()
+ self.assertEqual(wanted, metadata['Description'])
+
+ # save the file somewhere and make sure we can read it back
+ out = StringIO()
+ metadata.write_file(out)
+ out.seek(0)
+
+ out.seek(0)
+ metadata = Metadata()
+ metadata.read_file(out)
+ self.assertEqual(wanted, metadata['Description'])
+
+ def test_description_folding(self):
+ # make sure the indentation is preserved
+ out = StringIO()
+ desc = dedent("""\
+ example::
+ We start here
+ and continue here
+ and end here.
+ """)
+
+ metadata = Metadata()
+ metadata['description'] = desc
+ metadata.write_file(out)
+
+ folded_desc = desc.replace('\n', '\n' + (7 * ' ') + '|')
+ self.assertIn(folded_desc, out.getvalue())
+
+ def test_project_url(self):
+ metadata = Metadata()
+ metadata['Project-URL'] = [('one', 'http://ok')]
+ self.assertEqual(metadata['Project-URL'], [('one', 'http://ok')])
+ self.assertEqual(metadata['Metadata-Version'], '1.2')
+
+ # make sure this particular field is handled properly when written
+ fp = StringIO()
+ metadata.write_file(fp)
+ self.assertIn('Project-URL: one,http://ok', fp.getvalue().split('\n'))
+
+ fp.seek(0)
+ metadata = Metadata()
+ metadata.read_file(fp)
 self.assertEqual(metadata['Project-Url'], [('one', 'http://ok')])
- file_ = StringIO()
- metadata.write_file(file_)
- file_.seek(0)
- res = file_.read().split('\n')
- self.assertIn('Project-URL: one,http://ok', res)
 
- file_.seek(0)
+ # TODO copy tests for v1.1 requires, obsoletes and provides from distutils
+ # (they're useless but we support them so we should test them anyway)
+
+ def test_provides_dist(self):
+ fields = {'name': 'project',
+ 'version': '1.0',
+ 'provides_dist': ['project', 'my.project']}
+ metadata = Metadata(mapping=fields)
+ self.assertEqual(metadata['Provides-Dist'],
+ ['project', 'my.project'])
+ self.assertEqual(metadata['Metadata-Version'], '1.2', metadata)
+ self.assertNotIn('Requires', metadata)
+ self.assertNotIn('Obsoletes', metadata)
+
+ @unittest.skip('needs to be implemented')
+ def test_provides_illegal(self):
+ # TODO check the versions (like distutils does for old provides field)
+ self.assertRaises(ValueError, Metadata,
+ mapping={'name': 'project',
+ 'version': '1.0',
+ 'provides_dist': ['my.pkg (splat)']})
+
+ def test_requires_dist(self):
+ fields = {'name': 'project',
+ 'version': '1.0',
+ 'requires_dist': ['other', 'another (==1.0)']}
+ metadata = Metadata(mapping=fields)
+ self.assertEqual(metadata['Requires-Dist'],
+ ['other', 'another (==1.0)'])
+ self.assertEqual(metadata['Metadata-Version'], '1.2')
+ self.assertNotIn('Provides', metadata)
+ self.assertEqual(metadata['Requires-Dist'],
+ ['other', 'another (==1.0)'])
+ self.assertNotIn('Obsoletes', metadata)
+
+ # make sure write_file uses one RFC 822 header per item
+ fp = StringIO()
+ metadata.write_file(fp)
+ lines = fp.getvalue().split('\n')
+ self.assertIn('Requires-Dist: other', lines)
+ self.assertIn('Requires-Dist: another (==1.0)', lines)
+
+ # test warnings for invalid version predicates
+ # XXX this would cause no warnings if we used update (or the mapping
+ # argument of the constructor), see comment in Metadata.update
 metadata = Metadata()
- metadata.read_file(file_)
- self.assertEqual(metadata['Project-Url'], [('one', 'http://ok')])
+ metadata['Requires-Dist'] = 'Funky (Groovie)'
+ metadata['Requires-Python'] = '1-4'
+ self.assertEqual(len(self.get_logs()), 2)
+
+ # test multiple version predicates
+ metadata = Metadata()
+
+ # XXX check PEP and see if 3 == 3.0
+ metadata['Requires-Python'] = '>=2.6, <3.0'
+ metadata['Requires-Dist'] = ['Foo (>=2.6, <3.0)']
+ self.assertEqual([], self.get_logs(logging.WARNING))
+
+ @unittest.skip('needs to be implemented')
+ def test_requires_illegal(self):
+ self.assertRaises(ValueError, Metadata,
+ mapping={'name': 'project',
+ 'version': '1.0',
+ 'requires': ['my.pkg (splat)']})
+
+ def test_obsoletes_dist(self):
+ fields = {'name': 'project',
+ 'version': '1.0',
+ 'obsoletes_dist': ['other', 'another (<1.0)']}
+ metadata = Metadata(mapping=fields)
+ self.assertEqual(metadata['Obsoletes-Dist'],
+ ['other', 'another (<1.0)'])
+ self.assertEqual(metadata['Metadata-Version'], '1.2')
+ self.assertNotIn('Provides', metadata)
+ self.assertNotIn('Requires', metadata)
+ self.assertEqual(metadata['Obsoletes-Dist'],
+ ['other', 'another (<1.0)'])
+
+ @unittest.skip('needs to be implemented')
+ def test_obsoletes_illegal(self):
+ self.assertRaises(ValueError, Metadata,
+ mapping={'name': 'project',
+ 'version': '1.0',
+ 'obsoletes': ['my.pkg (splat)']})
 
 
 def test_suite():
diff --git a/Lib/packaging/tests/test_run.py b/Lib/packaging/tests/test_run.py
--- a/Lib/packaging/tests/test_run.py
+++ b/Lib/packaging/tests/test_run.py
@@ -3,16 +3,16 @@
 import os
 import sys
 import shutil
-from tempfile import mkstemp
 from io import StringIO
 
 from packaging import install
 from packaging.tests import unittest, support, TESTFN
 from packaging.run import main
 
+from test.script_helper import assert_python_ok
+
 # setup script that uses __file__
 setup_using___file__ = """\
-
 __file__
 
 from packaging.run import setup
@@ -20,7 +20,6 @@
 """
 
 setup_prints_cwd = """\
-
 import os
 print os.getcwd()
 
@@ -29,11 +28,12 @@
 """
 
 
-class CoreTestCase(support.TempdirManager, support.LoggingCatcher,
- unittest.TestCase):
+class RunTestCase(support.TempdirManager,
+ support.LoggingCatcher,
+ unittest.TestCase):
 
 def setUp(self):
- super(CoreTestCase, self).setUp()
+ super(RunTestCase, self).setUp()
 self.old_stdout = sys.stdout
 self.cleanup_testfn()
 self.old_argv = sys.argv, sys.argv[:]
@@ -43,7 +43,7 @@
 self.cleanup_testfn()
 sys.argv = self.old_argv[0]
 sys.argv[:] = self.old_argv[1]
- super(CoreTestCase, self).tearDown()
+ super(RunTestCase, self).tearDown()
 
 def cleanup_testfn(self):
 path = TESTFN
@@ -77,9 +77,16 @@
 os.chmod(install_path, old_mod)
 install.get_path = old_get_path
 
+ def test_show_help(self):
+ # smoke test, just makes sure some help is displayed
+ status, out, err = assert_python_ok('-m', 'packaging.run', '--help')
+ self.assertEqual(status, 0)
+ self.assertGreater(out, b'')
+ self.assertEqual(err, b'')
+
 
 def test_suite():
- return unittest.makeSuite(CoreTestCase)
+ return unittest.makeSuite(RunTestCase)
 
 if __name__ == "__main__":
 unittest.main(defaultTest="test_suite")
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -278,6 +278,10 @@
 ZLIB_RUNTIME_VERSION, in the zlib module. Patch by Torsten Landschoff.
 
 - Issue #12959: Add collections.ChainMap to collections.__all__.
+ 
+- Issue #8933: distutils' PKG-INFO files and packaging's METADATA files will
+ now correctly report Metadata-Version: 1.1 instead of 1.0 if a Classifier or
+ Download-URL field is present.
 
 - Issue #12567: Add curses.unget_wch() function. Push a character so the next
 get_wch() will return it.
-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /