Skip to main content
Code Review

Return to Question

edited tags
Link
200_success
  • 145.6k
  • 22
  • 190
  • 479
added 2 characters in body; edited title
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

A "safe""safe" copy function for Python

I have a Python script for doing "safe""safe" file copying.

  • Existing files should never be overwritten. So if I try to copy $file1$file1 to $location$location, and there is already $file2$file2 at $location$location, then $file2$file2 will not be overwritten.
  • Exact filenames are not important. So if I try to copy a file to $location.txt$location.txt, and because there’s already a different file there, it instead gets copied to $location-1.txt$location-1.txt, that’s okay.
  • Copying should be idempotent. That is, if I try to copy a file to $location$location, and it’sit's already there, nothing else happens. I’mI'm not going to create more copies at $location-1$location-1, $location-2$location-2, $location-3$location-3, etc.

Here's the code:

  • Does it make sense? Is it clear what the code is doing?
  • Can I replace any of this with standard library functions?
  • I wrote it in Python 2, but will run it in 2 and 3. Brief testing suggests that it runs fine in Python 3, but pointers to anything I’veI've missed would be helpful.
  • Is this good Python?

A "safe" copy function for Python

I have a Python script for doing "safe" file copying.

  • Existing files should never be overwritten. So if I try to copy $file1 to $location, and there is already $file2 at $location, then $file2 will not be overwritten.
  • Exact filenames are not important. So if I try to copy a file to $location.txt, and because there’s already a different file there, it instead gets copied to $location-1.txt, that’s okay.
  • Copying should be idempotent. That is, if I try to copy a file to $location, and it’s already there, nothing else happens. I’m not going to create more copies at $location-1, $location-2, $location-3, etc.

Here's the code:

  • Does it make sense? Is it clear what the code is doing?
  • Can I replace any of this with standard library functions?
  • I wrote it in Python 2, but will run it in 2 and 3. Brief testing suggests that it runs fine in Python 3, but pointers to anything I’ve missed would be helpful.
  • Is this good Python?

A "safe" copy function for Python

I have a Python script for doing "safe" file copying.

  • Existing files should never be overwritten. So if I try to copy $file1 to $location, and there is already $file2 at $location, then $file2 will not be overwritten.
  • Exact filenames are not important. So if I try to copy a file to $location.txt, and because there’s already a different file there, it instead gets copied to $location-1.txt, that’s okay.
  • Copying should be idempotent. That is, if I try to copy a file to $location, and it's already there, nothing else happens. I'm not going to create more copies at $location-1, $location-2, $location-3, etc.
  • Does it make sense? Is it clear what the code is doing?
  • Can I replace any of this with standard library functions?
  • I wrote it in Python 2, but will run it in 2 and 3. Brief testing suggests that it runs fine in Python 3, but pointers to anything I've missed would be helpful.
  • Is this good Python?
Source Link
alexwlchan
  • 8.7k
  • 1
  • 23
  • 55

A "safe" copy function for Python

I have a Python script for doing "safe" file copying.

There are a couple of rules for this copy function:

  • Existing files should never be overwritten. So if I try to copy $file1 to $location, and there is already $file2 at $location, then $file2 will not be overwritten.
  • Exact filenames are not important. So if I try to copy a file to $location.txt, and because there’s already a different file there, it instead gets copied to $location-1.txt, that’s okay.
  • Copying should be idempotent. That is, if I try to copy a file to $location, and it’s already there, nothing else happens. I’m not going to create more copies at $location-1, $location-2, $location-3, etc.

An example use case: I'm importing some camera photos into a folder, but some of the photos may be duplicates (and I don't want two copies) or have the same filename as another photo (and I want to keep both, but small changes to the name aren't important).

Here's the code:

import filecmp
import os
import shutil
def increment_filename(filename, marker="-"):
 """Appends a counter to a filename, or increments an existing counter."""
 basename, fileext = os.path.splitext(filename)
 # If there isn't a counter already, then append one
 if marker not in basename:
 components = [basename, 1, fileext]
 # If it looks like there might be a counter, then try to coerce it to an
 # integer and increment it. If that fails, then just append a new counter.
 else:
 base, counter = basename.rsplit(marker, 1)
 try:
 new_counter = int(counter) + 1
 components = [base, new_counter, fileext]
 except ValueError:
 components = [base, 1, fileext]
 # Drop in the marker before the counter
 components.insert(1, marker)
 new_filename = "%s%s%d%s" % tuple(components)
 return new_filename
def copyfile(src, dst):
 """Copies a file from path src to path dst.
 If a file already exists at dst, it will not be overwritten, but:
 * If it is the same as the source file, do nothing
 * If it is different to the source file, pick a new name for the copy that
 is distinct and unused, then copy the file there.
 Returns the path to the copy.
 """
 if not os.path.exists(src):
 raise ValueError("Source file does not exist: {}".format(src))
 # Create a folder for dst if one does not already exist
 if not os.path.exists(os.path.dirname(dst)):
 os.makedirs(os.path.dirname(dst))
 # Keep trying to copy the file until it works
 while True:
 
 # If there is no file of the same name at the destination path, copy
 # to the destination
 if not os.path.exists(dst):
 shutil.copyfile(src, dst)
 return dst
 
 # If the namesake is the same as the source file, then we don't need to
 # do anything else
 if filecmp.cmp(src, dst):
 return dst
 
 # There is a namesake which is different to the source file, so pick a
 # new destination path
 dst = increment_filename(dst)
 return dst

Particular areas I’m unsure about:

  • Does it make sense? Is it clear what the code is doing?
  • Can I replace any of this with standard library functions?
  • I wrote it in Python 2, but will run it in 2 and 3. Brief testing suggests that it runs fine in Python 3, but pointers to anything I’ve missed would be helpful.
  • Is this good Python?
lang-py

AltStyle によって変換されたページ (->オリジナル) /