PYTHON 72
Glob.py Guest on 16th April 2021 11:35:27 AM
  1. """
  2. Filename globbing utility. Mostly a copy of `glob` from Python 3.5.
  3.  
  4. Changes include:
  5. * `yield from` and PEP3102 `*` removed.
  6. * Hidden files are not ignored.
  7. """
  8.  
  9. import os
  10. import re
  11. import fnmatch
  12.  
  13. __all__ = ["glob", "iglob", "escape"]
  14.  
  15.  
  16. def glob(pathname, recursive=False):
  17.     """Return a list of paths matching a pathname pattern.
  18.  
  19.    The pattern may contain simple shell-style wildcards a la
  20.    fnmatch. However, unlike fnmatch, filenames starting with a
  21.    dot are special cases that are not matched by '*' and '?'
  22.    patterns.
  23.  
  24.    If recursive is true, the pattern '**' will match any files and
  25.    zero or more directories and subdirectories.
  26.    """
  27.     return list(iglob(pathname, recursive=recursive))
  28.  
  29.  
  30. def iglob(pathname, recursive=False):
  31.     """Return an iterator which yields the paths matching a pathname pattern.
  32.  
  33.    The pattern may contain simple shell-style wildcards a la
  34.    fnmatch. However, unlike fnmatch, filenames starting with a
  35.    dot are special cases that are not matched by '*' and '?'
  36.    patterns.
  37.  
  38.    If recursive is true, the pattern '**' will match any files and
  39.    zero or more directories and subdirectories.
  40.    """
  41.     it = _iglob(pathname, recursive)
  42.     if recursive and _isrecursive(pathname):
  43.         s = next(it)  # skip empty string
  44.         assert not s
  45.     return it
  46.  
  47.  
  48. def _iglob(pathname, recursive):
  49.     dirname, basename = os.path.split(pathname)
  50.     if not has_magic(pathname):
  51.         if basename:
  52.             if os.path.lexists(pathname):
  53.                 yield pathname
  54.         else:
  55.             # Patterns ending with a slash should match only directories
  56.             if os.path.isdir(dirname):
  57.                 yield pathname
  58.         return
  59.     if not dirname:
  60.         if recursive and _isrecursive(basename):
  61.             for x in glob2(dirname, basename):
  62.                 yield x
  63.         else:
  64.             for x in glob1(dirname, basename):
  65.                 yield x
  66.         return
  67.     # `os.path.split()` returns the argument itself as a dirname if it is a
  68.     # drive or UNC path.  Prevent an infinite recursion if a drive or UNC path
  69.     # contains magic characters (i.e. r'\\?\C:').
  70.     if dirname != pathname and has_magic(dirname):
  71.         dirs = _iglob(dirname, recursive)
  72.     else:
  73.         dirs = [dirname]
  74.     if has_magic(basename):
  75.         if recursive and _isrecursive(basename):
  76.             glob_in_dir = glob2
  77.         else:
  78.             glob_in_dir = glob1
  79.     else:
  80.         glob_in_dir = glob0
  81.     for dirname in dirs:
  82.         for name in glob_in_dir(dirname, basename):
  83.             yield os.path.join(dirname, name)
  84.  
  85.  
  86. # These 2 helper functions non-recursively glob inside a literal directory.
  87. # They return a list of basenames. `glob1` accepts a pattern while `glob0`
  88. # takes a literal basename (so it only has to check for its existence).
  89.  
  90.  
  91. def glob1(dirname, pattern):
  92.     if not dirname:
  93.         if isinstance(pattern, bytes):
  94.             dirname = os.curdir.encode('ASCII')
  95.         else:
  96.             dirname = os.curdir
  97.     try:
  98.         names = os.listdir(dirname)
  99.     except OSError:
  100.         return []
  101.     return fnmatch.filter(names, pattern)
  102.  
  103.  
  104. def glob0(dirname, basename):
  105.     if not basename:
  106.         # `os.path.split()` returns an empty basename for paths ending with a
  107.         # directory separator.  'q*x/' should match only directories.
  108.         if os.path.isdir(dirname):
  109.             return [basename]
  110.     else:
  111.         if os.path.lexists(os.path.join(dirname, basename)):
  112.             return [basename]
  113.     return []
  114.  
  115.  
  116. # This helper function recursively yields relative pathnames inside a literal
  117. # directory.
  118.  
  119.  
  120. def glob2(dirname, pattern):
  121.     assert _isrecursive(pattern)
  122.     yield pattern[:0]
  123.     for x in _rlistdir(dirname):
  124.         yield x
  125.  
  126.  
  127. # Recursively yields relative pathnames inside a literal directory.
  128. def _rlistdir(dirname):
  129.     if not dirname:
  130.         if isinstance(dirname, bytes):
  131.             dirname = os.curdir.encode('ASCII')
  132.         else:
  133.             dirname = os.curdir
  134.     try:
  135.         names = os.listdir(dirname)
  136.     except os.error:
  137.         return
  138.     for x in names:
  139.         yield x
  140.         path = os.path.join(dirname, x) if dirname else x
  141.         for y in _rlistdir(path):
  142.             yield os.path.join(x, y)
  143.  
  144.  
  145. magic_check = re.compile('([*?[])')
  146. magic_check_bytes = re.compile(b'([*?[])')
  147.  
  148.  
  149. def has_magic(s):
  150.     if isinstance(s, bytes):
  151.         match = magic_check_bytes.search(s)
  152.     else:
  153.         match = magic_check.search(s)
  154.     return match is not None
  155.  
  156.  
  157. def _isrecursive(pattern):
  158.     if isinstance(pattern, bytes):
  159.         return pattern == b'**'
  160.     else:
  161.         return pattern == '**'
  162.  
  163.  
  164. def escape(pathname):
  165.     """Escape all special characters.
  166.    """
  167.     # Escaping is done by wrapping any of "*?[" between square brackets.
  168.     # Metacharacters do not work in the drive part and shouldn't be escaped.
  169.     drive, pathname = os.path.splitdrive(pathname)
  170.     if isinstance(pathname, bytes):
  171.         pathname = magic_check_bytes.sub(br'[\1]', pathname)
  172.     else:
  173.         pathname = magic_check.sub(r'[\1]', pathname)
  174.     return drive + pathname

Paste-bin is for source code and general debugging text.

Login or Register to edit, delete and keep track of your pastes and more.

Raw Paste

Login or Register to edit or fork this paste. It's free.