beeware / briefcase

Tools to support converting a Python project into a standalone native application.

Home Page:https://briefcase.readthedocs.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

On Windows, renaming a directory that was just created can fail with `PermissionError: [WinError 5] Access denied`

rmartin16 opened this issue · comments

Describe the bug

Using os.rename() (or pathlib.Path.rename()) can fail on Windows if Briefcase does not have exclusive access to all files in the directory.

A common pattern Briefcase uses is to run shutil.unpack_archive() and rename the unpacked directory; for instance, Android cmdline-tools and Java's JDK. In between these two operations, a background process may acquire a handle on a file; for instance, a Windows file indexer or an antivirus scanner.

Modern Linux file systems are much more resilient to these types of conflicts; so, I would only expect to see this on Windows.

Steps to reproduce

import os
from pathlib import Path

Path("orig-dir-1").mkdir()
Path("orig-dir-1/orig-file").touch()
Path("orig-dir-1").rename("new-dir-1")
os.listdir("new-dir-1")

Path("orig-dir-2").mkdir()
Path("orig-dir-2/orig-file").touch()
Path("orig-dir-2/orig-file").open()
Path("orig-dir-2").rename("new-dir-2")
python
Python 3.11.3 (tags/v3.11.3:f3909b8, Apr  4 2023, 23:49:59) [MSC v.1934 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> from pathlib import Path
>>>
>>> Path("orig-dir-1").mkdir()
>>> Path("orig-dir-1/orig-file").touch()
>>> Path("orig-dir-1").rename("new-dir-1")
WindowsPath('new-dir-1')
>>> os.listdir("new-dir-1")
['orig-file']
>>>
>>> Path("orig-dir-2").mkdir()
>>> Path("orig-dir-2/orig-file").touch()
>>> Path("orig-dir-2/orig-file").open()
<_io.TextIOWrapper name='orig-dir-2\\orig-file' mode='r' encoding='cp1252'>
>>> Path("orig-dir-2").rename("new-dir-2")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\user\.pyenv\pyenv-win\versions\3.11.3\Lib\pathlib.py", line 1175, in rename
    os.rename(self, target)
PermissionError: [WinError 5] Access is denied: 'orig-dir-2' -> 'new-dir-2'
>>>

Expected behavior

Renaming these directories in the Briefcase cache should be successful.

Screenshots

No response

Environment

  • Operating System: Windows 11
  • Python version: 3.11.3
  • Software versions:
    • Briefcase: 0.3.18

Logs

No response

Additional context

Origin: beeware/beeware#348

See also #394 for a tangentially related issue.

Unfortunately this is a common issue on WIndows, and I don't think there's any workaround except putting all renames and deletions in a retry loop. There are packages such as tenacity which make this easier.

pycon24, taking a look at this. Thanks!

Path("orig-dir-1").mkdir()
Path("orig-dir-1/orig-file").touch()
Path("orig-dir-1").rename("new-dir-1")
os.listdir("new-dir-1")

Path("orig-dir-2").mkdir()
Path("orig-dir-2/orig-file").touch()
Path("orig-dir-2/orig-file").open()
Path("orig-dir-2").rename("new-dir-2")

Path("orig-dir-2").mkdir()
Path("orig-dir-2/orig-file").touch()
Path("orig-dir-2/orig-file").open()
Path("orig-dir-2").rename("new-dir-3")

Path("orig-dir-2").mkdir()
Path("orig-dir-2/orig-file").touch()
Path("orig-dir-2/orig-file").open()
Path("orig-dir-2").rename("new-dir-4")

@Deepak6546kumar It's not clear what you're trying to communicate with this code sample. We already had a replication case; what extra information are you providing here?