[Python-checkins] r80244 - in python/branches/py3k: Doc/library/shutil.rst Lib/shutil.py Lib/test/test_shutil.py Misc/NEWS

tarek.ziade python-checkins at python.org
Tue Apr 20 10:57:33 CEST 2010


Author: tarek.ziade
Date: Tue Apr 20 10:57:33 2010
New Revision: 80244

Log:
Fixed #6547: Added the ignore_dangling_symlinks option to shutil.copytree

Modified:
   python/branches/py3k/Doc/library/shutil.rst
   python/branches/py3k/Lib/shutil.py
   python/branches/py3k/Lib/test/test_shutil.py
   python/branches/py3k/Misc/NEWS

Modified: python/branches/py3k/Doc/library/shutil.rst
==============================================================================
--- python/branches/py3k/Doc/library/shutil.rst	(original)
+++ python/branches/py3k/Doc/library/shutil.rst	Tue Apr 20 10:57:33 2010
@@ -99,6 +99,12 @@
    symbolic links in the new tree; if false or omitted, the contents of the
    linked files are copied to the new tree.
 
+   When *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
+   want to silent this exception.
+
    If *ignore* is given, it must be a callable that will receive as its
    arguments the directory being visited by :func:`copytree`, and a list of its
    contents, as returned by :func:`os.listdir`.  Since :func:`copytree` is
@@ -120,6 +126,11 @@
       Added the *copy_function* argument to be able to provide a custom copy
       function.
 
+    .. versionchanged:: 3.2
+      Added the *ignore_dangling_symlinks* argument to silent dangling symlinks
+      errors when *symlinks* is false.
+
+
 .. function:: rmtree(path, ignore_errors=False, onerror=None)
 
    .. index:: single: directory; deleting

Modified: python/branches/py3k/Lib/shutil.py
==============================================================================
--- python/branches/py3k/Lib/shutil.py	(original)
+++ python/branches/py3k/Lib/shutil.py	Tue Apr 20 10:57:33 2010
@@ -147,7 +147,8 @@
         return set(ignored_names)
     return _ignore_patterns
 
-def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2):
+def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2,
+             ignore_dangling_symlinks=False):
     """Recursively copy a directory tree.
 
     The destination directory must not already exist.
@@ -156,7 +157,13 @@
     If the optional symlinks flag is true, symbolic links in the
     source tree result in symbolic links in the destination tree; if
     it is false, the contents of the files pointed to by symbolic
-    links are copied.
+    links are copied. If the file pointed by the symlink doesn't
+    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
+    want to silent this exception.
+
 
     The optional ignore argument is a callable. If given, it
     is called with the `src` parameter, which is the directory
@@ -190,9 +197,16 @@
         srcname = os.path.join(src, name)
         dstname = os.path.join(dst, name)
         try:
-            if symlinks and os.path.islink(srcname):
+            if os.path.islink(srcname):
                 linkto = os.readlink(srcname)
-                os.symlink(linkto, dstname)
+                if symlinks:
+                    os.symlink(linkto, dstname)
+                else:
+                    # ignore dangling symlink if the flag is on
+                    if not os.path.exists(linkto) and ignore_dangling_symlinks:
+                        continue
+                    # otherwise let the copy occurs. copy2 will raise an error
+                    copy_function(srcname, dstname)
             elif os.path.isdir(srcname):
                 copytree(srcname, dstname, symlinks, ignore, copy_function)
             else:

Modified: python/branches/py3k/Lib/test/test_shutil.py
==============================================================================
--- python/branches/py3k/Lib/test/test_shutil.py	(original)
+++ python/branches/py3k/Lib/test/test_shutil.py	Tue Apr 20 10:57:33 2010
@@ -13,7 +13,7 @@
 from distutils.spawn import find_executable, spawn
 from shutil import (_make_tarball, _make_zipfile, make_archive,
                     register_archive_format, unregister_archive_format,
-                    get_archive_formats)
+                    get_archive_formats, Error)
 import tarfile
 import warnings
 
@@ -351,6 +351,26 @@
         shutil.copytree(src_dir, dst_dir, copy_function=_copy)
         self.assertEquals(len(copied), 2)
 
+    def test_copytree_dangling_symlinks(self):
+
+        # a dangling symlink raises an error at the end
+        src_dir = self.mkdtemp()
+        dst_dir = os.path.join(self.mkdtemp(), 'destination')
+        os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
+        os.mkdir(os.path.join(src_dir, 'test_dir'))
+        self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456')
+        self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
+
+        # a dangling symlink is ignored with the proper flag
+        dst_dir = os.path.join(self.mkdtemp(), 'destination2')
+        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
+        dst_dir = os.path.join(self.mkdtemp(), 'destination3')
+        shutil.copytree(src_dir, dst_dir, symlinks=True)
+        self.assertIn('test.txt', os.listdir(dst_dir))
+
     @unittest.skipUnless(zlib, "requires zlib")
     def test_make_tarball(self):
         # creating something to tar

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Tue Apr 20 10:57:33 2010
@@ -318,6 +318,8 @@
 Library
 -------
 
+- Issue #6547: Added the ignore_dangling_symlinks option to shutil.copytree.
+
 - Issue #1540112: Now allowing the choice of a copy function in 
   shutil.copytree.
 


More information about the Python-checkins mailing list