From 453aa7867f99080ed36ce78b9f778dc33f4d209e Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 13 Jun 2026 01:52:46 -0400 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=90=9B=20fix(env):=20reject=20a=20fil?= =?UTF-8?q?e=20as=20--env-dir=20and=20drop=20a=20mutable=20default?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Raise BuildException when --env-dir points at a regular file instead of letting os.makedirs produce a raw FileExistsError - Change mutable default `constraints: Collection[str] = []` to `()` (B006) - Add a test asserting the new "not a directory" error path Assisted-by: ClaudeCode:claude-sonnet-4.6 --- src/build/env.py | 5 ++++- tests/test_env.py | 13 +++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/build/env.py b/src/build/env.py index 25d08cf1..44857f2f 100644 --- a/src/build/env.py +++ b/src/build/env.py @@ -121,6 +121,9 @@ def __enter__(self) -> Self: path = tempfile.mkdtemp(prefix='build-env-') else: path = self._requested_path + if os.path.exists(path) and not os.path.isdir(path): + msg = f'Build environment location is not a directory: {path}' + raise BuildException(msg) if os.path.isdir(path): with os.scandir(path) as entries: if next(entries, None) is not None: @@ -203,7 +206,7 @@ def installed_versions(self, requirements: Collection[str]) -> dict[str, str]: def install( self, requirements: Collection[str], - constraints: Collection[str] = [], + constraints: Collection[str] = (), *, _fresh: bool = False, # Used internally by CLI to support preset PYTHONPATH ) -> None: diff --git a/tests/test_env.py b/tests/test_env.py index becd53e0..e75243ca 100644 --- a/tests/test_env.py +++ b/tests/test_env.py @@ -696,6 +696,19 @@ def test_env_dir_rejects_non_empty_location(tmp_path: pathlib.Path) -> None: assert tmp_path.joinpath('sentinel').exists() +def test_env_dir_rejects_file_at_location(tmp_path: pathlib.Path) -> None: + file_path = tmp_path / 'env-file' + file_path.touch() + + with ( + pytest.raises(build.BuildException, match='Build environment location is not a directory'), + build.env.DefaultIsolatedEnv(path=str(file_path)), + ): + raise AssertionError + + assert file_path.is_file() + + @pytest.mark.usefixtures('mock_env_create') def test_env_dir_accepts_existing_empty_location(tmp_path: pathlib.Path) -> None: with build.env.DefaultIsolatedEnv(path=str(tmp_path)) as env: From d82e39af6c95ee18cc03670988e80381e03f4f8f Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 13 Jun 2026 01:53:11 -0400 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9D=20docs(changelog):=20add=20fra?= =?UTF-8?q?gment=20for=20#1100?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: ClaudeCode:claude-sonnet-4.6 --- docs/changelog/1100.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/changelog/1100.bugfix.rst diff --git a/docs/changelog/1100.bugfix.rst b/docs/changelog/1100.bugfix.rst new file mode 100644 index 00000000..e4e98b87 --- /dev/null +++ b/docs/changelog/1100.bugfix.rst @@ -0,0 +1 @@ +Raise a friendly :class:`build.BuildException` when ``--env-dir`` points at an existing regular file instead of letting :func:`os.makedirs` surface a raw :exc:`FileExistsError`; also replace the mutable default ``[]`` in :meth:`DefaultIsolatedEnv.install`'s ``constraints`` parameter with an immutable tuple ``()``. From 528b9fe4572d8eaa19d7196e85370c26a6e53d58 Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Sat, 13 Jun 2026 01:54:34 -0400 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=8E=A8=20style:=20reformat=20changelo?= =?UTF-8?q?g=20fragment=20with=20docstrfmt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Assisted-by: ClaudeCode:claude-opus-4.8 --- docs/changelog/1100.bugfix.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog/1100.bugfix.rst b/docs/changelog/1100.bugfix.rst index e4e98b87..ba0e78fa 100644 --- a/docs/changelog/1100.bugfix.rst +++ b/docs/changelog/1100.bugfix.rst @@ -1 +1,3 @@ -Raise a friendly :class:`build.BuildException` when ``--env-dir`` points at an existing regular file instead of letting :func:`os.makedirs` surface a raw :exc:`FileExistsError`; also replace the mutable default ``[]`` in :meth:`DefaultIsolatedEnv.install`'s ``constraints`` parameter with an immutable tuple ``()``. +Raise a friendly :class:`build.BuildException` when ``--env-dir`` points at an existing regular file instead of letting +:func:`os.makedirs` surface a raw :exc:`FileExistsError`; also replace the mutable default ``[]`` in +:meth:`DefaultIsolatedEnv.install`'s ``constraints`` parameter with an immutable tuple ``()``.