PurePath.full_match: Validate Paths with Glob Patterns

Published on: September 15, 2026
Reading time: 4 minutes
Code and file paths for Python PurePath.full_match

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.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Asynchronous Python code representing asyncio.eager_task_factory
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    asyncio.eager_task_factory: Reduce Task Overhead

    Learn Python asyncio.eager_task_factory to reduce scheduling overhead, understand ordering changes, and optimize short coroutines safely.

    Ler mais

    Tempo de leitura: 4 minutos
    14/09/2026
    Developer working with UTC timestamps and Python calendar.timegm
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    calendar.timegm: Convert UTC to Unix Timestamps

    Learn Python calendar.timegm to convert UTC date tuples into Unix timestamps safely and avoid local-time conversion bugs.

    Ler mais

    Tempo de leitura: 5 minutos
    14/09/2026
    Programmer analyzing code to identify file MIME types with Python
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    mimetypes.guess_file_type: Detect MIME Types

    Learn Python mimetypes.guess_file_type for MIME detection in paths, URLs, uploads, and HTTP responses with safe fallbacks.

    Ler mais

    Tempo de leitura: 5 minutos
    13/09/2026
    Server components representing isolated Python interpreters running in parallel
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    InterpreterPoolExecutor: True Parallelism in Python

    Learn Python InterpreterPoolExecutor for CPU-bound tasks, isolated interpreters, true parallelism, and safer concurrency design.

    Ler mais

    Tempo de leitura: 6 minutos
    13/09/2026
    Microprocessor representing CPUs available to a Python process
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    os.process_cpu_count: Count Available CPUs

    Learn Python os.process_cpu_count to size workers according to the CPUs actually available to the process.

    Ler mais

    Tempo de leitura: 4 minutos
    12/09/2026
    Laptop with digital code representing SQLite BLOB data
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    sqlite3.Blob: Incremental BLOB Reads and Writes

    Learn Python sqlite3.Blob for incremental BLOB reads and writes, lower memory use, and safer binary data handling in SQLite.

    Ler mais

    Tempo de leitura: 5 minutos
    12/09/2026