https://github.com/python/cpython/commit/86b8617747699416fcf9cd4ce6ea1da58a66f70e
commit: 86b8617747699416fcf9cd4ce6ea1da58a66f70e
branch: main
author: Jakub KulĂ­k <[email protected]>
committer: vstinner <[email protected]>
date: 2026-04-02T15:50:38Z
summary:

Move root user checks to test.support (#146195)

files:
M Lib/test/support/__init__.py
M Lib/test/test_mailbox.py
M Lib/test/test_os/test_os.py
M Lib/test/test_pathlib/test_pathlib.py

diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 3da662b0c4d50a..8ff061e074074f 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -71,7 +71,8 @@
     "BrokenIter",
     "in_systemd_nspawn_sync_suppressed",
     "run_no_yield_async_fn", "run_yielding_async_fn", "async_yield",
-    "reset_code", "on_github_actions"
+    "reset_code", "on_github_actions",
+    "requires_root_user", "requires_non_root_user",
     ]
 
 
@@ -3317,3 +3318,8 @@ def control_characters_c0() -> list[str]:
     C0 control characters defined as the byte range 0x00-0x1F, and 0x7F.
     """
     return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"]
+
+
+_ROOT_IN_POSIX = hasattr(os, 'geteuid') and os.geteuid() == 0
+requires_root_user = unittest.skipUnless(_ROOT_IN_POSIX, "test needs root 
privilege")
+requires_non_root_user = unittest.skipIf(_ROOT_IN_POSIX, "test needs non-root 
account")
diff --git a/Lib/test/test_mailbox.py b/Lib/test/test_mailbox.py
index 7421076ddd4c3a..019c699bff55c4 100644
--- a/Lib/test/test_mailbox.py
+++ b/Lib/test/test_mailbox.py
@@ -11,6 +11,7 @@
 from test.support import import_helper, warnings_helper
 from test.support import os_helper
 from test.support import refleak_helper
+from test.support import requires_root_user
 from test.support import socket_helper
 import unittest
 import textwrap
@@ -1086,6 +1087,7 @@ def test_permissions_after_flush(self):
 
         self.assertEqual(os.stat(self._path).st_mode, mode)
 
+    @requires_root_user
     @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
     def test_ownership_after_flush(self):
         # See issue gh-117467
@@ -1108,10 +1110,7 @@ def test_ownership_after_flush(self):
         else:
             self.skipTest("test needs more than one group")
 
-        try:
-            os.chown(self._path, other_uid, other_gid)
-        except OSError:
-            self.skipTest('test needs root privilege')
+        os.chown(self._path, other_uid, other_gid)
         # Change permissions as in test_permissions_after_flush.
         mode = st.st_mode | 0o666
         os.chmod(self._path, mode)
diff --git a/Lib/test/test_os/test_os.py b/Lib/test/test_os/test_os.py
index 06f69caad12bc8..7e670e5a139d99 100644
--- a/Lib/test/test_os/test_os.py
+++ b/Lib/test/test_os/test_os.py
@@ -33,6 +33,8 @@
 from test.support import os_helper
 from test.support import socket_helper
 from test.support import infinite_recursion
+from test.support import requires_root_user
+from test.support import requires_non_root_user
 from test.support import warnings_helper
 from platform import win32_is_iot
 from .utils import create_file
@@ -67,10 +69,6 @@
 from test.support.os_helper import FakePath
 
 
-root_in_posix = False
-if hasattr(os, 'geteuid'):
-    root_in_posix = (os.geteuid() == 0)
-
 # Detect whether we're on a Linux system that uses the (now outdated
 # and unmaintained) linuxthreads threading library.  There's an issue
 # when combining linuxthreads with a failed execv call: see
@@ -2257,8 +2255,8 @@ def test_chown_gid(self):
         gid = os.stat(os_helper.TESTFN).st_gid
         self.assertEqual(gid, gid_2)
 
-    @unittest.skipUnless(root_in_posix and len(all_users) > 1,
-                         "test needs root privilege and more than one user")
+    @requires_root_user
+    @unittest.skipUnless(len(all_users) > 1, "test needs more than one user")
     def test_chown_with_root(self):
         uid_1, uid_2 = all_users[:2]
         gid = os.stat(os_helper.TESTFN).st_gid
@@ -2269,8 +2267,8 @@ def test_chown_with_root(self):
         uid = os.stat(os_helper.TESTFN).st_uid
         self.assertEqual(uid, uid_2)
 
-    @unittest.skipUnless(not root_in_posix and len(all_users) > 1,
-                         "test needs non-root account and more than one user")
+    @requires_non_root_user
+    @unittest.skipUnless(len(all_users) > 1, "test needs and more than one 
user")
     def test_chown_without_permission(self):
         uid_1, uid_2 = all_users[:2]
         gid = os.stat(os_helper.TESTFN).st_gid
diff --git a/Lib/test/test_pathlib/test_pathlib.py 
b/Lib/test/test_pathlib/test_pathlib.py
index ef9ea0d11d06a6..d346a1a6160d6b 100644
--- a/Lib/test/test_pathlib/test_pathlib.py
+++ b/Lib/test/test_pathlib/test_pathlib.py
@@ -20,6 +20,7 @@
 from test.support import is_emscripten, is_wasi, is_wasm32
 from test.support import infinite_recursion
 from test.support import os_helper
+from test.support import requires_root_user
 from test.support.os_helper import TESTFN, FS_NONASCII, FakePath
 try:
     import fcntl
@@ -35,11 +36,6 @@
     posix = None
 
 
-root_in_posix = False
-if hasattr(os, 'geteuid'):
-    root_in_posix = (os.geteuid() == 0)
-
-
 def patch_replace(old_test):
     def new_replace(self, target):
         raise OSError(errno.EXDEV, "Cross-device link", self, target)
@@ -1554,7 +1550,7 @@ def raiser(*args, **kwargs):
             self.assertRaises(FileNotFoundError, source.copy, target)
 
     @unittest.skipIf(sys.platform == "win32" or sys.platform == "wasi", 
"directories are always readable on Windows and WASI")
-    @unittest.skipIf(root_in_posix, "test fails with root privilege")
+    @requires_root_user
     def test_copy_dir_no_read_permission(self):
         base = self.cls(self.base)
         source = base / 'dirE'
@@ -2027,7 +2023,7 @@ def test_owner(self):
         self.assertEqual(expected_name, p.owner())
 
     @unittest.skipUnless(pwd, "the pwd module is needed for this test")
-    @unittest.skipUnless(root_in_posix, "test needs root privilege")
+    @requires_root_user
     def test_owner_no_follow_symlinks(self):
         all_users = [u.pw_uid for u in pwd.getpwall()]
         if len(all_users) < 2:
@@ -2062,7 +2058,7 @@ def test_group(self):
         self.assertEqual(expected_name, p.group())
 
     @unittest.skipUnless(grp, "the grp module is needed for this test")
-    @unittest.skipUnless(root_in_posix, "test needs root privilege")
+    @requires_root_user
     def test_group_no_follow_symlinks(self):
         all_groups = [g.gr_gid for g in grp.getgrall()]
         if len(all_groups) < 2:

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to