[docs] [issue27886] Docs: the difference between rename and replace is not obvious
Eryk Sun
report at bugs.python.org
Sun Aug 28 18:56:53 EDT 2016
Eryk Sun added the comment:
Having rename() in pathlib is fine as long as it links to the os docs. This probably needs a new issue, but I do see room for improvement in the latter.
For Unix, the os.rename and os.replace docs should clarify that an empty destination directory can be replaced by another directory. For example:
>>> os.mkdir('foo1')
>>> os.mkdir('foo2')
>>> os.rename('foo1', 'foo2')
The specification of rename [1] states that "[i]f the *old* argument points to the pathname of a directory, the *new* argument shall not point to the pathname of a file that is not a directory". It further specifies that "[i]f *new* names an existing directory, it shall be required to be an empty directory". Windows, on the other hand, doesn't allow replacing a directory, even an empty one. The wording for os.rename and os.replace could be changed to something like: "[i]f dst is a directory, OSError will be raised, except not on Unix if src is a directory and dst is empty".
Windows MoveFileEx calls NtSetInformationFile to set the FileRenameInformation [2]. The MSDN docs do not explicitly require that the operation is atomic, unlike POSIX rename. I think it's a reasonable expectation that a Windows filesystem should rename atomically, and that's probably the case. However, it should be clear that only Unix guarantees this, e.g. "[i]f successful, on Unix the renaming will be an atomic operation, as required by POSIX".
MSDN claims that a rename will fail in the following cases:
A file or directory can only be renamed within a volume.
Even if ReplaceIfExists is set to TRUE, the rename operation
will still fail if a file with the same name already exists
and is a directory, a read-only file, or a currently
executing file.
A file cannot be renamed if it has any open handles, unless it
is only open because of a batch opportunistic lock (oplock)
and the batch oplock can be broken immediately.
A file cannot be renamed if a file with the same name exists
and has open handles (except in the batch-oplock case
described earlier).
A directory cannot be renamed if it or any of its
subdirectories contains a file that has open handles (except
in the batch-oplock case described earlier).
For the third case, actually an open file can be renamed if delete/rename access is shared. For example:
>>> with open('foo1', 'w') as f: f.write('foo1')
...
4
Open the file with shared delete access:
>>> SHARE_ALL = 7
>>> _winapi.CreateFile('foo1', 0x80000000, SHARE_ALL, 0, 3, 0, 0)
224
and rename/replace succeeds:
>>> os.replace('foo1', 'foo2')
>>> open('foo2').read()
'foo1'
Anyway, the os.replace docs could state in general that: "[o]n Windows, a PermissionError will be raised if dst is a read-only file, or if either src or dst is currently open, or if src is a directory with an open file".
[1]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html
[2]: https://msdn.microsoft.com/en-us/library/ff540344
----------
nosy: +eryksun
_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue27886>
_______________________________________
More information about the docs
mailing list