pythonshutilnetwork-share

Why am I getting permission denied when copying from a directory I can read in Python?


I've got a very large Plex library of mixed file types on my home server (Ubuntu). I'm attempting to pull the compatible types into a client iTunes library using python. I've got it mounted in Windows 11 as M: using credentials that give me full permissions. Here's the snippet I'm attempting to run:

import os
from pathlib import Path
import shutil


for f in Path("M:/Music").rglob("**/*"):
    if not str(f).endswith(".opus"):  # iTunes doesn't like OPUS files
        filename = os.path.split(f)[1]
        local_root = Path("C:/Users/username/Music/iTunes Media/Automatically Add to iTunes").as_posix()
        
        album_dir = Path(f).parent.as_posix()
        album_dir_name = os.path.split(album_dir)[1]
        artist_dir = Path(album_dir).parent.as_posix()
        artist_dir_name = os.path.split(artist_dir)[1]
        
        new_artist_dir = os.path.join(local_root, artist_dir_name)
        new_album_dir = os.path.join(new_artist_dir, album_dir_name)
        new_file = os.path.join(new_album_dir, filename)

        shutil.copy(f, new_file)

The shutil.copy call gives me:

PermissionError:  [Errono 13] Permission denied: 'M:\\Music\\Academy of St Martin in the Fields'  # the first artist path in the rglob

I'm able to traverse and list all files on the drive without issue. In Windows I've got the drive mounted with full privileges, which I thought inherit to Python via the os module. In my workplace, I am able to copy/move from the NAS to local drives without any extra logging in, also a hybrid Windows/Linux environment.

I have seen a couple cases where people resorted to using either pywin32 or Windows own net use command via subprocess but with no thorough examples, and neither have worked for me. How do I copy content from my mounted network share using Python?


Solution

  • This happens if you are trying to open a file, but your path is a folder.

    This can happen easily by mistake.

    To defend against that, use:

    import os
    
    path = r"my/path/to/file.txt"
    assert os.path.isfile(path)
    with open(path, "r") as f:
        pass
    

    The assertion will fail if the path is actually of a folder.