Why am I getting Flake8 F821 error when the variable exists? - python

I have a function that's returning a variable, and a second function that's using it. In my main func though flake8 is coming up that the variable is undefined.
I tried adding it as a global var, and placing a tox.ini file in the same folder as my script with ignore = F821 but this didn't register either. A
Any suggestions? Code block is below for reference. new_folder is the culprit
def createDestination(self):
'''
split the src variable for machine type
and create a folder with 'Evo' - machine
'''
s = src.split('\\')
new_folder = (dst + '\\Evo ' + s[-1])
if not os.path.exists(new_folder):
os.makedirs(new_folder)
return self.new_folder
def copyPrograms(new_folder):
'''
find all TB-Deco programs in second tier directory.
'''
# create file of folders in directory
folder_list = os.listdir(src)
# iterate the folder list
for folder in folder_list:
# create a new directory inside each folder
folder_src = (src + '\\' + folder)
# create a list of the files in the folder
file_list = os.listdir(folder_src)
# iterate the list of files
for file in file_list:
# if the file ends in .part .PART .dbp or .DBP - add it to a list
if (file.endswith('.part') or file.endswith('.PART') or
file.endswith('.dbp') or file.endswith('.DBP')):
# create a location variable for that file
file_src = (src + folder + '\\' + file)
# copy the file from the server to dst folder
new_file = ('Evo ' + file)
file_dst = (new_folder + '\\' + new_file)
if not os.path.exists(file_dst):
shutil.copy2(file_src, file_dst)
def main():
createDestination()
copyPrograms(new_folder)
if __name__ == "__main__":
main()

The first problem is that createDestination never defines an attribute self.new_folder, only a local variable new_folder. The indentation is also off, as you want to return new_folder whether or not you had to create it first.
def createDestination(self):
'''
split the src variable for machine type
and create a folder with 'Evo' - machine
'''
s = src.split('\\')
new_folder = (dst + '\\Evo ' + s[-1])
if not os.path.exists(new_folder):
os.makedirs(new_folder)
return new_folder # not self.new_folder
Second, you never assigned the return value of createDestination to any name so that you could pass it to copyPrograms as an argument.
def main():
new_folder = createDestination()
copyPrograms(new_folder)
Names have scope, and a variable named new_folder inside createDestination is distinct from one by the same name in main. As a corollary, there's no need to use the same name; the following definition of main works just as well:
def main():
d = createDestination()
copyPrograms(d)
and you don't even need to name the return value; you can pass it directly as
def main():
copyPrograms(createDestination())

Related

How can I avoid repeating a for loop in two different functions

I am writing an ImageCollection class in python that should hold a dictionary with a name and the image-object (pygame.image object).
In one case I want to load all images inside a folder to the dictionary and in another case just specific files, for example only button-files.
What I have written so far is this:
class ImageCollection:
def __init__(self):
self.dict = {}
def load_images(self, path):
directory = os.fsencode(path)
for file in os.listdir(directory):
file_name = os.fsdecode(file)
img_path = path + "/" + file_name
if file_name.endswith(".jpg") or file_name.endswith(".png"):
# Remove extension for dictionary entry name and add image to dictionary
#-----------------------------------------------------------------------
dict_entry_name = file_name.removesuffix(".jpg").removesuffix(".png")
self.dict.update({dict_entry_name: image.Image(img_path, 0)})
def load_specific_images(self, path, contains_str):
directory = os.fsencode(path)
for file in os.listdir(directory):
file_name = os.fsdecode(file)
img_path = path + "/" + file_name
if file_name.endswith(".jpg") or file_name.endswith(".png"):
if file_name.rfind(contains_str):
# Remove extension for dictionary entry name and add image to dictionary
#-----------------------------------------------------------------------
dict_entry_name = file_name.removesuffix(".jpg").removesuffix(".png")
self.dict.update({dict_entry_name: image.Image(img_path, 0)})
The only problem is that this is probably bad programming pattern, right? In this case it probably doesnt matter but I would like to know what the best-practice in this case would be.
How can I avoid repeating myself in two different functions when the only difference is just a single if condition?
I have tried creating a "dict_add" function that creates the entry.
Then I was thinking I could create two different functions, one which directly calls "dict_add" and the other one checks for the specific condition and then calls "dict_add".
Then I thought I could add create just a single function with the for-loop but pass a function as an argument (which would be a callback I assume?). But one callback would need an additional argument so thats where I got stuck and wondered if my approach was correct.
You could make the contains_str an optional argument.
In cases where you want to load_images - you just provide the path
In cases where you want to load specific images - you provide the path and the contains_str argument
In both cases you call load_images(...)
Code:
class ImageCollection:
def __init__(self):
self.dict = {}
def load_images(self, path, contains_str=""):
directory = os.fsencode(path)
for file in os.listdir(directory):
file_name = os.fsdecode(file)
img_path = path + "/" + file_name
if file_name.endswith(".jpg") or file_name.endswith(".png"):
if contains_str == "" or (contains_str != "" and file_name.rfind(contains_str)):
# Remove extension for dictionary entry name and add image to dictionary
#-----------------------------------------------------------------------
dict_entry_name = file_name.removesuffix(".jpg").removesuffix(".png")
self.dict.update({dict_entry_name: image.Image(img_path, 0)})

python create a file in a directory errors

write a python program to create a .html file in a directory, the directory can be created correctly, use function open to create this .html file and try to write some content in this file,but the .html file can not be created,
def save_public_figure_page(self,type,p_f_name):
glovar.date = time.strftime("%Y%m%d", time.localtime())
p_f_page_file_directory = os.path.join("dataset", "html",type,glovar.date,p_f_name)
data_storage.directory_create(p_f_page_file_directory)
html_user_page = glovar.webdriver_browser.page_source
p_f_page_file = os.path.join(p_f_page_file_directory,type + "_" + p_f_name + ".html")
html_file = open(p_f_page_file, "w", encoding='utf-8')
html_file.write(html_user_page)
html_file.close()
the directory_create function in data_storage is:
#create the file storage directory
def directory_create(path):
directory = os.path.join(os.path.dirname(__file__),path)
if not os.path.exists(directory):
os.makedirs(directory)
it errors:
<class 'FileNotFoundError'> at /public_figure_name_sub
[Errno 2] No such file or directory: 'dataset\\html\\public_figure\\20170404\\Donald Trump \\public_figure_Donald Trump .html'
the current directory is under /dataset/, I found the directory:
F:\MyDocument\F\My Document\Training\Python\PyCharmProject\FaceBookCrawl\dataset\html\public_figure\20170404\Donald Trump
has been created correctly,but the file——public_figure_Donald Trump .html can not be created correctly,could you please tell me the reason and how to correct
As suggested by Jean-François Fabre, your file has a space just before the ".html".
To solve this, use trim() in the variable p_f_name in your 7th line:
# Added trim() to p_f_name
p_f_page_file = os.path.join(p_f_page_file_directory,type +
"_" + p_f_name.trim() + ".html")
This will create the file:
public_figure_Donald Trump.html
instead of
public_figure_Donald Trump .html
PD: Anyway your filename has a lot of spaces between Donald and Trump. I don't know where the file name comes but you might want to fix it.
Function save_public_figure_page
class public_figure:
def save_public_figure_page(self, type, p_f_name):
glovar.date = time.strftime("%Y%m%d", time.localtime())
p_f_name = p_f_name.trim() # Trim the name to get rid of extra spaces
p_f_page_name = '{t}_{pfn}.html'.format(t=type, pfn=p_f_name)
p_f_page_file_directory = os.path.join(
directory, # Add the directory from the data_storage.directory property
"dataset", "html",
type, glovar.date, p_f_name,
)
if data_storage.directory_create(self.p_f_page_file_directory):
html_user_page = glovar.webdriver_browser.page_source
p_f_page_file = os.path.join(p_f_page_file_directory, p_f_page_name)
html_file = open(p_f_page_file, "w", encoding='utf-8')
html_file.write(html_user_page)
html_file.close()
directory_create method of data_storage
#create the file storage directory
class data_storage:
def directory_create(self, path):
self.directory = os.path.join(os.path.dirname(__file__), path)
if not os.path.exists(self.directory):
try:
os.makedirs(self.directory)
except:
raise
else:
return True
else:
return True

delete older folder with similar name using python

I need to iterate over a folder tree. I have to check each subfolder, which looks like this:
moduleA-111-date
moduleA-112-date
moduleA-113-date
moduleB-111-date
moduleB-112-date
etc.
I figured out how to iterate over a folder tree. I can also use stat with mtime to get the date of the folder which seems easier than parsing the name of the date.
How do I single out modules with the same prefix (such as "moduleA") and compare their mtime's so I can delete the oldest?
Since you have no code, I assume that you're looking for design help. I'd lead my students to something like:
Make a list of the names
From each name, find the prefix, such as "moduleA. Put those in a set.
For each prefix in the set
Find all names with that prefix; put these in a temporary list
Sort this list.
For each file in this list *except* the last (newest)
delete the file
Does this get you moving?
I'm posting the code (answer) here, I suppose my question wasn't clear since I'm getting minus signs but anyway the solution wasn't as straight forward as I thought, I'm sure the code could use some fine tuning but it get's the job done.
#!/usr/bin/python
import os
import sys
import fnmatch
import glob
import re
import shutil
##########################################################################################################
#Remove the directory
def remove(path):
try:
shutil.rmtree(path)
print "Deleted : %s" % path
except OSError:
print OSError
print "Unable to remove folder: %s" % path
##########################################################################################################
#This function will look for the .sh files in a given path and returns them as a list.
def searchTreeForSh(path):
full_path = path+'*.sh'
listOfFolders = glob.glob(full_path)
return listOfFolders
##########################################################################################################
#Gets the full path to files containig .sh and returns a list of folder names (prefix) to be acted upon.
#listOfScripts is a list of full paths to .sh file
#dirname is the value that holds the root directory where listOfScripts is operating in
def getFolderNames(listOfScripts):
listOfFolders = []
folderNames = []
for foldername in listOfScripts:
listOfFolders.append(os.path.splitext(foldername)[0])
for folders in listOfFolders:
folder = folders.split('/')
foldersLen=len(folder)
folderNames.append(folder[foldersLen-1])
folderNames.sort()
return folderNames
##########################################################################################################
def minmax(items):
return max(items)
##########################################################################################################
#This function will check the latest entry in the tuple provided, and will then send "everything" to the remove function except that last entry
def sortBeforeDelete(statDir, t):
count = 0
tuple(statDir)
timeNotToDelete = minmax(statDir)
for ff in t:
if t[count][1] == timeNotToDelete:
count += 1
continue
else:
remove(t[count][0])
count += 1
##########################################################################################################
#A loop to run over the fullpath which is broken into items (see os.listdir above), elemenates the .sh and the .txt files, leaves only folder names, then matches it to one of the
#name in the "folders" variable
def coolFunction(folderNames, path):
localPath = os.listdir(path)
for folder in folderNames:
t = () # a tuple to act as sort of a dict, it will hold the folder name and it's equivalent st_mtime
statDir = [] # a list that will hold the st_mtime for all the folder names in subDirList
for item in localPath:
if os.path.isdir(path + item) == True:
if re.search(folder, item):
mtime = os.stat(path + '/' + item)
statDir.append(mtime.st_mtime)
t = t + ((path + item,mtime.st_mtime),)# the "," outside the perenthasis is how to make t be a list of lists and not set the elements one after theother.
if t == ():continue
sortBeforeDelete(statDir, t)
##########################################################################################################
def main(path):
dirs = os.listdir(path)
for component in dirs:
if os.path.isdir(component) == True:
newPath = path + '/' + component + '/'
listOfFolders= searchTreeForSh(newPath)
folderNames = getFolderNames(listOfFolders)
coolFunction(folderNames, newPath)
##########################################################################################################
if __name__ == "__main__":
main(sys.argv[1])

Auto-increment file name Python

I am trying to write a function that assigns a path name and filename to a variable that is based on a name of a file than exists in the folder. Then, if the name of the file already exists the file name is auto-incremented. I have seen some posts on this using while loop but I cannot get my head around this and would like to wrap it in a recursive function.
Here is what I have so far. When testing with print statement every works well. But it does not return the new name back to the main program.
def checkfile(ii, new_name,old_name):
if not os.path.exists(new_name):
return new_name
if os.path.exists(new_name):
ii+=1
new_name = os.path.join(os.path.split(old_name)[0],str(ii) + 'snap_'+ os.path.split(old_name)[1])
print new_name
old_name = “D:\Bar\foo”
new_name= os.path.join(os.path.split(old_name)[0],”output_” + os.path.split(old_name)[1])
checkfile(0,new_name,old_name)
While I wouldn't recommend using recursion for this (python's stack maxes out at about 1000 function calls deep), you're just missing a return for the recursive bit:
new_name= os.path.join(os.path.split(old_name)[0],”output_” + os.path.split(old_name)[1])
checkfile(0,new_name,old_name)
Should instead be:
new_name= os.path.join(os.path.split(old_name)[0],”output_” + os.path.split(old_name)[1])
return checkfile(ii,new_name,old_name)
But really, you can make this a whole lot simpler by re-writing it as:
def checkfile(path):
path = os.path.expanduser(path)
if not os.path.exists(path):
return path
root, ext = os.path.splitext(os.path.expanduser(path))
dir = os.path.dirname(root)
fname = os.path.basename(root)
candidate = fname+ext
index = 0
ls = set(os.listdir(dir))
while candidate in ls:
candidate = "{}_{}{}".format(fname,index,ext)
index += 1
return os.path.join(dir,candidate)
This form also handles the fact that filenames have extensions, which your original code doesn't, at least not very clearly. It also avoids needless os.path.exist's, which can be very expensive, especially if the path is a network location.

How to add characters to filename using glob in Python?

The following is a snippet of code. The script takes the input files from a "Test" folder, runs a function and then outputs the files with the same name in the "Results" folder (i.e. "Example_Layer.shp"). How could I set it so that the output file would instead read "Example_Layer(A).shp"?
#Set paths
path_dir = home + "\Desktop\Test\\"
path_res = path_dir + "Results\\"
def run():
#Set definitions
input = path_res + "/" + "input.shp"
output = path_res + "/" + fname
#Set current path to path_dir and search for only .shp files then run function
os.chdir(path_dir)
for fname in glob.glob("*.shp"):
run_function, input, output
run()
You currently calculate the output variable once (which IMO wouldn't work since you don't have any fname defined yet).
Move the statement where you compute the output variable within the for loop, like below:
#Set paths
path_dir = home + "\Desktop\Test\\"
path_res = path_dir + "Results\\"
def run():
#Set definitions
input = path_res + "/" + "input.shp"
#Set current path to path_dir and search for only .shp files then run function
os.chdir(path_dir)
for fname in glob.glob("*.shp"):
output = path_res + "/" + fname
run_function, input, output
run()
To answer your question:
How could I set it so that the output file would instead read "Example_Layer(A).shp"
You can use shutil.copy to copy the file to the new directory, adding a "(A)" to each file name using os.path.join to join the path and new filename:
path_dir = home + "\Desktop\Test\\"
path_res = path_dir + "Results\\"
import os
import shutil
def run():
os.chdir(path_dir)
for fname in glob.glob("*.shp"):
name,ex = fname.rsplit(".",1) # split on "." to rejoin later adding a ("A")
# use shutil.copy to copy the file after adding ("A")
shutil.copy(fname,os.path.join(path_res,"{}{}{}".format(name,"(A)",ex)))
# to move and rename in one step
#shutil.move(fname,os.path.join(path_res,"{}{}{}".format(name,"(A)",ex)))

Categories