mirror of https://github.com/python/cpython
bpo-26791: Update shutil.move() to provide the same symlink move behavior as the mv shell when moving a symlink into a directory that is the target of the symlink (GH-21759)
This commit is contained in:
parent
1b19d73768
commit
c66b577d9f
|
@ -885,7 +885,7 @@ def move(src, dst, copy_function=copy2):
|
|||
sys.audit("shutil.move", src, dst)
|
||||
real_dst = dst
|
||||
if os.path.isdir(dst):
|
||||
if _samefile(src, dst):
|
||||
if _samefile(src, dst) and not os.path.islink(src):
|
||||
# We might be on a case insensitive filesystem,
|
||||
# perform the rename anyway.
|
||||
os.rename(src, dst)
|
||||
|
|
|
@ -2688,6 +2688,35 @@ class TestMove(BaseTest, unittest.TestCase):
|
|||
finally:
|
||||
os.rmdir(dst_dir)
|
||||
|
||||
# bpo-26791: Check that a symlink to a directory can
|
||||
# be moved into that directory.
|
||||
@mock_rename
|
||||
def _test_move_symlink_to_dir_into_dir(self, dst):
|
||||
src = os.path.join(self.src_dir, 'linktodir')
|
||||
dst_link = os.path.join(self.dst_dir, 'linktodir')
|
||||
os.symlink(self.dst_dir, src, target_is_directory=True)
|
||||
shutil.move(src, dst)
|
||||
self.assertTrue(os.path.islink(dst_link))
|
||||
self.assertTrue(os.path.samefile(self.dst_dir, dst_link))
|
||||
self.assertFalse(os.path.exists(src))
|
||||
|
||||
# Repeat the move operation with the destination
|
||||
# symlink already in place (should raise shutil.Error).
|
||||
os.symlink(self.dst_dir, src, target_is_directory=True)
|
||||
with self.assertRaises(shutil.Error):
|
||||
shutil.move(src, dst)
|
||||
self.assertTrue(os.path.samefile(self.dst_dir, dst_link))
|
||||
self.assertTrue(os.path.exists(src))
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
def test_move_symlink_to_dir_into_dir(self):
|
||||
self._test_move_symlink_to_dir_into_dir(self.dst_dir)
|
||||
|
||||
@os_helper.skip_unless_symlink
|
||||
def test_move_symlink_to_dir_into_symlink_to_dir(self):
|
||||
dst = os.path.join(self.src_dir, 'otherlinktodir')
|
||||
os.symlink(self.dst_dir, dst, target_is_directory=True)
|
||||
self._test_move_symlink_to_dir_into_dir(dst)
|
||||
|
||||
@os_helper.skip_unless_dac_override
|
||||
@unittest.skipUnless(hasattr(os, 'lchflags')
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
:func:`shutil.move` now moves a symlink into a directory when that
|
||||
directory is the target of the symlink. This provides the same behavior as
|
||||
the mv shell command. The previous behavior raised an exception. Patch by
|
||||
Jeffrey Kintscher.
|
Loading…
Reference in New Issue