0

I know this question is asked and answered many places on this site but none of the resolutions work for me. Basically, I need shutil.copy to work the same way as shutil.move works (and it does) but when I do .copy I get the Error 13 Permissions error on the source file.

I can't do shutil.copytree because I need not the content of the first file folder to be copied but the file folder itself (with the contents inside). I've tried checking the permissions, modifying, nothing works.

I've also tried using the full path including the folder names (no variables) and I still get the same error.

This is in Windows 7 and 8.1

Here is the code:

import os
import csv
import re
from os import path
from distutils.dir_util import copy_tree
import shutil


# Open the csv file
f = open("Consumers.csv")
csv_f = csv.reader(f)


#Loop throught the csv file
for eachrow in csv_f:
   
    #loop through the folders in the directory
     for foldname in os.listdir():

        #If the folder name is the same as a field in the first column of the csv file 
            if (foldname == eachrow[0]):
                
                #Name the second column filed name "bucket."  
                #This is also the name of a folder in the same directory
                bucket = eachrow[1]
                
                #copy the first folder (and contents) into the second folder
                shutil.copy (foldname, bucket)
            

And the error:


PermissionError                           Traceback (most recent call last)
<ipython-input-36-61e009418603> in <module>
     25 
     26                 #copy the first folder (and contents) into the second folder
---> 27                 shutil.copy (foldname, bucket)
     28 
     29 

~\Anaconda3\lib\shutil.py in copy(src, dst, follow_symlinks)
    243     if os.path.isdir(dst):
    244         dst = os.path.join(dst, os.path.basename(src))
--> 245     copyfile(src, dst, follow_symlinks=follow_symlinks)
    246     copymode(src, dst, follow_symlinks=follow_symlinks)
    247     return dst

~\Anaconda3\lib\shutil.py in copyfile(src, dst, follow_symlinks)
    118         os.symlink(os.readlink(src), dst)
    119     else:
--> 120         with open(src, 'rb') as fsrc:
    121             with open(dst, 'wb') as fdst:
    122                 copyfileobj(fsrc, fdst)

PermissionError: [Errno 13] Permission denied: 'Last1_First1_11111'

Any help would be greatly appreciated!

  • see https://stackoverflow.com/questions/23870808/oserror-errno-13-permission-denied – balderman Oct 03 '20 at 17:45
  • Is `Last1_First1_11111` a file or a directory? `shutil.copy` only supports copying files, and you will get a 'Permission denied' error on Windows attempting to perform file operations on a directory. – Luke Woodward Oct 03 '20 at 18:02
  • Thanks for the quick response. Yes, it's a directory. I guess what made me think I could do it is because it worked to shutil.move the directory. So if this command can't move a directory (which I really need to be able to do) can you help me with one that can? Thanks! – Kimberly Andersen Oct 03 '20 at 18:08
  • I would expect `shutil.copytree` to be able to copy directory trees. From reading your question it's not clear why it doesn't. – Luke Woodward Oct 03 '20 at 19:08
  • Thanks. Because it wants to create the folder fresh each time. The error is: FileExistsError: [WinError 183] Cannot create a file when that file already exists: 'BHS'...the problem is, it's looping through hundreds of directories and dozens will need to go into the "BHS" directory. Do you know a way around this? – Kimberly Andersen Oct 03 '20 at 19:35
  • Some few last points: Problems can result from (1) your code (2) something else, or both. W.r.t. (1): (a) Be even more specific: Are `folder 1/a` _relative_ or _absolute_? If relative then: Copy `parent 1/folder 1` to `parent a/folder a` with `parent 1/a` _absolute_. (b) How do you [debug](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) to make sure the variables contain the expected values? – Timus Oct 04 '20 at 15:24
  • W.r.t. (2) ((1) fixed): Do you have the permission to write in your target folder? – Timus Oct 04 '20 at 15:25
  • @Timus I am not sure exactly what you mean, I will have to look into this. I've been busy all day today but will attack this again at work tomorrow. Thanks! Kim – Kimberly Andersen Oct 05 '20 at 00:46

1 Answers1

0

I've done something similar once. So maybe this helps, if I understand you correctly.

You can modify the behaviour of copytree via the ignore= option. ignore= takes a callable that in turn takes the currently (i.e. during the recursion) visited path and a list of that path's content as arguments. It has to return an iterable that copytree then ignores.

I've used the following imports (you can adjust that):

import shutil
import os

Take this as ignore function:

def ignore(path, content_list):
    return [
        content
        for content in content_list
        if os.path.isdir(os.path.join(path, content))
    ]

It packs all subdirectories of the visited path in the ignore list. The effect is that copytree stops its recursion after the first directory and the files in it!

Instead of

shutil.copy (foldname, bucket)

use

shutil.copytree(foldname, bucket, ignore=ignore)

It worked as designed for me. But I'm a bit unsure how your path structure exactly looks like. It would be good if foldname and bucket were absolute paths.

To ensure that I would add the following to the imports (the Path class makes working with paths extremely easy):

from pathlib import Path

Then supplement the loop through the folder with

    #loop through the folders in the directory
     for foldname in os.listdir():
         fold_path = Path(foldname).resolve()

and use (instead of the version above)

shutil.copytree(fold_path, (fold_path.parent / bucket),
                ignore=ignore,
                dirs_exist_ok=True)

That's my understanding of what you are trying to achieve. (It's always good to illustrate questions with small examples to ensure that your intend is really clear.)

EDIT: Complete program (without comments and imports that aren't needed in this part):

import csv
import os
import shutil
from pathlib import Path

def ignore(path, content_list):
    return [
        content
        for content in content_list
        if os.path.isdir(os.path.join(path, content))
    ]

f = open("Consumers.csv")
csv_f = csv.reader(f)

for eachrow in csv_f:
    for foldname in os.listdir():
        fold_path = Path(foldname).resolve()
        if foldname == eachrow[0]:
            bucket = eachrow[1]
            shutil.copytree(fold_path, 
                            (fold_path.parent / bucket),
                            ignore=ignore,
                            dirs_exist_ok=True)
Timus
  • 10,974
  • 5
  • 14
  • 28
  • Thank you so much for this detail and the code! I'll continue to work on it over the weekend...I'm not exactly sure where what you wrote above fits into the code I have, but I'll continue to review and try to make it work. It's nice to know there's a possible solution. Thanks again!! – Kimberly Andersen Oct 03 '20 at 23:38
  • Timus, thank you so much for this! I really appreciate it. So, I copied this whole edit in, but still got an error: FileExistsError: [WinError 183] Cannot create a file when that file already exists: 'C:\\Users\\Kimberly\\Work Python\\Buckets\\BHS' Sorry to be a pain! – Kimberly Andersen Oct 04 '20 at 01:50
  • Timus, thank you so much. I did get an error with 'dirs_exist_ok' but I can continue to work on this, I don't want to keep taking up your time! And as for the description, I appreciate your input, this is my first time posting. So let me see if I can make this make sense. I have 13k folders and each of them has a bunch of PDFs in them. We'll call those folders folder1, folder2 , folder 3. Then I have seven other folders, folder a, folder b, folder c. All of the numbered folders need to be moved into the lettered folders. the csv has the numbered folders in the first column ... – Kimberly Andersen Oct 04 '20 at 12:32
  • ...and the lettered folders in the second column. The reason I have to use copy instead of move is because sometimes the numbered folders need to go into two or three different lettered folders. This is for security, as only certain people have access to certain lettered folders (HIPPA content.) I hope that makes more sense. – Kimberly Andersen Oct 04 '20 at 12:35