Skip to content

Fix ensure_empty_dir leaving directory symlinks behind - #300

Open
Str0k wants to merge 1 commit into
tox-dev:mainfrom
Str0k:githubpower/t_e673392d
Open

Fix ensure_empty_dir leaving directory symlinks behind#300
Str0k wants to merge 1 commit into
tox-dev:mainfrom
Str0k:githubpower/t_e673392d

Conversation

@Str0k

@Str0k Str0k commented Sep 13, 2026

Copy link
Copy Markdown

ensure_empty_dir in pyproject_api/_util.py used rmtree(sub_path, ignore_errors=True) for every entry that is_dir(). When an entry is a symlink pointing to a directory, rmtree raises OSError('Cannot call rmtree on a symbolic link'), which ignore_errors=True swallows, so the symlink is silently left in place and the directory is not emptied. The callers, e.g. _check_metadata_dir in _frontend.py:348, rely on it to 'start with fresh' before prepare_metadata_for_build_wheel/editable, so a stale symlink in the metadata directory survives and the subsequent mkdir(exist_ok=True) does not restore a truly fresh state. After the fix the rmtree call is guarded with 'and not sub_path.is_symlink()', so symlinks to directories are removed via unlink like any other non-directory entry, without following or traversing the link target.

shutil.rmtree documents that calling it on a symlink raises OSError; combined with ignore_errors=True this turned a hard error into a silent no-op, violating the function's documented contract of leaving the path empty. Trigger: run prepare_metadata_for_build_editable twice with the same metadata_directory that contains a symlink to a directory; on the second run the directory is not emptied. The fix is one guard clause in the existing branch, keeping rmtree for real directories and unlink for everything else, including symlinks; the regression test asserts both that the link is removed and that its target's contents are untouched.

Validation:

  • Regression on unchanged base: 1 assertion failure(s); with patch: 1 tests, exit 0.
  • Full suite: base 61 tests (exit 1); patch 61 tests (exit 0).

AI assistance: implementation and independent review used Hermes with GLM 5.3. Test evidence was reproduced in clean checkouts. This does not represent a human review.
An additional model reviewed the supplied patch and evidence without executing tools.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant