PurePath.full_match checks whether an entire path matches a glob-style pattern. It is useful when an application must validate filenames, directory structures, extensions, or logical paths without touching the file system. Because the method evaluates the whole path, it avoids partial matches that can make filters too permissive.
This guide explains the method, its pattern syntax, the difference from match, case sensitivity, cross-platform behavior, testing, upload validation, and production design.
What PurePath.full_match does
PurePath models a path logically. It does not check whether the path exists, so it is ideal for parsers, APIs, tests, manifests, archives, and user-provided values.
from pathlib import PurePath
path = PurePath("data/2026/report.csv")
print(path.full_match("data/**/*.csv"))
The result is true because the pattern describes the complete path. No directory is opened and no file metadata is read.
Why complete matching matters
A suffix check such as endswith('.csv') confirms an extension but says nothing about the directory. A regular expression can describe both, but usually requires more escaping and platform-specific handling. A glob pattern is often clearer.
from pathlib import PurePath
values = [
PurePath("input/customers.csv"),
PurePath("input/2026/sales.csv"),
PurePath("backup/sales.csv"),
]
for item in values:
if item.full_match("input/**/*.csv"):
print("accepted:", item)
Only paths that satisfy the complete structure are accepted. This is valuable in import jobs, upload processors, build systems, and command-line tools.
Glob pattern essentials
A single asterisk matches characters within one path component. A question mark matches one character. Bracket expressions describe sets or ranges. A double asterisk can span directory levels.
from pathlib import PurePath
examples = [
("logs/app.log", "logs/*.log"),
("img/photo1.png", "img/photo?.png"),
("data/a.csv", "data/[ab].csv"),
("src/pkg/module.py", "src/**/*.py"),
]
for value, pattern in examples:
print(value, PurePath(value).full_match(pattern))
Keeping path rules in glob form makes them easy to review and change.
full_match versus match
PurePath.match has historical behavior that can evaluate relative patterns from the right side of a path. That is useful for broad searches, but it may be surprising when a security or business rule must validate the complete input. full_match communicates that stricter intention.
from pathlib import PurePath
p = PurePath("project/src/app.py")
print(p.match("src/*.py"))
print(p.full_match("src/*.py"))
print(p.full_match("project/src/*.py"))
Use full_match when the pattern is a contract for the whole value. Use match when suffix-oriented behavior is desired or required for compatibility.
Case sensitivity
The optional case_sensitive argument lets you make behavior explicit. When omitted, the default follows the path family. POSIX paths are generally case-sensitive, while Windows paths generally are not.
from pathlib import PurePosixPath
path = PurePosixPath("Images/Photo.PNG")
print(path.full_match("images/*.png"))
print(path.full_match("images/*.png", case_sensitive=False))
Explicit case rules prevent test suites from behaving differently on Linux and Windows.
POSIX and Windows path families
You can analyze paths for a platform other than the current operating system. PurePosixPath understands forward-slash paths. PureWindowsPath understands drives, backslashes, and Windows conventions.
from pathlib import PurePosixPath, PureWindowsPath
web = PurePosixPath("assets/css/site.css")
win = PureWindowsPath(r"C:\Projects\app\main.py")
print(web.full_match("assets/**/*.css"))
print(win.full_match(r"C:\Projects\**\*.py"))
This is useful for remote manifests, archive entries, deployment files, and cross-platform build metadata.
Upload validation
Complete path matching can be one layer in an upload policy. It does not replace MIME inspection, size limits, malware scanning, or safe destination handling, but it can restrict accepted logical locations and extensions.
from pathlib import PurePosixPath
PATTERN = "uploads/**/*.csv"
def allowed(value: str) -> bool:
path = PurePosixPath(value)
return path.full_match(PATTERN, case_sensitive=False)
Also reject parent-directory components and resolve final destinations safely. For broader path handling, read Python pathlib.Path.walk.
Classification pipelines
A dictionary of patterns can classify artifacts without deeply nested conditionals.
from pathlib import PurePath
RULES = {
"incoming": "data/incoming/**/*.json",
"processed": "data/processed/**/*.parquet",
"log": "logs/**/*.log",
}
def classify(value: str) -> str | None:
path = PurePath(value)
for name, pattern in RULES.items():
if path.full_match(pattern, case_sensitive=False):
return name
return None
This design works well with directory traversal from Python os.fwalk and packaged tools described in Python zipapp.
Common mistakes
The first mistake is forgetting that the method matches the complete path. A pattern such as *.py may not describe a path containing directories. Add an explicit prefix or use **/*.py when multiple levels are allowed.
The second mistake is mixing path separators and semantics. Use the correct pure path class for the data being analyzed.
The third mistake is treating a glob match as a complete security boundary. It validates shape, not file contents or permissions.
Automated tests
Pure paths make tests fast because no temporary directory is required.
from pathlib import PurePosixPath
def allowed(value: str) -> bool:
return PurePosixPath(value).full_match(
"reports/**/*.csv",
case_sensitive=False,
)
def test_valid():
assert allowed("reports/2026/january.csv")
def test_bad_extension():
assert not allowed("reports/2026/january.exe")
def test_bad_directory():
assert not allowed("private/january.csv")
For stronger interfaces, see Python typing.override and Python dataclasses.KW_ONLY.
Version compatibility
Check the minimum Python version supported by your project before adopting a recent API. If older environments must remain supported, hide the operation behind a small adapter and test the fallback separately.
from pathlib import PurePath
def matches(path: str, pattern: str) -> bool:
obj = PurePath(path)
method = getattr(obj, "full_match", None)
if method is None:
raise RuntimeError("PurePath.full_match is unavailable")
return method(pattern)
Use the official pathlib documentation as the primary reference and the fnmatch documentation for pattern concepts.
Design recommendations
Keep patterns centralized, name them according to business intent, and add positive and negative examples to tests. Make case behavior explicit when rules must be portable. Convert incoming values to a known path family instead of relying on the host platform. Log rejected paths carefully without exposing private directory information.
When patterns become too broad, split one rule into several named rules. This is easier to audit than a single complex expression. When the rule depends on file metadata or content, perform those checks after the logical path has passed the first filter.
Conclusion
PurePath.full_match is a readable way to verify that an entire logical path follows a glob pattern. It avoids fragile string comparisons, requires no disk access, supports explicit case behavior, and works with POSIX or Windows semantics.
Use it for path contracts, artifact classification, upload rules, build systems, and testable cross-platform filters. Keep patterns specific and combine them with content, permission, and destination checks whenever input is untrusted.







