summaryrefslogtreecommitdiffstats
path: root/Lib/packaging/tests/test_manifest.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/packaging/tests/test_manifest.py')
-rw-r--r--Lib/packaging/tests/test_manifest.py331
1 files changed, 331 insertions, 0 deletions
diff --git a/Lib/packaging/tests/test_manifest.py b/Lib/packaging/tests/test_manifest.py
new file mode 100644
index 0000000..7aa59c1
--- /dev/null
+++ b/Lib/packaging/tests/test_manifest.py
@@ -0,0 +1,331 @@
+"""Tests for packaging.manifest."""
+import os
+import re
+from io import StringIO
+from packaging.errors import PackagingTemplateError
+from packaging.manifest import Manifest, _translate_pattern, _glob_to_re
+
+from packaging.tests import unittest, support
+
+MANIFEST_IN = """\
+include ok
+include xo
+exclude xo
+include foo.tmp
+include buildout.cfg
+global-include *.x
+global-include *.txt
+global-exclude *.tmp
+recursive-include f *.oo
+recursive-exclude global *.x
+graft dir
+prune dir3
+"""
+
+MANIFEST_IN_2 = """\
+recursive-include foo *.py # ok
+# nothing here
+
+#
+
+recursive-include bar \\
+ *.dat *.txt
+"""
+
+MANIFEST_IN_3 = """\
+README
+file1
+"""
+
+
+def make_local_path(s):
+ """Converts '/' in a string to os.sep"""
+ return s.replace('/', os.sep)
+
+
+class ManifestTestCase(support.TempdirManager,
+ support.LoggingCatcher,
+ unittest.TestCase):
+
+ def assertNoWarnings(self):
+ self.assertEqual(self.get_logs(), [])
+
+ def assertWarnings(self):
+ self.assertNotEqual(self.get_logs(), [])
+
+ def test_manifest_reader(self):
+ tmpdir = self.mkdtemp()
+ MANIFEST = os.path.join(tmpdir, 'MANIFEST.in')
+ with open(MANIFEST, 'w') as f:
+ f.write(MANIFEST_IN_2)
+
+ manifest = Manifest()
+ manifest.read_template(MANIFEST)
+
+ warnings = self.get_logs()
+ # the manifest should have been read and 3 warnings issued
+ # (we didn't provide the files)
+ self.assertEqual(3, len(warnings))
+ for warning in warnings:
+ self.assertIn('no files found matching', warning)
+
+ # manifest also accepts file-like objects
+ with open(MANIFEST) as f:
+ manifest.read_template(f)
+
+ # the manifest should have been read and 3 warnings issued
+ # (we didn't provide the files)
+ self.assertEqual(3, len(warnings))
+
+ def test_default_actions(self):
+ tmpdir = self.mkdtemp()
+ self.addCleanup(os.chdir, os.getcwd())
+ os.chdir(tmpdir)
+ self.write_file('README', 'xxx')
+ self.write_file('file1', 'xxx')
+ content = StringIO(MANIFEST_IN_3)
+ manifest = Manifest()
+ manifest.read_template(content)
+ self.assertEqual(['README', 'file1'], manifest.files)
+
+ def test_glob_to_re(self):
+ sep = os.sep
+ if os.sep == '\\':
+ sep = r'\\'
+
+ for glob, regex in (
+ # simple cases
+ ('foo*', r'foo[^%(sep)s]*\Z(?ms)'),
+ ('foo?', r'foo[^%(sep)s]\Z(?ms)'),
+ ('foo??', r'foo[^%(sep)s][^%(sep)s]\Z(?ms)'),
+ # special cases
+ (r'foo\\*', r'foo\\\\[^%(sep)s]*\Z(?ms)'),
+ (r'foo\\\*', r'foo\\\\\\[^%(sep)s]*\Z(?ms)'),
+ ('foo????', r'foo[^%(sep)s][^%(sep)s][^%(sep)s][^%(sep)s]\Z(?ms)'),
+ (r'foo\\??', r'foo\\\\[^%(sep)s][^%(sep)s]\Z(?ms)'),
+ ):
+ regex = regex % {'sep': sep}
+ self.assertEqual(_glob_to_re(glob), regex)
+
+ def test_process_template_line(self):
+ # testing all MANIFEST.in template patterns
+ manifest = Manifest()
+ l = make_local_path
+
+ # simulated file list
+ manifest.allfiles = ['foo.tmp', 'ok', 'xo', 'four.txt',
+ 'buildout.cfg',
+ # filelist does not filter out VCS directories,
+ # it's sdist that does
+ l('.hg/last-message.txt'),
+ l('global/one.txt'),
+ l('global/two.txt'),
+ l('global/files.x'),
+ l('global/here.tmp'),
+ l('f/o/f.oo'),
+ l('dir/graft-one'),
+ l('dir/dir2/graft2'),
+ l('dir3/ok'),
+ l('dir3/sub/ok.txt'),
+ ]
+
+ for line in MANIFEST_IN.split('\n'):
+ if line.strip() == '':
+ continue
+ manifest._process_template_line(line)
+
+ wanted = ['ok',
+ 'buildout.cfg',
+ 'four.txt',
+ l('.hg/last-message.txt'),
+ l('global/one.txt'),
+ l('global/two.txt'),
+ l('f/o/f.oo'),
+ l('dir/graft-one'),
+ l('dir/dir2/graft2'),
+ ]
+
+ self.assertEqual(manifest.files, wanted)
+
+ def test_remove_duplicates(self):
+ manifest = Manifest()
+ manifest.files = ['a', 'b', 'a', 'g', 'c', 'g']
+ # files must be sorted beforehand (like sdist does)
+ 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):
+ l = make_local_path
+ # 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', l('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', l('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', l('d/c.py')]
+
+ manifest._process_template_line('exclude *.py')
+ self.assertEqual(manifest.files, ['b.txt', l('d/c.py')])
+ self.assertNoWarnings()
+
+ manifest._process_template_line('exclude *.rb')
+ self.assertEqual(manifest.files, ['b.txt', l('d/c.py')])
+ self.assertWarnings()
+
+ # global-include
+ manifest = Manifest()
+ manifest.allfiles = ['a.py', 'b.txt', l('d/c.py')]
+
+ manifest._process_template_line('global-include *.py')
+ self.assertEqual(manifest.files, ['a.py', l('d/c.py')])
+ self.assertNoWarnings()
+
+ manifest._process_template_line('global-include *.rb')
+ self.assertEqual(manifest.files, ['a.py', l('d/c.py')])
+ self.assertWarnings()
+
+ # global-exclude
+ manifest = Manifest()
+ manifest.files = ['a.py', 'b.txt', l('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', l('d/b.py'), l('d/c.txt'), l('d/d/e.py')]
+
+ manifest._process_template_line('recursive-include d *.py')
+ self.assertEqual(manifest.files, [l('d/b.py'), l('d/d/e.py')])
+ self.assertNoWarnings()
+
+ manifest._process_template_line('recursive-include e *.py')
+ self.assertEqual(manifest.files, [l('d/b.py'), l('d/d/e.py')])
+ self.assertWarnings()
+
+ # recursive-exclude
+ manifest = Manifest()
+ manifest.files = ['a.py', l('d/b.py'), l('d/c.txt'), l('d/d/e.py')]
+
+ manifest._process_template_line('recursive-exclude d *.py')
+ self.assertEqual(manifest.files, ['a.py', l('d/c.txt')])
+ self.assertNoWarnings()
+
+ manifest._process_template_line('recursive-exclude e *.py')
+ self.assertEqual(manifest.files, ['a.py', l('d/c.txt')])
+ self.assertWarnings()
+
+ # graft
+ manifest = Manifest()
+ manifest.allfiles = ['a.py', l('d/b.py'), l('d/d/e.py'), l('f/f.py')]
+
+ manifest._process_template_line('graft d')
+ self.assertEqual(manifest.files, [l('d/b.py'), l('d/d/e.py')])
+ self.assertNoWarnings()
+
+ manifest._process_template_line('graft e')
+ self.assertEqual(manifest.files, [l('d/b.py'), l('d/d/e.py')])
+ self.assertWarnings()
+
+ # prune
+ manifest = Manifest()
+ manifest.files = ['a.py', l('d/b.py'), l('d/d/e.py'), l('f/f.py')]
+
+ manifest._process_template_line('prune d')
+ self.assertEqual(manifest.files, ['a.py', l('f/f.py')])
+ self.assertNoWarnings()
+
+ manifest._process_template_line('prune e')
+ self.assertEqual(manifest.files, ['a.py', l('f/f.py')])
+ self.assertWarnings()
+
+
+def test_suite():
+ return unittest.makeSuite(ManifestTestCase)
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')