I am developing a Python script that will process large amounts of data from an experiment. Files are read in, calculations are made, images are plotted and saved as .pngs, and calculated parameters are outputted to a .txt file.
When I save a file, the user is prompted if they want to overwrite any existing files. If yes, a file overwrite is attempted. If the file is locked/open in another program, a number is appended to the filename and then saved. If they do not want to overwrite, a number is appended to the filename.
In order to not have redundant code, I wrote a generic "save" method:
def _handle_file_save(path, save, overwrite, *args):
"""
Handles file collisions when saving files. If "overwrite" is true,
overwrites file, if "overwrite" is false or the file to be overwritten
is locked from editing, appends a number on end of filename to avoid
file collision.
Args:
path (str): the path to the file to be saved
save(): The save function used to save file
overwrite (bool): true if user wants to overwrite file
args: generic tuple of arguments used for different save functions
"""
if os.path.isfile(path):
if overwrite:
try:
print "Saving \"" + path + "\""
save(path, args)
# Signifies problem writing file (lack of permissions, open
# in another program, etc.)
except EnvironmentError:
# save as incremented file number
print "Whoops! Looks like %s is locked!" % path
path = gen_alt_filename(path)
save(path, args)
else:
# save as incremented file number
path = gen_alt_filename(path)
print "Saving as \"" + path + "\" instead"
save(path, args)
else:
print "Saving \"" + path + "\""
save(path, args)
print "\n"
I pass in a generic save function and any arguments that save function needs if any. Some file outputs don't require any arguments.
Flaws:
The client could pass in any arbitrary function as "save" and execute it. Is this a security risk?
The variable
args
gets passed to the save function regardless of whether that method actually takes any args (i.e. args could be empty, but gets passed anyway.Doesn't check if appended filepath is also a locked/open file (could fix this with a while loop I suppose).
Possible improvements:
Use Python's functools.partial
to reduce the function call's signature to one without "args
" if args
is empty.
Alternative:
Instead of passing a generic save function, I could replace "
save(path, args)
" with "new_file = open(path, 'w')
" (i.e. test file write, if successful, return the path to that file and write there).Don't merge code, let every save method handle its own collisions separately.
Nothing about any of this seems elegant. I'd greatly appreciate some advice on this, and how I can improve my coding strategies.