diff --git a/src/build/env.py b/src/build/env.py index 4b0725ad..4dc69d5f 100644 --- a/src/build/env.py +++ b/src/build/env.py @@ -13,7 +13,7 @@ import tempfile from types import TracebackType -from typing import Callable, Iterable, List, Optional, Tuple, Type +from typing import Callable, Dict, Iterable, List, Optional, Tuple, Type import packaging.requirements import packaging.version @@ -84,8 +84,17 @@ def _subprocess(cmd: List[str]) -> None: class IsolatedEnvBuilder: """Builder object for isolated environments.""" + _ENV_VARS_TO_CLEAR = ( + 'PYTHONHOME', + 'PYTHONPATH', + 'PYTHONPLATLIBDIR', + 'PYTHONSTARTUP', + 'PYTHONNOUSERSITE', + ) + def __init__(self) -> None: self._path: Optional[str] = None + self._old_env_values: Dict[str, Optional[str]] = {} def __enter__(self) -> IsolatedEnv: """ @@ -102,16 +111,19 @@ def __enter__(self) -> IsolatedEnv: else: self.log('Creating venv isolated environment...') executable, scripts_dir = _create_isolated_env_venv(self._path) - return _IsolatedEnvVenvPip( - path=self._path, - python_executable=executable, - scripts_dir=scripts_dir, - log=self.log, - ) except Exception: # cleanup folder if creation fails self.__exit__(*sys.exc_info()) raise + self._old_env_values = {name: os.environ.pop(name, None) for name in self._ENV_VARS_TO_CLEAR} + + return _IsolatedEnvVenvPip( + path=self._path, + python_executable=executable, + scripts_dir=scripts_dir, + log=self.log, + ) + def __exit__( self, exc_type: Optional[Type[BaseException]], exc_val: Optional[BaseException], exc_tb: Optional[TracebackType] ) -> None: @@ -122,6 +134,10 @@ def __exit__( :param exc_val: The value of exception raised (if any) :param exc_tb: The traceback of exception raised (if any) """ + for name, old_value in self._old_env_values.items(): + if old_value is not None: + os.environ[name] = old_value + self._old_env_values = {} if self._path is not None and os.path.exists(self._path): # in case the user already deleted skip remove shutil.rmtree(self._path) diff --git a/tests/test_env.py b/tests/test_env.py index 7aeda328..50d155cf 100644 --- a/tests/test_env.py +++ b/tests/test_env.py @@ -112,7 +112,7 @@ def test_isolated_env_log(mocker, caplog, package_test_flit): ('INFO', 'Installing packages in isolated environment... (something)'), ] if sys.version_info >= (3, 8): # stacklevel - assert [(record.lineno) for record in caplog.records] == [105, 103, 194] + assert [(record.lineno) for record in caplog.records] == [105, 112, 210] @pytest.mark.isolated @@ -165,3 +165,24 @@ def test_venv_symlink(mocker, has_symlink): build.env._fs_supports_symlink.cache_clear() assert supports_symlink is has_symlink + + +def test_clear_env_vars(monkeypatch, mocker): + mocker.patch('build.env._create_isolated_env_venv', return_value=(None, None)) + + keys = ( + 'PYTHONHOME', + 'PYTHONPATH', + 'PYTHONPLATLIBDIR', + 'PYTHONSTARTUP', + 'PYTHONNOUSERSITE', + ) + for key in keys: + monkeypatch.setenv(key, 'hello!') + + with build.env.IsolatedEnvBuilder(): + for key in keys: + assert key not in os.environ + + for key in keys: + assert os.environ[key] == 'hello!'