Skip to content

Commit df1d940

Browse files
committed
Reversed changes from issue9584
2 parents 3df8887 + 9b3fb0c commit df1d940

File tree

4 files changed

+25
-118
lines changed

4 files changed

+25
-118
lines changed

Doc/library/glob.rst

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313

1414
The :mod:`glob` module finds all the pathnames matching a specified pattern
1515
according to the rules used by the Unix shell. No tilde expansion is done, but
16-
``*``, ``?``, character ranges expressed with ``[]`` and list of options
17-
expressed with ``{}`` will be correctly matched. This is done by using the
18-
:func:`os.listdir` and :func:`fnmatch.fnmatch` functions in concert, and not by
19-
actually invoking a subshell. (For tilde and shell variable expansion, use
16+
``*``, ``?``, and character ranges expressed with ``[]`` will be correctly
17+
matched. This is done by using the :func:`os.listdir` and
18+
:func:`fnmatch.fnmatch` functions in concert, and not by actually invoking a
19+
subshell. (For tilde and shell variable expansion, use
2020
:func:`os.path.expanduser` and :func:`os.path.expandvars`.)
2121

2222

@@ -47,8 +47,7 @@ preserved. ::
4747
['1.gif', 'card.gif']
4848
>>> glob.glob('?.gif')
4949
['1.gif']
50-
>>> glob.glob('?.{gif,txt}')
51-
['1.gif', '2.txt']
50+
5251

5352
.. seealso::
5453

Lib/glob.py

Lines changed: 18 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ def glob(pathname):
1414
"""
1515
return list(iglob(pathname))
1616

17-
1817
def iglob(pathname):
1918
"""Return an iterator which yields the paths matching a pathname pattern.
2019
@@ -25,24 +24,21 @@ def iglob(pathname):
2524
if os.path.lexists(pathname):
2625
yield pathname
2726
return
28-
pathnames = expand_braces(pathname)
29-
for pathname in pathnames:
30-
dirname, basename = os.path.split(pathname)
31-
if not dirname:
32-
yield from glob1(None, basename)
33-
return
34-
35-
if has_magic(dirname):
36-
dirs = iglob(dirname)
37-
else:
38-
dirs = [dirname]
39-
if has_magic(basename):
40-
glob_in_dir = glob1
41-
else:
42-
glob_in_dir = glob0
43-
for dirname in dirs:
44-
for name in glob_in_dir(dirname, basename):
45-
yield os.path.join(dirname, name)
27+
dirname, basename = os.path.split(pathname)
28+
if not dirname:
29+
yield from glob1(None, basename)
30+
return
31+
if has_magic(dirname):
32+
dirs = iglob(dirname)
33+
else:
34+
dirs = [dirname]
35+
if has_magic(basename):
36+
glob_in_dir = glob1
37+
else:
38+
glob_in_dir = glob0
39+
for dirname in dirs:
40+
for name in glob_in_dir(dirname, basename):
41+
yield os.path.join(dirname, name)
4642

4743
# These 2 helper functions non-recursively glob inside a literal directory.
4844
# They return a list of basenames. `glob1` accepts a pattern while `glob0`
@@ -74,37 +70,12 @@ def glob0(dirname, basename):
7470
return []
7571

7672

77-
magic_check = re.compile('[*?[{]')
78-
magic_check_bytes = re.compile(b'[*?[{]')
73+
magic_check = re.compile('[*?[]')
74+
magic_check_bytes = re.compile(b'[*?[]')
75+
7976
def has_magic(s):
8077
if isinstance(s, bytes):
8178
match = magic_check_bytes.search(s)
8279
else:
8380
match = magic_check.search(s)
8481
return match is not None
85-
86-
brace_matcher = re.compile(r'.*(\{.+?[^\\]\})')
87-
def expand_braces(text):
88-
"""Find the rightmost, innermost set of braces and, if it contains a
89-
comma-separated list, expand its contents recursively (any of its items
90-
may itself be a list enclosed in braces).
91-
92-
Return the full set of expanded strings.
93-
"""
94-
res = set()
95-
96-
match = brace_matcher.search(text)
97-
if match is not None:
98-
sub = match.group(1)
99-
open_brace, close_brace = match.span(1)
100-
if "," in sub:
101-
for pat in sub.strip('{}').split(','):
102-
res.update(expand_braces(text[:open_brace] + pat + text[close_brace:]))
103-
104-
else:
105-
res.update(expand_braces(text[:open_brace] + sub.replace('}', '\\}') + text[close_brace:]))
106-
107-
else:
108-
res.add(text.replace('\\}', '}'))
109-
110-
return res

Lib/test/test_glob.py

Lines changed: 2 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import os
66
import shutil
77

8-
class GlobTestsBase(unittest.TestCase):
8+
class GlobTests(unittest.TestCase):
99

1010
def norm(self, *parts):
1111
return os.path.normpath(os.path.join(self.tempdir, *parts))
@@ -45,8 +45,6 @@ def glob(self, *parts):
4545
def assertSequencesEqual_noorder(self, l1, l2):
4646
self.assertEqual(set(l1), set(l2))
4747

48-
class GlobTests(GlobTestsBase):
49-
5048
def test_glob_literal(self):
5149
eq = self.assertSequencesEqual_noorder
5250
eq(self.glob('a'), [self.norm('a')])
@@ -107,67 +105,9 @@ def test_glob_broken_symlinks(self):
107105
eq(self.glob('sym1'), [self.norm('sym1')])
108106
eq(self.glob('sym2'), [self.norm('sym2')])
109107

110-
class GlobBracesTests(GlobTestsBase):
111-
112-
def setUp(self):
113-
super(GlobBracesTests, self).setUp()
114-
self.mktemp('c{}d')
115-
self.mktemp('c{deg')
116-
self.mktemp('c{dfg')
117-
self.mktemp('cd{f}g')
118-
self.mktemp('ce{f}g')
119-
self.mktemp('cdf}g')
120-
self.mktemp('cef}g')
121-
122-
def match_pattern_with_results(self, patterns, paths):
123-
expected = [self.norm(path) for path in [os.path.join(*parts) for parts in paths]]
124-
actual = [os.path.normpath(g) for g in self.glob(*patterns)]
125-
self.assertSequencesEqual_noorder(actual, expected)
126-
127-
def test_two_terms(self):
128-
self.match_pattern_with_results(['a{aa,ab}'], [["aaa"], ["aab"]])
129-
130-
def test_missing_first_plus_nested(self):
131-
self.match_pattern_with_results(['a{,a{a,b}}'], [['a'], ['aaa'], ['aab']])
132-
133-
def test_one_subpath_with_two_file_terms(self):
134-
self.match_pattern_with_results(['a', '{D,bcd}'], [['a', 'D'], ['a', 'bcd']])
135-
136-
def test_two_subpath_terms_with_two_file_terms(self):
137-
self.match_pattern_with_results(['{aaa,aab}', '{F,zzzF}'], [('aaa', 'zzzF'), ('aab', 'F')])
138-
139-
def test_two_subpath_terms_with_wildcard_file_term(self):
140-
self.match_pattern_with_results(['aa{a,b}', '*F'], [('aaa', 'zzzF'), ('aab', 'F')])
141-
142-
def test_wildcard_subpath_with_file_missing_first_term(self):
143-
self.match_pattern_with_results(['aa?', '{,zzz}F'], [('aaa', 'zzzF'), ('aab', 'F')])
144-
145-
#
146-
# Edge cases where braces should not be expanded
147-
#
148-
def test_empty_braces(self):
149-
self.assertSequencesEqual_noorder(self.glob('c{}d'), [self.norm('c{}d')])
150-
151-
def test_missing_end_brace(self):
152-
self.assertSequencesEqual_noorder(self.glob('c{d{e,f}g'), map(self.norm, ['c{deg', 'c{dfg']))
153-
154-
def test_second_brace_one_term(self):
155-
self.assertSequencesEqual_noorder(self.glob('c{d,e}{f}g'), map(self.norm, ['cd{f}g', 'ce{f}g']))
156-
157-
def test_outer_term_missing_first_brace(self):
158-
self.assertSequencesEqual_noorder(self.glob('c{d,e}f}g'), map(self.norm, ['cdf}g', 'cef}g']))
159-
160-
#
161-
# Braces containing folder separators
162-
#
163-
def test_embedded_separator1(self):
164-
self.match_pattern_with_results(['a/{D,bcd/{EF,efg}}'], [('a', 'D'), ('a', 'bcd', 'EF'), ('a', 'bcd', 'efg')])
165-
166-
def test_embedded_separator2(self):
167-
self.match_pattern_with_results(['aa{a/zzz,b/}F'], [('aaa', 'zzzF'), ('aab', 'F')])
168108

169109
def test_main():
170-
run_unittest(GlobTests, GlobBracesTests)
110+
run_unittest(GlobTests)
171111

172112

173113
if __name__ == "__main__":

Misc/NEWS

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ What's New in Python 3.4.0 Alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13-
- Issue #9584: glob.glob now expands braces to a list of strings.
14-
Original patch by Mathieu Bridon.
15-
1613
- Issue #8271: the utf-8 decoder now outputs the correct number of U+FFFD
1714
characters when used with the 'replace' error handler on invalid utf-8
1815
sequences. Patch by Serhiy Storchaka, tests by Ezio Melotti.

0 commit comments

Comments
 (0)