Skip to content

cache

Private Methods

Private methods, if any (those starting with _), are documented for completeness but do not offer any stability guarantees. They may change or be removed at any time without notice.

Polytropos cache management.

This module handles the Polytropos cache directory, including cleanup of stale editable symlinks and full cache eviction via gc.

Defaults to /var/cache/polytropos/ when the process has write access to it, $XDG_CACHE_HOME/polytropos/ otherwise, or ~/.cache/polytropos/ as fallback.

Remove broken symlinks and empty dirs from the editable cache base.

Source code in src/polytropos/cache.py
def _cleanup_stale_symlinks(cache_base: Path) -> None:
    """Remove broken symlinks and empty dirs from the editable cache base."""
    for entry in cache_base.iterdir():
        if not entry.is_dir() or entry.name.startswith("."):
            continue
        addons_dir = entry / "odoo" / "addons"
        if not addons_dir.is_dir():
            continue
        for file in addons_dir.iterdir():
            if file.is_symlink() and not file.exists():
                shutil.rmtree(entry)
                break

_get_editable_cache_base()

Get the base directory for editable install symlinks.

Resolution order: 1. POLYTROPOS_CACHE_DIR/editable/ (if POLYTROPOS_CACHE_DIR is set) 2. /var/cache/polytropos/editable/ (when writable) 3. XDG_CACHE_HOME/polytropos/editable/ (default) 4. ~/.cache/polytropos/editable/ (fallback)

Source code in src/polytropos/cache.py
def _get_editable_cache_base() -> Path:
    """Get the base directory for editable install symlinks.

    Resolution order:
    1. ``POLYTROPOS_CACHE_DIR/editable/`` (if ``POLYTROPOS_CACHE_DIR`` is set)
    2. ``/var/cache/polytropos/editable/`` (when writable)
    3. ``XDG_CACHE_HOME/polytropos/editable/`` (default)
    4. ``~/.cache/polytropos/editable/`` (fallback)
    """
    return _get_polytropos_cache_dir() / "editable"

_get_polytropos_cache_dir()

Get the root Polytropos cache directory.

Resolution order: 1. POLYTROPOS_CACHE_DIR env var (explicit override) 2. /var/cache/polytropos/ (when writable — tries to create it) 3. XDG_CACHE_HOME/polytropos/ (default) 4. ~/.cache/polytropos/ (fallback)

Source code in src/polytropos/cache.py
def _get_polytropos_cache_dir() -> Path:
    """Get the root Polytropos cache directory.

    Resolution order:
    1. ``POLYTROPOS_CACHE_DIR`` env var (explicit override)
    2. ``/var/cache/polytropos/`` (when writable — tries to create it)
    3. ``XDG_CACHE_HOME/polytropos/`` (default)
    4. ``~/.cache/polytropos/`` (fallback)
    """
    env_dir = os.environ.get("POLYTROPOS_CACHE_DIR")
    if env_dir:
        return Path(env_dir)
    var_cache = Path("/var/cache/polytropos")
    try:
        var_cache.mkdir(parents=True, exist_ok=True)
    except OSError:
        pass
    else:
        if os.access(str(var_cache), os.W_OK):
            return var_cache
    xdg_cache = os.environ.get("XDG_CACHE_HOME")
    if xdg_cache:
        return Path(xdg_cache) / "polytropos"
    return Path.home() / ".cache" / "polytropos"

_maybe_cleanup_stale_editables()

Remove broken symlinks from the editable cache, at most once per hour.

A marker file .last_cleanup stores the ISO 8601 timestamp of the last run. If the file is missing or older than 1 hour, scan all subdirectories of the editable cache base and remove broken symlinks (and empty parent dirs).

Source code in src/polytropos/cache.py
def _maybe_cleanup_stale_editables() -> None:
    """Remove broken symlinks from the editable cache, at most once per hour.

    A marker file ``.last_cleanup`` stores the ISO 8601 timestamp of the last run.
    If the file is missing or older than 1 hour, scan all subdirectories of the
    editable cache base and remove broken symlinks (and empty parent dirs).
    """
    if os.environ.get("POLYTROPOS_EDITABLE_IN_SOURCE"):
        return
    cache_base = _get_editable_cache_base()
    marker = cache_base / ".last_cleanup"
    try:
        cache_base.mkdir(parents=True, exist_ok=True)
    except OSError:
        return
    now = time.time()
    try:
        last = datetime.fromisoformat(marker.read_text().strip()).timestamp()
    except (OSError, ValueError):
        last = 0.0
    if now - last < 3600:
        return
    marker.write_text(datetime.fromtimestamp(now).isoformat(timespec="seconds"))
    _cleanup_stale_symlinks(cache_base)

gc(full=False)

Garbage-collect the Polytropos cache.

See :func:_get_polytropos_cache_dir for the default cache directory resolution order.

Parameters:

Name Type Description Default
full bool

If True, delete the entire Polytropos cache directory. Otherwise, only remove broken symlinks from the editable cache.

False
Source code in src/polytropos/cache.py
def gc(full: bool = False) -> None:
    """Garbage-collect the Polytropos cache.

    See :func:`_get_polytropos_cache_dir` for the default cache directory
    resolution order.

    Args:
        full: If True, delete the entire Polytropos cache directory.
              Otherwise, only remove broken symlinks from the editable cache.
    """
    if full:
        cache_dir = _get_polytropos_cache_dir()
        if cache_dir.exists():
            shutil.rmtree(cache_dir)
            logger.info("Deleted cache: %s", cache_dir)
        return
    _maybe_cleanup_stale_editables()