Skip to content

profiles

profiles

Allowlist profile loading and composition.

Finds, reads, and merges .txt allowlist profiles from user and bundled directories. User profiles override bundled ones with the same name, so site-specific customisation works without forking.

ProfileLoader(*, user_dir, bundled_dir=None)

Loads and composes .txt allowlist profiles.

Searches user profiles first (overriding bundled), then falls back to the bundled profiles shipped with the package.

Create a profile loader.

Parameters:

Name Type Description Default
user_dir Path

User profiles directory (overrides bundled).

required
bundled_dir Path | None

Bundled profiles directory (auto-detected if None).

None
Source code in src/terok_shield/lib/profiles.py
def __init__(
    self,
    *,
    user_dir: Path,
    bundled_dir: Path | None = None,
) -> None:
    """Create a profile loader.

    Args:
        user_dir: User profiles directory (overrides bundled).
        bundled_dir: Bundled profiles directory (auto-detected if None).
    """
    self._user_dir = user_dir
    self._bundled_dir = bundled_dir or _bundled_dir()

load_profile(name)

Load a profile by name and return its entries.

User profiles take precedence over bundled profiles.

Raises:

Type Description
ValueError

If the name contains path separators or traversal.

FileNotFoundError

If the profile does not exist.

Source code in src/terok_shield/lib/profiles.py
def load_profile(self, name: str) -> list[str]:
    """Load a profile by name and return its entries.

    User profiles take precedence over bundled profiles.

    Raises:
        ValueError: If the name contains path separators or traversal.
        FileNotFoundError: If the profile does not exist.
    """
    path = self._find_profile(name)
    if path is None:
        raise FileNotFoundError(f"Profile not found: {name!r}")
    return _parse_entries(path.read_text())

compose_profiles(names)

Load and merge multiple profiles, deduplicating entries.

Preserves insertion order (first occurrence wins).

Raises:

Type Description
ValueError

If any name contains path separators or traversal.

FileNotFoundError

If any named profile does not exist.

Source code in src/terok_shield/lib/profiles.py
def compose_profiles(self, names: list[str]) -> list[str]:
    """Load and merge multiple profiles, deduplicating entries.

    Preserves insertion order (first occurrence wins).

    Raises:
        ValueError: If any name contains path separators or traversal.
        FileNotFoundError: If any named profile does not exist.
    """
    seen: set[str] = set()
    result: list[str] = []
    for name in names:
        for entry in self.load_profile(name):
            if entry not in seen:
                seen.add(entry)
                result.append(entry)
    return result

list_profiles()

List available profile names (bundled + user, deduplicated).

Source code in src/terok_shield/lib/profiles.py
def list_profiles(self) -> list[str]:
    """List available profile names (bundled + user, deduplicated)."""
    names: set[str] = set()
    for directory in (self._bundled_dir, self._user_dir):
        if directory.is_dir():
            names.update(f.stem for f in directory.glob("*.txt"))
    return sorted(names)