Skip to content

settings

settings #

The scratch's size budget, kept in settings.toml beside the objects.

Settings dataclass #

How much disk the cache may claim.

Attributes:

Name Type Description
max_size_gb float | None

A hard cap on the cache's bytes, in gigabytes; None is no cap.

free_space_ratio float

The fraction of releasable disk (free space plus the cache itself) the cache may occupy.

Source code in capturegraph-lib/capturegraph/recipes/scratch/settings.py
@dataclass(frozen=True, slots=True)
class Settings:
    """How much disk the cache may claim.

    Attributes:
        max_size_gb: A hard cap on the cache's bytes, in gigabytes; ``None`` is no cap.
        free_space_ratio: The fraction of releasable disk (free space plus the
            cache itself) the cache may occupy.
    """

    max_size_gb: float | None = None
    free_space_ratio: float = 0.5

    @classmethod
    def load_or_create(
        cls,
        root: Path,
        *,
        max_size_gb: float | None = None,
        free_space_ratio: float | None = None,
    ) -> Settings:
        """The settings under ``root``, overrides applied and persisted; a template if absent."""
        path = root / FILENAME
        if path.exists():
            stored = cls._parse(path)
        else:
            path.write_text(_TEMPLATE)
            stored = cls()
        overrides = {
            key: value
            for key, value in (("max_size_gb", max_size_gb), ("free_space_ratio", free_space_ratio))
            if value is not None
        }
        effective = replace(stored, **overrides)
        if effective != stored:
            path.write_text(effective._render())
        return effective

    def budget_bytes(self, available_bytes: int, cache_bytes: int) -> int:
        """The bytes the cache may hold given the disk's free space and its own size."""
        budget = max(self.free_space_ratio, 0.0) * (available_bytes + cache_bytes)
        if self.max_size_gb is not None:
            budget = min(budget, max(self.max_size_gb, 0.0) * BYTES_PER_GB)
        return int(max(budget, 0.0))

    @classmethod
    def _parse(cls, path: Path) -> Settings:
        try:
            data = tomllib.loads(path.read_text())
            return cls(
                max_size_gb=None if data.get("max_size_gb") is None else float(data["max_size_gb"]),
                free_space_ratio=float(data.get("free_space_ratio", cls.free_space_ratio)),
            )
        except (tomllib.TOMLDecodeError, TypeError, ValueError) as error:
            logger.warning(f"ignoring unreadable {path}: {error}")
            return cls()

    def _render(self) -> str:
        cap = (
            f"max_size_gb = {self.max_size_gb}"
            if self.max_size_gb is not None
            else "# max_size_gb = 50.0"
        )
        return (
            f"# CaptureGraph scratch settings\n{cap}\nfree_space_ratio = {self.free_space_ratio}\n"
        )

budget_bytes(available_bytes, cache_bytes) #

The bytes the cache may hold given the disk's free space and its own size.

Source code in capturegraph-lib/capturegraph/recipes/scratch/settings.py
def budget_bytes(self, available_bytes: int, cache_bytes: int) -> int:
    """The bytes the cache may hold given the disk's free space and its own size."""
    budget = max(self.free_space_ratio, 0.0) * (available_bytes + cache_bytes)
    if self.max_size_gb is not None:
        budget = min(budget, max(self.max_size_gb, 0.0) * BYTES_PER_GB)
    return int(max(budget, 0.0))

load_or_create(root, *, max_size_gb=None, free_space_ratio=None) classmethod #

The settings under root, overrides applied and persisted; a template if absent.

Source code in capturegraph-lib/capturegraph/recipes/scratch/settings.py
@classmethod
def load_or_create(
    cls,
    root: Path,
    *,
    max_size_gb: float | None = None,
    free_space_ratio: float | None = None,
) -> Settings:
    """The settings under ``root``, overrides applied and persisted; a template if absent."""
    path = root / FILENAME
    if path.exists():
        stored = cls._parse(path)
    else:
        path.write_text(_TEMPLATE)
        stored = cls()
    overrides = {
        key: value
        for key, value in (("max_size_gb", max_size_gb), ("free_space_ratio", free_space_ratio))
        if value is not None
    }
    effective = replace(stored, **overrides)
    if effective != stored:
        path.write_text(effective._render())
    return effective