Repository: iterative/dvc (python)

Issue:
`DVC_SITE_CACHE_DIR` environment variable does not override `.dvc/config` settings
# Bug Report


## Description

The documentation on [environment variables](https://dvc.org/doc/user-guide/env#environment-variables) says:
>  DVC_SITE_CACHE_DIR: Directory for the [site cache dir](https://dvc.org/doc/user-guide/project-structure/internal-files#site-cache-dir). Overrides [dvc config core.site_cache_dir](https://dvc.org/doc/command-reference/config).

However, this is not working as expected and if `core.site_cache_dir` is set in `.dvc/config`, the environment variable is ignored.

### Reproduce

Setup repo with `site_cache_dir` configuration:
```console
mkdir test_repo
cd test_repo
dvc init --no-scm
dvc config core.site_cache_dir /tmp/not_this_dir/
```

Check information:
```console
$ env DVC_SITE_CACHE_DIR=/tmp/use_this_dir/ dvc doctor
DVC version: 3.60.0 (conda)
---------------------------
Platform: Python 3.10.18 on macOS-15.5-x86_64-i386-64bit
Subprojects:
        dvc_data = 3.16.10
        dvc_objects = 5.1.1
        dvc_render = 1.0.2
        dvc_task = 0.40.2
        scmrepo = 3.3.11
Supports:
        gdrive (pydrive2 = 1.21.3),
        http (aiohttp = 3.9.5, aiohttp-retry = 2.9.1),
        https (aiohttp = 3.9.5, aiohttp-retry = 2.9.1),
        s3 (s3fs = 2025.5.1, boto3 = 1.37.3),
        ssh (sshfs = 2025.2.0)
Config:
        Global: /Users/rgoya/Library/Application Support/dvc
        System: /Library/Application Support/dvc
Cache types: <https://error.dvc.org/no-dvc-cache>
Caches: local
Remotes: None
Workspace directory: apfs on /dev/disk1s5s1
Repo: dvc (no_scm)
Repo.site_cache_dir: /tmp/not_this_dir/repo/c58163f0b6f80c77503e8859c67a9713
```

### Expected

The documentation states that `DVC_SITE_CACHE_DIR=/tmp/use_this_dir/` should override the config, so the last line should have read:
```console
Repo.site_cache_dir: /tmp/use_this_dir/repo/c58163f0b6f80c77503e8859c67a9713
```

Pull request description:
(fix) `DVC_SITE_CACHE_DIR` environment variable should override `core.site_cache_dir`
Fixes #10777

Currently: `Repo.site_cache_dir()` in `dvc/repo/__init__.py` selects first the configuration read in the config file, and if it does not exist it relies on `dirs.site_cache_dir()` to pick a value.

The documentation states that `DVC_DITE_CACHE_DIR` should override this configuration, therefore the order of priority for selecting the `site_cache_dir` is:
1. `DVC_SITE_CACHE_DIR`
2. `core.site_cache_dir`
3. `platformdirs` selection

For this, `dirs.site_cache_dir()` needs to know the three options.

This PR:
- enables `dirs.site_cache_dir()` to receive a configuration option so it can make the right choice between the three values;
- modifies `Repo.site_cache_dir()` to send `core.site_cache_dir` instead of picking itself; and
- enables tests for the proper return values.


----

* [X] ❗ I have followed the [Contributing to DVC](https://dvc.org/doc/user-guide/contributing/core) checklist.

* [x] 📖 If this PR requires [documentation](https://dvc.org/doc) updates, I have created a separate PR (or issue, at least) in [dvc.org](https://github.com/iterative/dvc.org) and linked it here.

Thank you for the contribution - we'll try to review it as soon as possible. 🙏


Patch:
diff --git a/dvc/dirs.py b/dvc/dirs.py
index 881a30840..eef78f856 100644
--- a/dvc/dirs.py
+++ b/dvc/dirs.py
@@ -1,4 +1,5 @@
 import os
+from typing import Optional
 
 import platformdirs
 
@@ -20,13 +21,16 @@ def global_config_dir():
     )
 
 
-def site_cache_dir():
+def site_cache_dir(config_site_cache_dir: Optional[str] = None):
     from platformdirs import PlatformDirs
     from platformdirs.unix import Unix
 
     if dvc_site_cache_dir := os.getenv(env.DVC_SITE_CACHE_DIR):
         return dvc_site_cache_dir
 
+    if config_site_cache_dir is not None:
+        return config_site_cache_dir
+
     if issubclass(Unix, PlatformDirs):
         # Return the cache directory shared by users, e.g. `/var/tmp/$appname`
         # NOTE: platformdirs>=5 changed `site_cache_dir` to return /var/cache/$appname.
diff --git a/dvc/repo/__init__.py b/dvc/repo/__init__.py
index 2b8962697..9f296f85e 100644
--- a/dvc/repo/__init__.py
+++ b/dvc/repo/__init__.py
@@ -609,7 +609,7 @@ class Repo:
         from dvc.fs import GitFileSystem
         from dvc.version import version_tuple
 
-        cache_dir = self.config["core"].get("site_cache_dir") or site_cache_dir()
+        cache_dir = site_cache_dir(self.config["core"].get("site_cache_dir"))
 
         subdir = None
         if isinstance(self.fs, GitFileSystem):


Test patch:
diff --git a/tests/unit/test_dirs.py b/tests/unit/test_dirs.py
index 259a330af..7ef79e364 100644
--- a/tests/unit/test_dirs.py
+++ b/tests/unit/test_dirs.py
@@ -21,3 +21,13 @@ def test_site_cache_dir_on_unix(monkeypatch):
 def test_site_cache_dir_env_var(monkeypatch):
     monkeypatch.setenv(DVC_SITE_CACHE_DIR, "foo_bar")
     assert site_cache_dir() == "foo_bar"
+
+
+def test_site_cache_dir_with_config_parameter(monkeypatch):
+    monkeypatch.delenv(DVC_SITE_CACHE_DIR)
+    assert site_cache_dir(config_site_cache_dir="foo_bar") == "foo_bar"
+
+
+def test_site_cache_dir_env_var_precedence(monkeypatch):
+    monkeypatch.setenv(DVC_SITE_CACHE_DIR, "foo")
+    assert site_cache_dir(config_site_cache_dir="bar") == "foo"