bpo-18108: Adding dir_fd and follow_symlinks keyword args to shutil.chown (GH-15811)

* Adding dir_fd and follow_symlinks keyword args to shutil.chown
* Extending test_shutil.TestShutil.test_chown to include new kwargs
* Updating shutil.chown documentation

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Berker Peksag <berker.peksag@gmail.com>
Co-authored-by: Zachary Ware <zachary.ware@gmail.com>
This commit is contained in:
tahia 2024-04-22 14:23:36 -04:00 committed by GitHub
parent 78ba4cb758
commit 8974a63f5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 53 additions and 4 deletions

View File

@ -421,7 +421,8 @@ Directory and files operations
.. availability:: Unix, Windows. .. availability:: Unix, Windows.
.. function:: chown(path, user=None, group=None) .. function:: chown(path, user=None, group=None, *, dir_fd=None, \
follow_symlinks=True)
Change owner *user* and/or *group* of the given *path*. Change owner *user* and/or *group* of the given *path*.
@ -436,6 +437,9 @@ Directory and files operations
.. versionadded:: 3.3 .. versionadded:: 3.3
.. versionchanged:: 3.13
Added *dir_fd* and *follow_symlinks* parameters.
.. function:: which(cmd, mode=os.F_OK | os.X_OK, path=None) .. function:: which(cmd, mode=os.F_OK | os.X_OK, path=None)

View File

@ -594,6 +594,10 @@ os.path
exactly one (back)slash to be absolute. exactly one (back)slash to be absolute.
(Contributed by Barney Gale and Jon Foster in :gh:`44626`.) (Contributed by Barney Gale and Jon Foster in :gh:`44626`.)
* Add support of *dir_fd* and *follow_symlinks* keyword arguments in
:func:`shutil.chown`.
(Contributed by Berker Peksag and Tahia K in :gh:`62308`)
pathlib pathlib
------- -------

View File

@ -1442,11 +1442,18 @@ elif _WINDOWS:
return _ntuple_diskusage(total, used, free) return _ntuple_diskusage(total, used, free)
def chown(path, user=None, group=None): def chown(path, user=None, group=None, *, dir_fd=None, follow_symlinks=True):
"""Change owner user and group of the given path. """Change owner user and group of the given path.
user and group can be the uid/gid or the user/group names, and in that case, user and group can be the uid/gid or the user/group names, and in that case,
they are converted to their respective uid/gid. they are converted to their respective uid/gid.
If dir_fd is set, it should be an open file descriptor to the directory to
be used as the root of *path* if it is relative.
If follow_symlinks is set to False and the last element of the path is a
symbolic link, chown will modify the link itself and not the file being
referenced by the link.
""" """
sys.audit('shutil.chown', path, user, group) sys.audit('shutil.chown', path, user, group)
@ -1472,7 +1479,8 @@ def chown(path, user=None, group=None):
if _group is None: if _group is None:
raise LookupError("no such group: {!r}".format(group)) raise LookupError("no such group: {!r}".format(group))
os.chown(path, _user, _group) os.chown(path, _user, _group, dir_fd=dir_fd,
follow_symlinks=follow_symlinks)
def get_terminal_size(fallback=(80, 24)): def get_terminal_size(fallback=(80, 24)):
"""Get the size of the terminal window. """Get the size of the terminal window.

View File

@ -2212,7 +2212,9 @@ class TestMisc(BaseTest, unittest.TestCase):
def test_chown(self): def test_chown(self):
dirname = self.mkdtemp() dirname = self.mkdtemp()
filename = tempfile.mktemp(dir=dirname) filename = tempfile.mktemp(dir=dirname)
linkname = os.path.join(dirname, "chown_link")
write_file(filename, 'testing chown function') write_file(filename, 'testing chown function')
os.symlink(filename, linkname)
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
shutil.chown(filename) shutil.chown(filename)
@ -2233,7 +2235,7 @@ class TestMisc(BaseTest, unittest.TestCase):
gid = os.getgid() gid = os.getgid()
def check_chown(path, uid=None, gid=None): def check_chown(path, uid=None, gid=None):
s = os.stat(filename) s = os.stat(path)
if uid is not None: if uid is not None:
self.assertEqual(uid, s.st_uid) self.assertEqual(uid, s.st_uid)
if gid is not None: if gid is not None:
@ -2269,6 +2271,36 @@ class TestMisc(BaseTest, unittest.TestCase):
shutil.chown(dirname, user, group) shutil.chown(dirname, user, group)
check_chown(dirname, uid, gid) check_chown(dirname, uid, gid)
dirfd = os.open(dirname, os.O_RDONLY)
self.addCleanup(os.close, dirfd)
basename = os.path.basename(filename)
baselinkname = os.path.basename(linkname)
shutil.chown(basename, uid, gid, dir_fd=dirfd)
check_chown(filename, uid, gid)
shutil.chown(basename, uid, dir_fd=dirfd)
check_chown(filename, uid)
shutil.chown(basename, group=gid, dir_fd=dirfd)
check_chown(filename, gid=gid)
shutil.chown(basename, uid, gid, dir_fd=dirfd, follow_symlinks=True)
check_chown(filename, uid, gid)
shutil.chown(basename, uid, gid, dir_fd=dirfd, follow_symlinks=False)
check_chown(filename, uid, gid)
shutil.chown(linkname, uid, follow_symlinks=True)
check_chown(filename, uid)
shutil.chown(baselinkname, group=gid, dir_fd=dirfd, follow_symlinks=False)
check_chown(filename, gid=gid)
shutil.chown(baselinkname, uid, gid, dir_fd=dirfd, follow_symlinks=True)
check_chown(filename, uid, gid)
with self.assertRaises(TypeError):
shutil.chown(filename, uid, dir_fd=dirname)
with self.assertRaises(FileNotFoundError):
shutil.chown('missingfile', uid, gid, dir_fd=dirfd)
with self.assertRaises(ValueError):
shutil.chown(filename, dir_fd=dirfd)
@support.requires_subprocess() @support.requires_subprocess()
class TestWhich(BaseTest, unittest.TestCase): class TestWhich(BaseTest, unittest.TestCase):

View File

@ -0,0 +1 @@
:func:`shutil.chown` now supports *dir_fd* and *follow_symlinks* keyword arguments.