diff -r 58bd6a58365d Doc/library/glob.rst --- a/Doc/library/glob.rst Wed Feb 08 04:09:37 2012 +0100 +++ b/Doc/library/glob.rst Wed Feb 08 13:16:26 2012 +0200 @@ -35,6 +35,12 @@ without actually storing them all simultaneously. +.. function:: rglob(pathname) + + Return an :term:`iterator` which recursively walks the pathname pattern and + yields the same results as :func:`iglob` for each directory. + + For example, consider a directory containing only the following files: :file:`1.gif`, :file:`2.txt`, and :file:`card.gif`. :func:`glob` will produce the following results. Notice how any leading components of the path are diff -r 58bd6a58365d Lib/glob.py --- a/Lib/glob.py Wed Feb 08 04:09:37 2012 +0100 +++ b/Lib/glob.py Wed Feb 08 13:16:26 2012 +0200 @@ -4,7 +4,7 @@ import re import fnmatch -__all__ = ["glob", "iglob"] +__all__ = ["glob", "iglob", "rglob"] def glob(pathname): """Return a list of paths matching a pathname pattern. @@ -41,6 +41,36 @@ for name in glob_in_dir(dirname, basename): yield os.path.join(dirname, name) +def rglob(pathname): + """Return an iterator which recursively walks the pathname pattern and + yields the matching paths. + + The pattern may contain simple shell-style wildcards a la fnmatch. + + """ + if not has_magic(pathname): + if os.path.lexists(pathname): + yield pathname + return + dirname, basename = os.path.split(pathname) + if has_magic(dirname): + notmagic = [] + for part in dirname.split(os.sep): + if has_magic(part): + break + else: + notmagic.append(part) + dirbase = os.sep.join(notmagic) + else: + dirbase = dirname + if dirbase == '': + dirbase = '.' + for root, dirnames, filenames in os.walk(dirbase): + for fname in filenames: + fullpath = os.path.join(root, fname) + if fnmatch.fnmatch(fullpath, pathname): + yield fullpath + # These 2 helper functions non-recursively glob inside a literal directory. # They return a list of basenames. `glob1` accepts a pattern while `glob0` # takes a literal basename (so it only has to check for its existence). diff -r 58bd6a58365d Lib/test/test_glob.py --- a/Lib/test/test_glob.py Wed Feb 08 04:09:37 2012 +0100 +++ b/Lib/test/test_glob.py Wed Feb 08 13:16:26 2012 +0200 @@ -105,6 +105,17 @@ eq(self.glob('sym1'), [self.norm('sym1')]) eq(self.glob('sym2'), [self.norm('sym2')]) + def test_rglob(self): + eq = self.assertSequencesEqual_noorder + fs = ('aab', 'F'), ('aaa', 'zzzF'), ('a', 'bcd', 'EF') + expected = [self.norm(os.path.join(*i)) for i in fs] + res = glob.rglob(os.path.join(self.tempdir, '*F')) + eq(res, expected) + bcds = ('a', 'bcd', 'EF'), ('a', 'bcd', 'efg', 'ha') + expected = [self.norm(os.path.join(*i)) for i in bcds] + res = glob.rglob(os.path.join(self.tempdir, '*/bcd/*')) + eq(res, expected) + def test_main(): run_unittest(GlobTests)