diff --git a/docs/changelog/2074d.feature.rst b/docs/changelog/2074d.feature.rst new file mode 100644 index 000000000..3ee47a835 --- /dev/null +++ b/docs/changelog/2074d.feature.rst @@ -0,0 +1 @@ +Decouple discovery by duplicating info utils - by :user:`esafak`. diff --git a/src/virtualenv/discovery/builtin.py b/src/virtualenv/discovery/builtin.py index 841d36b16..8c2b0be81 100644 --- a/src/virtualenv/discovery/builtin.py +++ b/src/virtualenv/discovery/builtin.py @@ -9,9 +9,8 @@ from platformdirs import user_data_path -from virtualenv.info import IS_WIN, fs_path_id - from .discover import Discover +from .info import IS_WIN, fs_path_id from .py_info import PythonInfo from .py_spec import PythonSpec diff --git a/src/virtualenv/discovery/cached_py_info.py b/src/virtualenv/discovery/cached_py_info.py index 9bc463667..f0a1dc609 100644 --- a/src/virtualenv/discovery/cached_py_info.py +++ b/src/virtualenv/discovery/cached_py_info.py @@ -12,12 +12,12 @@ import logging import os import random +import subprocess import sys from collections import OrderedDict from pathlib import Path from shlex import quote from string import ascii_lowercase, ascii_uppercase, digits -from subprocess import Popen from typing import TYPE_CHECKING from virtualenv.app_data.na import AppDataDisabled @@ -27,7 +27,6 @@ from virtualenv.app_data.base import AppData from virtualenv.cache import Cache from virtualenv.discovery.py_info import PythonInfo -from virtualenv.util.subprocess import subprocess _CACHE = OrderedDict() _CACHE[Path(sys.executable)] = PythonInfo() @@ -145,7 +144,7 @@ def _run_subprocess(cls, exe, app_data, env): env.pop("__PYVENV_LAUNCHER__", None) LOGGER.debug("get interpreter info via cmd: %s", LogCmd(cmd)) try: - process = Popen( + process = subprocess.Popen( cmd, universal_newlines=True, stdin=subprocess.PIPE, diff --git a/src/virtualenv/discovery/info.py b/src/virtualenv/discovery/info.py new file mode 100644 index 000000000..c786a6a98 --- /dev/null +++ b/src/virtualenv/discovery/info.py @@ -0,0 +1,33 @@ +from __future__ import annotations + +import logging +import os +import sys +import tempfile + +_FS_CASE_SENSITIVE = None +LOGGER = logging.getLogger(__name__) +IS_WIN = sys.platform == "win32" + + +def fs_is_case_sensitive(): + """Check if the file system is case-sensitive.""" + global _FS_CASE_SENSITIVE # noqa: PLW0603 + + if _FS_CASE_SENSITIVE is None: + with tempfile.NamedTemporaryFile(prefix="TmP") as tmp_file: + _FS_CASE_SENSITIVE = not os.path.exists(tmp_file.name.lower()) + LOGGER.debug("filesystem is %scase-sensitive", "" if _FS_CASE_SENSITIVE else "not ") + return _FS_CASE_SENSITIVE + + +def fs_path_id(path: str) -> str: + """Get a case-normalized path identifier.""" + return path.casefold() if fs_is_case_sensitive() else path + + +__all__ = ( + "IS_WIN", + "fs_is_case_sensitive", + "fs_path_id", +) diff --git a/src/virtualenv/discovery/py_info.py b/src/virtualenv/discovery/py_info.py index f12e2c5cd..5f16dbc8a 100644 --- a/src/virtualenv/discovery/py_info.py +++ b/src/virtualenv/discovery/py_info.py @@ -659,7 +659,8 @@ def _possible_base(self): for base in possible_base: lower = base.lower() yield lower - from virtualenv.info import fs_is_case_sensitive # noqa: PLC0415 + + from .info import fs_is_case_sensitive # noqa: PLC0415 if fs_is_case_sensitive(): if base != lower: