glob.py 2.24 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1
"""Filename globbing utility."""
Guido van Rossum's avatar
Guido van Rossum committed
2

3
import sys
Guido van Rossum's avatar
Guido van Rossum committed
4
import os
5
import re
6
import fnmatch
Guido van Rossum's avatar
Guido van Rossum committed
7

Johannes Gijsbers's avatar
Johannes Gijsbers committed
8
__all__ = ["glob", "iglob"]
Guido van Rossum's avatar
Guido van Rossum committed
9

Guido van Rossum's avatar
Guido van Rossum committed
10
def glob(pathname):
Tim Peters's avatar
Tim Peters committed
11 12 13 14
    """Return a list of paths matching a pathname pattern.

    The pattern may contain simple shell-style wildcards a la fnmatch.

Johannes Gijsbers's avatar
Johannes Gijsbers committed
15 16 17 18
    """
    return list(iglob(pathname))

def iglob(pathname):
Benjamin Peterson's avatar
Benjamin Peterson committed
19
    """Return an iterator which yields the paths matching a pathname pattern.
Johannes Gijsbers's avatar
Johannes Gijsbers committed
20 21 22

    The pattern may contain simple shell-style wildcards a la fnmatch.

Tim Peters's avatar
Tim Peters committed
23 24
    """
    if not has_magic(pathname):
25
        if os.path.lexists(pathname):
Johannes Gijsbers's avatar
Johannes Gijsbers committed
26 27
            yield pathname
        return
Tim Peters's avatar
Tim Peters committed
28
    dirname, basename = os.path.split(pathname)
29
    if not dirname:
30
        for name in glob1(None, basename):
Johannes Gijsbers's avatar
Johannes Gijsbers committed
31 32 33 34
            yield name
        return
    if has_magic(dirname):
        dirs = iglob(dirname)
Tim Peters's avatar
Tim Peters committed
35
    else:
Johannes Gijsbers's avatar
Johannes Gijsbers committed
36 37 38
        dirs = [dirname]
    if has_magic(basename):
        glob_in_dir = glob1
Tim Peters's avatar
Tim Peters committed
39
    else:
Johannes Gijsbers's avatar
Johannes Gijsbers committed
40 41 42 43 44 45 46 47
        glob_in_dir = glob0
    for dirname in dirs:
        for name in glob_in_dir(dirname, basename):
            yield os.path.join(dirname, name)

# 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).
Guido van Rossum's avatar
Guido van Rossum committed
48 49

def glob1(dirname, pattern):
Johannes Gijsbers's avatar
Johannes Gijsbers committed
50
    if not dirname:
51 52 53 54
        if isinstance(pattern, bytes):
            dirname = bytes(os.curdir, 'ASCII')
        else:
            dirname = os.curdir
Tim Peters's avatar
Tim Peters committed
55 56 57 58
    try:
        names = os.listdir(dirname)
    except os.error:
        return []
59
    if pattern[0] != '.':
Alexandre Vassalotti's avatar
Alexandre Vassalotti committed
60
        names = [x for x in names if x[0] != '.']
61
    return fnmatch.filter(names, pattern)
Guido van Rossum's avatar
Guido van Rossum committed
62

Johannes Gijsbers's avatar
Johannes Gijsbers committed
63 64 65 66
def glob0(dirname, basename):
    if basename == '':
        # `os.path.split()` returns an empty basename for paths ending with a
        # directory separator.  'q*x/' should match only directories.
67
        if os.path.isdir(dirname):
Johannes Gijsbers's avatar
Johannes Gijsbers committed
68 69 70 71 72 73
            return [basename]
    else:
        if os.path.lexists(os.path.join(dirname, basename)):
            return [basename]
    return []

74

75
magic_check = re.compile('[*?[]')
76
magic_check_bytes = re.compile(b'[*?[]')
77

Guido van Rossum's avatar
Guido van Rossum committed
78
def has_magic(s):
79 80 81 82 83
    if isinstance(s, bytes):
        match = magic_check_bytes.search(s)
    else:
        match = magic_check.search(s)
    return match is not None