New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
shutil.move raises AttributeError if first argument is a pathlib.Path object and destination is a directory #76870
Comments
>>> import os, pathlib, shutil
>>> os.mkdir('test1')
>>> os.mkdir('test2')
>>> path = pathlib.Path('test1')
>>> shutil.move(path, 'test2')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/shutil.py", line 540, in move
real_dst = os.path.join(dst, _basename(src))
File "/usr/lib/python3.6/shutil.py", line 504, in _basename
return os.path.basename(path.rstrip(sep))
AttributeError: 'PosixPath' object has no attribute 'rstrip' |
Thanks for the bug report! shutil.move should certainly accept a path object, as shutil.copy does, though it should be noted that in your example, 'path' could become out of date as it does not refresh the path information. For example, with shutil.move fixed: >>> import os, pathlib, shutil
>>> os.mkdir('test1')
>>>
>>> os.mkdir('test2')
>>> path = pathlib.Path('test1')
>>> path.absolute()
PosixPath('/Users/e/Development/OSS/cpython/test1')
>>> shutil.move(path, 'test2')
'test2/test1'
>>> path.absolute()
PosixPath('/Users/e/Development/OSS/cpython/test2') test1 is now actually at '/Users/e/Development/OSS/cpython/test2/test1' For the fix: After trying a few different approaches, I think the simplest way is to cast the src to a string before finding its appropriate basename. I also added some comments to make it more clear why _basename is used over os.path.basename to hopefully save someone else time in the future. A more robust option would be to explicitly handle Path objects or to handle exceptions for any dst that cannot be cast to a string. However, the current patch fixes the issue without introducing new problems. |
In my test, the second call to path.absolute() is just returning the same result as the first call, which is what I would expect (as you say, the path object doesn't update automatically). However, your output shows it returning '/Users/e/Development/OSS/cpython/test2' instead of the (now broken) path from the first call. Maybe I'm missing something? |
Ah, you're right. That was a typo when I was redacting my full path. The path object remains unchanged even though the directory has moved. Should have been: >>> import os, pathlib, shutil
>>> os.mkdir('test1')
>>> os.mkdir('test2')
>>> path = pathlib.Path('test1')
>>> path.absolute()
PosixPath('/Users/e/Development/OSS/cpython/test1')
>>> shutil.move(path, 'test2')
'test2/test1'
>>> path.absolute()
PosixPath('/Users/e/Development/OSS/cpython/test1') test1 is now actually at '/Users/e/Development/OSS/cpython/test2/test1' |
3.9 only! |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: