# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0

"""Permission-safe wrapper around datasets.load_dataset.

A shared HF datasets cache can contain subtrees owned by another user (for
example populated by an earlier root-run job). datasets then raises
"[Errno 13] Permission denied: ..._builder.lock" while locking the cached
builder, killing the training run even though the dataset itself is fine.
Retry such loads in a Studio-owned cache so the run proceeds; the worst case
is one rebuild of the dataset in the fallback location.
"""

import logging
import os

from utils.paths.storage_roots import cache_root

logger = logging.getLogger(__name__)


def studio_datasets_cache() -> str:
    path = cache_root() / "hf-datasets"
    path.mkdir(parents = True, exist_ok = True)
    return str(path)


def load_dataset_cache_safe(*args, **kwargs):
    """datasets.load_dataset, retried in a Studio-owned cache on EACCES."""
    from datasets import load_dataset
    try:
        return load_dataset(*args, **kwargs)
    except PermissionError as error:
        fallback = studio_datasets_cache()
        logger.warning(
            "HF datasets cache is not writable (%s); rebuilding in %s",
            error,
            fallback,
        )
        kwargs["cache_dir"] = fallback
        # Nested builders consult the env var while the load runs; restore it
        # after so other datasets keep trying the shared cache first.
        old_env = os.environ.get("HF_DATASETS_CACHE")
        os.environ["HF_DATASETS_CACHE"] = fallback
        try:
            return load_dataset(*args, **kwargs)
        finally:
            if old_env is None:
                os.environ.pop("HF_DATASETS_CACHE", None)
            else:
                os.environ["HF_DATASETS_CACHE"] = old_env
