List package resource names without assuming filesystem paths

importlib.resources.files() returns a Traversable resource container, not a promise that a package is installed as an ordinary directory. That distinction matters because packages can be imported from mechanisms such as zip files. To list resource names, call files(package).iterdir() and work with each returned object's resource-oriented methods, including name and is_file().

This example creates a temporary package containing alpha.txt and beta.txt, imports it, and asks its resource container for direct children. The comprehension selects only text-file resources and sorts their names, so its output is deterministic: alpha.txt, beta.txt. The assertion checks the expected names for this controlled fixture.

The code deliberately does not convert a resource to pathlib.Path, call __file__, or construct a path relative to an installed package. Those approaches can couple an application to one installation layout. iterdir() is non-recursive, so nested resources require explicitly traversing child containers. Also, a package can expose Python source files and directories alongside intended data files; the suffix filter is an application policy, not proof that every matching file is safe or meaningful to consume. Validate names and content according to the package format before using them.

importlib.resources.files() was added in Python 3.9. AI assistance disclosure: this article was drafted with AI assistance.

See the official importlib.resources documentation.

import importlib
import importlib.resources as resources
import sys
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as directory:
    package_dir = Path(directory) / "demo_resources"
    package_dir.mkdir()
    (package_dir / "__init__.py").write_text("", encoding="utf-8")
    (package_dir / "alpha.txt").write_text("A", encoding="utf-8")
    (package_dir / "beta.txt").write_text("B", encoding="utf-8")

    sys.path.insert(0, directory)
    try:
        importlib.invalidate_caches()
        package = importlib.import_module("demo_resources")
        names = sorted(
            item.name
            for item in resources.files(package).iterdir()
            if item.is_file() and item.name.endswith(".txt")
        )
        assert names == ["alpha.txt", "beta.txt"]
        print(", ".join(names))
    finally:
        sys.path.remove(directory)
        sys.modules.pop("demo_resources", None)
alpha.txt, beta.txt

Comments

Popular posts from this blog

Compare Two Text Files in Python Without Modifying Them

Seven CSV Quality Checks to Run Before Importing Data

Explain why SQLite transactions cannot make an HTTP call atomic