I was trying to overwrite an existing file with another file I created, with a Python script, using os.rename. Instead of doing what the tin says, os.rename failed with the rather intimidating message:

OSError: [Errno 18] Invalid cross-device link

WTF? DuckDuckGo to the rescue. I found a thread from the Python mail-list, which I'll reproduce below:

Scott Whitney wrote:

os.rename(oldName,newName) gives: OSError: [Errno 18] Invalid cross-device link

mv from the shell works fine. This is Python 2.2.3 from RedHat 9.0.

Any suggestions (other than os.system('mv %s %s')?)

catch exception and copy if error == errno.EXDEV. (this is what "mv" does, of course)

or use shutil.move:

 >>> import shutil
 >>> help(shutil.move)

 Help on function move in module shutil:

 move(src, dst)
     Recursively move a file or directory to another location.

     If the destination is on our current filesystem,
     then simply use rename.  Otherwise, copy src to
     the dst and then remove src.  A lot more could be
     done here...  A look at a mv.c shows a lot of the
     issues this implementation glosses over.

And a subsequent mail from that thread:

mv is a surprisingly complex program, while os.rename is a wrapper around rename(2) which is probably documented on your system to return EXDEV under these circumstanes.

os.xxx is generally a fairly thin wrapper around what your OS provides, and inherits all the "gotchas". For some activities, os.shutil provides something that is between os.xxx and os.system("xxx") in complexity and capability.

The (somewhat silly) moral of the story: the os module might not be what you want. Or, the os module is a rather awkward way of learning about your OS's system calls.