Recipe2.29.Versioning Filenames


Recipe 2.29. Versioning Filenames

Credit: Robin Parmar, Martin Miller

Problem

You want to make a backup copy of a file, before you overwrite it, with the standard convention of appending a three-digit version number to the name of the old file.

Solution

We just need to code a function to perform the backup copy appropriately:

def VersionFile(file_spec, vtype='copy'):     import os, shutil     if os.path.isfile(file_spec):         # check the 'vtype' parameter         if vtype not in ('copy', 'rename'):              raise ValueError, 'Unknown vtype %r' % (vtype,)         # Determine root filename so the extension doesn't get longer         n, e = os.path.splitext(file_spec)         # Is e a three-digits integer preceded by a dot?         if len(e) == 4 and e[1:].isdigit( ):             num = 1 + int(e[1:])             root = n         else:             num = 0             root = file_spec         # Find next available file version         for i in xrange(num, 1000):              new_file = '%s.%03d' % (root, i)              if not os.path.exists(new_file):                   if vtype == 'copy':                       shutil.copy(file_spec, new_file)                   else:                       os.rename(file_spec, new_file)                   return True         raise RuntimeError, "Can't %s %r, all names taken"%(vtype,file_spec)     return False if _ _name_ _ == '_ _main_ _':       import os       # create a dummy file 'test.txt'       tfn = 'test.txt'       open(tfn, 'w').close( )       # version it 3 times       print VersionFile(tfn)       # emits: True       print VersionFile(tfn)       # emits: True       print VersionFile(tfn)       # emits: True       # remove all test.txt* files we just made       for x in ('', '.000', '.001', '.002'):           os.unlink(tfn + x)       # show what happens when the file does not exist       print VersionFile(tfn)       # emits: False       print VersionFile(tfn)       # emits: False

Discussion

The purpose of the VersionFile function is to ensure that an existing file is copied (or renamed, as indicated by the optional second parameter) before you open it for writing or updating and therefore modify it. It is polite to make such backups of files before you mangle them (one functionality some people still pine for from the good old VMS operating system, which performed it automatically!). The actual copy or renaming is performed by shutil.copy and os.rename, respectively, so the only issue is which name to use as the target.

A popular way to determine backups' names is versioning (i.e., appending to the filename a gradually incrementing number). This recipe determines the new name by first extracting the filename's root (just in case you call it with an already-versioned filename) and then successively appending to that root the further extensions .000, .001, and so on, until a name built in this manner does not correspond to any existing file. Then, and only then, is the name used as the target of a copy or renaming. Note that VersionFile is limited to 1,000 versions, so you should have an archive plan after that. The file must exist before it is first versionedyou cannot back up what does not yet exist. However, if the file doesn't exist, function VersionFile simply returns False (while it returns TRue if the file exists and has been successfully versioned), so you don't need to check before calling it!

See Also

Documentation for the os and shutil modules in the Library Reference and Python in a Nutshell.



Python Cookbook
Python Cookbook
ISBN: 0596007973
EAN: 2147483647
Year: 2004
Pages: 420

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net