sct_2015
sct_2015

Reputation: 29

Python Errno 2 - No such file, leading zeros

Here's my program:

import numpy as np
import scipy as sp
import itertools
import os
import csv
import shutil

src = 'src';
dst = 'dst';

data = []
n = 1

while n < 233:
    charn = str(n)
    for j in range(1,9): # This will represent each plug subdirectory
        for i in range(1,30):
            if i < 10:
                chari = str(i).zfill(2)
                charj = str(j).zfill(2)
                shutil.copytree(src+'HS_BIN_I'+chari+'_J'+charj+'/',dst+charn+'/'+'HS_BIN_I'+chari+'_J'+charj+'/')
            chari = str(i)
            charj = str(j).zfill(2)
            shutil.copytree(src+'HS_BIN_I'+chari+'_J'+charj+'/',dst+charn+'/'+'HS_BIN_I'+chari+'_J'+charj+'/')
    print chari
    print charj
    print charn
    n = n + 1

So I'm copying folders from one directory to another (232 different folders), but some folders have leading zeros. For instance, it might look like this:

HS_BIN_I01_J01

While others look like this:

HS_BIN_I12_J08 (J never goes beyond 08, while I goes up to 29).

So naturally, I need to accommodate for these leading zeros when I write my script. Unfortunately, I get the following error when I execute it:

Traceback (most recent call last):
  File "cpfldr_232points.py", line 34, in <module>
    shutil.copytree(src+'HS_BIN_I'+chari+'_J'+charj+'/',dst+charn+'/'+'HS_BIN_I'+chari+'_J'+charj+'/')
  File "/usr/lib64/python2.6/shutil.py", line 136, in copytree
    names = os.listdir(src)
OSError: [Errno 2] No such file or directory: '/src/HS_BIN_I1_J01/'

BUT! When I go into my destination directory, the folder has been copied correctly as:

HS_BIN_I01_J01.

So it says the folder doesn't exist, but then copies it correctly anyway and immediately stops (no other folders are copied).

What's going on here?

Thanks for your help!

Upvotes: 0

Views: 119

Answers (3)

Jonathan Eunice
Jonathan Eunice

Reputation: 22483

You're looping a lot more than 233 times. You're iterating n 232 times, j 8 times, and i 29 times. 232 * 8 * 29 = 53824. So one of the things going on is that you are generating a lot more paths than you think you are.

Second, it's entirely unclear what paths you're actually generating. The code is too complex to guess with ease. Instead of:

shutil.copytree(src+'HS_BIN_I'+chari+'_J'+charj+'/',dst+charn+'/'+'HS_BIN_I'+chari+'_J'+charj+'/')

Consider:

src_path = src+'HS_BIN_I'+chari+'_J'+charj+'/'
dst_path = dst+charn+'/'+'HS_BIN_I'+chari+'_J'+charj+'/'
shutil.copytree(src_path, dst_path)

It's easier to read, and it lets you insert an all-important print statement that will show you what results are occurring.

src_path = src+'HS_BIN_I'+chari+'_J'+charj+'/'
dst_path = dst+charn+'/'+'HS_BIN_I'+chari+'_J'+charj+'/'
print "src_path:", src_path, "dst_path:", dst_path
shutil.copytree(src_path, dst_path)

That will demonstrate that you are generating paths that seem to be missing a key "/" separator:

src_path: 'srcHS_BIN_I10_J08/'  dst_path: 'dst232/HS_BIN_I10_J08/'

Even better, generate your path statements with higher-level formatting operations. You're doing a lot of manual conversions that the format method of strings does more cleanly. For example,

src_path = "{src}/HS_BIN_I{i:02d}_J{j:02d}/'.format(**locals())

Does string interpolation of values (src, i, and j) from the local context (roughly, the function into which you should drop this code), and does so using format specifiers like :02d ("two-digit integer with leading zeros, if needed").

Final code:

def copy_dirs(src, dst):
    """
    Copy subfolders from `src` directory into `dst` directory,
    if they are present.
    """
    for n in range(1, 233):
        for j in range(1, 9):
            for i in range(1, 30):
                src_path = "{src}/HS_BIN_I{i:02d}_J{j:02d}/".format(**locals())
                dst_path = "{dst}/{n}/HS_BIN_I{i:02d}_J{j:02d}/".format(**locals())
                # print "src_path:", src_path, "dst_path:", dst_path
                if os.path.isdir(src_path):
                    shutil.copytree(src_path, dst_path)

I still don't think you want to copy 50K+ directories...but maybe you do. If so, this is a cleaner, more bulletproofed way to do it.

Upvotes: 0

nelfin
nelfin

Reputation: 1049

You can make the intention of your code clearer by utilising string formatting to do the zero-padding and the product method from itertools module in the Python standard library:

import itertools
import shutil
import os.path

src = 'src'
dst = 'dst'
for i, j in itertools.product(range(1, 9), range(1, 30)):
    dirname = 'HS_BIN_I{0:02}_J{1:02}'.format(i, j)
    destdir = '{prefix}{n}'.format(prefix=dst, n=i*j)
    shutil.copytree(os.path.join(src, dirname),
                    os.path.join(destdir, dirname))

Upvotes: 1

paidhima
paidhima

Reputation: 2392

I think you need an else statement:

    if i < 10:
        chari = str(i).zfill(2)
        charj = str(j).zfill(2)
        shutil.copytree(src+'HS_BIN_I'+chari+'_J'+charj+'/',dst+charn+'/'+'HS_BIN_I'+chari+'_J'+charj+'/')
    chari = str(i)
    charj = str(j).zfill(2)
    shutil.copytree(src+'HS_BIN_I'+chari+'_J'+charj+'/',dst+charn+'/'+'HS_BIN_I'+chari+'_J'+charj+'/')

Right now, your code will perform both of the bits of code above, whether the number is less than 10 or not. It should be:

if i < 10:
    chari = str(i).zfill(2)
    charj = str(j).zfill(2)
    shutil.copytree(src+'HS_BIN_I'+chari+'_J'+charj+'/',dst+charn+'/'+'HS_BIN_I'+chari+'_J'+charj+'/')
else:
    chari = str(i)
    charj = str(j).zfill(2)
    shutil.copytree(src+'HS_BIN_I'+chari+'_J'+charj+'/',dst+charn+'/'+'HS_BIN_I'+chari+'_J'+charj+'/')

You don't actually need the second part at all, however. After your if i in range(1, 30): just do:

chari = str(i).zfill(2)
charj = str(j).zfill(2)
shutil.copytree(src+'HS_BIN_I'+chari+'_J'+charj+'/',dst+charn+'/'+'HS_BIN_I'+chari+'_J'+charj+'/')

The zfill will take care of adding leading zeroes if necessary.

Upvotes: 0

Related Questions