1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
From: Colin Watson <cjwatson@debian.org>
Date: Fri, 9 Jan 2026 01:04:42 +0000
Subject: Fix test_dir_without_exec_permission on Python 3.14
One unit test fails on Python 3.14 as follows:
```
_____________ TestFolderTraversal.test_dir_without_exec_permission _____________
self = <test.unit.scan.test_folder_traversal.TestFolderTraversal object at 0x7f5530606350>
tmp_path = PosixPath('/tmp/pytest-of-sbuild/pytest-0/test_dir_without_exec_permissi0')
fs_perm_tool = <test.unit.conftest.UnixPermTool object at 0x7f55301ca510>
@pytest.mark.skipif(
platform.system() == 'Windows',
reason='Unix-only filesystem permissions are tested',
)
def test_dir_without_exec_permission(self, tmp_path, fs_perm_tool):
"""Test that a excluded directory/file without permissions emits warnings."""
no_perm_dir = tmp_path / 'no_perm_dir'
no_perm_dir.mkdir()
(no_perm_dir / 'file.txt').touch()
(no_perm_dir / 'file2.txt').touch()
# chmod -x no_perm_dir
no_perm_dir.chmod(0o600)
scan_policy = ScanPoliciesManager()
reporter = ProgressReport(sys.stdout, False)
folder = LocalFolder(str(tmp_path))
local_paths = folder.all_files(reporter=reporter, policies_manager=scan_policy)
absolute_paths = [path.absolute_path for path in local_paths]
assert not absolute_paths
# Check that no access warnings are issued for the excluded directory/file
> assert set(reporter.warnings) == {
f'WARNING: {tmp_path/"no_perm_dir/file.txt"} could not be accessed (no permissions to read?)',
f'WARNING: {tmp_path/"no_perm_dir/file2.txt"} could not be accessed (no permissions to read?)',
}
E AssertionError: assert {'WARNING: /t...en symlink?)'} == {'WARNING: /t...ns to read?)'}
E
E Extra items in the left set:
E 'WARNING: /tmp/pytest-of-sbuild/pytest-0/test_dir_without_exec_permissi0/no_perm_dir/file2.txt could not be accessed (broken symlink?)'
E 'WARNING: /tmp/pytest-of-sbuild/pytest-0/test_dir_without_exec_permissi0/no_perm_dir/file.txt could not be accessed (broken symlink?)'
E Extra items in the right set:
E 'WARNING: /tmp/pytest-of-sbuild/pytest-0/test_dir_without_exec_permissi0/no_perm_dir/file.txt could not be accessed (no permissions to read?)'
E 'WARNING: /tmp/pytest-of-sbuild/pytest-0/test_dir_without_exec_permissi0/no_perm_dir/file2.txt could not be accessed (no permissions to read?)'
E Use -v to get more diff
test/unit/scan/test_folder_traversal.py:721: AssertionError
```
This is due to https://github.com/python/cpython/pull/118243. I'm not
sure how important it is to preserve the exact same warning message
here, but the conservative approach is to do so;
https://docs.python.org/3/library/pathlib.html advises using `Path.stat`
to distinguish these cases.
Forwarded: https://github.com/Backblaze/b2-sdk-python/pull/560
Bug-Debian: https://bugs.debian.org/1123197
Last-Update: 2026-01-09
---
b2sdk/_internal/scan/folder.py | 8 +++++++-
changelog.d/+py314-test.fixed.md | 1 +
2 files changed, 8 insertions(+), 1 deletion(-)
create mode 100644 changelog.d/+py314-test.fixed.md
diff --git a/b2sdk/_internal/scan/folder.py b/b2sdk/_internal/scan/folder.py
index 38dda43..54b3ca2 100644
--- a/b2sdk/_internal/scan/folder.py
+++ b/b2sdk/_internal/scan/folder.py
@@ -13,6 +13,7 @@ import logging
import os
import platform
import re
+import stat
import sys
from abc import ABCMeta, abstractmethod
from pathlib import Path
@@ -274,14 +275,19 @@ class LocalFolder(AbstractFolder):
reporter.invalid_name(str(local_path), str(e))
continue
+ # Deliberately don't use Path.is_dir here: for directories
+ # without search permission, Python 3.13 raises PermissionError
+ # while Python 3.14 returns False.
try:
- is_dir = local_path.is_dir()
+ is_dir = stat.S_ISDIR(local_path.stat().st_mode)
except PermissionError: # `chmod -x dir` can trigger this
if reporter is not None and not policies_manager.should_exclude_local_directory(
str(relative_file_path)
):
reporter.local_permission_error(str(local_path))
continue
+ except (OSError, ValueError):
+ is_dir = False
if is_dir:
if policies_manager.should_exclude_local_directory(str(relative_file_path)):
diff --git a/changelog.d/+py314-test.fixed.md b/changelog.d/+py314-test.fixed.md
new file mode 100644
index 0000000..ab9421b
--- /dev/null
+++ b/changelog.d/+py314-test.fixed.md
@@ -0,0 +1 @@
+Fix `TestFolderTraversal.test_dir_without_exec_permission` on Python 3.14.
|