Skip to content

bpo-28356: Document os.rename() behavior on Windows for differing filesystems #27376

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

Merged
merged 4 commits into from
Jan 9, 2023

Conversation

rhyn0
Copy link
Contributor

@rhyn0 rhyn0 commented Jul 26, 2021

@bedevere-bot bedevere-bot added the docs Documentation in the Doc dir label Jul 26, 2021
@@ -2292,6 +2292,8 @@ features:
will fail with an :exc:`OSError` subclass in a number of cases:

On Windows, if *dst* exists a :exc:`FileExistsError` is always raised.
The operation will fail if *src* and *dst* are on different filesystems. Use
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say it "may" fail, and move this out of the "if dst exists" section (which is introduced in the preceding paragraph).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Zooba,

Thanks for the comment. The original (bpo-28356) talks about this, the main point of this documentation update is to alert users that it automatically will fail when moving across different disk drives (file systems).

This is something that is explained in errors in Python 3.8.10 but is missed in the documentation. See my terminal

As for the other point, I read it as being grouped together with Windows, as the next paragraph talks about Unix systems. I could rewrite the whole Windows paragraph, but I thought it better to tack it on to existing content.

I will leave it alone for now unless there is more discussion about this on either the bpo or in this thread.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a Windows dev, but @eryksun also said on the issue that it will always fail because of the specific Windows API call used in the implementation. On the other hand, perhaps we should say "may" so we can get away with changing the behavior in the future if we want.

As for the placement, the current docs (https://docs.python.org/3.10/library/os.html#os.rename) aren't very clear. The Unix paragraph has a bunch of other information beyond behavior if dst already exists. I'd actually suggest removing the "If dst exists, the operation will fail with an OSError subclass in a number of cases:" sentence completely. That way, we just have one paragraph talking about Windows oddities and one talking about Unix oddities.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation of os.rename() in Windows calls MoveFileExW() without the flag MOVEFILE_COPY_ALLOWED. The documentation states that "[i]f the destination is on another drive, you must [emphasis added] set the MOVEFILE_COPY_ALLOWED flag in dwFlags". This flag is not used by os.rename() or os.replace() because the destination is not supposed to be a copied file that has a new ID in the system.

POSIX rename() allows a system to support links across file systems, but the inode number -- and presumably the (dev, ino) tuple that uniquely identifies a file in the system -- must remain the same. I haven't seen this implemented. I've only ever seen rename fail with EXDEV in this case.

That said, using "may fail" is fine. A new version of NTFS and the Windows I/O manager could implement a type of reparse point that uses the FILE_ID_INFO, which in theory could be used to rename and hard link across two NTFS file systems.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, there's a difference between "will always fail with the current implementation" and "will always fail for all time". This is the first case, but if we write it in the docs, we've made it the second case.

Better to leave ourselves open here, in case we (or Microsoft) decide to enable it later. Then we don't need to deprecate the function for two releases before changing it.

@github-actions
Copy link

github-actions bot commented Sep 2, 2021

This PR is stale because it has been open for 30 days with no activity.

@github-actions github-actions bot added the stale Stale PR or inactive for long period of time. label Sep 2, 2021
@@ -0,0 +1 @@
The documentation about os.rename() used on Windows systems updated to reflect behavior about moving across filesystems. Patch by Ryan Ozawa
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The documentation about os.rename() used on Windows systems updated to reflect behavior about moving across filesystems. Patch by Ryan Ozawa
Document the behavior of :func:`os.rename` when moving across filesystems on Windows. Patch by Ryan Ozawa.

Shorter, and NEWS entries should be in the imperative

@@ -2292,6 +2292,8 @@ features:
will fail with an :exc:`OSError` subclass in a number of cases:

On Windows, if *dst* exists a :exc:`FileExistsError` is always raised.
The operation will fail if *src* and *dst* are on different filesystems. Use
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a Windows dev, but @eryksun also said on the issue that it will always fail because of the specific Windows API call used in the implementation. On the other hand, perhaps we should say "may" so we can get away with changing the behavior in the future if we want.

As for the placement, the current docs (https://docs.python.org/3.10/library/os.html#os.rename) aren't very clear. The Unix paragraph has a bunch of other information beyond behavior if dst already exists. I'd actually suggest removing the "If dst exists, the operation will fail with an OSError subclass in a number of cases:" sentence completely. That way, we just have one paragraph talking about Windows oddities and one talking about Unix oddities.

@github-actions github-actions bot removed the stale Stale PR or inactive for long period of time. label Aug 11, 2022
@slateny
Copy link
Contributor

slateny commented Dec 6, 2022

@rhyn0 Would you be interested in updating the PR per the reviews?

@zooba zooba added the skip news label Dec 6, 2022
@zooba
Copy link
Member

zooba commented Dec 6, 2022

This doesn't require a NEWS entry at all, it can be removed rather than updated.

@@ -2292,6 +2292,8 @@ features:
will fail with an :exc:`OSError` subclass in a number of cases:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to keep this sentence since explicitly stating that all the related exceptions below are subclasses of OSError could be helpful for easily catching the exceptions, but I can remove it nonetheless if wanted here.

@@ -2292,6 +2292,8 @@ features:
will fail with an :exc:`OSError` subclass in a number of cases:

On Windows, if *dst* exists a :exc:`FileExistsError` is always raised.
The operation may fail if *src* and *dst* are on different filesystems. Use
:func:`shutil.move` to support moves to a different filesystem.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe since this statement is Windows-specific, it's fine to keep it under the Windows section despite being slightly unrelated to the general case of dst existing. But let me know if it's preferred to open up a new paragraph above/below (or if removing the sentence on dst exists is preferred).

@zooba
Copy link
Member

zooba commented Jan 9, 2023

Thanks for all the changes!

@zooba zooba merged commit e098137 into python:main Jan 9, 2023
@zooba zooba added needs backport to 3.10 only security fixes needs backport to 3.11 only security fixes labels Jan 9, 2023
@miss-islington
Copy link
Contributor

Thanks @rhyn0 for the PR, and @zooba for merging it 🌮🎉.. I'm working now to backport this PR to: 3.11.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Thanks @rhyn0 for the PR, and @zooba for merging it 🌮🎉.. I'm working now to backport this PR to: 3.10.
🐍🍒⛏🤖

@bedevere-bot
Copy link

GH-100896 is a backport of this pull request to the 3.11 branch.

@bedevere-bot bedevere-bot removed the needs backport to 3.11 only security fixes label Jan 9, 2023
@bedevere-bot
Copy link

GH-100897 is a backport of this pull request to the 3.10 branch.

@bedevere-bot bedevere-bot removed the needs backport to 3.10 only security fixes label Jan 9, 2023
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jan 9, 2023
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Jan 9, 2023
miss-islington added a commit that referenced this pull request Jan 9, 2023
miss-islington added a commit that referenced this pull request Jan 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Documentation in the Doc dir skip news
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants