[Python-checkins] cpython: Consolidate tests for packaging.metadata.

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


http://hg.python.org/cpython/rev/f0581d9ad978
changeset:   72349:f0581d9ad978
user:        Éric Araujo <merwok at netwok.org>
date:        Sat Sep 10 05:18:20 2011 +0200
summary:
  Consolidate tests for packaging.metadata.

New tests were added in test_metadata and old tests inherited from
distutils were still in test_dist, so I moved them into test_metadata
(except for one which was more at home in test_run) and merged
duplicates.

I also added some skips to lure contributors <wink>, optimized the
Metadata.update method a trifle, and added notes about a number of
issues.

A note: The tests in test_dist used to dump the Metadata objects to a
file in the METADATA format and look for strings in its contents; I
updated them to use the mapping API of Metadata instead.  For some
fields with special writing rules, I have added tests to ensure my
conversion did not lose anything.

files:
  Lib/packaging/metadata.py            |   14 +-
  Lib/packaging/tests/test_dist.py     |  252 +--------
  Lib/packaging/tests/test_metadata.py |  377 ++++++++++----
  Lib/packaging/tests/test_run.py      |   23 +-
  4 files changed, 324 insertions(+), 342 deletions(-)


diff --git a/Lib/packaging/metadata.py b/Lib/packaging/metadata.py
--- a/Lib/packaging/metadata.py
+++ b/Lib/packaging/metadata.py
@@ -354,11 +354,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 +377,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/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,202 @@
         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.2')
 
-    def test_project_urls(self):
-        # project-url is a bit specific, make sure we write it
-        # properly in PKG-INFO
         metadata = Metadata()
-        metadata['Version'] = '1.0'
-        metadata['Project-Url'] = [('one', 'http://ok')]
+        metadata['Obsoletes'] = 'ok'
+        self.assertEqual(metadata['Metadata-Version'], '1.1')
+
+        del metadata['Obsoletes']
+        metadata['Obsoletes-Dist'] = 'ok'
+        self.assertEqual(metadata['Metadata-Version'], '1.2')
+
+        self.assertRaises(MetadataConflictError, metadata.set,
+                          'Obsoletes', 'ok')
+
+        del metadata['Obsoletes']
+        del metadata['Obsoletes-Dist']
+        metadata['Version'] = '1'
+        self.assertEqual(metadata['Metadata-Version'], '1.0')
+
+        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")

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


More information about the Python-checkins mailing list