The resources system provides unified access to static files (templates, icons, configs, etc.) that work identically in development and PyInstaller-bundled executables. Using importlib.resources, it abstracts away environment-specific path resolution.
Resources are static files bundled with your Python package. They’re accessible whether your code is running from source files or a PyInstaller executable.
When distributing Python applications as executables, traditional file access breaks:
# ❌ Breaks in PyInstaller executableswith open("templates/config.json") as f: config = json.load(f)# ❌ Also breaks - relies on __file__ which may not existmodule_dir = Path(__file__).parenttemplate_path = module_dir / "templates" / "email.html"
With resources:
# ✓ Works in development AND executablesfrom pyrig.src.resource import resource_pathimport myapp.templatestemplate_path = resource_path("email.html", myapp.templates)with open(template_path) as f: template = f.read()
Pyrig provides a single function for resource access:
src/resource.py
def resource_path(name: str, package: ModuleType) -> Path: """Get filesystem path to a resource file within a package. Provides cross-platform, environment-agnostic access to static resources bundled with Python packages. Args: name: Resource filename (e.g., "config.json", "icon.png"). Can include subdirectory paths relative to the package (e.g., "templates/email.html"). package: Package module object containing the resource. Import the package's __init__.py module and pass it directly. Returns: Absolute path to the resource file. Example: >>> from pyrig import resources >>> path = resource_path("GITIGNORE", resources) >>> content = path.read_text() """ resource_path = files(package) / name with as_file(resource_path) as path: return path
from pyrig.src.resource import resource_pathimport myapp.resourcesimport myapp.resources.templates# Get resource pathsicon_path = resource_path("icon.png", myapp.resources)config_path = resource_path("config.json", myapp.resources)template_path = resource_path("email.html", myapp.resources.templates)# Use the pathswith open(config_path) as f: config = json.load(f)with open(template_path) as f: template = f.read()image = Image.open(icon_path)
The returned path is valid immediately and remains valid after the function returns (for file-based packages, which is always the case for pyrig projects).
# ❌ Breaks when installed or movedconfig_path = Path("/home/user/myapp/config.json")# ✓ Works regardless of installation locationconfig_path = resource_path("config.json", myapp.resources)
from pathlib import Pathimport jsonfrom pyrig.src.resource import resource_pathimport myapp.resourcesdef load_default_config() -> dict: """Load default configuration from resources.""" config_path = resource_path("config.json", myapp.resources) with open(config_path) as f: return json.load(f)def load_user_config() -> dict: """Load user configuration, falling back to default.""" user_config_path = Path.home() / ".myapp" / "config.json" if user_config_path.exists(): with open(user_config_path) as f: return json.load(f) # Fall back to default from resources return load_default_config()