| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
If a sequence of path separators is given to the new argument, `translate()` produces a pattern that matches similarly to `pathlib.Path.glob()`. Specifically: - A `*` pattern segment matches precisely one path segment. - A `**` pattern segment matches any number of path segments - If `**` appears in any other position within the pattern, `ValueError` is raised. - `*` and `?` wildcards in other positions don't match path separators. This change allows us to factor out a lot of complex code in pathlib.
|
~20% globbing speedup: $ ./python -m timeit -s 'from pathlib import Path; p = Path()' 'list(p.glob("**/*", follow_symlinks=False))'
2 loops, best of 5: 175 msec per loop # before
2 loops, best of 5: 146 msec per loop # after |
Sorry, something went wrong.
Co-authored-by: Jason R. Coombs <jaraco@jaraco.com>
|
I've moved this to a new glob.translate() function. It was easy enough to implement a recursive argument, so I did that and made its default False to match glob(). It's much harder to implement an include_hidden argument, so I've left that for now. I don't feel great about it, tbh. |
Sorry, something went wrong.
|
Right, after some futzing around I'm going to mark this PR as ready again. In fnmatch.py, I've split the translate() method into _translate() and _join_translated_parts(). This minimises the diff, risk, and performance impact in that module. (In #109879 I've re-implemented fnmatch.translate(), but that PR is an optional side-quest now) In glob.py, I've spent some time making the implementation of translate(include_hidden=False) as clear and performant as I can. There's still a fair whack of regex involved but I think it's followable. In pathlib.py, I've made pattern matching use str(path) directly, rather than a slight variant that represents empty paths as '' rather than '.'. |
Sorry, something went wrong.
|
Timings: $ ./python -m timeit -n 5 -s 'from glob import glob' 'list(glob("**/*", recursive=True, include_hidden=True))'
5 loops, best of 5: 105 msec per loop # for interest
$ ./python -m timeit -n 5 -s 'from pathlib import Path; p = Path()' 'list(p.glob("**/*", follow_symlinks=True))'
5 loops, best of 5: 86.6 msec per loop # before
5 loops, best of 5: 72.7 msec per loop # after
So Path.glob() is ~20% faster than before, and ~45% faster than glob.glob(), at least for this test case. |
Sorry, something went wrong.
There was a problem hiding this comment.
A desk review:
A
Sorry, something went wrong.
Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
|
I've realised that the docs are a bit skew-whiff. Fix is in a separate PR: #110418 |
Sorry, something went wrong.
|
Is it correct to keep duplicated path separators? >>> glob.translate('a//b')
'(?s:a//b)\\Z' |
Sorry, something went wrong.
glob() keeps them: >>> os.makedirs('a/b')
>>> glob.glob('a//b')
['a//b']So I reckon yes? |
Sorry, something went wrong.
|
Also, the number of additional slashes is meaningful in some cases, e.g. in Windows UNC paths or POSIX paths starting with two forward slashes. I don't think a pattern like /foo should match a path like //foo, and vice-versa. |
Sorry, something went wrong.
|
Hey @encukou, do you think I can merge this, or should I wait for a more complete review from someone? |
Sorry, something went wrong.
|
Oh, I should have been more clear that I wouldn't get to a thorough review in any reasonable time. |
Sorry, something went wrong.
Add `glob.translate()` function that converts a pathname with shell wildcards to a regular expression. The regular expression is used by pathlib to implement `match()` and `glob()`. This function differs from `fnmatch.translate()` in that wildcards do not match path separators by default, and that a `*` pattern segment matches precisely one path segment. When *recursive* is set to true, `**` pattern segments match any number of path segments, and `**` cannot appear outside its own segment. In pathlib, this change speeds up directory walking (because `_make_child_relpath()` does less work), makes path objects smaller (they don't need a `_lines` slot), and removes the need for some gnarly code. Co-authored-by: Jason R. Coombs <jaraco@jaraco.com> Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
Add `glob.translate()` function that converts a pathname with shell wildcards to a regular expression. The regular expression is used by pathlib to implement `match()` and `glob()`. This function differs from `fnmatch.translate()` in that wildcards do not match path separators by default, and that a `*` pattern segment matches precisely one path segment. When *recursive* is set to true, `**` pattern segments match any number of path segments, and `**` cannot appear outside its own segment. In pathlib, this change speeds up directory walking (because `_make_child_relpath()` does less work), makes path objects smaller (they don't need a `_lines` slot), and removes the need for some gnarly code. Co-authored-by: Jason R. Coombs <jaraco@jaraco.com> Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com>
| Back | FazBrowse Home | New Git URL |
Add glob.translate() function that converts a pathname with shell wildcards to a regular expression. The regular expression is used by pathlib to implement match() and glob().
This function differs from fnmatch.translate() in that wildcards do not match path separators by default, and that a * pattern segment matches precisely one path segment. When recursive is set to true, ** pattern segments match any number of path segments, and ** cannot appear outside its own segment.
In pathlib, this change speeds up directory walking (because _make_child_relpath() does less work), makes path objects smaller (they don't need a _lines slot), and removes the need for some gnarly code.
📚 Documentation preview 📚: https://cpython-previews--106703.org.readthedocs.build/