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!
Related
I am trying to work on copying files to a different directory based on a specific file name listed in excel. I am using shutil to copy files from one directory to another directory, but it keep showing the FileNotFound.
This is the error message:
Traceback (most recent call last):
File "C:\Python\HellWorld\TestCopyPaste.py", line 20, in <module>
shutil.copytree(i, output_file, dirs_exist_ok=True)
File "C:\Users\Asus\Anaconda3\envs\untitled\lib\shutil.py", line 556, in copytree
with os.scandir(src) as itr:
FileNotFoundError: [WinError 3] The system cannot find the path specified: 'Test.pdf'
I am still new to python, please let me know if there's any part can be enhanced :)
Below are my codes:
import os
import shutil
import pandas as pd
#Set file path
input_file = "C:\\Users\\Asus\\Desktop\\Python\\Input\\"
output_file = "C:\\Users\\Asus\\Desktop\\Python\\Output\\"
#Set new variable for the file path to store the list of files
file_list = os.listdir(input_file)
#search the required file name that need to copy to another location
#Create loop to search the files
condition = pd.read_excel(r'C:\\Users\\Asus\\Desktop\\Python\Condition.xlsx')
for i in file_list:
for filename in condition:
if filename in i:
print(i)
shutil.copytree(i, output_file, dirs_exist_ok=True)
As mentioned in comments one issue is that you aren't joining the filename to the full filepath ("input_file").
I'm not really familiar with shutil but I believe the function you want to use is shutil.copy not shutil.copytree. It looks like copytree copies the directory structure of a specified source directory and you are specifically only looking at a list of files within a top level directory. Another issue is how you are reading the excel file.
Assuming the files are listed in a single column it should be something like:
condition = pd.read_excel("C:\\Users\\Asus\\Desktop\\Python\\Condition.xlsx",index_col=None,header=None)
(I also removed your 'r' prefix to the string in this part)
Then to get the items in the first column: condition[0].tolist()
I also believe the second for loop is unnecessary. You can use the same if statement you already have in a single loop.
The following is my solution, just change he paths to what you want. I changed variable names to make it a little more readable as well.
(assumes all files are listed in a single column in excel with no header. And all file are in the input file directory with no subdirectories)
import os
import shutil
import pandas as pd
#Set file path
input_file_dir = "C:\\Users\\myusername\\py\\input\\"
output_file_dir = "C:\\Users\\myusername\\py\\output\\"
#Set new variable for the file path to store the list of files
file_list_from_dir = os.listdir(input_file_dir)
#search the required file name that need to copy to another location
#Create loop to search the files
file_list_from_excel = pd.read_excel("C:\\Users\\myusername\\py\\Condition.xlsx",index_col=None,header=None)
file_list_from_excel = file_list_from_excel[0].tolist()
for thefileNameinDir in file_list_from_dir:
if thefileNameinDir in file_list_from_excel:
print(f"File matched: {thefileNameinDir}")
tempSourcePath = os.path.join(input_file_dir,thefileNameinDir)
shutil.copy(tempSourcePath, output_file_dir)
I tried creating a code where the file, when you run creates a replica of itself and deletes the original file.
Here is my code:
import shutil
import os
loc=os.getcwd()
shutil.move("./aa/test.py", loc, copy_function=shutil.copy2)
But the issue with this is that:
this code is only 1 time usable and to use it again, I need to change the name of the file or delete the newly created file and then run it again.
Also, If I run it inside a folder, It will always create the new file outside the folder (in a dir up from the exceuting program).
How Do I fix this?
Some Notes:
The copy should be made at the exact place where the original file was.
The folder was empty, just having this file. The file doesn't needs to be in a folder but I just used it as a test instance.
Yes, I understand that if I delete the original file it should stop working. I actually have a figure in my mind of how It should work:
First, a new file with the exact same content in it will be made > in the same path as the original file (with a different name probably).
Then, the original file will be deleted and the 2nd file (which is > the copy of the original file) will be renamed as the exact name and > extension as of the original file which got deleted.
This thing above should repeat every time I run the .py file (containing this code) thus making this code portable and suitable for multiple uses.
Maybe the code to be executed after the file deletion can be stored in memory cache (I guess?).
Easiest way (in pseudo code):
Get name of current script.
Read all contents in memory.
Delete current script.
Write memory contents into new file with the same name.
this code is only 1 time usable and to use it again, I need to change the name of the file or delete the newly created file and then run it again.
That is of course because the file is called differently. You could approach this by having no other files in that folder, or always prefixing the filename in the same way, so that you can find the file although it always is called differently.
Also, If I run it inside a folder, It will always create the new file outside the folder (in a dir up from the exceuting program).
That is because you move it from ./aa to ./. You can take the path of the file and reuse it, apart for the filename, and then it would be in the same folder.
Hey TheKaushikGoswami,
I believe your code does exactly what you told him to and as everybody before me stated, surely only works once. :)
I would like to throw in another idea:
First off I'd personally believe that shutil.move is more of a method for actually moving a file into another directory, as you did by accident.
https://docs.python.org/3/library/shutil.html#shutil.move
So why not firstly parameterize your folder (makes it easier for gui/cmd access) and then just copy to a temporary file and then copying from that temporary file. That way you wont get caught in errors raised if you try to create files already existing and have an easy-to-understand code!
Like so:
import shutil
import os
try:
os.mkdir('./aa/')
except:
print('Folder already exists!')
dest= './aa/'
file= 'test.py'
copypath = dest + 'tmp' + file
srcpath = dest + file
shutil.copy2(srcpath, copypath, follow_symlinks=True)
os.remove(srcpath)
shutil.copy2(copypath, srcpath, follow_symlinks=True)
os.remove(copypath)
But may I ask what your use-case is for that since it really doesn't change anything for me other than creating an exact same file?
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"
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
I'm just trying to write a little application that takes a value from a file named 'DATA.DAT' and renames the folder which contains that file with that value.
The .py script runs in another folder and allows the user to define the path. To give you a better idea, the user defined path must be like (on a mac) '/Users/User/Desktop/FOLDER' and 'FOLDER' should contain 'DATA.DAT'.
That's how a little part of the source code looks like:
try:
data = open('DATA.DAT').read()
data_data = data[12:17]
path_paths = path.rsplit('/')
basepath = '/'.join(path_paths[:-1])
chdir(basepath)
if path_paths[-1] <> data_data:
rename(path_paths[-1], data_data)
raw_input('Folder name has been corrected! Thank you.')
quit()
else:
print('Folder name was already correct! Thank you.')
quit()
except IndexError:
raw_input('ERROR!')
quit()
Well, it works; but it raise and exception when 'FOLDER' contains more than one file (actually, 'FOLDER' should contain just 'DATA.DAT' and other folders. That doesn't give problems.)...
Traceback (most recent call last):
File "/Users/User/Desktop/example.py", line 72, in <module>
rename(path_paths[-1], data_data)
OSError: [Errno 66] Directory not empty
Just to prevent that this happens, is there a way to fix it? Thanks.
Edit: The right tool is shutil.move:
shutil.move(path_paths[-1], data_data)
assuming path_paths[-1] is the absolute directory you want to rename, and data_data is the absolute directory name you want to rename it to.
The destination directory must not already exist for this to work. The two locations don't need to be on the same filesystem.
Old answer: Use os.renames instead of os.rename.
It will recursively create any needed directories.
It is much easier to use shutil.
Althoug a decade later.. is possible to replace the way for split path
path_paths = path.rsplit('/')
for
path_paths = os.path.split(path)[1]
And for renaming problem:
os.rename('myfolder/oldname', 'myfolder/newname')