Learning to let go (or how I learned to live with a bomb) ...
Ask yourself: what exactly are you afraid of, and how will you deal with this if this happens? In the example below, you want to avoid data loss. The way you deal with this is to search for any combination of conditions that you think are a mistake and put a huge amount of records into it. Everything will continue to go wrong, and it is not clear that having a large registration volume will be a good way to handle this. Draw what you are trying to achieve:
for each file in a tree if file is below the root move it into the root if nothing went wrong delete empty subtrees
So, what things can go wrong in this process? Well, there are many ways in which file transfer operations can be blocked due to the underlying file system. Can we list them all and provide good ways to deal with them? No ... but in general you will deal with them the same way. Sometimes a mistake is just a mistake, no matter what it is.
So, in this case, if any error occurs, you want to undo and undo any changes. The way you decide to do this is to back up and restore it when something goes wrong. But your most likely mistake is that the file system is full, in which case these steps are likely to fail. Okay, so this is a fairly common problem - if you are worried about unknown errors at any time, how to stop your recovery path from being incorrect?
The general answer is to make sure that you do some intermediate work first, and then take one unpleasant (hopefully, atomic) step. In your case, you need to flip the recovery. Instead of backing up as a backup, create a copy of the result. If all goes well, you can replace the new result with the old source tree. Or, if you are really paranoid, you can leave this step to the person. The advantage here is that if something goes wrong, you can just interrupt and throw away the partial state that you created.
Then your structure will look like this:
make empty result directory for every file in the tree copy file into new result on failure abort otherwise move result over old source directory
By the way, in your current script there is an error that this pseudo-code becomes more obvious: if you have files with the same names in different branches, they overwrite each other in a new flattened version.
The second point in this psuedo code is that all error handling is in the same place (i.e. wrap the creation of a new directory and a recursive copy inside one try block and catch all errors after it), this solves your original question about the big relation of registration / error checking to the actual working code.
backup_dirname = str(uuid.uuid4()) try: shutil.mkdir(backup_dirname) for root, dirs, files in os.walk(dirname, topdown=False): for file in files: full_filename = os.path.join(root, file) target_filename = os.path.join(backup_dirname,file) shutil.copy(full_filename, target_filename) catch Exception, e: print >>sys.stderr, "Something went wrong %s" % e exit(-1) shutil.move(back_dirname,root) # I would do this bit by hand really