Skip to content

Commit c945a28

Browse files
feat: improve homebrew path detection (#370)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 9f616e9 commit c945a28

File tree

2 files changed

+50
-33
lines changed

2 files changed

+50
-33
lines changed

src/platformdirs/macos.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,14 @@ def site_data_dir(self) -> str:
3434
"""
3535
:return: data directory shared by users, e.g. ``/Library/Application Support/$appname/$version``.
3636
If we're using a Python binary managed by `Homebrew <https://brew.sh>`_, the directory
37-
will be under the Homebrew prefix, e.g. ``/opt/homebrew/share/$appname/$version``.
37+
will be under the Homebrew prefix, e.g. ``$homebrew_prefix/share/$appname/$version``.
3838
If `multipath <platformdirs.api.PlatformDirsABC.multipath>` is enabled, and we're in Homebrew,
3939
the response is a multi-path string separated by ":", e.g.
40-
``/opt/homebrew/share/$appname/$version:/Library/Application Support/$appname/$version``
40+
``$homebrew_prefix/share/$appname/$version:/Library/Application Support/$appname/$version``
4141
"""
42-
is_homebrew = sys.prefix.startswith("/opt/homebrew")
43-
path_list = [self._append_app_name_and_version("/opt/homebrew/share")] if is_homebrew else []
42+
is_homebrew = "/opt/python" in sys.prefix
43+
homebrew_prefix = sys.prefix.split("/opt/python")[0] if is_homebrew else ""
44+
path_list = [self._append_app_name_and_version(f"{homebrew_prefix}/share")] if is_homebrew else []
4445
path_list.append(self._append_app_name_and_version("/Library/Application Support"))
4546
if self.multipath:
4647
return os.pathsep.join(path_list)
@@ -71,13 +72,14 @@ def site_cache_dir(self) -> str:
7172
"""
7273
:return: cache directory shared by users, e.g. ``/Library/Caches/$appname/$version``.
7374
If we're using a Python binary managed by `Homebrew <https://brew.sh>`_, the directory
74-
will be under the Homebrew prefix, e.g. ``/opt/homebrew/var/cache/$appname/$version``.
75+
will be under the Homebrew prefix, e.g. ``$homebrew_prefix/var/cache/$appname/$version``.
7576
If `multipath <platformdirs.api.PlatformDirsABC.multipath>` is enabled, and we're in Homebrew,
7677
the response is a multi-path string separated by ":", e.g.
77-
``/opt/homebrew/var/cache/$appname/$version:/Library/Caches/$appname/$version``
78+
``$homebrew_prefix/var/cache/$appname/$version:/Library/Caches/$appname/$version``
7879
"""
79-
is_homebrew = sys.prefix.startswith("/opt/homebrew")
80-
path_list = [self._append_app_name_and_version("/opt/homebrew/var/cache")] if is_homebrew else []
80+
is_homebrew = "/opt/python" in sys.prefix
81+
homebrew_prefix = sys.prefix.split("/opt/python")[0] if is_homebrew else ""
82+
path_list = [self._append_app_name_and_version(f"{homebrew_prefix}/var/cache")] if is_homebrew else []
8183
path_list.append(self._append_app_name_and_version("/Library/Caches"))
8284
if self.multipath:
8385
return os.pathsep.join(path_list)

tests/test_macos.py

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -88,28 +88,43 @@ def test_macos(mocker: MockerFixture, params: dict[str, Any], func: str) -> None
8888
)
8989
@pytest.mark.parametrize("multipath", [pytest.param(True, id="multipath"), pytest.param(False, id="singlepath")])
9090
def test_macos_homebrew(mocker: MockerFixture, params: dict[str, Any], multipath: bool, site_func: str) -> None:
91-
mocker.patch("sys.prefix", "/opt/homebrew/opt/python")
92-
93-
result = getattr(MacOS(multipath=multipath, **params), site_func)
94-
95-
home = str(Path("~").expanduser())
96-
suffix_elements = tuple(params[i] for i in ("appname", "version") if i in params)
97-
suffix = os.sep.join(("", *suffix_elements)) if suffix_elements else "" # noqa: PTH118
98-
99-
expected_path_map = {
100-
"site_cache_path": Path(f"/opt/homebrew/var/cache{suffix}"),
101-
"site_data_path": Path(f"/opt/homebrew/share{suffix}"),
102-
}
103-
expected_map = {
104-
"site_data_dir": f"/opt/homebrew/share{suffix}",
105-
"site_config_dir": f"/opt/homebrew/share{suffix}",
106-
"site_cache_dir": f"/opt/homebrew/var/cache{suffix}",
107-
"site_runtime_dir": f"{home}/Library/Caches/TemporaryItems{suffix}",
108-
}
109-
if multipath:
110-
expected_map["site_data_dir"] += f":/Library/Application Support{suffix}"
111-
expected_map["site_config_dir"] += f":/Library/Application Support{suffix}"
112-
expected_map["site_cache_dir"] += f":/Library/Caches{suffix}"
113-
expected = expected_path_map[site_func] if site_func.endswith("_path") else expected_map[site_func]
114-
115-
assert result == expected
91+
test_data = [
92+
{
93+
"sys_prefix": "/opt/homebrew/opt/[email protected]/Frameworks/Python.framework/Versions/3.13",
94+
"homebrew_prefix": "/opt/homebrew",
95+
},
96+
{
97+
"sys_prefix": "/usr/local/opt/[email protected]/Frameworks/Python.framework/Versions/3.13",
98+
"homebrew_prefix": "/usr/local",
99+
},
100+
{
101+
"sys_prefix": "/myown/arbitrary/prefix/opt/[email protected]/Frameworks/Python.framework/Versions/3.13",
102+
"homebrew_prefix": "/myown/arbitrary/prefix",
103+
},
104+
]
105+
for prefix in test_data:
106+
mocker.patch("sys.prefix", prefix["sys_prefix"])
107+
108+
result = getattr(MacOS(multipath=multipath, **params), site_func)
109+
110+
home = str(Path("~").expanduser())
111+
suffix_elements = tuple(params[i] for i in ("appname", "version") if i in params)
112+
suffix = os.sep.join(("", *suffix_elements)) if suffix_elements else "" # noqa: PTH118
113+
114+
expected_path_map = {
115+
"site_cache_path": Path(f"{prefix['homebrew_prefix']}/var/cache{suffix}"),
116+
"site_data_path": Path(f"{prefix['homebrew_prefix']}/share{suffix}"),
117+
}
118+
expected_map = {
119+
"site_data_dir": f"{prefix['homebrew_prefix']}/share{suffix}",
120+
"site_config_dir": f"{prefix['homebrew_prefix']}/share{suffix}",
121+
"site_cache_dir": f"{prefix['homebrew_prefix']}/var/cache{suffix}",
122+
"site_runtime_dir": f"{home}/Library/Caches/TemporaryItems{suffix}",
123+
}
124+
if multipath:
125+
expected_map["site_data_dir"] += f":/Library/Application Support{suffix}"
126+
expected_map["site_config_dir"] += f":/Library/Application Support{suffix}"
127+
expected_map["site_cache_dir"] += f":/Library/Caches{suffix}"
128+
expected = expected_path_map[site_func] if site_func.endswith("_path") else expected_map[site_func]
129+
130+
assert result == expected

0 commit comments

Comments
 (0)