How to take a pathname string with wildcards and resolve the glob with pathlib? How to take a pathname string with wildcards and resolve the glob with pathlib? python-3.x python-3.x

How to take a pathname string with wildcards and resolve the glob with pathlib?


If you're starting from the string "~/pythoncode/*.py" and you'd like to expand and glob, you will need to split the path first. Luckily pathlib provides .name and .parent to help you out:

def expandpath(path_pattern) -> Iterable[Path]:    p = Path(path_pattern)    return Path(p.parent).expanduser().glob(p.name)expandpath("~/pythonpath/*.py")

Note this simple solution will only work when only the name includes a glob, it will not work with globs in other parts of the path, like: ~/python*/*.py. A more general solution that is a bit more complex:

def expandpath(path_pattern) -> Iterable[Path]:    p = Path(path_pattern).expanduser()    parts = p.parts[p.is_absolute():]    return Path(p.root).glob(str(Path(*parts)))expandpath("~/python*/*.py")

note-2: the above function fails (IndexError: tuple index out of range) with these degenerate paths: '', '.', '/'


pathlib.Path.glob does not support absolute (non-relative) path patterns, but glob.glob does:

from glob import globfrom pathlib import Pathpaths = [Path(p) for p in glob('/foo/*/bar')]

Or in connection with Path.expanduser:

paths = [Path(p) for p in glob(str(Path('~/.bash*').expanduser()))]


I found that I really wanted the inline expansion. It wasn't as easy as I thought it'd be.

Anyhow, here's what I've got. Only trivialy tested, but let me know where it falls down for you and I'll edit it.

def expand_pathglobs(pathparts, basepaths=None):    # Logic:    # 0. Argue with a Path(str).parts and optional ['/start','/dirs'].    # 1. for each basepath, expand out pathparts[0] into "expandedpaths"    # 2. If there are no more pathparts, expandedpaths is the result.    # 3. Otherwise, recurse with expandedpaths and the remaining pathparts.    # eg: expand_pathglobs('/tmp/a*/b*')    #   --> /tmp/a1/b1    #   --> /tmp/a2/b2    if isinstance(pathparts, str) or isinstance(pathparts, Path):        pathparts = Path(pathparts).parts    if basepaths == None:        return expand_pathglobs(pathparts[1:], [Path(pathparts[0])])    else:        assert pathparts[0] != '/'    expandedpaths = []    for p in basepaths:        assert isinstance(p, Path)        globs = p.glob(pathparts[0])        for g in globs:            expandedpaths.append(g)    if len(pathparts) > 1:        return expand_pathglobs(pathparts[1:], expandedpaths)    return expandedpaths