From 30cc65460e196902ac9d5c2892c8f5ddfcb46486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Tue, 11 Oct 2011 02:18:12 +0200 Subject: [PATCH 1/3] =?UTF-8?q?Add=20tests=20for=20Unicode=20handling=20in?= =?UTF-8?q?=20packaging=E2=80=99=20check=20and=20register=20(#13114)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Lib/packaging/tests/test_command_check.py | 25 +++++++++++++++-- Lib/packaging/tests/test_command_register.py | 28 ++++++++++++++------ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/Lib/packaging/tests/test_command_check.py b/Lib/packaging/tests/test_command_check.py index 271e457961c..3a4ab42176c 100644 --- a/Lib/packaging/tests/test_command_check.py +++ b/Lib/packaging/tests/test_command_check.py @@ -56,6 +56,15 @@ class CheckTestCase(support.LoggingCatcher, cmd = self._run(metadata, strict=True) self.assertEqual([], self.get_logs(logging.WARNING)) + # now a test with non-ASCII characters + metadata = {'home_page': 'xxx', 'author': '\u00c9ric', + 'author_email': 'xxx', 'name': 'xxx', + 'version': '1.2', + 'summary': 'Something about esszet \u00df', + 'description': 'More things about esszet \u00df'} + cmd = self._run(metadata) + self.assertEqual([], self.get_logs(logging.WARNING)) + def test_check_metadata_1_2(self): # let's run the command with no metadata at all # by default, check is checking the metadata @@ -95,14 +104,26 @@ class CheckTestCase(support.LoggingCatcher, @unittest.skipUnless(_HAS_DOCUTILS, "requires docutils") def test_check_restructuredtext(self): - # let's see if it detects broken rest in long_description + # let's see if it detects broken rest in description broken_rest = 'title\n===\n\ntest' pkg_info, dist = self.create_dist(description=broken_rest) cmd = check(dist) cmd.check_restructuredtext() self.assertEqual(len(self.get_logs(logging.WARNING)), 1) + # clear warnings from the previous call + self.loghandler.flush() - pkg_info, dist = self.create_dist(description='title\n=====\n\ntest') + # let's see if we have an error with strict=1 + metadata = {'home_page': 'xxx', 'author': 'xxx', + 'author_email': 'xxx', + 'name': 'xxx', 'version': '1.2', + 'description': broken_rest} + self.assertRaises(PackagingSetupError, self._run, metadata, + strict=True, all=True) + self.loghandler.flush() + + # and non-broken rest, including a non-ASCII character to test #12114 + dist = self.create_dist(description='title\n=====\n\ntest \u00df')[1] cmd = check(dist) cmd.check_restructuredtext() self.assertEqual([], self.get_logs(logging.WARNING)) diff --git a/Lib/packaging/tests/test_command_register.py b/Lib/packaging/tests/test_command_register.py index 9872e2e6dc3..73d983439b0 100644 --- a/Lib/packaging/tests/test_command_register.py +++ b/Lib/packaging/tests/test_command_register.py @@ -200,12 +200,10 @@ class RegisterTestCase(support.TempdirManager, @unittest.skipUnless(DOCUTILS_SUPPORT, 'needs docutils') def test_strict(self): - # testing the script option - # when on, the register command stops if - # the metadata is incomplete or if - # long_description is not reSt compliant + # testing the strict option: when on, the register command stops if the + # metadata is incomplete or if description contains bad reST - # empty metadata + # empty metadata # XXX this is not really empty.. cmd = self._get_cmd({'name': 'xxx', 'version': 'xxx'}) cmd.ensure_finalized() cmd.strict = True @@ -213,16 +211,15 @@ class RegisterTestCase(support.TempdirManager, register_module.input = inputs self.assertRaises(PackagingSetupError, cmd.run) - # metadata is OK but long_description is broken + # metadata is OK but description is broken metadata = {'home_page': 'xxx', 'author': 'xxx', 'author_email': 'éxéxé', - 'name': 'xxx', 'version': 'xxx', + 'name': 'xxx', 'version': '4.2', 'description': 'title\n==\n\ntext'} cmd = self._get_cmd(metadata) cmd.ensure_finalized() cmd.strict = True - self.assertRaises(PackagingSetupError, cmd.run) # now something that works @@ -243,6 +240,21 @@ class RegisterTestCase(support.TempdirManager, cmd.ensure_finalized() cmd.run() + # and finally a Unicode test (bug #12114) + metadata = {'home_page': 'xxx', 'author': '\u00c9ric', + 'author_email': 'xxx', 'name': 'xxx', + 'version': 'xxx', + 'summary': 'Something about esszet \u00df', + 'description': 'More things about esszet \u00df'} + + cmd = self._get_cmd(metadata) + cmd.ensure_finalized() + cmd.strict = True + inputs = Inputs('1', 'tarek', 'y') + register_module.input = inputs + cmd.ensure_finalized() + cmd.run() + def test_register_pep345(self): cmd = self._get_cmd({}) cmd.ensure_finalized() From 2336c8553c27ea12f3e5e6d1119e5cc93e7b6404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Tue, 11 Oct 2011 02:45:51 +0200 Subject: [PATCH 2/3] Increase test coverage for distutils.filelist (#11751). Patch by Justin Love. --- Lib/distutils/tests/test_filelist.py | 203 +++++++++++++++++++++++++-- Misc/ACKS | 1 + 2 files changed, 196 insertions(+), 8 deletions(-) diff --git a/Lib/distutils/tests/test_filelist.py b/Lib/distutils/tests/test_filelist.py index c7e5201b172..f3304b2e336 100644 --- a/Lib/distutils/tests/test_filelist.py +++ b/Lib/distutils/tests/test_filelist.py @@ -1,11 +1,25 @@ """Tests for distutils.filelist.""" +import re import unittest - -from distutils.filelist import glob_to_re, FileList -from test.support import captured_stdout, run_unittest from distutils import debug +from distutils.log import WARN +from distutils.errors import DistutilsTemplateError +from distutils.filelist import glob_to_re, translate_pattern, FileList -class FileListTestCase(unittest.TestCase): +from test.support import captured_stdout, run_unittest +from distutils.tests import support + + +class FileListTestCase(support.LoggingSilencer, + unittest.TestCase): + + def assertNoWarnings(self): + self.assertEqual(self.get_logs(WARN), []) + self.clear_logs() + + def assertWarnings(self): + self.assertGreater(len(self.get_logs(WARN)), 0) + self.clear_logs() def test_glob_to_re(self): # simple cases @@ -23,18 +37,191 @@ class FileListTestCase(unittest.TestCase): file_list = FileList() with captured_stdout() as stdout: file_list.debug_print('xxx') - stdout.seek(0) - self.assertEqual(stdout.read(), '') + self.assertEqual(stdout.getvalue(), '') debug.DEBUG = True try: with captured_stdout() as stdout: file_list.debug_print('xxx') - stdout.seek(0) - self.assertEqual(stdout.read(), 'xxx\n') + self.assertEqual(stdout.getvalue(), 'xxx\n') finally: debug.DEBUG = False + def test_set_allfiles(self): + file_list = FileList() + files = ['a', 'b', 'c'] + file_list.set_allfiles(files) + self.assertEqual(file_list.allfiles, files) + + def test_remove_duplicates(self): + file_list = FileList() + file_list.files = ['a', 'b', 'a', 'g', 'c', 'g'] + # files must be sorted beforehand (sdist does it) + file_list.sort() + file_list.remove_duplicates() + self.assertEqual(file_list.files, ['a', 'b', 'c', 'g']) + + def test_translate_pattern(self): + # not regex + self.assertTrue(hasattr( + translate_pattern('a', anchor=True, is_regex=False), + 'search')) + + # is a regex + regex = re.compile('a') + self.assertEqual( + translate_pattern(regex, anchor=True, is_regex=True), + regex) + + # plain string flagged as regex + self.assertTrue(hasattr( + translate_pattern('a', anchor=True, is_regex=True), + 'search')) + + # glob support + self.assertTrue(translate_pattern( + '*.py', anchor=True, is_regex=False).search('filelist.py')) + + def test_exclude_pattern(self): + # return False if no match + file_list = FileList() + self.assertFalse(file_list.exclude_pattern('*.py')) + + # return True if files match + file_list = FileList() + file_list.files = ['a.py', 'b.py'] + self.assertTrue(file_list.exclude_pattern('*.py')) + + # test excludes + file_list = FileList() + file_list.files = ['a.py', 'a.txt'] + file_list.exclude_pattern('*.py') + self.assertEqual(file_list.files, ['a.txt']) + + def test_include_pattern(self): + # return False if no match + file_list = FileList() + file_list.set_allfiles([]) + self.assertFalse(file_list.include_pattern('*.py')) + + # return True if files match + file_list = FileList() + file_list.set_allfiles(['a.py', 'b.txt']) + self.assertTrue(file_list.include_pattern('*.py')) + + # test * matches all files + file_list = FileList() + self.assertIsNone(file_list.allfiles) + file_list.set_allfiles(['a.py', 'b.txt']) + file_list.include_pattern('*') + self.assertEqual(file_list.allfiles, ['a.py', 'b.txt']) + + def test_process_template(self): + # invalid lines + file_list = FileList() + for action in ('include', 'exclude', 'global-include', + 'global-exclude', 'recursive-include', + 'recursive-exclude', 'graft', 'prune', 'blarg'): + self.assertRaises(DistutilsTemplateError, + file_list.process_template_line, action) + + # include + file_list = FileList() + file_list.set_allfiles(['a.py', 'b.txt', 'd/c.py']) + + file_list.process_template_line('include *.py') + self.assertEqual(file_list.files, ['a.py']) + self.assertNoWarnings() + + file_list.process_template_line('include *.rb') + self.assertEqual(file_list.files, ['a.py']) + self.assertWarnings() + + # exclude + file_list = FileList() + file_list.files = ['a.py', 'b.txt', 'd/c.py'] + + file_list.process_template_line('exclude *.py') + self.assertEqual(file_list.files, ['b.txt', 'd/c.py']) + self.assertNoWarnings() + + file_list.process_template_line('exclude *.rb') + self.assertEqual(file_list.files, ['b.txt', 'd/c.py']) + self.assertWarnings() + + # global-include + file_list = FileList() + file_list.set_allfiles(['a.py', 'b.txt', 'd/c.py']) + + file_list.process_template_line('global-include *.py') + self.assertEqual(file_list.files, ['a.py', 'd/c.py']) + self.assertNoWarnings() + + file_list.process_template_line('global-include *.rb') + self.assertEqual(file_list.files, ['a.py', 'd/c.py']) + self.assertWarnings() + + # global-exclude + file_list = FileList() + file_list.files = ['a.py', 'b.txt', 'd/c.py'] + + file_list.process_template_line('global-exclude *.py') + self.assertEqual(file_list.files, ['b.txt']) + self.assertNoWarnings() + + file_list.process_template_line('global-exclude *.rb') + self.assertEqual(file_list.files, ['b.txt']) + self.assertWarnings() + + # recursive-include + file_list = FileList() + file_list.set_allfiles(['a.py', 'd/b.py', 'd/c.txt', 'd/d/e.py']) + + file_list.process_template_line('recursive-include d *.py') + self.assertEqual(file_list.files, ['d/b.py', 'd/d/e.py']) + self.assertNoWarnings() + + file_list.process_template_line('recursive-include e *.py') + self.assertEqual(file_list.files, ['d/b.py', 'd/d/e.py']) + self.assertWarnings() + + # recursive-exclude + file_list = FileList() + file_list.files = ['a.py', 'd/b.py', 'd/c.txt', 'd/d/e.py'] + + file_list.process_template_line('recursive-exclude d *.py') + self.assertEqual(file_list.files, ['a.py', 'd/c.txt']) + self.assertNoWarnings() + + file_list.process_template_line('recursive-exclude e *.py') + self.assertEqual(file_list.files, ['a.py', 'd/c.txt']) + self.assertWarnings() + + # graft + file_list = FileList() + file_list.set_allfiles(['a.py', 'd/b.py', 'd/d/e.py', 'f/f.py']) + + file_list.process_template_line('graft d') + self.assertEqual(file_list.files, ['d/b.py', 'd/d/e.py']) + self.assertNoWarnings() + + file_list.process_template_line('graft e') + self.assertEqual(file_list.files, ['d/b.py', 'd/d/e.py']) + self.assertWarnings() + + # prune + file_list = FileList() + file_list.files = ['a.py', 'd/b.py', 'd/d/e.py', 'f/f.py'] + + file_list.process_template_line('prune d') + self.assertEqual(file_list.files, ['a.py', 'f/f.py']) + self.assertNoWarnings() + + file_list.process_template_line('prune e') + self.assertEqual(file_list.files, ['a.py', 'f/f.py']) + self.assertWarnings() + + def test_suite(): return unittest.makeSuite(FileListTestCase) diff --git a/Misc/ACKS b/Misc/ACKS index 0fd2192545e..b32de2e0858 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -554,6 +554,7 @@ Nick Lockwood Stephanie Lockwood Anne Lord Tom Loredo +Justin Love Jason Lowe Tony Lownds Ray Loyzaga From aa2cb3a530640a4ed375c7c0125aefbe39f362ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Araujo?= Date: Tue, 11 Oct 2011 03:06:16 +0200 Subject: [PATCH 3/3] Increase test coverage for packaging.manifest (#11751). Patch by Justin Love. --- Lib/packaging/manifest.py | 4 +- Lib/packaging/tests/test_manifest.py | 197 ++++++++++++++++++++++++++- 2 files changed, 199 insertions(+), 2 deletions(-) diff --git a/Lib/packaging/manifest.py b/Lib/packaging/manifest.py index a3798530a58..5eee174cc6e 100644 --- a/Lib/packaging/manifest.py +++ b/Lib/packaging/manifest.py @@ -147,7 +147,9 @@ class Manifest(object): def _parse_template_line(self, line): words = line.split() - if len(words) == 1: + if len(words) == 1 and words[0] not in ( + 'include', 'exclude', 'global-include', 'global-exclude', + 'recursive-include', 'recursive-exclude', 'graft', 'prune'): # no action given, let's use the default 'include' words.insert(0, 'include') diff --git a/Lib/packaging/tests/test_manifest.py b/Lib/packaging/tests/test_manifest.py index e0bcbbc3e9f..1c7aa934269 100644 --- a/Lib/packaging/tests/test_manifest.py +++ b/Lib/packaging/tests/test_manifest.py @@ -1,8 +1,10 @@ """Tests for packaging.manifest.""" import os +import re import logging from io import StringIO -from packaging.manifest import Manifest +from packaging.errors import PackagingTemplateError +from packaging.manifest import Manifest, _translate_pattern, _glob_to_re from packaging.tests import unittest, support @@ -34,6 +36,12 @@ class ManifestTestCase(support.TempdirManager, os.chdir(self.cwd) super(ManifestTestCase, self).tearDown() + def assertNoWarnings(self): + self.assertEqual(self.get_logs(logging.WARNING), []) + + def assertWarnings(self): + self.assertGreater(len(self.get_logs(logging.WARNING)), 0) + def test_manifest_reader(self): tmpdir = self.mkdtemp() MANIFEST = os.path.join(tmpdir, 'MANIFEST.in') @@ -69,6 +77,193 @@ class ManifestTestCase(support.TempdirManager, manifest.read_template(content) self.assertEqual(['README', 'file1'], manifest.files) + def test_glob_to_re(self): + # simple cases + self.assertEqual(_glob_to_re('foo*'), 'foo[^/]*\\Z(?ms)') + self.assertEqual(_glob_to_re('foo?'), 'foo[^/]\\Z(?ms)') + self.assertEqual(_glob_to_re('foo??'), 'foo[^/][^/]\\Z(?ms)') + + # special cases + self.assertEqual(_glob_to_re(r'foo\\*'), r'foo\\\\[^/]*\Z(?ms)') + self.assertEqual(_glob_to_re(r'foo\\\*'), r'foo\\\\\\[^/]*\Z(?ms)') + self.assertEqual(_glob_to_re('foo????'), r'foo[^/][^/][^/][^/]\Z(?ms)') + self.assertEqual(_glob_to_re(r'foo\\??'), r'foo\\\\[^/][^/]\Z(?ms)') + + def test_remove_duplicates(self): + manifest = Manifest() + manifest.files = ['a', 'b', 'a', 'g', 'c', 'g'] + # files must be sorted beforehand + manifest.sort() + manifest.remove_duplicates() + self.assertEqual(manifest.files, ['a', 'b', 'c', 'g']) + + def test_translate_pattern(self): + # blackbox test of a private function + + # not regex + pattern = _translate_pattern('a', anchor=True, is_regex=False) + self.assertTrue(hasattr(pattern, 'search')) + + # is a regex + regex = re.compile('a') + pattern = _translate_pattern(regex, anchor=True, is_regex=True) + self.assertEqual(pattern, regex) + + # plain string flagged as regex + pattern = _translate_pattern('a', anchor=True, is_regex=True) + self.assertTrue(hasattr(pattern, 'search')) + + # glob support + pattern = _translate_pattern('*.py', anchor=True, is_regex=False) + self.assertTrue(pattern.search('filelist.py')) + + def test_exclude_pattern(self): + # return False if no match + manifest = Manifest() + self.assertFalse(manifest.exclude_pattern('*.py')) + + # return True if files match + manifest = Manifest() + manifest.files = ['a.py', 'b.py'] + self.assertTrue(manifest.exclude_pattern('*.py')) + + # test excludes + manifest = Manifest() + manifest.files = ['a.py', 'a.txt'] + manifest.exclude_pattern('*.py') + self.assertEqual(manifest.files, ['a.txt']) + + def test_include_pattern(self): + # return False if no match + manifest = Manifest() + manifest.allfiles = [] + self.assertFalse(manifest._include_pattern('*.py')) + + # return True if files match + manifest = Manifest() + manifest.allfiles = ['a.py', 'b.txt'] + self.assertTrue(manifest._include_pattern('*.py')) + + # test * matches all files + manifest = Manifest() + self.assertIsNone(manifest.allfiles) + manifest.allfiles = ['a.py', 'b.txt'] + manifest._include_pattern('*') + self.assertEqual(manifest.allfiles, ['a.py', 'b.txt']) + + def test_process_template(self): + # invalid lines + manifest = Manifest() + for action in ('include', 'exclude', 'global-include', + 'global-exclude', 'recursive-include', + 'recursive-exclude', 'graft', 'prune'): + self.assertRaises(PackagingTemplateError, + manifest._process_template_line, action) + + # implicit include + manifest = Manifest() + manifest.allfiles = ['a.py', 'b.txt', 'd/c.py'] + + manifest._process_template_line('*.py') + self.assertEqual(manifest.files, ['a.py']) + self.assertNoWarnings() + + # include + manifest = Manifest() + manifest.allfiles = ['a.py', 'b.txt', 'd/c.py'] + + manifest._process_template_line('include *.py') + self.assertEqual(manifest.files, ['a.py']) + self.assertNoWarnings() + + manifest._process_template_line('include *.rb') + self.assertEqual(manifest.files, ['a.py']) + self.assertWarnings() + + # exclude + manifest = Manifest() + manifest.files = ['a.py', 'b.txt', 'd/c.py'] + + manifest._process_template_line('exclude *.py') + self.assertEqual(manifest.files, ['b.txt', 'd/c.py']) + self.assertNoWarnings() + + manifest._process_template_line('exclude *.rb') + self.assertEqual(manifest.files, ['b.txt', 'd/c.py']) + self.assertWarnings() + + # global-include + manifest = Manifest() + manifest.allfiles = ['a.py', 'b.txt', 'd/c.py'] + + manifest._process_template_line('global-include *.py') + self.assertEqual(manifest.files, ['a.py', 'd/c.py']) + self.assertNoWarnings() + + manifest._process_template_line('global-include *.rb') + self.assertEqual(manifest.files, ['a.py', 'd/c.py']) + self.assertWarnings() + + # global-exclude + manifest = Manifest() + manifest.files = ['a.py', 'b.txt', 'd/c.py'] + + manifest._process_template_line('global-exclude *.py') + self.assertEqual(manifest.files, ['b.txt']) + self.assertNoWarnings() + + manifest._process_template_line('global-exclude *.rb') + self.assertEqual(manifest.files, ['b.txt']) + self.assertWarnings() + + # recursive-include + manifest = Manifest() + manifest.allfiles = ['a.py', 'd/b.py', 'd/c.txt', 'd/d/e.py'] + + manifest._process_template_line('recursive-include d *.py') + self.assertEqual(manifest.files, ['d/b.py', 'd/d/e.py']) + self.assertNoWarnings() + + manifest._process_template_line('recursive-include e *.py') + self.assertEqual(manifest.files, ['d/b.py', 'd/d/e.py']) + self.assertWarnings() + + # recursive-exclude + manifest = Manifest() + manifest.files = ['a.py', 'd/b.py', 'd/c.txt', 'd/d/e.py'] + + manifest._process_template_line('recursive-exclude d *.py') + self.assertEqual(manifest.files, ['a.py', 'd/c.txt']) + self.assertNoWarnings() + + manifest._process_template_line('recursive-exclude e *.py') + self.assertEqual(manifest.files, ['a.py', 'd/c.txt']) + self.assertWarnings() + + # graft + manifest = Manifest() + manifest.allfiles = ['a.py', 'd/b.py', 'd/d/e.py', 'f/f.py'] + + manifest._process_template_line('graft d') + self.assertEqual(manifest.files, ['d/b.py', 'd/d/e.py']) + self.assertNoWarnings() + + manifest._process_template_line('graft e') + self.assertEqual(manifest.files, ['d/b.py', 'd/d/e.py']) + self.assertWarnings() + + # prune + manifest = Manifest() + manifest.files = ['a.py', 'd/b.py', 'd/d/e.py', 'f/f.py'] + + manifest._process_template_line('prune d') + self.assertEqual(manifest.files, ['a.py', 'f/f.py']) + self.assertNoWarnings() + + manifest._process_template_line('prune e') + self.assertEqual(manifest.files, ['a.py', 'f/f.py']) + self.assertWarnings() + def test_suite(): return unittest.makeSuite(ManifestTestCase)