Reusable, generic save method
Security risk? The client could pass in any arbitrary function as "save" and execute it.


A client can change your code, and it's there fault for not using the function as intended.




  variable "args" gets passed to the save function regardless of whether that method actually takes any args


save(path, *args)


This way it will see there is no arguments and not error.




  Instead of passing a generic save function, I could replace "save(path, args)" with "new_file = open(path, 'w')"


This is a better idea. This is as things like json.dump use a file object.
You could make it so that it works in a with statement, and return the file object.



print "Saving \"" + path + "\""


You should use str.format.

print "Saving \"{}\"".format(path)




You can add the ability of making it work with with statements with the below. If you want to know about these special functions look here.

class _handle_file_save:
    def __init__(self, path):
        self.path = path
        self.file_handler = open(self.path)

    def __enter__(self):
        return self.file_handler

    def __exit__(self, exc_type, exc_value, traceback):
        self.file_handler.close()


Now, we can enter your function without the save parameter. This will allow us to do what you want.

class _handle_file_save:
    def __init__(self, path, overwrite, *args):
        self.path = path
        self.overwrite = overwrite
        self.args = args

    def _open(self):
        if os.path.isfile:

        # ... Just copy the rest.


However we now have the problem of


  Doesn't check if appended filepath is also a locked/open file


And so we can make it a recursive function!

class _handle_file_save:
    def _open_recursive(self, path):
        try:
            self.file_handler = open(path, *self.args)
            print "Saving \"{}\"".format(path)
        except EnvironmentError:
            self._open_recursive(gen_alt_filename(path))


Lets now get the _open function to work now.

class _handle_file_save:
    def _open(self):
        if os.path.isfile(self.path):
            if overwrite:
                self._open_recursive(self.path)
            else:
                self._open_recursive(
                    gen_alt_filename(self.path))
        else:
            self._open_recursive(self.path)


You may want to change it so there is only one if statement. However you may not want the first else to be recursive.



If we wrap it all up we get:

class _handle_file_save:
    def __init__(self, path, overwrite, *args):
        self.path = path
        self.overwrite = overwrite
        self.args = args
        self.file_handler = None

    def _open(self):
        if os.path.isfile(self.path):
            if overwrite:
                self._open_recursive(self.path)
            else:
                self._open_recursive(
                    gen_alt_filename(self.path))
        else:
            self._open_recursive(self.path)

    def _open_recursive(self, path):
        try:
            self.file_handler = open(path, *self.args)
            print "Saving \"{}\"".format(path)
        except EnvironmentError:
            self._open_recursive(gen_alt_filename(path))

    def __enter__(self):
        self._open()
        if self.file_handler is None:
            raise TypeError('self.file_handler never set.')
        return self.file_handler

    def __exit__(self, exc_type, exc_value, traceback):
        self.file_handler.close()


You may want to change the error in __enter__.

This should work, however I don't know how to generate a locked file. But it seems like you know how to check.

Also it has the added support of allowing you to put all your file checking functions, I'm looking at you gen_alt_filename, into it to if you wish.

It's more complex, however it would work better then passing a save function as usage is just like open.

with _handle_file_save('file', False, 'rb') as file_:
    # Do something with `file_`