Eryk Sun <eryk...@gmail.com> added the comment:
The directory probably has the "readonly" attribute set. The documentation includes a basic remove_readonly error handler for rmtree [1]: import os, stat import shutil def remove_readonly(func, path, _): "Clear the readonly bit and reattempt the removal" os.chmod(path, stat.S_IWRITE) func(path) shutil.rmtree(directory, onerror=remove_readonly) That the readonly attribute prevents unlinking a directory is not particularly useful because a directory has to be empty anyway in order to unlink it. This is in contrast to the "immutable" file attribute in Linux, which prevents any modification of a directory, such as linking or unlinking files in it. Windows inherits its comparatively simplistic behavior for readonly directories from MS-DOS. Since setting a directory as readonly is practically useless, the Windows shell reuses this attribute to indicate a customized folder [2]. If a directory is flagged readonly, the shell checks for and reads a "desktop.ini" file in it that can set a custom name, icon, tooltip, etc. Given you're copying a folder that contains a desktop.ini file, it's very likely that the readonly attribute is set. shutil.copytree will copy the readonly attribute to the destination directory via os.chmod. This is the only file attribute that gets copied (e.g. hidden and system aren't handled), due to a hack in the Windows CRT that conflates the readonly file attribute as a write 'permission' for chmod() and stat(). (Being readonly is an attribute of the file or directory, not a granted permission. os.access is the correct function to take both attributes and permissions into account, not os.stat.) Python inherits the CRT behavior in its own implementation of os.chmod and os.stat in Windows. It does so as an accident of history, not because it's justified. [1] https://docs.python.org/3/library/shutil.html#rmtree-example [2] https://docs.microsoft.com/en-us/windows/win32/shell/how-to-customize-folders-with-desktop-ini ---------- _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue38868> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com