[Python-checkins] cpython: #12191: add shutil.chown() to change user and/or group owner of a given path

sandro.tosi python-checkins at python.org
Mon Aug 22 23:29:03 CEST 2011


http://hg.python.org/cpython/rev/d1fd0f0f8e68
changeset:   72039:d1fd0f0f8e68
parent:      72037:e3be2941c834
user:        Sandro Tosi <sandro.tosi at gmail.com>
date:        Mon Aug 22 23:28:27 2011 +0200
summary:
  #12191: add shutil.chown() to change user and/or group owner of a given path also specifying their names.

files:
  Doc/library/os.rst      |   3 +
  Doc/library/shutil.rst  |  14 ++++++
  Lib/shutil.py           |  31 +++++++++++++++
  Lib/test/test_shutil.py |  59 +++++++++++++++++++++++++++++
  Misc/NEWS               |   3 +
  5 files changed, 110 insertions(+), 0 deletions(-)


diff --git a/Doc/library/os.rst b/Doc/library/os.rst
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -1530,6 +1530,9 @@
    Change the owner and group id of *path* to the numeric *uid* and *gid*. To leave
    one of the ids unchanged, set it to -1.
 
+   See :func:`shutil.chown` for a higher-level function that accepts names in
+   addition to numeric ids.
+
    Availability: Unix.
 
 
diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst
--- a/Doc/library/shutil.rst
+++ b/Doc/library/shutil.rst
@@ -183,6 +183,20 @@
 
    Availability: Unix, Windows.
 
+.. function:: chown(path, user=None, group=None)
+
+   Change owner *user* and/or *group* of the given *path*.
+
+   *user* can be a system user name or a uid; the same applies to *group*. At
+   least one argument is required.
+
+   See also :func:`os.chown`, the underlying function.
+
+   Availability: Unix.
+
+   .. versionadded:: 3.3
+
+
 .. exception:: Error
 
    This exception collects exceptions that are raised during a multi-file
diff --git a/Lib/shutil.py b/Lib/shutil.py
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -790,3 +790,34 @@
         total, free = nt._getdiskusage(path)
         used = total - free
         return _ntuple_diskusage(total, used, free)
+
+def chown(path, user=None, group=None):
+    """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,
+    they are converted to their respective uid/gid.
+    """
+
+    if user is None and group is None:
+        raise ValueError("user and/or group must be set")
+
+    _user = user
+    _group = group
+
+    # -1 means don't change it
+    if user is None:
+        _user = -1
+    # user can either be an int (the uid) or a string (the system username)
+    elif isinstance(user, str):
+        _user = _get_uid(user)
+        if _user is None:
+            raise LookupError("no such user: {!r}".format(user))
+
+    if group is None:
+        _group = -1
+    elif not isinstance(group, int):
+        _group = _get_gid(group)
+        if _group is None:
+            raise LookupError("no such group: {!r}".format(group))
+
+    os.chown(path, _user, _group)
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -712,6 +712,65 @@
         self.assertGreaterEqual(usage.total, usage.used)
         self.assertGreater(usage.total, usage.free)
 
+    @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
+    @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
+    def test_chown(self):
+
+        # cleaned-up automatically by TestShutil.tearDown method
+        dirname = self.mkdtemp()
+        filename = tempfile.mktemp(dir=dirname)
+        write_file(filename, 'testing chown function')
+
+        with self.assertRaises(ValueError):
+            shutil.chown(filename)
+
+        with self.assertRaises(LookupError):
+            shutil.chown(filename, user='non-exising username')
+
+        with self.assertRaises(LookupError):
+            shutil.chown(filename, group='non-exising groupname')
+
+        with self.assertRaises(TypeError):
+            shutil.chown(filename, b'spam')
+
+        with self.assertRaises(TypeError):
+            shutil.chown(filename, 3.14)
+
+        uid = os.getuid()
+        gid = os.getgid()
+
+        def check_chown(path, uid=None, gid=None):
+            s = os.stat(filename)
+            if uid is not None:
+                self.assertEqual(uid, s.st_uid)
+            if gid is not None:
+                self.assertEqual(gid, s.st_gid)
+
+        shutil.chown(filename, uid, gid)
+        check_chown(filename, uid, gid)
+        shutil.chown(filename, uid)
+        check_chown(filename, uid)
+        shutil.chown(filename, user=uid)
+        check_chown(filename, uid)
+        shutil.chown(filename, group=gid)
+        check_chown(filename, gid)
+
+        shutil.chown(dirname, uid, gid)
+        check_chown(dirname, uid, gid)
+        shutil.chown(dirname, uid)
+        check_chown(dirname, uid)
+        shutil.chown(dirname, user=uid)
+        check_chown(dirname, uid)
+        shutil.chown(dirname, group=gid)
+        check_chown(dirname, gid)
+
+        user = pwd.getpwuid(uid)[0]
+        group = grp.getgrgid(gid)[0]
+        shutil.chown(filename, user, group)
+        check_chown(filename, uid, gid)
+        shutil.chown(dirname, user, group)
+        check_chown(dirname, uid, gid)
+
 
 class TestMove(unittest.TestCase):
 
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -1144,6 +1144,9 @@
 
 - Issue #9347: Fix formatting for tuples in argparse type= error messages.
 
+- Issue #12191: Added shutil.chown() to change user and/or group owner of a
+  given path also specifying their names.
+
 Build
 -----
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list