Path: blob/main/test/lib/python3.9/site-packages/setuptools/glob.py
4798 views
"""1Filename globbing utility. Mostly a copy of `glob` from Python 3.5.23Changes include:4* `yield from` and PEP3102 `*` removed.5* Hidden files are not ignored.6"""78import os9import re10import fnmatch1112__all__ = ["glob", "iglob", "escape"]131415def glob(pathname, recursive=False):16"""Return a list of paths matching a pathname pattern.1718The pattern may contain simple shell-style wildcards a la19fnmatch. However, unlike fnmatch, filenames starting with a20dot are special cases that are not matched by '*' and '?'21patterns.2223If recursive is true, the pattern '**' will match any files and24zero or more directories and subdirectories.25"""26return list(iglob(pathname, recursive=recursive))272829def iglob(pathname, recursive=False):30"""Return an iterator which yields the paths matching a pathname pattern.3132The pattern may contain simple shell-style wildcards a la33fnmatch. However, unlike fnmatch, filenames starting with a34dot are special cases that are not matched by '*' and '?'35patterns.3637If recursive is true, the pattern '**' will match any files and38zero or more directories and subdirectories.39"""40it = _iglob(pathname, recursive)41if recursive and _isrecursive(pathname):42s = next(it) # skip empty string43assert not s44return it454647def _iglob(pathname, recursive):48dirname, basename = os.path.split(pathname)49glob_in_dir = glob2 if recursive and _isrecursive(basename) else glob15051if not has_magic(pathname):52if basename:53if os.path.lexists(pathname):54yield pathname55else:56# Patterns ending with a slash should match only directories57if os.path.isdir(dirname):58yield pathname59return6061if not dirname:62yield from glob_in_dir(dirname, basename)63return64# `os.path.split()` returns the argument itself as a dirname if it is a65# drive or UNC path. Prevent an infinite recursion if a drive or UNC path66# contains magic characters (i.e. r'\\?\C:').67if dirname != pathname and has_magic(dirname):68dirs = _iglob(dirname, recursive)69else:70dirs = [dirname]71if not has_magic(basename):72glob_in_dir = glob073for dirname in dirs:74for name in glob_in_dir(dirname, basename):75yield os.path.join(dirname, name)767778# These 2 helper functions non-recursively glob inside a literal directory.79# They return a list of basenames. `glob1` accepts a pattern while `glob0`80# takes a literal basename (so it only has to check for its existence).818283def glob1(dirname, pattern):84if not dirname:85if isinstance(pattern, bytes):86dirname = os.curdir.encode('ASCII')87else:88dirname = os.curdir89try:90names = os.listdir(dirname)91except OSError:92return []93return fnmatch.filter(names, pattern)949596def glob0(dirname, basename):97if not basename:98# `os.path.split()` returns an empty basename for paths ending with a99# directory separator. 'q*x/' should match only directories.100if os.path.isdir(dirname):101return [basename]102else:103if os.path.lexists(os.path.join(dirname, basename)):104return [basename]105return []106107108# This helper function recursively yields relative pathnames inside a literal109# directory.110111112def glob2(dirname, pattern):113assert _isrecursive(pattern)114yield pattern[:0]115for x in _rlistdir(dirname):116yield x117118119# Recursively yields relative pathnames inside a literal directory.120def _rlistdir(dirname):121if not dirname:122if isinstance(dirname, bytes):123dirname = os.curdir.encode('ASCII')124else:125dirname = os.curdir126try:127names = os.listdir(dirname)128except os.error:129return130for x in names:131yield x132path = os.path.join(dirname, x) if dirname else x133for y in _rlistdir(path):134yield os.path.join(x, y)135136137magic_check = re.compile('([*?[])')138magic_check_bytes = re.compile(b'([*?[])')139140141def has_magic(s):142if isinstance(s, bytes):143match = magic_check_bytes.search(s)144else:145match = magic_check.search(s)146return match is not None147148149def _isrecursive(pattern):150if isinstance(pattern, bytes):151return pattern == b'**'152else:153return pattern == '**'154155156def escape(pathname):157"""Escape all special characters.158"""159# Escaping is done by wrapping any of "*?[" between square brackets.160# Metacharacters do not work in the drive part and shouldn't be escaped.161drive, pathname = os.path.splitdrive(pathname)162if isinstance(pathname, bytes):163pathname = magic_check_bytes.sub(br'[\1]', pathname)164else:165pathname = magic_check.sub(r'[\1]', pathname)166return drive + pathname167168169