[issue15202] followlinks/follow_symlinks/symlinks flags unification

Serhiy Storchaka report at bugs.python.org
Sun Jul 1 15:10:10 CEST 2012


Serhiy Storchaka <storchaka at gmail.com> added the comment:

Here is an updated patches (with index 3). No aliased parameters, only
new parameters renamed. Some minor errors have fixed.

----------
Added file: http://bugs.python.org/file26225/followlinks-to-follow_symlinks-3.patch
Added file: http://bugs.python.org/file26226/symlinks-to-follow_symlinks-3.patch

_______________________________________
Python tracker <report at bugs.python.org>
<http://bugs.python.org/issue15202>
_______________________________________
-------------- next part --------------
diff -r a1c8302e6b27 Doc/library/os.rst
--- a/Doc/library/os.rst	Sun Jul 01 12:24:20 2012 +0200
+++ b/Doc/library/os.rst	Sun Jul 01 15:54:02 2012 +0300
@@ -2211,7 +2211,7 @@
               os.rmdir(os.path.join(root, name))
 
 
-.. function:: fwalk(top='.', topdown=True, onerror=None, followlinks=False, *, dir_fd=None)
+.. function:: fwalk(top='.', topdown=True, onerror=None, follow_symlinks=False, *, dir_fd=None)
 
    .. index::
       single: directory; walking
diff -r a1c8302e6b27 Lib/os.py
--- a/Lib/os.py	Sun Jul 01 12:24:20 2012 +0200
+++ b/Lib/os.py	Sun Jul 01 15:54:02 2012 +0300
@@ -424,7 +424,7 @@
 
 if {open, stat} <= supports_dir_fd and {listdir, stat} <= supports_fd:
 
-    def fwalk(top=".", topdown=True, onerror=None, followlinks=False, *, dir_fd=None):
+    def fwalk(top=".", topdown=True, onerror=None, follow_symlinks=False, *, dir_fd=None):
         """Directory tree generator.
 
         This behaves exactly like walk(), except that it yields a 4-tuple
@@ -435,7 +435,7 @@
         and `dirfd` is a file descriptor referring to the directory `dirpath`.
 
         The advantage of fwalk() over walk() is that it's safe against symlink
-        races (when followlinks is False).
+        races (when follow_symlinks is False).
 
         If dir_fd is not None, it should be a file descriptor open to a directory,
           and top should be relative; top will then be relative to that directory.
@@ -462,13 +462,13 @@
         orig_st = stat(top, follow_symlinks=False, dir_fd=dir_fd)
         topfd = open(top, O_RDONLY, dir_fd=dir_fd)
         try:
-            if (followlinks or (st.S_ISDIR(orig_st.st_mode) and
-                                path.samestat(orig_st, stat(topfd)))):
-                yield from _fwalk(topfd, top, topdown, onerror, followlinks)
+            if (follow_symlinks or (st.S_ISDIR(orig_st.st_mode) and
+                                    path.samestat(orig_st, stat(topfd)))):
+                yield from _fwalk(topfd, top, topdown, onerror, follow_symlinks)
         finally:
             close(topfd)
 
-    def _fwalk(topfd, toppath, topdown, onerror, followlinks):
+    def _fwalk(topfd, toppath, topdown, onerror, follow_symlinks):
         # Note: This uses O(depth of the directory tree) file descriptors: if
         # necessary, it can be adapted to only require O(1) FDs, see issue
         # #13734.
@@ -499,16 +499,16 @@
 
         for name in dirs:
             try:
-                orig_st = stat(name, dir_fd=topfd, follow_symlinks=followlinks)
+                orig_st = stat(name, dir_fd=topfd, follow_symlinks=follow_symlinks)
                 dirfd = open(name, O_RDONLY, dir_fd=topfd)
             except error as err:
                 if onerror is not None:
                     onerror(err)
                 return
             try:
-                if followlinks or path.samestat(orig_st, stat(dirfd)):
+                if follow_symlinks or path.samestat(orig_st, stat(dirfd)):
                     dirpath = path.join(toppath, name)
-                    yield from _fwalk(dirfd, dirpath, topdown, onerror, followlinks)
+                    yield from _fwalk(dirfd, dirpath, topdown, onerror, follow_symlinks)
             finally:
                 close(dirfd)
 
diff -r a1c8302e6b27 Lib/test/test_os.py
--- a/Lib/test/test_os.py	Sun Jul 01 12:24:20 2012 +0200
+++ b/Lib/test/test_os.py	Sun Jul 01 15:54:02 2012 +0300
@@ -745,10 +745,11 @@
         """
         compare with walk() results.
         """
-        for topdown, followlinks in itertools.product((True, False), repeat=2):
-            d = {'topdown': topdown, 'followlinks': followlinks}
-            walk_kwargs.update(d)
-            fwalk_kwargs.update(d)
+        walk_kwargs = walk_kwargs.copy()
+        fwalk_kwargs = fwalk_kwargs.copy()
+        for topdown, follow_symlinks in itertools.product((True, False), repeat=2):
+            walk_kwargs.update(topdown=topdown, followlinks=follow_symlinks)
+            fwalk_kwargs.update(topdown=topdown, follow_symlinks=follow_symlinks)
 
             expected = {}
             for root, dirs, files in os.walk(**walk_kwargs):
@@ -774,8 +775,8 @@
 
     def test_yields_correct_dir_fd(self):
         # check returned file descriptors
-        for topdown, followlinks in itertools.product((True, False), repeat=2):
-            args = support.TESTFN, topdown, None, followlinks
+        for topdown, follow_symlinks in itertools.product((True, False), repeat=2):
+            args = support.TESTFN, topdown, None, follow_symlinks
             for root, dirs, files, rootfd in os.fwalk(*args):
                 # check that the FD is valid
                 os.fstat(rootfd)
-------------- next part --------------
diff -r a1c8302e6b27 Doc/library/shutil.rst
--- a/Doc/library/shutil.rst	Sun Jul 01 12:24:20 2012 +0200
+++ b/Doc/library/shutil.rst	Sun Jul 01 16:04:48 2012 +0300
@@ -47,7 +47,7 @@
    be copied.
 
 
-.. function:: copyfile(src, dst, symlinks=False)
+.. function:: copyfile(src, dst, follow_symlinks=True)
 
    Copy the contents (no metadata) of the file named *src* to a file named
    *dst* and return *dst*.  *dst* must be the complete target file name; look at
@@ -59,63 +59,63 @@
    such as character or block devices and pipes cannot be copied with this
    function.  *src* and *dst* are path names given as strings.
 
-   If *symlinks* is true and *src* is a symbolic link, a new symbolic link will
+   If *follow_symlinks* is false and *src* is a symbolic link, a new symbolic link will
    be created instead of copying the file *src* points to.
 
    .. versionchanged:: 3.3
       :exc:`IOError` used to be raised instead of :exc:`OSError`.
-      Added *symlinks* argument.
+      Added *follow_symlinks* argument.
 
    .. versionchanged:: 3.3
       Added return of the *dst*.
 
-.. function:: copymode(src, dst, symlinks=False)
+.. function:: copymode(src, dst, follow_symlinks=True)
 
    Copy the permission bits from *src* to *dst*.  The file contents, owner, and
    group are unaffected.  *src* and *dst* are path names given as strings.  If
-   *symlinks* is true, *src* a symbolic link and the operating system supports
+   *follow_symlinks* is false, *src* a symbolic link and the operating system supports
    modes for symbolic links (for example BSD-based ones), the mode of the link
    will be copied.
 
    .. versionchanged:: 3.3
-      Added *symlinks* argument.
+      Added *follow_symlinks* argument.
 
-.. function:: copystat(src, dst, symlinks=False)
+.. function:: copystat(src, dst, follow_symlinks=True)
 
    Copy the permission bits, last access time, last modification time, and flags
    from *src* to *dst*.  The file contents, owner, and group are unaffected.  *src*
    and *dst* are path names given as strings.  If *src* and *dst* are both
-   symbolic links and *symlinks* true, the stats of the link will be copied as
+   symbolic links and *follow_symlinks* false, the stats of the link will be copied as
    far as the platform allows.
 
    .. versionchanged:: 3.3
-      Added *symlinks* argument.
+      Added *follow_symlinks* argument.
 
-.. function:: copy(src, dst, symlinks=False)
+.. function:: copy(src, dst, follow_symlinks=True)
 
    Copy the file *src* to the file or directory *dst* and return the file's
    destination.  If *dst* is a directory, a
    file with the same basename as *src*  is created (or overwritten) in the
    directory specified.  Permission bits are copied.  *src* and *dst* are path
-   names given as strings.  If *symlinks* is true, symbolic links won't be
+   names given as strings.  If *follow_symlinks* is false, symbolic links won't be
    followed but recreated instead -- this resembles GNU's :program:`cp -P`.
 
    .. versionchanged:: 3.3
-      Added *symlinks* argument.
+      Added *follow_symlinks* argument.
 
    .. versionchanged:: 3.3
       Added return of the *dst*.
 
-.. function:: copy2(src, dst, symlinks=False)
+.. function:: copy2(src, dst, follow_symlinks=True)
 
    Similar to :func:`shutil.copy`, including that the destination is
    returned, but metadata is copied as well. This is
-   similar to the Unix command :program:`cp -p`.  If *symlinks* is true,
+   similar to the Unix command :program:`cp -p`.  If *follow_symlinks* is false,
    symbolic links won't be followed but recreated instead -- this resembles
    GNU's :program:`cp -P`.
 
    .. versionchanged:: 3.3
-      Added *symlinks* argument, try to copy extended file system attributes
+      Added *follow_symlinks* argument, try to copy extended file system attributes
       too (currently Linux only).
 
    .. versionchanged:: 3.3
diff -r a1c8302e6b27 Lib/shutil.py
--- a/Lib/shutil.py	Sun Jul 01 12:24:20 2012 +0200
+++ b/Lib/shutil.py	Sun Jul 01 16:04:48 2012 +0300
@@ -82,10 +82,10 @@
     return (os.path.normcase(os.path.abspath(src)) ==
             os.path.normcase(os.path.abspath(dst)))
 
-def copyfile(src, dst, symlinks=False):
+def copyfile(src, dst, follow_symlinks=True):
     """Copy data from src to dst.
 
-    If optional flag `symlinks` is set and `src` is a symbolic link, a new
+    If optional flag `follow_symlinks` is not set and `src` is a symbolic link, a new
     symlink will be created instead of copying the file it points to.
 
     """
@@ -103,7 +103,7 @@
             if stat.S_ISFIFO(st.st_mode):
                 raise SpecialFileError("`%s` is a named pipe" % fn)
 
-    if symlinks and os.path.islink(src):
+    if not follow_symlinks and os.path.islink(src):
         os.symlink(os.readlink(src), dst)
     else:
         with open(src, 'rb') as fsrc:
@@ -111,15 +111,15 @@
                 copyfileobj(fsrc, fdst)
     return dst
 
-def copymode(src, dst, symlinks=False):
+def copymode(src, dst, follow_symlinks=True):
     """Copy mode bits from src to dst.
 
-    If the optional flag `symlinks` is set, symlinks aren't followed if and
+    If the optional flag `follow_symlinks` is not set, symlinks aren't followed if and
     only if both `src` and `dst` are symlinks. If `lchmod` isn't available (eg.
     Linux), in these cases, this method does nothing.
 
     """
-    if symlinks and os.path.islink(src) and os.path.islink(dst):
+    if not follow_symlinks and os.path.islink(src) and os.path.islink(dst):
         if hasattr(os, 'lchmod'):
             stat_func, chmod_func = os.lstat, os.lchmod
         else:
@@ -132,10 +132,10 @@
     st = stat_func(src)
     chmod_func(dst, stat.S_IMODE(st.st_mode))
 
-def copystat(src, dst, symlinks=False):
+def copystat(src, dst, follow_symlinks=True):
     """Copy all stat info (mode bits, atime, mtime, flags) from src to dst.
 
-    If the optional flag `symlinks` is set, symlinks aren't followed if and
+    If the optional flag `follow_symlinks` is not set, symlinks aren't followed if and
     only if both `src` and `dst` are symlinks.
 
     """
@@ -143,7 +143,7 @@
         pass
 
     # follow symlinks (aka don't not follow symlinks)
-    follow = not (symlinks and os.path.islink(src) and os.path.islink(dst))
+    follow = follow_symlinks or not (os.path.islink(src) and os.path.islink(dst))
     if follow:
         # use the real function if it exists
         def lookup(name):
@@ -186,19 +186,19 @@
                 raise
 
 if hasattr(os, 'listxattr'):
-    def _copyxattr(src, dst, symlinks=False):
+    def _copyxattr(src, dst, follow_symlinks=True):
         """Copy extended filesystem attributes from `src` to `dst`.
 
         Overwrite existing attributes.
 
-        If the optional flag `symlinks` is set, symlinks won't be followed.
+        If the optional flag `follow_symlinks` is not set, symlinks won't be followed.
 
         """
 
-        for name in os.listxattr(src, follow_symlinks=symlinks):
+        for name in os.listxattr(src, follow_symlinks=follow_symlinks):
             try:
-                value = os.getxattr(src, name, follow_symlinks=symlinks)
-                os.setxattr(dst, name, value, follow_symlinks=symlinks)
+                value = os.getxattr(src, name, follow_symlinks=follow_symlinks)
+                os.setxattr(dst, name, value, follow_symlinks=follow_symlinks)
             except OSError as e:
                 if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA):
                     raise
@@ -206,36 +206,36 @@
     def _copyxattr(*args, **kwargs):
         pass
 
-def copy(src, dst, symlinks=False):
+def copy(src, dst, follow_symlinks=True):
     """Copy data and mode bits ("cp src dst"). Return the file's destination.
 
     The destination may be a directory.
 
-    If the optional flag `symlinks` is set, symlinks won't be followed. This
+    If the optional flag `follow_symlinks` is not set, symlinks won't be followed. This
     resembles GNU's "cp -P src dst".
 
     """
     if os.path.isdir(dst):
         dst = os.path.join(dst, os.path.basename(src))
-    copyfile(src, dst, symlinks=symlinks)
-    copymode(src, dst, symlinks=symlinks)
+    copyfile(src, dst, follow_symlinks=follow_symlinks)
+    copymode(src, dst, follow_symlinks=follow_symlinks)
     return dst
 
-def copy2(src, dst, symlinks=False):
+def copy2(src, dst, follow_symlinks=True):
     """Copy data and all stat info ("cp -p src dst"). Return the file's
     destination."
 
     The destination may be a directory.
 
-    If the optional flag `symlinks` is set, symlinks won't be followed. This
+    If the optional flag `follow_symlinks` is not set, symlinks won't be followed. This
     resembles GNU's "cp -P src dst".
 
     """
     if os.path.isdir(dst):
         dst = os.path.join(dst, os.path.basename(src))
-    copyfile(src, dst, symlinks=symlinks)
-    copystat(src, dst, symlinks=symlinks)
-    _copyxattr(src, dst, symlinks=symlinks)
+    copyfile(src, dst, follow_symlinks=follow_symlinks)
+    copystat(src, dst, follow_symlinks=follow_symlinks)
+    _copyxattr(src, dst, follow_symlinks=follow_symlinks)
     return dst
 
 def ignore_patterns(*patterns):
@@ -307,7 +307,7 @@
                     # code with a custom `copy_function` may rely on copytree
                     # doing the right thing.
                     os.symlink(linkto, dstname)
-                    copystat(srcname, dstname, symlinks=symlinks)
+                    copystat(srcname, dstname, follow_symlinks=not symlinks)
                 else:
                     # ignore dangling symlink if the flag is on
                     if not os.path.exists(linkto) and ignore_dangling_symlinks:
diff -r a1c8302e6b27 Lib/test/test_shutil.py
--- a/Lib/test/test_shutil.py	Sun Jul 01 12:24:20 2012 +0200
+++ b/Lib/test/test_shutil.py	Sun Jul 01 16:04:48 2012 +0300
@@ -277,17 +277,17 @@
         os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
         # link to link
         os.lchmod(dst_link, stat.S_IRWXO)
-        shutil.copymode(src_link, dst_link, symlinks=True)
+        shutil.copymode(src_link, dst_link, follow_symlinks=False)
         self.assertEqual(os.lstat(src_link).st_mode,
                          os.lstat(dst_link).st_mode)
         self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
         # src link - use chmod
         os.lchmod(dst_link, stat.S_IRWXO)
-        shutil.copymode(src_link, dst, symlinks=True)
+        shutil.copymode(src_link, dst, follow_symlinks=False)
         self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
         # dst link - use chmod
         os.lchmod(dst_link, stat.S_IRWXO)
-        shutil.copymode(src, dst_link, symlinks=True)
+        shutil.copymode(src, dst_link, follow_symlinks=False)
         self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
 
     @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
@@ -302,7 +302,7 @@
         write_file(dst, 'foo')
         os.symlink(src, src_link)
         os.symlink(dst, dst_link)
-        shutil.copymode(src_link, dst_link, symlinks=True)  # silent fail
+        shutil.copymode(src_link, dst_link, follow_symlinks=False)  # silent fail
 
     @support.skip_unless_symlink
     def test_copystat_symlinks(self):
@@ -326,10 +326,10 @@
         src_link_stat = os.lstat(src_link)
         # follow
         if hasattr(os, 'lchmod'):
-            shutil.copystat(src_link, dst_link, symlinks=False)
+            shutil.copystat(src_link, dst_link, follow_symlinks=True)
             self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
         # don't follow
-        shutil.copystat(src_link, dst_link, symlinks=True)
+        shutil.copystat(src_link, dst_link, follow_symlinks=False)
         dst_link_stat = os.lstat(dst_link)
         if os.utime in os.supports_follow_symlinks:
             for attr in 'st_atime', 'st_mtime':
@@ -341,7 +341,7 @@
         if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
             self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
         # tell to follow but dst is not a link
-        shutil.copystat(src_link, dst, symlinks=True)
+        shutil.copystat(src_link, dst, follow_symlinks=False)
         self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
                         00000.1)
 
@@ -429,10 +429,10 @@
         dst_link = os.path.join(tmp_dir, 'qux')
         write_file(dst, 'bar')
         os.symlink(dst, dst_link)
-        shutil._copyxattr(src_link, dst_link, symlinks=True)
+        shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
         self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
         self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
-        shutil._copyxattr(src_link, dst, symlinks=True)
+        shutil._copyxattr(src_link, dst, follow_symlinks=False)
         self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
 
     @support.skip_unless_symlink
@@ -446,12 +446,12 @@
         if hasattr(os, 'lchmod'):
             os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
         # don't follow
-        shutil.copy(src_link, dst, symlinks=False)
+        shutil.copy(src_link, dst, follow_symlinks=True)
         self.assertFalse(os.path.islink(dst))
         self.assertEqual(read_file(src), read_file(dst))
         os.remove(dst)
         # follow
-        shutil.copy(src_link, dst, symlinks=True)
+        shutil.copy(src_link, dst, follow_symlinks=False)
         self.assertTrue(os.path.islink(dst))
         self.assertEqual(os.readlink(dst), os.readlink(src_link))
         if hasattr(os, 'lchmod'):
@@ -473,12 +473,12 @@
         src_stat = os.stat(src)
         src_link_stat = os.lstat(src_link)
         # follow
-        shutil.copy2(src_link, dst, symlinks=False)
+        shutil.copy2(src_link, dst, follow_symlinks=True)
         self.assertFalse(os.path.islink(dst))
         self.assertEqual(read_file(src), read_file(dst))
         os.remove(dst)
         # don't follow
-        shutil.copy2(src_link, dst, symlinks=True)
+        shutil.copy2(src_link, dst, follow_symlinks=False)
         self.assertTrue(os.path.islink(dst))
         self.assertEqual(os.readlink(dst), os.readlink(src_link))
         dst_stat = os.lstat(dst)
@@ -516,7 +516,7 @@
         write_file(src, 'foo')
         os.symlink(src, link)
         # don't follow
-        shutil.copyfile(link, dst_link, symlinks=True)
+        shutil.copyfile(link, dst_link, follow_symlinks=False)
         self.assertTrue(os.path.islink(dst_link))
         self.assertEqual(os.readlink(link), os.readlink(dst_link))
         # follow


More information about the Python-bugs-list mailing list