classification
Title: shutil.move() can't move a directory in non-empty directory on Windows
Type: behavior Stage: resolved
Components: Library (Lib), Windows Versions: Python 3.4, Python 3.3, Python 2.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: serhiy.storchaka Nosy List: francismb, hynek, python-dev, serhiy.storchaka, tarek
Priority: normal Keywords: needs review, patch

Created on 2013-12-01 19:01 by serhiy.storchaka, last changed 2014-02-11 08:58 by serhiy.storchaka. This issue is now closed.

Files
File name Uploaded Description Edit
shutil_move_dir_altsep.patch serhiy.storchaka, 2014-01-30 21:39 review
shutil_move_dir_altsep_python27.patch francismb, 2014-02-10 22:03 manually to 2.7
Messages (9)
msg204948 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2013-12-01 19:01
Perhaps following code fails on Windows (while successes on Linux): 

import os, shutil
os.makedirs('foo')
os.makedirs('bar/boo')
shutil.move('foo/', 'bar/')

However shutil.move('foo', 'bar/') and shutil.move('foo\\', 'bar/') should work.
msg205585 - (view) Author: Francis MB (francismb) * Date: 2013-12-08 17:01
Just feedback on windows7. I tried the tests inside IDLE and done 'Run Module' (F5) (deleting the directories between tests):

test_A:

import os, shutil
os.makedirs('foo')
os.makedirs('bar/boo')
shutil.move('foo/', 'bar/')

test_B:

import os, shutil
os.makedirs('foo')
os.makedirs('bar/boo')
shutil.move('foo', 'bar/')

and finally test_C:

import os, shutil
os.makedirs('foo')
os.makedirs('bar/boo')
shutil.move('foo\\', 'bar/')


... and got the same traceback:

Python 2.7.6 (default, Nov 10 2013, 19:24:18) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>> 

Traceback (most recent call last):
  File "D:\temp\test.py", line 4, in <module>
    shutil.move('foo/','bar/')
  File "D:\programs\Python27\lib\shutil.py", line 291, in move
    raise Error, "Destination path '%s' already exists" % real_dst
Error: Destination path 'bar/' already exists
>>>
msg205588 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2013-12-08 17:44
Thank you Francisco for testing. Here is different bug than I expected.

Looks as shutil.move() can't move a directory in non-empty directory on Windows.
msg209739 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2014-01-30 21:39
I suppose this patch should fix a bug on Windows.
msg210874 - (view) Author: Francis MB (francismb) * Date: 2014-02-10 22:01
First I've reviewed #msg205585 again (no patch applied). Notice that Traceback was not accurate:

test_A:

>>> os.makedirs('foo')
>>> os.makedirs('bar/foo')
>>> shutil.move('foo/', 'bar/')

Traceback (most recent call last):
  File "<pyshell#15>", line 1, in <module>
    shutil.move('foo/', 'bar/')
  File "D:\programs\Python27\lib\shutil.py", line 291, in move
    raise Error, "Destination path '%s' already exists" % real_dst
Error: Destination path 'bar/' already exists

test_B:
>>> os.makedirs('foo')
>>> os.makedirs('bar/foo')
>>> shutil.move('foo', 'bar/')

Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    shutil.move('foo', 'bar/')
  File "D:\programs\Python27\lib\shutil.py", line 291, in move
    raise Error, "Destination path '%s' already exists" % real_dst
Error: Destination path 'bar/foo' already exists


test_C:
>>> os.makedirs('foo')
>>> os.makedirs('bar/foo')
>>> shutil.move('foo\\', 'bar/')

Traceback (most recent call last):
  File "<pyshell#12>", line 1, in <module>
    shutil.move('foo\\', 'bar/')
  File "D:\programs\Python27\lib\shutil.py", line 291, in move
    raise Error, "Destination path '%s' already exists" % real_dst
Error: Destination path 'bar/foo' already exists
msg210876 - (view) Author: Francis MB (francismb) * Date: 2014-02-10 22:03
I've applied the patch manually to 2.7. Then I've done the tests again (notice test_A traceback):

test_A:
>>> import os, shutil
>>> os.makedirs('foo')
>>> os.makedirs('bar/foo')
>>> shutil.move('foo/', 'bar/')

Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    shutil.move('foo/', 'bar/')
  File "D:\programs\Python27\lib\shutil.py", line 292, in move
    raise Error, "Destination path '%s' already exists" % real_dst
Error: Destination path 'bar/foo' already exists


test_B:
>>> os.makedirs('foo')
>>> os.makedirs('bar/foo')
>>> shutil.move('foo', 'bar/')

Traceback (most recent call last):
  File "<pyshell#19>", line 1, in <module>
    shutil.move('foo', 'bar/')
  File "D:\programs\Python27\lib\shutil.py", line 292, in move
    raise Error, "Destination path '%s' already exists" % real_dst
Error: Destination path 'bar/foo' already exists

test_C:
>>> os.makedirs('foo')
>>> os.makedirs('bar/foo')
>>> shutil.move('foo\\', 'bar/')

Traceback (most recent call last):
  File "<pyshell#22>", line 1, in <module>
    shutil.move('foo\\', 'bar/')
  File "D:\programs\Python27\lib\shutil.py", line 292, in move
    raise Error, "Destination path '%s' already exists" % real_dst
Error: Destination path 'bar/foo' already exists
msg210877 - (view) Author: Francis MB (francismb) * Date: 2014-02-10 22:06
And finally the test runs:

1) The original. No new tests, no new patch.

== CPython 2.7.6 (default, Nov 10 2013, 19:24:18) [MSC v.1500 32 bit (Intel)]
==   Windows-7-6.1.7601-SP1 little-endian
==   c:\users\brugue\appdata\local\temp\test_python_5444
Testing with flags: sys.flags(debug=0, py3k_warning=0, division_warning=0, division_new=0, inspect=0, interactive=0, optimize=0, dont_write_bytecode=0, no_user_site=0, no_site=0, ignore_environment=0, tabcheck=0, verbose=0, unicode=0, bytes_warning=0, hash_randomization=0)
test_shutil
test_copystat_handles_harmless_chflags_errors (test.test_shutil.TestShutil) ... skipped 'requires os.chflags, EOPNOTSUPP & ENOTSUP'
test_copytree_simple (test.test_shutil.TestShutil) ... ok
test_copytree_with_exclude (test.test_shutil.TestShutil) ... ok
test_make_archive (test.test_shutil.TestShutil) ... ok
test_make_archive_cwd (test.test_shutil.TestShutil) ... ok
test_make_archive_owner_group (test.test_shutil.TestShutil) ... ok
test_make_tarball (test.test_shutil.TestShutil) ... ok
test_make_zipfile (test.test_shutil.TestShutil) ... ok
test_on_error (test.test_shutil.TestShutil) ... ok
test_register_archive_format (test.test_shutil.TestShutil) ... ok
test_rmtree_dont_delete_file (test.test_shutil.TestShutil) ... ok
test_rmtree_errors (test.test_shutil.TestShutil) ... ok
test_tarfile_root_owner (test.test_shutil.TestShutil) ... skipped 'Requires grp and pwd support'
test_tarfile_vs_tar (test.test_shutil.TestShutil) ... skipped 'Need the tar command to run'
test_destinsrc_false_negative (test.test_shutil.TestMove) ... ok
test_destinsrc_false_positive (test.test_shutil.TestMove) ... ok
test_dont_move_dir_in_itself (test.test_shutil.TestMove) ... ok
test_existing_file_inside_dest_dir (test.test_shutil.TestMove) ... ok
test_move_dir (test.test_shutil.TestMove) ... ok
test_move_dir_other_fs (test.test_shutil.TestMove) ... ok
test_move_dir_to_dir (test.test_shutil.TestMove) ... ok
test_move_dir_to_dir_other_fs (test.test_shutil.TestMove) ... ok
test_move_file (test.test_shutil.TestMove) ... ok
test_move_file_other_fs (test.test_shutil.TestMove) ... ok
test_move_file_to_dir (test.test_shutil.TestMove) ... ok
test_move_file_to_dir_other_fs (test.test_shutil.TestMove) ... ok
test_move_dir_caseinsensitive (test.test_shutil.TestCopyFile) ... ok
test_w_dest_close_fails (test.test_shutil.TestCopyFile) ... ok
test_w_dest_open_fails (test.test_shutil.TestCopyFile) ... ok
test_w_source_close_fails (test.test_shutil.TestCopyFile) ... ok
test_w_source_open_fails (test.test_shutil.TestCopyFile) ... ok

----------------------------------------------------------------------
Ran 31 tests in 0.359s

OK (skipped=3)
1 test OK.

2) New tests, no new patch:
== CPython 2.7.6 (default, Nov 10 2013, 19:24:18) [MSC v.1500 32 bit (Intel)]
==   Windows-7-6.1.7601-SP1 little-endian
==   c:\users\brugue\appdata\local\temp\test_python_5724
Testing with flags: sys.flags(debug=0, py3k_warning=0, division_warning=0, division_new=0, inspect=0, interactive=0, optimize=0, dont_write_bytecode=0, no_user_site=0, no_site=0, ignore_environment=0, tabcheck=0, verbose=0, unicode=0, bytes_warning=0, hash_randomization=0)
test_shutil
test_copystat_handles_harmless_chflags_errors (test.test_shutil.TestShutil) ... skipped 'requires os.chflags, EOPNOTSUPP & ENOTSUP'
test_copytree_simple (test.test_shutil.TestShutil) ... ok
test_copytree_with_exclude (test.test_shutil.TestShutil) ... ok
test_make_archive (test.test_shutil.TestShutil) ... ok
test_make_archive_cwd (test.test_shutil.TestShutil) ... ok
test_make_archive_owner_group (test.test_shutil.TestShutil) ... ok
test_make_tarball (test.test_shutil.TestShutil) ... ok
test_make_zipfile (test.test_shutil.TestShutil) ... ok
test_on_error (test.test_shutil.TestShutil) ... ok
test_register_archive_format (test.test_shutil.TestShutil) ... ok
test_rmtree_dont_delete_file (test.test_shutil.TestShutil) ... ok
test_rmtree_errors (test.test_shutil.TestShutil) ... ok
test_tarfile_root_owner (test.test_shutil.TestShutil) ... skipped 'Requires grp and pwd support'
test_tarfile_vs_tar (test.test_shutil.TestShutil) ... skipped 'Need the tar command to run'
test_destinsrc_false_negative (test.test_shutil.TestMove) ... ok
test_destinsrc_false_positive (test.test_shutil.TestMove) ... ok
test_dont_move_dir_in_itself (test.test_shutil.TestMove) ... ok
test_existing_file_inside_dest_dir (test.test_shutil.TestMove) ... ok
test_move_dir (test.test_shutil.TestMove) ... ok
test_move_dir_altsep_to_dir (test.test_shutil.TestMove) ... ERROR
test_move_dir_other_fs (test.test_shutil.TestMove) ... ok
test_move_dir_sep_to_dir (test.test_shutil.TestMove) ... ok
test_move_dir_to_dir (test.test_shutil.TestMove) ... ok
test_move_dir_to_dir_other_fs (test.test_shutil.TestMove) ... ok
test_move_file (test.test_shutil.TestMove) ... ok
test_move_file_other_fs (test.test_shutil.TestMove) ... ok
test_move_file_to_dir (test.test_shutil.TestMove) ... ok
test_move_file_to_dir_other_fs (test.test_shutil.TestMove) ... ok
test_move_dir_caseinsensitive (test.test_shutil.TestCopyFile) ... ok
test_w_dest_close_fails (test.test_shutil.TestCopyFile) ... ok
test_w_dest_open_fails (test.test_shutil.TestCopyFile) ... ok
test_w_source_close_fails (test.test_shutil.TestCopyFile) ... ok
test_w_source_open_fails (test.test_shutil.TestCopyFile) ... ok

======================================================================
ERROR: test_move_dir_altsep_to_dir (test.test_shutil.TestMove)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "D:\programs\Python27\lib\test\test_shutil.py", line 710, in test_move_dir_altsep_to_dir
    os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
  File "D:\programs\Python27\lib\test\test_shutil.py", line 637, in _check_move_dir
    shutil.move(src, dst)
  File "D:\programs\Python27\lib\shutil.py", line 291, in move
    raise Error, "Destination path '%s' already exists" % real_dst
Error: Destination path 'c:\users\brugue\appdata\local\temp\tmptncsw1\' already exists

----------------------------------------------------------------------
Ran 33 tests in 0.156s

FAILED (errors=1, skipped=3)
1 test failed:
    test_shutil

3) News tests and new patch:

== CPython 2.7.6 (default, Nov 10 2013, 19:24:18) [MSC v.1500 32 bit (Intel)]
==   Windows-7-6.1.7601-SP1 little-endian
==   c:\users\brugue\appdata\local\temp\test_python_5792
Testing with flags: sys.flags(debug=0, py3k_warning=0, division_warning=0, division_new=0, inspect=0, interactive=0, optimize=0, dont_write_bytecode=0, no_user_site=0, no_site=0, ignore_environment=0, tabcheck=0, verbose=0, unicode=0, bytes_warning=0, hash_randomization=0)
test_shutil
test_copystat_handles_harmless_chflags_errors (test.test_shutil.TestShutil) ... skipped 'requires os.chflags, EOPNOTSUPP & ENOTSUP'
test_copytree_simple (test.test_shutil.TestShutil) ... ok
test_copytree_with_exclude (test.test_shutil.TestShutil) ... ok
test_make_archive (test.test_shutil.TestShutil) ... ok
test_make_archive_cwd (test.test_shutil.TestShutil) ... ok
test_make_archive_owner_group (test.test_shutil.TestShutil) ... ok
test_make_tarball (test.test_shutil.TestShutil) ... ok
test_make_zipfile (test.test_shutil.TestShutil) ... ok
test_on_error (test.test_shutil.TestShutil) ... ok
test_register_archive_format (test.test_shutil.TestShutil) ... ok
test_rmtree_dont_delete_file (test.test_shutil.TestShutil) ... ok
test_rmtree_errors (test.test_shutil.TestShutil) ... ok
test_tarfile_root_owner (test.test_shutil.TestShutil) ... skipped 'Requires grp and pwd support'
test_tarfile_vs_tar (test.test_shutil.TestShutil) ... skipped 'Need the tar command to run'
test_destinsrc_false_negative (test.test_shutil.TestMove) ... ok
test_destinsrc_false_positive (test.test_shutil.TestMove) ... ok
test_dont_move_dir_in_itself (test.test_shutil.TestMove) ... ok
test_existing_file_inside_dest_dir (test.test_shutil.TestMove) ... ok
test_move_dir (test.test_shutil.TestMove) ... ok
test_move_dir_altsep_to_dir (test.test_shutil.TestMove) ... ok
test_move_dir_other_fs (test.test_shutil.TestMove) ... ok
test_move_dir_sep_to_dir (test.test_shutil.TestMove) ... ok
test_move_dir_to_dir (test.test_shutil.TestMove) ... ok
test_move_dir_to_dir_other_fs (test.test_shutil.TestMove) ... ok
test_move_file (test.test_shutil.TestMove) ... ok
test_move_file_other_fs (test.test_shutil.TestMove) ... ok
test_move_file_to_dir (test.test_shutil.TestMove) ... ok
test_move_file_to_dir_other_fs (test.test_shutil.TestMove) ... ok
test_move_dir_caseinsensitive (test.test_shutil.TestCopyFile) ... ok
test_w_dest_close_fails (test.test_shutil.TestCopyFile) ... ok
test_w_dest_open_fails (test.test_shutil.TestCopyFile) ... ok
test_w_source_close_fails (test.test_shutil.TestCopyFile) ... ok
test_w_source_open_fails (test.test_shutil.TestCopyFile) ... ok

----------------------------------------------------------------------
Ran 33 tests in 0.171s

OK (skipped=3)
1 test OK.


Hope it helps! Regards,

francis
msg210902 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2014-02-11 07:59
Thank you Francisco!
msg210907 - (view) Author: Roundup Robot (python-dev) Date: 2014-02-11 08:41
New changeset 51afe7839f8a by Serhiy Storchaka in branch '2.7':
Issue #19856: shutil.move() failed to move a directory to other directory
http://hg.python.org/cpython/rev/51afe7839f8a

New changeset 373ec8711ad0 by Serhiy Storchaka in branch '3.3':
Issue #19856: shutil.move() failed to move a directory to other directory
http://hg.python.org/cpython/rev/373ec8711ad0

New changeset 41610ad5c755 by Serhiy Storchaka in branch 'default':
Issue #19856: shutil.move() failed to move a directory to other directory
http://hg.python.org/cpython/rev/41610ad5c755
History
Date User Action Args
2014-02-11 08:58:57serhiy.storchakasetstatus: open -> closed
resolution: fixed
stage: patch review -> resolved
2014-02-11 08:41:15python-devsetnosy: + python-dev
messages: + msg210907
2014-02-11 07:59:30serhiy.storchakasetmessages: + msg210902
2014-02-10 22:06:11francismbsetmessages: + msg210877
2014-02-10 22:03:31francismbsetfiles: + shutil_move_dir_altsep_python27.patch

messages: + msg210876
2014-02-10 22:01:23francismbsetmessages: + msg210874
2014-02-10 17:37:44serhiy.storchakasetkeywords: + needs review
assignee: serhiy.storchaka
2014-01-30 21:39:20serhiy.storchakasetfiles: + shutil_move_dir_altsep.patch
keywords: + patch
messages: + msg209739

stage: needs patch -> patch review
2013-12-14 19:59:50serhiy.storchakasetstage: needs patch
2013-12-08 17:44:41serhiy.storchakasetnosy: + tarek, hynek

messages: + msg205588
title: Possible bug in shutil.move() on Windows -> shutil.move() can't move a directory in non-empty directory on Windows
2013-12-08 17:01:14francismbsetnosy: + francismb
messages: + msg205585
2013-12-01 19:01:14serhiy.storchakacreate