Skip to content

Commit 58485d7

Browse files
RonnyPfannschmidtCursor AIclaude
committed
fix: address review feedback on rm_rf permission handling
- Move `import stat` to module level (no lazy import) - Bound parent chmod by start_path to prevent escaping rm_rf scope - Use `p.is_dir()` and `rm_rf(p)` consistently with Path objects - Rewrite changelog to be user-facing (no internal function names) Co-authored-by: Cursor AI <ai@cursor.sh> Co-authored-by: Anthropic Claude Sonnet 4 <claude@anthropic.com>
1 parent ce05986 commit 58485d7

2 files changed

Lines changed: 9 additions & 9 deletions

File tree

changelog/7940.bugfix.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Fixed ``rm_rf`` failing to remove directories when the ``S_IXUSR`` (owner execute) permission bit is missing -- supersedes :pr:`7941`.
1+
Fixed cleanup of temporary directories failing when subdirectories have their execute permission removed.

src/_pytest/pathlib.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from pathlib import PurePath
2525
from posixpath import sep as posix_sep
2626
import shutil
27+
import stat
2728
import sys
2829
import types
2930
from types import ModuleType
@@ -79,8 +80,6 @@ def _chmod_rwx(p: str) -> bool:
7980
Returns True if permissions were actually changed, False if they were
8081
already sufficient or couldn't be changed.
8182
"""
82-
import stat
83-
8483
try:
8584
old_mode = os.stat(p).st_mode
8685
perm_mode = stat.S_IMODE(old_mode)
@@ -124,18 +123,19 @@ def on_rm_rf_error(
124123

125124
if func in (os.open, os.scandir):
126125
# Directory traversal failed (e.g. missing S_IXUSR). Fix permissions
127-
# on the path and its parent, then remove it ourselves since rmtree
128-
# skips entries after the error handler returns.
126+
# on the path and its parent (bounded by start_path), then remove it
127+
# ourselves since rmtree skips entries after the error handler returns.
129128
# See: https://github.com/pytest-dev/pytest/issues/7940
130129
p = Path(path)
131130
parent_changed = False
132-
if p.parent != p:
133-
parent_changed = _chmod_rwx(str(p.parent))
131+
parent = p.parent
132+
if parent not in (p, start_path):
133+
parent_changed = _chmod_rwx(str(parent))
134134
path_changed = _chmod_rwx(path)
135135
if not (parent_changed or path_changed):
136136
return False
137-
if os.path.isdir(path):
138-
rm_rf(Path(path))
137+
if p.is_dir():
138+
rm_rf(p)
139139
else:
140140
try:
141141
os.unlink(path)

0 commit comments

Comments
 (0)