Migrating to 2.0¶
rglob 2.0 is a top-to-bottom modernization (see the
roadmap). The vast majority of changes are
additive — new helpers, new CLI flags, better docs. One intentional
breaking change is worth calling out:
The breaking change: list[Path] return type¶
rglob() and rglob_() now return list[pathlib.Path] instead of
list[str]. The new find() / find_all() family already returns Path,
so code that already migrated to them is unaffected.
One-line migration¶
- paths: list[str] = rglob("/repo", "*.py")
+ paths: list[Path] = rglob("/repo", "*.py") # if you want Path
+ paths: list[str] = [str(p) for p in rglob("/repo", "*.py")] # if you want str
Why this changes¶
- Modern Python (
pathlib.Path,os.PathLike,mypystrict mode) is much nicer to use withPathinstances than raw strings. - The Phase 3 walker rewrite is on
os.scandir, which natively producesPath-compatible entries. - Downstream filters introduced in Phase 5 (
--gitignore,min_size,kinds=...) wantPathsemantics anyway.
See ADR-0003 for the full reasoning.
Other changes worth knowing¶
These are not breaking, but they are new defaults you might encounter:
Sorted output¶
rglob() and find() now sort entries by default (the 1.x walker
documented its output as "not guaranteed sorted"). Pass sort=False to opt
out:
paths = rglob.find_all("/repo", "*.py", sort=False)
Python floor: 3.11¶
rglob 2.0 requires Python 3.11+ (3.10 reaches upstream EOL in October
2026; see ADR-0002). Pin rglob<2 if you
need 3.10 support:
rglob<2; python_version<"3.11"
rglob>=2; python_version>="3.11"
** patterns now work¶
The 1.x README explicitly disclaimed ** support
("**/*.py" is not supported here). The 2.0 walker handles ** natively:
rglob.find_all("/repo", "**/*.py")
Symlink handling is opt-in¶
By default, the walker does not follow symbolic links. Pass
follow_symlinks=True to opt in; cycles are terminated automatically via a
realpath memo. See ADR-0008.
Hidden files are skipped by default¶
Dotfiles and dot-directories are skipped unless you pass hidden=True.
Doing a clean upgrade¶
- Bump your pin to
rglob>=2,<3. - Run your test suite — type checkers will flag any
list[str]callers. - Apply the
str(p)wrap where you really need strings, or migrate toPathsemantics. - Adopt
find()/find_all()for new code — they have the full filter suite (exclude,max_depth,hidden,kinds,min_size, etc.).
If you hit anything surprising, please file an issue at https://github.com/chris-piekarski/python-rglob/issues.