I am having trouble copying directories - python

I am trying to copy my Automater workflows, I have listed them in a config file, and I would like to loop through the config file and copy the directories. They have spaces in the names and I am having trouble.
It prints the filename correctly etc but the copy fails as there seems to be extra " " around the name with the copy
import os
import shutil
confdir=os.getenv("my_config")
dropbox=os.getenv("dropbox")
conffile = ('services.conf')
conffilename=os.path.join(confdir, conffile)
sourcedir= (r'~/Library/Services/')
destdir=os.path.join(dropbox, "My_backups")
for file_name in open(conffilename):
sourcefile=os.path.join(sourcedir, repr(file_name.strip()))
print sourcefile
destfile=os.path.join(destdir, file_name.strip())
shutil.copytree(sourcefile, destfile)
And the error is
~/Library/Services/'Add PDF Metadata.workflow'
Traceback (most recent call last):
File "Untitled 3.py", line 15, in <module>
shutil.copytree(sourcefile, destfile)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/shutil.py", line 168, in copytree
names = os.listdir(src)
OSError: [Errno 2] No such file or directory: "~/Library/Services/'Add PDF Metadata.workflow'"
Thanks in advance
I have tried the suggestions below but it still is not working

Why are you using repr() on file_name.strip()? That will surround your filename with single quotes - and those aren't present in the file path. Remove the repr(), and it should work.

shutil.copytree(src, dst) will recursively copy a directory tree (and all the files in it) located at src to a new directory tree at dst. It is not meant to be used with files.
Here, you want to copy single files around, not a complete directory tree, you should just use shutil.copy or shutil.copy2.
If the files may be located in a directory tree that you want to reproduce, then you could use os.makedirs for the path returned by os.path.dirname(destfile) before calling shutil.copy(sourcefile) to actually copy the file to destfile.
However, be aware that calling os.makedirs with a destination that already exists will raise an error so you probably want to try / except.

It didn't like the ~ I put the full path in. I have also just edited one more bit and used sourcedir=os.path.expanduser('~/Library/Services/') to expand the home directory

Related

Not randomising file names because of a problem

I'm beginning to learn python and I thought I should try to make a program.
So I tried to make minecraft texture randomizer. I think my code makes sense but there is a huge problem I did not think through. When I rename the files in a random order. It cant rename for example. "Obsidian.png" -> "Endstone.png" as obsidian so I tried using os.mkdir() and copy the file and paste it into that folder, then it would rename that file, however there is still a message. And just to clarify I will make it so it will delete the old folder and rename the new folder to the same name.
My code:
import random
import shutil
def my_shuffle(arr):
random.shuffle(arr)
return arr
os.chdir('C:/Users/PC Specialist/Documents/Python Scripts/r/assets\minecraft/textures/item')
oldTextures = os.listdir()
newRandomizedTextures = my_shuffle(os.listdir())
print(newRandomizedTextures)
i = 0
os.mkdir("C:/Users/PC Specialist/Documents/Python Scripts/r/assets\minecraft/textures/item1")
for x in newRandomizedTextures:
shutil.copy('C:/Users/PC Specialist/Documents/Python Scripts/r/assets\minecraft/textures/item/' + oldTextures[i], 'C:/Users/PC Specialist/Documents/Python Scripts/r/assets\minecraft/textures/item1')
os.rename('C:/Users/PC Specialist/Documents/Python Scripts/r/assets\minecraft/textures/item1/' + oldTextures[i], 'C:/Users/PC Specialist/Documents/Python Scripts/r/assets/minecraft/textures/item1/' + newRandomizedTextures[i])
i = i + 1
This is the error:
Traceback (most recent call last):
File "C:\Users\PC Specialist\Documents\Python\pythonProject\main.py", line 16, in <module>
os.mkdir("C:/Users/PC Specialist/Documents/Python Scripts/r/assets\minecraft/textures/item1")
FileExistsError: [WinError 183] Cannot create a file when that file already exists: 'C:/Users/PC Specialist/Documents/Python Scripts/r/assets\\minecraft/textures/item1'
Your original error is because of the mkdir line. The second time you run the script it will try to make that same dir again. You could just manually create the dir and remove that line or put a try/except around it and ignore the error:
try:
os.mkdir("/blah")
except FileExistsError:
# ignore
pass
I think it's a similar problem when you're testing your shutil.move. You should clean the directory between runs.
One neat trick you can use:
for i, newTexture in enumerate(newRandomizedTextures):
print(i)
print(newTexture)
enumerate will give you the index.
For each set of files which will replace each other, you will need to rename at least one of the files to a temporary name. But the simple brute-force solution is to rename all your files twice: First, to a temporary name, then to the final names, now that none of them will be taken.
Here is a quick and dirty sketch:
import shutil
import os
import random
originals = os.scandir('.')
for idx, file in enumerate(originals):
shutil.move(file, 'temp%08i.png' % idx)
random.shuffle(originals)
for idx, file in enumerate(originals):
shutil.move('temp%08i.png' % idx, file)
This will leave some temporary files behind if you interrupt it midway through; probably keep a list of the original file names handy somewhere, in case that happens (probably with checksums so you can discover which contents go with which original file name).
Notice also that this will rename files in the current directory; don't run it somewhere important!

How to use the file path as the source parameter from os.walk to copy files

Okay, so I'm not sure how to get python to use the path to a file that it found through an os.walk function as the source parameter for the shutil.copy(source, destination) arguments.
My code example is this
for folderName, subfolders, filenames in os.walk('/Users/me/Documents'):
print('The current folder is '+folderName)
for subfolder in subfolders:
print('SUBFOLDER OF '+folderName+": "+subfolder)
for filename in filenames:
print("FILE INSIDE "+folderName+": "+filename)
if filename.endswith('.txt'):
os.chdir(filename)
shutil.copy(filename, '/Users/me/Documents/School/IT 145/Text Files')
print("")
If the file has a .txt extension, I would like python to copy that file to the specified folder.
My error message I get is this
The current folder is /Users/me/Documents/Text Files
FILE INSIDE /Users/me/Documents/Text Files: guest.txt
Traceback (most recent call last):
File "/Users/me/Documents/School/IT 145/Programming Work/os_walk.py", line 16, in <module>
os.chdir(filename)
FileNotFoundError: [Errno 2] No such file or directory: 'guest.txt'
From what I understand, python is going back to the current working directory to do the shutil.copy, but I don't understand why if I pass it the file path that it just found it won't use that as the source path for the file to copy.
This is my first ever python programming class, and really my first brush with python all, so any teaching thoughts would be greatly appreciated. Thank you very much.
Your current code never leaves its original working directory. You can verify this by running:
print(os.getcwd())
Your os.walk() does not change the current directory (CWD).
Your attempt at changing the CWD:
os.chdir(filename)
does not work since filename is a file name and not a directory.
os.chdir(folderName)
would work.
You could use the approach of changing into the directory just to copy the file. But, you can't be doing that it every iteration of your loop, either -- only on the first. Or, better yet, you could change into the directory at the start. In any case, I advice against this approach since its an unnecessary overhead.
Instead, just prefix the filename with its parent directory -- i.e. folderName when you call shutil.copy().
For example:
shutil.copy(os.path.join(folderName, filename), '/Users/me/Documents/School/IT 145/Text Files')
Side note for readability:
Put '/Users/me/Documents' and '/Users/me/Documents/School/IT 145/Text Files' into named variables -- which makes it easier to read, change and/or reuse if needed.
Side note for portability:
Aim to use os.path.join() instead of using / for the directory separator.

Renaming Files in Python, Getting FileNotFoundError [duplicate]

I am trying to write a program to categorize into folders a large amount of files according to their respective groups indicated in the file name. I wrote the followin code, but when I run it it gives me a file not found error, even though the file is in the given path. I'd appreciate any help in figuring out what is wrong.
import os
old_dir = '/Users/User/Desktop/MyFolder'
for f in os.listdir(old_dir):
file_name, file_ext = os.path.splitext(f)
file_name.split('-')
split_file_name = file_name.split('-')
new_dir = os.path.join(old_dir,
'-'.join(split_file_name[:3]),
split_file_name[5],
f)
os.rename(os.path.join(old_dir, f), new_dir)
Here's the error:
Traceback (most recent call last):
File "/Users/User/Documents/Sort Files into Folders/Sort Files into Folders.py", line 19, in <module>
os.rename(os.path.join(old_dir, f), new_dir)
FileNotFoundError: [Errno 2] No such file or directory: '/Users/User/Desktop/MyFolder/AHA35-3_30x1_12-31-7d-g1a1-ArmPro.jpg' -> '/Users/User/Desktop/MyFolder/AHA35-3_30x1_12-31/ArmPro/AHA35-3_30x1_12-31-7d-g1a1-ArmPro.jpg
os.rename does not automatically create new directories (recursively), if the new name happens to be a filename in a directory that does not exist.
To create the directories first, you can (in Python 3) use:
os.makedirs(dirname, exist_ok=True)
where dirname can contain subdirectories (existing or not).
Alternatively, use os.renames, that can handle new and intermediate directories. From the documentation:
Recursive directory or file renaming function. Works like rename(), except creation of any intermediate directories needed to make the new pathname good is attempted first
os.rename need path, so it should look like:
os.rename(path+old_name, path+new_name)

python: zipfile.ZipFile No such file or directory

There is folder path:
P:\\2018\\Archive\\
There are many zipfiles I want to create programmatically, but am starting with test. I will name this test zip file "CO_007_II.zip" and will attempt to create in above location:
import zipfile as zp
with zp.ZipFile("P:\\2018\\Archive\\CO_007_II.zip",'w') as myzip:
myzip.write(r"P:\2018\CO_007_II")
But I get error!
...
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
File "C:\Python27\ArcGIS10.2\lib\zipfile.py", line 752, in __init__
self.fp = open(file, modeDict[mode])
IOError: [Errno 2] No such file or directory: 'P:\\2018\\Archive\\CO_007_II.zip'
Is this not method for creating new zipfile? I know file does not exist. Is why I am using 'w' mode, no?
This is documentation:
https://docs.python.org/3/library/zipfile.html
It says:
'w' to truncate and write a new file
Example on documentation page:
with ZipFile('spam.zip', 'w') as myzip:
myzip.write('eggs.txt')
code worked two days ago to create new zip file but did not add folder. Today nothing works! Why not? All paths valid. How do I create new zip file with python and add folders to it?
I also encountered a similar issue and came here looking for answers. Since this was the top hit, I'll add what I discovered.
The answer provided by #metatoaster didn't work for me, when stepping through the code I found that the path returned true to isdir.
In my case, the path length exceeded the Windows max path length (260 chars) which was causing it to fail despite the folder path being valid.
Hope that helps someone else down the line!
The only way this could be reproduced was to create a zipfile in a directory that does NOT exist yet. The only way to be sure (you cannot trust a file manager; only way to verify is to check from within the program itself) is to assign the desired path of the new zip file to a variable (e.g. path), and then call isdir(dirname(path)). For example:
from os.path import isdir
from os.path import dirname
target = "P:\\2018\\Archive\\CO_007_II.zip"
if not isdir(dirname(target)):
print('cannot create zipfile because target does not exists')
else:
# create the zipfile
I had the same issue. It was the long path. I solved by adding this //?/C at the beginning of the path
path = r"//?/C:\Users\Camilo\Proyectos"

Adding file to existing zipfile

I'm using python's zipfile module.
Having a zip file located in a path of:
/home/user/a/b/c/test.zip
And having another file created under /home/user/a/b/c/1.txt
I want to add this file to existing zip, I did:
zip = zipfile.ZipFile('/home/user/a/b/c/test.zip','a')
zip.write('/home/user/a/b/c/1.txt')
zip.close()`
And got all the subfolders appears in path when unzipping the file, how do I just enter the zip file without path's subfolders?
I tried also :
zip.write(os.path.basename('/home/user/a/b/c/1.txt'))
And got an error that file doesn't exist, although it does.
You got very close:
zip.write(path_to_file, os.path.basename(path_to_file))
should do the trick for you.
Explanation: The zip.write function accepts a second argument (the arcname) which is the filename to be stored in the zip archive, see the documentation for zipfile more details.
os.path.basename() strips off the directories in the path for you, so that the file will be stored in the archive under just it's name.
Note that if you only zip.write(os.path.basename(path_to_file)) it will look for the file in the current directory where it (as the error says) does not exist.
import zipfile
# Open a zip file at the given filepath. If it doesn't exist, create one.
# If the directory does not exist, it fails with FileNotFoundError
filepath = '/home/user/a/b/c/test.zip'
with zipfile.ZipFile(filepath, 'a') as zipf:
# Add a file located at the source_path to the destination within the zip
# file. It will overwrite existing files if the names collide, but it
# will give a warning
source_path = '/home/user/a/b/c/1.txt'
destination = 'foobar.txt'
zipf.write(source_path, destination)

Categories

Resources