1import glob 2import os 3import shutil 4import sys 5import unittest 6 7from test.support import (TESTFN, skip_unless_symlink, 8 can_symlink, create_empty_file, change_cwd) 9 10 11class GlobTests(unittest.TestCase): 12 13 def norm(self, *parts): 14 return os.path.normpath(os.path.join(self.tempdir, *parts)) 15 16 def joins(self, *tuples): 17 return [os.path.join(self.tempdir, *parts) for parts in tuples] 18 19 def mktemp(self, *parts): 20 filename = self.norm(*parts) 21 base, file = os.path.split(filename) 22 if not os.path.exists(base): 23 os.makedirs(base) 24 create_empty_file(filename) 25 26 def setUp(self): 27 self.tempdir = TESTFN + "_dir" 28 self.mktemp('a', 'D') 29 self.mktemp('aab', 'F') 30 self.mktemp('.aa', 'G') 31 self.mktemp('.bb', 'H') 32 self.mktemp('aaa', 'zzzF') 33 self.mktemp('ZZZ') 34 self.mktemp('EF') 35 self.mktemp('a', 'bcd', 'EF') 36 self.mktemp('a', 'bcd', 'efg', 'ha') 37 if can_symlink(): 38 os.symlink(self.norm('broken'), self.norm('sym1')) 39 os.symlink('broken', self.norm('sym2')) 40 os.symlink(os.path.join('a', 'bcd'), self.norm('sym3')) 41 42 def tearDown(self): 43 shutil.rmtree(self.tempdir) 44 45 def glob(self, *parts, **kwargs): 46 if len(parts) == 1: 47 pattern = parts[0] 48 else: 49 pattern = os.path.join(*parts) 50 p = os.path.join(self.tempdir, pattern) 51 res = glob.glob(p, **kwargs) 52 self.assertCountEqual(glob.iglob(p, **kwargs), res) 53 bres = [os.fsencode(x) for x in res] 54 self.assertCountEqual(glob.glob(os.fsencode(p), **kwargs), bres) 55 self.assertCountEqual(glob.iglob(os.fsencode(p), **kwargs), bres) 56 return res 57 58 def assertSequencesEqual_noorder(self, l1, l2): 59 l1 = list(l1) 60 l2 = list(l2) 61 self.assertEqual(set(l1), set(l2)) 62 self.assertEqual(sorted(l1), sorted(l2)) 63 64 def test_glob_literal(self): 65 eq = self.assertSequencesEqual_noorder 66 eq(self.glob('a'), [self.norm('a')]) 67 eq(self.glob('a', 'D'), [self.norm('a', 'D')]) 68 eq(self.glob('aab'), [self.norm('aab')]) 69 eq(self.glob('zymurgy'), []) 70 71 res = glob.glob('*') 72 self.assertEqual({type(r) for r in res}, {str}) 73 res = glob.glob(os.path.join(os.curdir, '*')) 74 self.assertEqual({type(r) for r in res}, {str}) 75 76 res = glob.glob(b'*') 77 self.assertEqual({type(r) for r in res}, {bytes}) 78 res = glob.glob(os.path.join(os.fsencode(os.curdir), b'*')) 79 self.assertEqual({type(r) for r in res}, {bytes}) 80 81 def test_glob_one_directory(self): 82 eq = self.assertSequencesEqual_noorder 83 eq(self.glob('a*'), map(self.norm, ['a', 'aab', 'aaa'])) 84 eq(self.glob('*a'), map(self.norm, ['a', 'aaa'])) 85 eq(self.glob('.*'), map(self.norm, ['.aa', '.bb'])) 86 eq(self.glob('?aa'), map(self.norm, ['aaa'])) 87 eq(self.glob('aa?'), map(self.norm, ['aaa', 'aab'])) 88 eq(self.glob('aa[ab]'), map(self.norm, ['aaa', 'aab'])) 89 eq(self.glob('*q'), []) 90 91 def test_glob_nested_directory(self): 92 eq = self.assertSequencesEqual_noorder 93 if os.path.normcase("abCD") == "abCD": 94 # case-sensitive filesystem 95 eq(self.glob('a', 'bcd', 'E*'), [self.norm('a', 'bcd', 'EF')]) 96 else: 97 # case insensitive filesystem 98 eq(self.glob('a', 'bcd', 'E*'), [self.norm('a', 'bcd', 'EF'), 99 self.norm('a', 'bcd', 'efg')]) 100 eq(self.glob('a', 'bcd', '*g'), [self.norm('a', 'bcd', 'efg')]) 101 102 def test_glob_directory_names(self): 103 eq = self.assertSequencesEqual_noorder 104 eq(self.glob('*', 'D'), [self.norm('a', 'D')]) 105 eq(self.glob('*', '*a'), []) 106 eq(self.glob('a', '*', '*', '*a'), 107 [self.norm('a', 'bcd', 'efg', 'ha')]) 108 eq(self.glob('?a?', '*F'), [self.norm('aaa', 'zzzF'), 109 self.norm('aab', 'F')]) 110 111 def test_glob_directory_with_trailing_slash(self): 112 # Patterns ending with a slash shouldn't match non-dirs 113 res = glob.glob(self.norm('Z*Z') + os.sep) 114 self.assertEqual(res, []) 115 res = glob.glob(self.norm('ZZZ') + os.sep) 116 self.assertEqual(res, []) 117 # When there is a wildcard pattern which ends with os.sep, glob() 118 # doesn't blow up. 119 res = glob.glob(self.norm('aa*') + os.sep) 120 self.assertEqual(len(res), 2) 121 # either of these results is reasonable 122 self.assertIn(set(res), [ 123 {self.norm('aaa'), self.norm('aab')}, 124 {self.norm('aaa') + os.sep, self.norm('aab') + os.sep}, 125 ]) 126 127 def test_glob_bytes_directory_with_trailing_slash(self): 128 # Same as test_glob_directory_with_trailing_slash, but with a 129 # bytes argument. 130 res = glob.glob(os.fsencode(self.norm('Z*Z') + os.sep)) 131 self.assertEqual(res, []) 132 res = glob.glob(os.fsencode(self.norm('ZZZ') + os.sep)) 133 self.assertEqual(res, []) 134 res = glob.glob(os.fsencode(self.norm('aa*') + os.sep)) 135 self.assertEqual(len(res), 2) 136 # either of these results is reasonable 137 self.assertIn(set(res), [ 138 {os.fsencode(self.norm('aaa')), 139 os.fsencode(self.norm('aab'))}, 140 {os.fsencode(self.norm('aaa') + os.sep), 141 os.fsencode(self.norm('aab') + os.sep)}, 142 ]) 143 144 @skip_unless_symlink 145 def test_glob_symlinks(self): 146 eq = self.assertSequencesEqual_noorder 147 eq(self.glob('sym3'), [self.norm('sym3')]) 148 eq(self.glob('sym3', '*'), [self.norm('sym3', 'EF'), 149 self.norm('sym3', 'efg')]) 150 self.assertIn(self.glob('sym3' + os.sep), 151 [[self.norm('sym3')], [self.norm('sym3') + os.sep]]) 152 eq(self.glob('*', '*F'), 153 [self.norm('aaa', 'zzzF'), 154 self.norm('aab', 'F'), self.norm('sym3', 'EF')]) 155 156 @skip_unless_symlink 157 def test_glob_broken_symlinks(self): 158 eq = self.assertSequencesEqual_noorder 159 eq(self.glob('sym*'), [self.norm('sym1'), self.norm('sym2'), 160 self.norm('sym3')]) 161 eq(self.glob('sym1'), [self.norm('sym1')]) 162 eq(self.glob('sym2'), [self.norm('sym2')]) 163 164 @unittest.skipUnless(sys.platform == "win32", "Win32 specific test") 165 def test_glob_magic_in_drive(self): 166 eq = self.assertSequencesEqual_noorder 167 eq(glob.glob('*:'), []) 168 eq(glob.glob(b'*:'), []) 169 eq(glob.glob('?:'), []) 170 eq(glob.glob(b'?:'), []) 171 eq(glob.glob('\\\\?\\c:\\'), ['\\\\?\\c:\\']) 172 eq(glob.glob(b'\\\\?\\c:\\'), [b'\\\\?\\c:\\']) 173 eq(glob.glob('\\\\*\\*\\'), []) 174 eq(glob.glob(b'\\\\*\\*\\'), []) 175 176 def check_escape(self, arg, expected): 177 self.assertEqual(glob.escape(arg), expected) 178 self.assertEqual(glob.escape(os.fsencode(arg)), os.fsencode(expected)) 179 180 def test_escape(self): 181 check = self.check_escape 182 check('abc', 'abc') 183 check('[', '[[]') 184 check('?', '[?]') 185 check('*', '[*]') 186 check('[[_/*?*/_]]', '[[][[]_/[*][?][*]/_]]') 187 check('/[[_/*?*/_]]/', '/[[][[]_/[*][?][*]/_]]/') 188 189 @unittest.skipUnless(sys.platform == "win32", "Win32 specific test") 190 def test_escape_windows(self): 191 check = self.check_escape 192 check('?:?', '?:[?]') 193 check('*:*', '*:[*]') 194 check(r'\\?\c:\?', r'\\?\c:\[?]') 195 check(r'\\*\*\*', r'\\*\*\[*]') 196 check('//?/c:/?', '//?/c:/[?]') 197 check('//*/*/*', '//*/*/[*]') 198 199 def rglob(self, *parts, **kwargs): 200 return self.glob(*parts, recursive=True, **kwargs) 201 202 def test_recursive_glob(self): 203 eq = self.assertSequencesEqual_noorder 204 full = [('EF',), ('ZZZ',), 205 ('a',), ('a', 'D'), 206 ('a', 'bcd'), 207 ('a', 'bcd', 'EF'), 208 ('a', 'bcd', 'efg'), 209 ('a', 'bcd', 'efg', 'ha'), 210 ('aaa',), ('aaa', 'zzzF'), 211 ('aab',), ('aab', 'F'), 212 ] 213 if can_symlink(): 214 full += [('sym1',), ('sym2',), 215 ('sym3',), 216 ('sym3', 'EF'), 217 ('sym3', 'efg'), 218 ('sym3', 'efg', 'ha'), 219 ] 220 eq(self.rglob('**'), self.joins(('',), *full)) 221 eq(self.rglob(os.curdir, '**'), 222 self.joins((os.curdir, ''), *((os.curdir,) + i for i in full))) 223 dirs = [('a', ''), ('a', 'bcd', ''), ('a', 'bcd', 'efg', ''), 224 ('aaa', ''), ('aab', '')] 225 if can_symlink(): 226 dirs += [('sym3', ''), ('sym3', 'efg', '')] 227 eq(self.rglob('**', ''), self.joins(('',), *dirs)) 228 229 eq(self.rglob('a', '**'), self.joins( 230 ('a', ''), ('a', 'D'), ('a', 'bcd'), ('a', 'bcd', 'EF'), 231 ('a', 'bcd', 'efg'), ('a', 'bcd', 'efg', 'ha'))) 232 eq(self.rglob('a**'), self.joins(('a',), ('aaa',), ('aab',))) 233 expect = [('a', 'bcd', 'EF'), ('EF',)] 234 if can_symlink(): 235 expect += [('sym3', 'EF')] 236 eq(self.rglob('**', 'EF'), self.joins(*expect)) 237 expect = [('a', 'bcd', 'EF'), ('aaa', 'zzzF'), ('aab', 'F'), ('EF',)] 238 if can_symlink(): 239 expect += [('sym3', 'EF')] 240 eq(self.rglob('**', '*F'), self.joins(*expect)) 241 eq(self.rglob('**', '*F', ''), []) 242 eq(self.rglob('**', 'bcd', '*'), self.joins( 243 ('a', 'bcd', 'EF'), ('a', 'bcd', 'efg'))) 244 eq(self.rglob('a', '**', 'bcd'), self.joins(('a', 'bcd'))) 245 246 with change_cwd(self.tempdir): 247 join = os.path.join 248 eq(glob.glob('**', recursive=True), [join(*i) for i in full]) 249 eq(glob.glob(join('**', ''), recursive=True), 250 [join(*i) for i in dirs]) 251 eq(glob.glob(join('**', '*'), recursive=True), 252 [join(*i) for i in full]) 253 eq(glob.glob(join(os.curdir, '**'), recursive=True), 254 [join(os.curdir, '')] + [join(os.curdir, *i) for i in full]) 255 eq(glob.glob(join(os.curdir, '**', ''), recursive=True), 256 [join(os.curdir, '')] + [join(os.curdir, *i) for i in dirs]) 257 eq(glob.glob(join(os.curdir, '**', '*'), recursive=True), 258 [join(os.curdir, *i) for i in full]) 259 eq(glob.glob(join('**','zz*F'), recursive=True), 260 [join('aaa', 'zzzF')]) 261 eq(glob.glob('**zz*F', recursive=True), []) 262 expect = [join('a', 'bcd', 'EF'), 'EF'] 263 if can_symlink(): 264 expect += [join('sym3', 'EF')] 265 eq(glob.glob(join('**', 'EF'), recursive=True), expect) 266 267 def test_glob_many_open_files(self): 268 depth = 30 269 base = os.path.join(self.tempdir, 'deep') 270 p = os.path.join(base, *(['d']*depth)) 271 os.makedirs(p) 272 pattern = os.path.join(base, *(['*']*depth)) 273 iters = [glob.iglob(pattern, recursive=True) for j in range(100)] 274 for it in iters: 275 self.assertEqual(next(it), p) 276 pattern = os.path.join(base, '**', 'd') 277 iters = [glob.iglob(pattern, recursive=True) for j in range(100)] 278 p = base 279 for i in range(depth): 280 p = os.path.join(p, 'd') 281 for it in iters: 282 self.assertEqual(next(it), p) 283 284 285@skip_unless_symlink 286class SymlinkLoopGlobTests(unittest.TestCase): 287 288 def test_selflink(self): 289 tempdir = TESTFN + "_dir" 290 os.makedirs(tempdir) 291 self.addCleanup(shutil.rmtree, tempdir) 292 with change_cwd(tempdir): 293 os.makedirs('dir') 294 create_empty_file(os.path.join('dir', 'file')) 295 os.symlink(os.curdir, os.path.join('dir', 'link')) 296 297 results = glob.glob('**', recursive=True) 298 self.assertEqual(len(results), len(set(results))) 299 results = set(results) 300 depth = 0 301 while results: 302 path = os.path.join(*(['dir'] + ['link'] * depth)) 303 self.assertIn(path, results) 304 results.remove(path) 305 if not results: 306 break 307 path = os.path.join(path, 'file') 308 self.assertIn(path, results) 309 results.remove(path) 310 depth += 1 311 312 results = glob.glob(os.path.join('**', 'file'), recursive=True) 313 self.assertEqual(len(results), len(set(results))) 314 results = set(results) 315 depth = 0 316 while results: 317 path = os.path.join(*(['dir'] + ['link'] * depth + ['file'])) 318 self.assertIn(path, results) 319 results.remove(path) 320 depth += 1 321 322 results = glob.glob(os.path.join('**', ''), recursive=True) 323 self.assertEqual(len(results), len(set(results))) 324 results = set(results) 325 depth = 0 326 while results: 327 path = os.path.join(*(['dir'] + ['link'] * depth + [''])) 328 self.assertIn(path, results) 329 results.remove(path) 330 depth += 1 331 332 333if __name__ == "__main__": 334 unittest.main() 335