GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GH-73435: Add `pathlib.PurePath.full_match()` by barneygale · Pull Request #114350 · python/cpython

Conversation

@barneygale

@barneygale barneygale commented Jan 20, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

In #101398 we added support for the recursive wildcard ** in pathlib.PurePath.match(). This should allow arbitrary prefix and suffix matching, like p.match('foo/**') or p.match('**/foo'), but there's a problem: for relative patterns only, match() implicitly inserts a ** token on the left hand side, causing all patterns to match from the right. As a result, it's impossible to match relative patterns from the left: PurePath('foo/bar').match('bar/**') is true!

This PR reverts the changes to match(), and instead adds a new full_match() method that:

  • Allows empty patterns
  • Supports the recursive wildcard **
  • Matches the entire path when given a relative pattern

  • Issue: Support recursive wildcards in pathlib.PurePath.match() #73435

📚 Documentation preview 📚: https://cpython-previews--114350.org.readthedocs.build/en/114350/library/pathlib.html#pathlib.PurePath.globmatch

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@barneygale
pythonGH-73435: Add pathlib.PurePath.globmatch()
1c8bf81
In 49f90ba we added support for the recursive wildcard `**` in
`pathlib.PurePath.match()`. This should allow arbitrary prefix and suffix
matching, like `p.match('foo/**')` or `p.match('**/foo')`, but there's a
problem: for relative patterns only, `match()` implicitly inserts a `**`
token on the left hand side, causing all patterns to match from the right.
As a result, it's impossible to match relative patterns from the left:
`PurePath('foo/bar').match('bar/**')` is true!

This commit reverts the changes to `match()`, and instead adds a new
`globmatch()` method that:

- Supports the recursive wildcard `**`
- Matches the *entire* path when given a relative pattern

As a result, `globmatch()`'s pattern language exactly matches that of
`glob()`.
@barneygale barneygale added type-feature A feature request or enhancement topic-pathlib labels Jan 20, 2024
@barneygale
barneygale requested review from AlexWaygood, hugovk, jaraco and zooba January 20, 2024 18:51
@bedevere-app bedevere-app Bot added the awaiting core review label Jan 20, 2024
@bedevere-app bedevere-app Bot mentioned this pull request Jan 20, 2024
Support recursive wildcards in pathlib.PurePath.match() #73435
Closed
@barneygale
Simplify match() code slightly.
7f9222a
hugovk
hugovk reviewed Jan 20, 2024
View reviewed changes
Comment thread Doc/library/pathlib.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/pathlib/_abc.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@barneygale
Improve variable names
ed203e8
@zooba

zooba commented Jan 22, 2024

Copy link
Copy Markdown
Member

Does the problem extend beyond "** is allowed to match nothing"? Or can we change the existing algorithm to require that a trailing ** has to match at least one segment?

Presumably .match("foo\\*") has to find something after foo\, so would be a better version of "foo\\**" anyway, but I can't imagine anyone being happy that "foo\\**" matches "foo\\" - you wouldn't specify the ** if you didn't want something to be found there.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@barneygale

barneygale commented Jan 22, 2024

Copy link
Copy Markdown
Contributor Author

** matching nothing is quite normal I think - it's what glob.glob(), pathlib.Path.glob(), zsh, and IIRC bash do. If you want at least one segment after foo/, you can spell that with foo/**/*.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@barneygale

barneygale commented Jan 22, 2024

Copy link
Copy Markdown
Contributor Author

e.g. zsh man page:

A pathname component of the form '(foo/)#' matches a path consisting of zero or more directories matching the pattern foo.

As a shorthand, '**/' is equivalent to '(*/)#'; note that this therefore matches files in the current directory as well as subdirectories. Thus:

ls (*/)#bar

or

ls **/bar

does a recursive directory search for files named 'bar' (potentially including the file 'bar' in the current directory).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@zooba

zooba commented Jan 22, 2024

Copy link
Copy Markdown
Member

Okay, I definitely like having full in the name somewhere then. It's still a match, and the parallel is fullmatch is way more helpful than to glob (which would just raise questions about "how does match do its matching then?")

barneygale reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

barneygale added 2 commits January 22, 2024 22:49
@barneygale
globmatch --> full_match
aaa1ddb
@barneygale
Improve docstrings.
5c2ea0e
@barneygale barneygale changed the title GH-73435: Add pathlib.PurePath.globmatch() GH-73435: Add pathlib.PurePath.full_match() Jan 22, 2024
@barneygale
Note difference in empty pattern handling.
a5eaf81
zooba
zooba reviewed Jan 24, 2024
View reviewed changes

@zooba zooba left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/pathlib/_abc.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

@barneygale barneygale added the skip news label Jan 25, 2024
barneygale added 3 commits January 26, 2024 00:04
@barneygale
Double compiled pattern cache size
6fd7b01
@barneygale
Fix handling of empty paths and patterns.
2172b4d
@barneygale
Couple more test cases.
f60f147
@barneygale

barneygale commented Jan 26, 2024

Copy link
Copy Markdown
Contributor Author

Thanks for the reviews, both.

hugovk reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@barneygale
barneygale enabled auto-merge (squash) January 26, 2024 00:51
@barneygale
barneygale merged commit b69548a into python:main Jan 26, 2024
@bedevere-app bedevere-app Bot removed the awaiting core review label Jan 26, 2024
aisk pushed a commit to aisk/cpython that referenced this pull request Feb 11, 2024
@barneygale @aisk
pythonGH-73435: Add pathlib.PurePath.full_match() (python#114350)
3a7ecb0
In 49f90ba we added support for the recursive wildcard `**` in
`pathlib.PurePath.match()`. This should allow arbitrary prefix and suffix
matching, like `p.match('foo/**')` or `p.match('**/foo')`, but there's a
problem: for relative patterns only, `match()` implicitly inserts a `**`
token on the left hand side, causing all patterns to match from the right.
As a result, it's impossible to match relative patterns from the left:
`PurePath('foo/bar').match('bar/**')` is true!

This commit reverts the changes to `match()`, and instead adds a new
`full_match()` method that:

- Allows empty patterns
- Supports the recursive wildcard `**`
- Matches the *entire* path when given a relative pattern
Glyphack pushed a commit to Glyphack/cpython that referenced this pull request Sep 2, 2024
@barneygale @Glyphack
pythonGH-73435: Add pathlib.PurePath.full_match() (python#114350)
f7bece1
In 49f90ba we added support for the recursive wildcard `**` in
`pathlib.PurePath.match()`. This should allow arbitrary prefix and suffix
matching, like `p.match('foo/**')` or `p.match('**/foo')`, but there's a
problem: for relative patterns only, `match()` implicitly inserts a `**`
token on the left hand side, causing all patterns to match from the right.
As a result, it's impossible to match relative patterns from the left:
`PurePath('foo/bar').match('bar/**')` is true!

This commit reverts the changes to `match()`, and instead adds a new
`full_match()` method that:

- Allows empty patterns
- Supports the recursive wildcard `**`
- Matches the *entire* path when given a relative pattern
@barneygale barneygale mentioned this pull request Oct 10, 2025
GH-139282: Support recursive wildcard in pathlib.PurePath.match() #139311
Open
@coderabbitai coderabbitai Bot mentioned this pull request Apr 24, 2026
Add per-file ignores and update tags shelkesays/safelint#13
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@hugovk hugovk hugovk left review comments
@zooba zooba zooba left review comments
@jaraco jaraco Awaiting requested review from jaraco
@AlexWaygood AlexWaygood Awaiting requested review from AlexWaygood

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

skip news topic-pathlib type-feature A feature request or enhancement

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@barneygale @zooba @hugovk
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.