Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 34k
GH-73991: Add pathlib.Path.move()#122073
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
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
f6d09c01dc0bfbf488ff8ff7746f29e51f536955abd5950475de963ee1c0d9ea98aed40af6396348cabdaca70d1aa27f4804b115abe48d2aa5ee60af9219ee5ad2c1d46b1fc2d889dff9d9210892cc785b8372aa8199fd5175d6878182a88File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -2072,6 +2072,125 @@ def test_copy_dangling_symlink(self): | ||
| self.assertTrue(target2.joinpath('link').is_symlink()) | ||
| self.assertEqual(target2.joinpath('link').readlink(), self.cls('nonexistent')) | ||
| def test_move_file(self): | ||
| base = self.cls(self.base) | ||
| source = base / 'fileA' | ||
| source_text = source.read_text() | ||
| target = base / 'fileA_moved' | ||
| result = source.move(target) | ||
picnixz marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| self.assertEqual(result, target) | ||
| self.assertFalse(source.exists()) | ||
| self.assertTrue(target.exists()) | ||
| self.assertEqual(source_text, target.read_text()) | ||
| def test_move_file_to_file(self): | ||
| base = self.cls(self.base) | ||
| source = base / 'fileA' | ||
| source_text = source.read_text() | ||
| target = base / 'dirB' / 'fileB' | ||
| result = source.move(target) | ||
| self.assertEqual(result, target) | ||
| self.assertFalse(source.exists()) | ||
| self.assertTrue(target.exists()) | ||
| self.assertEqual(source_text, target.read_text()) | ||
| def test_move_file_to_dir(self): | ||
| base = self.cls(self.base) | ||
| source = base / 'fileA' | ||
| target = base / 'dirB' | ||
picnixz marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| self.assertRaises(OSError, source.move, target) | ||
picnixz marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| def test_move_file_to_itself(self): | ||
| base = self.cls(self.base) | ||
| source = base / 'fileA' | ||
| self.assertRaises(OSError, source.move, source) | ||
| def test_move_dir(self): | ||
| base = self.cls(self.base) | ||
| source = base / 'dirC' | ||
| target = base / 'dirC_moved' | ||
| result = source.move(target) | ||
| self.assertEqual(result, target) | ||
| self.assertFalse(source.exists()) | ||
| self.assertTrue(target.is_dir()) | ||
| self.assertTrue(target.joinpath('dirD').is_dir()) | ||
| self.assertTrue(target.joinpath('dirD', 'fileD').is_file()) | ||
| self.assertEqual(target.joinpath('dirD', 'fileD').read_text(), | ||
| "this is file D\n") | ||
| self.assertTrue(target.joinpath('fileC').is_file()) | ||
| self.assertTrue(target.joinpath('fileC').read_text(), | ||
| "this is file C\n") | ||
| def test_move_dir_to_dir(self): | ||
| base = self.cls(self.base) | ||
| source = base / 'dirC' | ||
| target = base / 'dirB' | ||
| self.assertRaises(OSError, source.move, target) | ||
| self.assertTrue(source.exists()) | ||
| self.assertTrue(target.exists()) | ||
picnixz marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| def test_move_dir_to_itself(self): | ||
| base = self.cls(self.base) | ||
| source = base / 'dirC' | ||
| self.assertRaises(OSError, source.move, source) | ||
| self.assertTrue(source.exists()) | ||
| def test_move_dir_into_itself(self): | ||
picnixz marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| base = self.cls(self.base) | ||
| source = base / 'dirC' | ||
| target = base / 'dirC' / 'bar' | ||
| self.assertRaises(OSError, source.move, target) | ||
| self.assertTrue(source.exists()) | ||
| self.assertFalse(target.exists()) | ||
| @needs_symlinks | ||
| def test_move_file_symlink(self): | ||
| base = self.cls(self.base) | ||
| source = base / 'linkA' | ||
| source_readlink = source.readlink() | ||
| target = base / 'linkA_moved' | ||
| result = source.move(target) | ||
| self.assertEqual(result, target) | ||
| self.assertFalse(source.exists()) | ||
| self.assertTrue(target.is_symlink()) | ||
| self.assertEqual(source_readlink, target.readlink()) | ||
| @needs_symlinks | ||
| def test_move_file_symlink_to_itself(self): | ||
| base = self.cls(self.base) | ||
| source = base / 'linkA' | ||
| self.assertRaises(OSError, source.move, source) | ||
| @needs_symlinks | ||
| def test_move_dir_symlink(self): | ||
| base = self.cls(self.base) | ||
| source = base / 'linkB' | ||
| source_readlink = source.readlink() | ||
| target = base / 'linkB_moved' | ||
| result = source.move(target) | ||
| self.assertEqual(result, target) | ||
| self.assertFalse(source.exists()) | ||
| self.assertTrue(target.is_symlink()) | ||
| self.assertEqual(source_readlink, target.readlink()) | ||
| @needs_symlinks | ||
| def test_move_dir_symlink_to_itself(self): | ||
| base = self.cls(self.base) | ||
| source = base / 'linkB' | ||
| self.assertRaises(OSError, source.move, source) | ||
picnixz marked this conversation as resolved. Show resolvedHide resolvedUh oh!There was an error while loading. Please reload this page. | ||
| @needs_symlinks | ||
| def test_move_dangling_symlink(self): | ||
| base = self.cls(self.base) | ||
| source = base / 'brokenLink' | ||
| source_readlink = source.readlink() | ||
| target = base / 'brokenLink_moved' | ||
| result = source.move(target) | ||
| self.assertEqual(result, target) | ||
| self.assertFalse(source.exists()) | ||
| self.assertTrue(target.is_symlink()) | ||
| self.assertEqual(source_readlink, target.readlink()) | ||
| def test_iterdir(self): | ||
| P = self.cls | ||
| p = P(self.base) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Add :meth:`pathlib.Path.move`, which moves a file or directory tree. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just me thinking loud, but do you think we should have a boolean to not overwrite an existing target (in which case, a
FileExistsErrorwould be raised)?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could add a
clobber=Trueargument, but I think that would be a separate PR.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have thought of
strict(strict=False by default, strict=True would raise) orreplace=True. But we can address this question later. Otherwise, it's just a three liner where users would doif not os.exists(target)if they want to avoid replacing files.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Clobber" has some currency already, e.g. in
mv --no-clobber. But yeah, let's discuss later.