test_manifest.py 10.6 KB
Newer Older
1 2
"""Tests for packaging.manifest."""
import os
3
import re
4
from io import StringIO
5 6
from packaging.errors import PackagingTemplateError
from packaging.manifest import Manifest, _translate_pattern, _glob_to_re
7 8 9

from packaging.tests import unittest, support

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
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 = """\
26 27 28 29 30 31 32 33 34
recursive-include foo *.py   # ok
# nothing here

#

recursive-include bar \\
  *.dat   *.txt
"""

35
MANIFEST_IN_3 = """\
36 37 38 39 40
README
file1
"""


41 42 43 44 45
def make_local_path(s):
    """Converts '/' in a string to os.sep"""
    return s.replace('/', os.sep)


46 47 48 49
class ManifestTestCase(support.TempdirManager,
                       support.LoggingCatcher,
                       unittest.TestCase):

50
    def assertNoWarnings(self):
51
        self.assertEqual(self.get_logs(), [])
52 53

    def assertWarnings(self):
54
        self.assertNotEqual(self.get_logs(), [])
55

56 57 58 59
    def test_manifest_reader(self):
        tmpdir = self.mkdtemp()
        MANIFEST = os.path.join(tmpdir, 'MANIFEST.in')
        with open(MANIFEST, 'w') as f:
60
            f.write(MANIFEST_IN_2)
61 62 63 64

        manifest = Manifest()
        manifest.read_template(MANIFEST)

65
        warnings = self.get_logs()
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
        # 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')
86
        content = StringIO(MANIFEST_IN_3)
87 88 89 90
        manifest = Manifest()
        manifest.read_template(content)
        self.assertEqual(['README', 'file1'], manifest.files)

91
    def test_glob_to_re(self):
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
        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)
149 150 151 152

    def test_remove_duplicates(self):
        manifest = Manifest()
        manifest.files = ['a', 'b', 'a', 'g', 'c', 'g']
153
        # files must be sorted beforehand (like sdist does)
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
        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):
213
        l = make_local_path
214 215 216 217 218 219 220 221 222 223
        # 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()
224
        manifest.allfiles = ['a.py', 'b.txt', l('d/c.py')]
225 226 227 228 229 230 231

        manifest._process_template_line('*.py')
        self.assertEqual(manifest.files, ['a.py'])
        self.assertNoWarnings()

        # include
        manifest = Manifest()
232
        manifest.allfiles = ['a.py', 'b.txt', l('d/c.py')]
233 234 235 236 237 238 239 240 241 242 243

        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()
244
        manifest.files = ['a.py', 'b.txt', l('d/c.py')]
245 246

        manifest._process_template_line('exclude *.py')
247
        self.assertEqual(manifest.files, ['b.txt', l('d/c.py')])
248 249 250
        self.assertNoWarnings()

        manifest._process_template_line('exclude *.rb')
251
        self.assertEqual(manifest.files, ['b.txt', l('d/c.py')])
252 253 254 255
        self.assertWarnings()

        # global-include
        manifest = Manifest()
256
        manifest.allfiles = ['a.py', 'b.txt', l('d/c.py')]
257 258

        manifest._process_template_line('global-include *.py')
259
        self.assertEqual(manifest.files, ['a.py', l('d/c.py')])
260 261 262
        self.assertNoWarnings()

        manifest._process_template_line('global-include *.rb')
263
        self.assertEqual(manifest.files, ['a.py', l('d/c.py')])
264 265 266 267
        self.assertWarnings()

        # global-exclude
        manifest = Manifest()
268
        manifest.files = ['a.py', 'b.txt', l('d/c.py')]
269 270 271 272 273 274 275 276 277 278 279

        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()
280
        manifest.allfiles = ['a.py', l('d/b.py'), l('d/c.txt'), l('d/d/e.py')]
281 282

        manifest._process_template_line('recursive-include d *.py')
283
        self.assertEqual(manifest.files, [l('d/b.py'), l('d/d/e.py')])
284 285 286
        self.assertNoWarnings()

        manifest._process_template_line('recursive-include e *.py')
287
        self.assertEqual(manifest.files, [l('d/b.py'), l('d/d/e.py')])
288 289 290 291
        self.assertWarnings()

        # recursive-exclude
        manifest = Manifest()
292
        manifest.files = ['a.py', l('d/b.py'), l('d/c.txt'), l('d/d/e.py')]
293 294

        manifest._process_template_line('recursive-exclude d *.py')
295
        self.assertEqual(manifest.files, ['a.py', l('d/c.txt')])
296 297 298
        self.assertNoWarnings()

        manifest._process_template_line('recursive-exclude e *.py')
299
        self.assertEqual(manifest.files, ['a.py', l('d/c.txt')])
300 301 302 303
        self.assertWarnings()

        # graft
        manifest = Manifest()
304
        manifest.allfiles = ['a.py', l('d/b.py'), l('d/d/e.py'), l('f/f.py')]
305 306

        manifest._process_template_line('graft d')
307
        self.assertEqual(manifest.files, [l('d/b.py'), l('d/d/e.py')])
308 309 310
        self.assertNoWarnings()

        manifest._process_template_line('graft e')
311
        self.assertEqual(manifest.files, [l('d/b.py'), l('d/d/e.py')])
312 313 314 315
        self.assertWarnings()

        # prune
        manifest = Manifest()
316
        manifest.files = ['a.py', l('d/b.py'), l('d/d/e.py'), l('f/f.py')]
317 318

        manifest._process_template_line('prune d')
319
        self.assertEqual(manifest.files, ['a.py', l('f/f.py')])
320 321 322
        self.assertNoWarnings()

        manifest._process_template_line('prune e')
323
        self.assertEqual(manifest.files, ['a.py', l('f/f.py')])
324 325
        self.assertWarnings()

326 327 328 329 330 331

def test_suite():
    return unittest.makeSuite(ManifestTestCase)

if __name__ == '__main__':
    unittest.main(defaultTest='test_suite')