Serhiy Storchaka <storch...@gmail.com> added the comment:
Here is updated patches. The type of exception thrown when specifying
mutually exclusive arguments changed from ValueError to TypeError (in
accordance with the raised in similar conflicts exceptions). Slightly
modified documentation. Taken into account some of Larry's comments.
Only os.walk had followlinks and shutil.copytree had symlinks before
3.3. So these are the only functions preserved the old arguments.
os.fwalk and another five public functions from shutil got a new
argument only in 3.3, for them it just renamed (may be to make them
keyword-only?). Larry worrying, isn't it too late? But it would be
strange to have in 3.3 new and immediately obsolete arguments. Moreover
the support for the two arguments complicate and slow down the code. If
you postpone it to 3.4, there will not be another solution, but now we
can do less mess.
----------
Added file:
http://bugs.python.org/file26194/followlinks-to-follow_symlinks-2.patch
Added file: http://bugs.python.org/file26195/symlinks-to-follow_symlinks-2.patch
_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue15202>
_______________________________________
diff -r d0f775432705 Doc/library/os.rst
--- a/Doc/library/os.rst Thu Jun 28 01:45:48 2012 +0200
+++ b/Doc/library/os.rst Thu Jun 28 11:02:52 2012 +0300
@@ -2128,7 +2128,8 @@
and the *dir_fd*, *follow_symlinks*, and *ns* parameters.
-.. function:: walk(top, topdown=True, onerror=None, followlinks=False)
+.. function:: walk(top, topdown=True, onerror=None, followlinks=False, *,
+ follow_symlinks=False)
.. index::
single: directory; walking
@@ -2168,12 +2169,12 @@
is available as the ``filename`` attribute of the exception object.
By default, :func:`walk` will not walk down into symbolic links that
resolve to
- directories. Set *followlinks* to ``True`` to visit directories pointed to
by
+ directories. Set *follow_symlinks* to ``True`` to visit directories pointed
to by
symlinks, on systems that support them.
.. note::
- Be aware that setting *followlinks* to ``True`` can lead to infinite
+ Be aware that setting *follow_symlinks* to ``True`` can lead to infinite
recursion if a link points to a parent directory of itself. :func:`walk`
does not keep track of the directories it visited already.
@@ -2210,8 +2211,13 @@
for name in dirs:
os.rmdir(os.path.join(root, name))
-
-.. function:: fwalk(top='.', topdown=True, onerror=None, followlinks=False, *,
dir_fd=None)
+ .. versionchanged:: 3.3
+ Added *follow_symlinks* as alias to *followlinks*. *followlinks* should
+ not be used in new code. A :exc:`TypeError` is raised if both
+ *followlinks* and *follow_symlinks* are specified.
+
+
+.. function:: fwalk(top='.', topdown=True, onerror=None,
follow_symlinks=False, *, dir_fd=None)
.. index::
single: directory; walking
diff -r d0f775432705 Lib/os.py
--- a/Lib/os.py Thu Jun 28 01:45:48 2012 +0200
+++ b/Lib/os.py Thu Jun 28 11:02:52 2012 +0300
@@ -331,7 +331,9 @@
__all__.extend(["makedirs", "removedirs", "renames"])
-def walk(top, topdown=True, onerror=None, followlinks=False):
+_sentry = object()
+
+def walk(top, topdown=True, onerror=None, followlinks=_sentry, *,
follow_symlinks=_sentry):
"""Directory tree generator.
For each directory in the directory tree rooted at top (including top
@@ -369,7 +371,7 @@
By default, os.walk does not follow symbolic links to subdirectories on
systems that support them. In order to get this functionality, set the
- optional argument 'followlinks' to true.
+ optional argument 'follow_symlinks' to True.
Caution: if you pass a relative pathname for top, don't change the
current working directory between resumptions of walk. walk never
@@ -387,7 +389,15 @@
if 'CVS' in dirs:
dirs.remove('CVS') # don't visit CVS directories
"""
+ if follow_symlinks is _sentry:
+ follow_symlinks = followlinks is not _sentry and followlinks
+ elif followlinks is not _sentry:
+ raise TypeError("walk() got values for both 'follow_symlinks' and"
+ " 'followlinks' arguments")
+ yield from _walk(top, topdown, onerror, follow_symlinks)
+
+def _walk(top, topdown, onerror, follow_symlinks):
islink, join, isdir = path.islink, path.join, path.isdir
# We may not have read permission for top, in which case we can't
@@ -415,8 +425,8 @@
yield top, dirs, nondirs
for name in dirs:
new_path = join(top, name)
- if followlinks or not islink(new_path):
- yield from walk(new_path, topdown, onerror, followlinks)
+ if follow_symlinks or not islink(new_path):
+ yield from walk(new_path, topdown, onerror, follow_symlinks)
if not topdown:
yield top, dirs, nondirs
@@ -424,7 +434,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 +445,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 +472,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 +509,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 d0f775432705 Lib/test/test_os.py
--- a/Lib/test/test_os.py Thu Jun 28 01:45:48 2012 +0200
+++ b/Lib/test/test_os.py Thu Jun 28 11:02:52 2012 +0300
@@ -712,6 +712,14 @@
if support.can_symlink():
# Walk, following symlinks.
+ for root, dirs, files in os.walk(walk_path, follow_symlinks=True):
+ if root == link_path:
+ self.assertEqual(dirs, [])
+ self.assertEqual(files, ["tmp4"])
+ break
+ else:
+ self.fail("Didn't follow symlink with follow_symlinks=True")
+ # Walk, using backward compatible argument name "followlinks".
for root, dirs, files in os.walk(walk_path, followlinks=True):
if root == link_path:
self.assertEqual(dirs, [])
@@ -720,6 +728,12 @@
else:
self.fail("Didn't follow symlink with followlinks=True")
+ # Incompatible using new and old argument names for
"follow_symlinks".
+ with self.assertRaises(TypeError):
+ for x in os.walk(walk_path,
+ follow_symlinks=True, followlinks=True):
+ break
+
def tearDown(self):
# Tear everything down. This is a decent use for bottom-up on
# Windows, which doesn't have a recursive delete command. The
@@ -745,8 +759,8 @@
"""
compare with walk() results.
"""
- for topdown, followlinks in itertools.product((True, False), repeat=2):
- d = {'topdown': topdown, 'followlinks': followlinks}
+ for topdown, follow_symlinks in itertools.product((True, False),
repeat=2):
+ d = {'topdown': topdown, 'follow_symlinks': follow_symlinks}
walk_kwargs.update(d)
fwalk_kwargs.update(d)
@@ -774,8 +788,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)
diff -r d0f775432705 Modules/_ctypes/libffi/generate-ios-source-and-headers.py
--- a/Modules/_ctypes/libffi/generate-ios-source-and-headers.py Thu Jun 28
01:45:48 2012 +0200
+++ b/Modules/_ctypes/libffi/generate-ios-source-and-headers.py Thu Jun 28
11:02:52 2012 +0300
@@ -83,7 +83,7 @@
headers_seen = collections.defaultdict(set)
def move_source_tree(src_dir, dest_dir, dest_include_dir, arch=None,
prefix=None, suffix=None):
- for root, dirs, files in os.walk(src_dir, followlinks=True):
+ for root, dirs, files in os.walk(src_dir, follow_symlinks=True):
relroot = os.path.relpath(root,src_dir)
def move_dir(arch, prefix='', suffix='', files=[]):
diff -r d0f775432705 Modules/_ctypes/libffi/generate-osx-source-and-headers.py
--- a/Modules/_ctypes/libffi/generate-osx-source-and-headers.py Thu Jun 28
01:45:48 2012 +0200
+++ b/Modules/_ctypes/libffi/generate-osx-source-and-headers.py Thu Jun 28
11:02:52 2012 +0300
@@ -77,7 +77,7 @@
headers_seen = collections.defaultdict(set)
def move_source_tree(src_dir, dest_dir, dest_include_dir, arch=None,
prefix=None, suffix=None):
- for root, dirs, files in os.walk(src_dir, followlinks=True):
+ for root, dirs, files in os.walk(src_dir, follow_symlinks=True):
relroot = os.path.relpath(root,src_dir)
def move_dir(arch, prefix='', suffix='', files=[]):
diff -r d0f775432705 Doc/library/shutil.rst
--- a/Doc/library/shutil.rst Thu Jun 28 01:45:48 2012 +0200
+++ b/Doc/library/shutil.rst Thu Jun 28 11:03:18 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=False)
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
@@ -128,7 +128,9 @@
match one of the glob-style *patterns* provided. See the example below.
-.. function:: copytree(src, dst, symlinks=False, ignore=None,
copy_function=copy2, ignore_dangling_symlinks=False)
+.. function:: copytree(src, dst, symlinks=False, ignore=None,
+ copy_function=copy2, ignore_dangling_symlinks=False, *,
+ follow_symlinks=True)
Recursively copy an entire directory tree rooted at *src*, returning the
destination directory. The destination
@@ -137,15 +139,17 @@
are copied with :func:`copystat`, individual files are copied using
:func:`shutil.copy2`.
- If *symlinks* is true, symbolic links in the source tree are represented as
+ If *follow_symlinks* is false or *symlinks* is true,
+ symbolic links in the source tree are represented as
symbolic links in the new tree and the metadata of the original links will
be copied as far as the platform allows; if false or omitted, the contents
and metadata of the linked files are copied to the new tree.
- When *symlinks* is false, if the file pointed by the symlink doesn't
+ When *follow_symlinks* is true or *symlinks* is false,
+ if the file pointed by the symlink doesn't
exist, a exception will be added in the list of errors raised in
a :exc:`Error` exception at the end of the copy process.
- You can set the optional *ignore_dangling_symlinks* flag to true if you
+ You can set the optional *ignore_dangling_symlinks* flag to ``True`` if you
want to silence this exception. Notice that this option has no effect
on platforms that don't support :func:`os.symlink`.
@@ -172,10 +176,15 @@
.. versionchanged:: 3.2
Added the *ignore_dangling_symlinks* argument to silent dangling symlinks
- errors when *symlinks* is false.
+ errors when *follow_symlinks* is true or *symlinks* is false.
.. versionchanged:: 3.3
- Copy metadata when *symlinks* is false.
+ Copy metadata when *follow_symlinks* is true or *symlinks* is false.
+
+ .. versionchanged:: 3.3
+ Added *follow_symlinks* argument with opposite meaning to *symlinks*.
+ *symlinks* should not be used in new code. A :exc:`TypeError` is raised
if
+ both *symlinks* and *follow_symlinks* are specified.
.. versionchanged:: 3.3
Added return of the *dst*.
@@ -312,7 +321,7 @@
above, with the docstring omitted. It demonstrates many of the other functions
provided by this module. ::
- def copytree(src, dst, symlinks=False):
+ def copytree(src, dst, *, follow_symlinks=True):
names = os.listdir(src)
os.makedirs(dst)
errors = []
@@ -320,11 +329,11 @@
srcname = os.path.join(src, name)
dstname = os.path.join(dst, name)
try:
- if symlinks and os.path.islink(srcname):
+ if not follow_symlinks and os.path.islink(srcname):
linkto = os.readlink(srcname)
os.symlink(linkto, dstname)
elif os.path.isdir(srcname):
- copytree(srcname, dstname, symlinks)
+ copytree(srcname, dstname, follow_symlinks =
follow_symlinks)
else:
copy2(srcname, dstname)
# XXX What about devices, sockets etc.?
diff -r d0f775432705 Lib/os.py
--- a/Lib/os.py Thu Jun 28 01:45:48 2012 +0200
+++ b/Lib/os.py Thu Jun 28 11:03:18 2012 +0300
@@ -388,6 +388,15 @@
dirs.remove('CVS') # don't visit CVS directories
"""
+ try:
+ fwalk
+ except NameError:
+ pass
+ else:
+ for x in fwalk(top, topdown=topdown, onerror=onerror,
followlinks=followlinks):
+ yield x[:-1]
+ return
+
islink, join, isdir = path.islink, path.join, path.isdir
# We may not have read permission for top, in which case we can't
diff -r d0f775432705 Lib/shutil.py
--- a/Lib/shutil.py Thu Jun 28 01:45:48 2012 +0200
+++ b/Lib/shutil.py Thu Jun 28 11:03:18 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 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):
@@ -250,8 +250,10 @@
return set(ignored_names)
return _ignore_patterns
-def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
- ignore_dangling_symlinks=False):
+_sentry = object()
+
+def copytree(src, dst, symlinks=_sentry, ignore=None, copy_function=copy2,
+ ignore_dangling_symlinks=False, *, follow_symlinks=_sentry):
"""Recursively copy a directory tree.
The destination directory must not already exist.
@@ -264,7 +266,7 @@
exist, an exception will be added in the list of errors raised in
an Error exception at the end of the copy process.
- You can set the optional ignore_dangling_symlinks flag to true if you
+ You can set the optional ignore_dangling_symlinks flag to True if you
want to silence this exception. Notice that this has no effect on
platforms that don't support os.symlink.
@@ -286,6 +288,12 @@
function that supports the same signature (like copy()) can be used.
"""
+ if symlinks is _sentry:
+ symlinks = follow_symlinks is not _sentry and not follow_symlinks
+ elif follow_symlinks is not _sentry:
+ raise TypeError("copytree() got values for both 'symlinks' and"
+ " 'follow_symlinks' arguments")
+
names = os.listdir(src)
if ignore is not None:
ignored_names = ignore(src, names)
@@ -307,7 +315,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 d0f775432705 Lib/test/test_shutil.py
--- a/Lib/test/test_shutil.py Thu Jun 28 01:45:48 2012 +0200
+++ b/Lib/test/test_shutil.py Thu Jun 28 11:03:18 2012 +0300
@@ -245,17 +245,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')
@@ -270,7 +270,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):
@@ -294,10 +294,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':
@@ -309,7 +309,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)
@@ -397,10 +397,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
@@ -414,12 +414,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'):
@@ -441,12 +441,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)
@@ -484,7 +484,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
@@ -555,6 +555,33 @@
if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
os.lchflags(src_link, stat.UF_NODUMP)
src_stat = os.lstat(src_link)
+ shutil.copytree(src_dir, dst_dir, follow_symlinks=False)
+ self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
+ self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
+ os.path.join(src_dir, 'file.txt'))
+ dst_stat = os.lstat(dst_link)
+ if hasattr(os, 'lchmod'):
+ self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
+ if hasattr(os, 'lchflags'):
+ self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
+
+ def test_copytree_symlinks_old(self):
+ tmp_dir = self.mkdtemp()
+ src_dir = os.path.join(tmp_dir, 'src')
+ dst_dir = os.path.join(tmp_dir, 'dst')
+ sub_dir = os.path.join(src_dir, 'sub')
+ os.mkdir(src_dir)
+ os.mkdir(sub_dir)
+ write_file((src_dir, 'file.txt'), 'foo')
+ src_link = os.path.join(sub_dir, 'link')
+ dst_link = os.path.join(dst_dir, 'sub/link')
+ os.symlink(os.path.join(src_dir, 'file.txt'),
+ src_link)
+ if hasattr(os, 'lchmod'):
+ os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
+ if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
+ os.lchflags(src_link, stat.UF_NODUMP)
+ src_stat = os.lstat(src_link)
shutil.copytree(src_dir, dst_dir, symlinks=True)
self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
@@ -565,6 +592,15 @@
if hasattr(os, 'lchflags'):
self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
+ def test_copytree_incompatible_args(self):
+ tmp_dir = self.mkdtemp()
+ src_dir = os.path.join(tmp_dir, 'src')
+ dst_dir = os.path.join(tmp_dir, 'dst')
+ sub_dir = os.path.join(src_dir, 'sub')
+ os.mkdir(src_dir)
+ os.mkdir(sub_dir)
+ self.assertRaises(TypeError, shutil.copytree, src_dir, dst_dir,
symlinks=True, follow_symlinks=False)
+
def test_copytree_with_exclude(self):
# creating data
join = os.path.join
@@ -748,9 +784,9 @@
shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
self.assertNotIn('test.txt', os.listdir(dst_dir))
- # a dangling symlink is copied if symlinks=True
+ # a dangling symlink is copied if follow_symlinks=False
dst_dir = os.path.join(self.mkdtemp(), 'destination3')
- shutil.copytree(src_dir, dst_dir, symlinks=True)
+ shutil.copytree(src_dir, dst_dir, follow_symlinks=False)
self.assertIn('test.txt', os.listdir(dst_dir))
def _copy_file(self, method):
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
http://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com