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