1"""Tests for distutils.filelist.""" 2import os 3import re 4import unittest 5from distutils import debug 6from distutils.log import WARN 7from distutils.errors import DistutilsTemplateError 8from distutils.filelist import glob_to_re, translate_pattern, FileList 9 10from test.test_support import captured_stdout, run_unittest 11from distutils.tests import support 12 13MANIFEST_IN = """\ 14include ok 15include xo 16exclude xo 17include foo.tmp 18include buildout.cfg 19global-include *.x 20global-include *.txt 21global-exclude *.tmp 22recursive-include f *.oo 23recursive-exclude global *.x 24graft dir 25prune dir3 26""" 27 28 29def make_local_path(s): 30 """Converts '/' in a string to os.sep""" 31 return s.replace('/', os.sep) 32 33 34class FileListTestCase(support.LoggingSilencer, 35 unittest.TestCase): 36 37 def assertNoWarnings(self): 38 self.assertEqual(self.get_logs(WARN), []) 39 self.clear_logs() 40 41 def assertWarnings(self): 42 self.assertGreater(len(self.get_logs(WARN)), 0) 43 self.clear_logs() 44 45 def test_glob_to_re(self): 46 sep = os.sep 47 if os.sep == '\\': 48 sep = re.escape(os.sep) 49 50 for glob, regex in ( 51 # simple cases 52 ('foo*', r'foo[^%(sep)s]*\Z(?ms)'), 53 ('foo?', r'foo[^%(sep)s]\Z(?ms)'), 54 ('foo??', r'foo[^%(sep)s][^%(sep)s]\Z(?ms)'), 55 # special cases 56 (r'foo\\*', r'foo\\\\[^%(sep)s]*\Z(?ms)'), 57 (r'foo\\\*', r'foo\\\\\\[^%(sep)s]*\Z(?ms)'), 58 ('foo????', r'foo[^%(sep)s][^%(sep)s][^%(sep)s][^%(sep)s]\Z(?ms)'), 59 (r'foo\\??', r'foo\\\\[^%(sep)s][^%(sep)s]\Z(?ms)')): 60 regex = regex % {'sep': sep} 61 self.assertEqual(glob_to_re(glob), regex) 62 63 def test_process_template_line(self): 64 # testing all MANIFEST.in template patterns 65 file_list = FileList() 66 l = make_local_path 67 68 # simulated file list 69 file_list.allfiles = ['foo.tmp', 'ok', 'xo', 'four.txt', 70 'buildout.cfg', 71 # filelist does not filter out VCS directories, 72 # it's sdist that does 73 l('.hg/last-message.txt'), 74 l('global/one.txt'), 75 l('global/two.txt'), 76 l('global/files.x'), 77 l('global/here.tmp'), 78 l('f/o/f.oo'), 79 l('dir/graft-one'), 80 l('dir/dir2/graft2'), 81 l('dir3/ok'), 82 l('dir3/sub/ok.txt'), 83 ] 84 85 for line in MANIFEST_IN.split('\n'): 86 if line.strip() == '': 87 continue 88 file_list.process_template_line(line) 89 90 wanted = ['ok', 91 'buildout.cfg', 92 'four.txt', 93 l('.hg/last-message.txt'), 94 l('global/one.txt'), 95 l('global/two.txt'), 96 l('f/o/f.oo'), 97 l('dir/graft-one'), 98 l('dir/dir2/graft2'), 99 ] 100 101 self.assertEqual(file_list.files, wanted) 102 103 def test_debug_print(self): 104 file_list = FileList() 105 with captured_stdout() as stdout: 106 file_list.debug_print('xxx') 107 self.assertEqual(stdout.getvalue(), '') 108 109 debug.DEBUG = True 110 try: 111 with captured_stdout() as stdout: 112 file_list.debug_print('xxx') 113 self.assertEqual(stdout.getvalue(), 'xxx\n') 114 finally: 115 debug.DEBUG = False 116 117 def test_set_allfiles(self): 118 file_list = FileList() 119 files = ['a', 'b', 'c'] 120 file_list.set_allfiles(files) 121 self.assertEqual(file_list.allfiles, files) 122 123 def test_remove_duplicates(self): 124 file_list = FileList() 125 file_list.files = ['a', 'b', 'a', 'g', 'c', 'g'] 126 # files must be sorted beforehand (sdist does it) 127 file_list.sort() 128 file_list.remove_duplicates() 129 self.assertEqual(file_list.files, ['a', 'b', 'c', 'g']) 130 131 def test_translate_pattern(self): 132 # not regex 133 self.assertTrue(hasattr( 134 translate_pattern('a', anchor=True, is_regex=False), 135 'search')) 136 137 # is a regex 138 regex = re.compile('a') 139 self.assertEqual( 140 translate_pattern(regex, anchor=True, is_regex=True), 141 regex) 142 143 # plain string flagged as regex 144 self.assertTrue(hasattr( 145 translate_pattern('a', anchor=True, is_regex=True), 146 'search')) 147 148 # glob support 149 self.assertTrue(translate_pattern( 150 '*.py', anchor=True, is_regex=False).search('filelist.py')) 151 152 def test_exclude_pattern(self): 153 # return False if no match 154 file_list = FileList() 155 self.assertFalse(file_list.exclude_pattern('*.py')) 156 157 # return True if files match 158 file_list = FileList() 159 file_list.files = ['a.py', 'b.py'] 160 self.assertTrue(file_list.exclude_pattern('*.py')) 161 162 # test excludes 163 file_list = FileList() 164 file_list.files = ['a.py', 'a.txt'] 165 file_list.exclude_pattern('*.py') 166 self.assertEqual(file_list.files, ['a.txt']) 167 168 def test_include_pattern(self): 169 # return False if no match 170 file_list = FileList() 171 file_list.set_allfiles([]) 172 self.assertFalse(file_list.include_pattern('*.py')) 173 174 # return True if files match 175 file_list = FileList() 176 file_list.set_allfiles(['a.py', 'b.txt']) 177 self.assertTrue(file_list.include_pattern('*.py')) 178 179 # test * matches all files 180 file_list = FileList() 181 self.assertIsNone(file_list.allfiles) 182 file_list.set_allfiles(['a.py', 'b.txt']) 183 file_list.include_pattern('*') 184 self.assertEqual(file_list.allfiles, ['a.py', 'b.txt']) 185 186 def test_process_template(self): 187 l = make_local_path 188 # invalid lines 189 file_list = FileList() 190 for action in ('include', 'exclude', 'global-include', 191 'global-exclude', 'recursive-include', 192 'recursive-exclude', 'graft', 'prune', 'blarg'): 193 self.assertRaises(DistutilsTemplateError, 194 file_list.process_template_line, action) 195 196 # include 197 file_list = FileList() 198 file_list.set_allfiles(['a.py', 'b.txt', l('d/c.py')]) 199 200 file_list.process_template_line('include *.py') 201 self.assertEqual(file_list.files, ['a.py']) 202 self.assertNoWarnings() 203 204 file_list.process_template_line('include *.rb') 205 self.assertEqual(file_list.files, ['a.py']) 206 self.assertWarnings() 207 208 # exclude 209 file_list = FileList() 210 file_list.files = ['a.py', 'b.txt', l('d/c.py')] 211 212 file_list.process_template_line('exclude *.py') 213 self.assertEqual(file_list.files, ['b.txt', l('d/c.py')]) 214 self.assertNoWarnings() 215 216 file_list.process_template_line('exclude *.rb') 217 self.assertEqual(file_list.files, ['b.txt', l('d/c.py')]) 218 self.assertWarnings() 219 220 # global-include 221 file_list = FileList() 222 file_list.set_allfiles(['a.py', 'b.txt', l('d/c.py')]) 223 224 file_list.process_template_line('global-include *.py') 225 self.assertEqual(file_list.files, ['a.py', l('d/c.py')]) 226 self.assertNoWarnings() 227 228 file_list.process_template_line('global-include *.rb') 229 self.assertEqual(file_list.files, ['a.py', l('d/c.py')]) 230 self.assertWarnings() 231 232 # global-exclude 233 file_list = FileList() 234 file_list.files = ['a.py', 'b.txt', l('d/c.py')] 235 236 file_list.process_template_line('global-exclude *.py') 237 self.assertEqual(file_list.files, ['b.txt']) 238 self.assertNoWarnings() 239 240 file_list.process_template_line('global-exclude *.rb') 241 self.assertEqual(file_list.files, ['b.txt']) 242 self.assertWarnings() 243 244 # recursive-include 245 file_list = FileList() 246 file_list.set_allfiles(['a.py', l('d/b.py'), l('d/c.txt'), 247 l('d/d/e.py')]) 248 249 file_list.process_template_line('recursive-include d *.py') 250 self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')]) 251 self.assertNoWarnings() 252 253 file_list.process_template_line('recursive-include e *.py') 254 self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')]) 255 self.assertWarnings() 256 257 # recursive-exclude 258 file_list = FileList() 259 file_list.files = ['a.py', l('d/b.py'), l('d/c.txt'), l('d/d/e.py')] 260 261 file_list.process_template_line('recursive-exclude d *.py') 262 self.assertEqual(file_list.files, ['a.py', l('d/c.txt')]) 263 self.assertNoWarnings() 264 265 file_list.process_template_line('recursive-exclude e *.py') 266 self.assertEqual(file_list.files, ['a.py', l('d/c.txt')]) 267 self.assertWarnings() 268 269 # graft 270 file_list = FileList() 271 file_list.set_allfiles(['a.py', l('d/b.py'), l('d/d/e.py'), 272 l('f/f.py')]) 273 274 file_list.process_template_line('graft d') 275 self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')]) 276 self.assertNoWarnings() 277 278 file_list.process_template_line('graft e') 279 self.assertEqual(file_list.files, [l('d/b.py'), l('d/d/e.py')]) 280 self.assertWarnings() 281 282 # prune 283 file_list = FileList() 284 file_list.files = ['a.py', l('d/b.py'), l('d/d/e.py'), l('f/f.py')] 285 286 file_list.process_template_line('prune d') 287 self.assertEqual(file_list.files, ['a.py', l('f/f.py')]) 288 self.assertNoWarnings() 289 290 file_list.process_template_line('prune e') 291 self.assertEqual(file_list.files, ['a.py', l('f/f.py')]) 292 self.assertWarnings() 293 294 295def test_suite(): 296 return unittest.makeSuite(FileListTestCase) 297 298if __name__ == "__main__": 299 run_unittest(test_suite()) 300