|
12 | 12 | import stat |
13 | 13 | import tempfile |
14 | 14 | import unittest |
| 15 | +import subprocess |
15 | 16 | from unittest import mock |
16 | 17 | from urllib.request import pathname2url |
17 | 18 |
|
@@ -3622,33 +3623,52 @@ def test_walk_symlink_location(self): |
3622 | 3623 | class PosixPathTest(PathTest, PurePosixPathTest): |
3623 | 3624 | cls = pathlib.PosixPath |
3624 | 3625 |
|
| 3626 | +@unittest.skipIf(os.name != 'nt', 'test requires a Windows-compatible system') |
| 3627 | +class WindowsPathTest(PathTest, PureWindowsPathTest): |
| 3628 | + cls = pathlib.WindowsPath |
| 3629 | + |
3625 | 3630 | def test_chmod_archive_bit_behavior(self): |
| 3631 | + import subprocess |
| 3632 | + |
| 3633 | + # gh-140774: Fix chmod failing to clear Read-Only if Archive bit is cleared. |
3626 | 3634 | base = self.cls(self.base) |
3627 | 3635 | filename = base / 'test_chmod_archive.txt' |
3628 | 3636 | filename.touch() |
3629 | | - self.addCleanup(filename.unlink, missing_ok=True) |
3630 | 3637 |
|
3631 | | - # Helper to check read-only status |
| 3638 | + # Robust cleanup: Force write permission before deleting |
| 3639 | + def force_remove(): |
| 3640 | + try: |
| 3641 | + os.chmod(filename, stat.S_IWRITE) |
| 3642 | + except OSError: |
| 3643 | + pass |
| 3644 | + try: |
| 3645 | + filename.unlink(missing_ok=True) |
| 3646 | + except OSError: |
| 3647 | + pass |
| 3648 | + |
| 3649 | + self.addCleanup(force_remove) |
| 3650 | + |
3632 | 3651 | def is_read_only(p): |
3633 | | - return (p.stat().st_file_attributes & stat.FILE_ATTRIBUTE_READONLY) > 0 |
| 3652 | + try: |
| 3653 | + return (p.stat().st_file_attributes & stat.FILE_ATTRIBUTE_READONLY) > 0 |
| 3654 | + except AttributeError: |
| 3655 | + return False |
| 3656 | + |
3634 | 3657 | try: |
3635 | 3658 | # Case 1: Archive bit CLEARED, Read-Only SET |
3636 | | - # We use attrib command to manipulate the Archive bit directly |
| 3659 | + # We use the Windows 'attrib' command to manipulate the Archive bit directly |
3637 | 3660 | subprocess.run(['attrib', '-a', '+r', str(filename)], check=True, shell=True) |
3638 | 3661 |
|
3639 | | - # This line used to fail silently (bug #140774) |
| 3662 | + # Try to make it Writable (clearing the Read-Only flag) |
3640 | 3663 | filename.chmod(stat.S_IWRITE | stat.S_IREAD) |
3641 | 3664 |
|
3642 | 3665 | self.assertFalse(is_read_only(filename), |
3643 | | - "chmod failed to clear Read-Only when Archive bit was cleared") |
| 3666 | + "chmod failed to clear Read-Only when Archive bit was cleared") |
3644 | 3667 |
|
3645 | 3668 | except subprocess.CalledProcessError: |
3646 | | - self.skipTest("attrib command failed or not available") |
3647 | | - |
3648 | | -@unittest.skipIf(os.name != 'nt', 'test requires a Windows-compatible system') |
3649 | | -class WindowsPathTest(PathTest, PureWindowsPathTest): |
3650 | | - cls = pathlib.WindowsPath |
3651 | | - |
| 3669 | + self.skipTest("attrib command failed") |
| 3670 | + except FileNotFoundError: |
| 3671 | + self.skipTest("attrib command not found") |
3652 | 3672 |
|
3653 | 3673 | class PathSubclassTest(PathTest): |
3654 | 3674 | class cls(pathlib.Path): |
|
0 commit comments