Skip to main content

Lib/pathlib/ (part 3)

Source:

cpython 3.14 @ ab2d84fe1023/Lib/pathlib/_local.py

This annotation covers filesystem traversal and metadata. See lib_pathlib2_detail for Path.open, Path.read_text, Path.write_bytes, Path.mkdir, and Path.unlink.

Map

LinesSymbolRole
1-100Path.globMatch files using a shell glob pattern
101-220Path.rglobRecursive glob: ** prefix
221-360Path.walkos.walk-style bottom-up/top-down traversal
361-480Path.stat / Path.lstatGet file metadata
481-600Path.chmod / Path.symlink_toPermissions and symlink creation

Reading

Path.glob

# CPython: Lib/pathlib/_local.py:680 Path.glob
def glob(self, pattern, *, case_sensitive=None, recurse_symlinks=False):
"""Yield all matching paths."""
if not pattern:
raise ValueError("Unacceptable pattern: {!r}".format(pattern))
drv, root, pattern_parts = self._flavour.parse_parts((pattern,))
if not pattern_parts:
raise ValueError("Unacceptable pattern: {!r}".format(pattern))
raw = pattern_parts[-1]
if raw == '**':
raise ValueError("Invalid pattern: '**' can only be a path component")
selector = _make_selector(tuple(pattern_parts), self._flavour, case_sensitive)
for p in selector.select_from(self):
yield p

path.glob('*.py') uses a _WildcardSelector that calls os.scandir. The ** pattern uses _RecursiveWildcardSelector. case_sensitive controls whether the comparison is case-folded.

Path.walk

# CPython: Lib/pathlib/_local.py:820 Path.walk
def walk(self, top_down=True, on_error=None, follow_symlinks=False):
"""Walk directory tree. Yields (dirpath, dirnames, filenames)."""
paths = [self]
while paths:
path = paths.pop()
if isinstance(path, tuple):
yield path
continue
try:
with os.scandir(path) as scandir_it:
dirnames = []
filenames = []
for entry in scandir_it:
if entry.is_dir(follow_symlinks=follow_symlinks):
dirnames.append(entry.name)
else:
filenames.append(entry.name)
except OSError as e:
if on_error is not None: on_error(e)
continue
if top_down:
yield path, dirnames, filenames
paths += [path / d for d in reversed(dirnames)]
else:
paths += [(path, dirnames, filenames)]
paths += [path / d for d in reversed(dirnames)]

Path.walk uses an explicit stack instead of recursion to avoid RecursionError for deeply nested directories. The top_down=False mode defers the yield until after children are processed.

Path.stat

# CPython: Lib/pathlib/_local.py:420 Path.stat
def stat(self, *, follow_symlinks=True):
"""Return os.stat_result for this path."""
return os.stat(self, follow_symlinks=follow_symlinks)

p.stat().st_size returns the file size. p.lstat() calls os.stat(follow_symlinks=False) to inspect the symlink itself. The returned os.stat_result has .st_mode, .st_size, .st_mtime, etc.

gopy notes

Path.glob is module/pathlib.Path.Glob in module/pathlib/module.go. Pattern matching uses Go's path/filepath.Match. Path.rglob uses filepath.WalkDir. Path.walk uses an explicit stack with os.ReadDir. Path.stat calls os.Stat or os.Lstat.