HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Rename files to titlecased

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
titlecasedfilesrename

Problem

I wrote this Python script to rename specified files to "titlecase", for example:

  • hello.txt to Hello.txt



  • hello there.txt to Hello There.txt



  • path/to/file.txt to path/to/File.txt



The main script:

``
#!/usr/bin/env python

import os
import re
import argparse

re_junk = re.compile(r'[._-]')
re_spaces = re.compile(r'\s\s+')

def print_rename(old_filename, new_filename):
print('{} -> {}'.format(old_filename, new_filename))

def do_rename(old_path, new_path):
print_rename(old_path, new_path)
os.rename(old_path, new_path)

def get_new_path(old_path):
""" Get the new path, titlecased and (a little bit) sanitized.
- Only operate on the basename:
+ don't touch parent directories
+ don't touch the extension
- Sanitize:
+ replace junk characters with space
+ replace multiple spaces with single space
+ trim extra spaces at start and end

:param old_path: the path to rename
:return: titlecased and a little bit sanitized new path
"""
dirpart, filepart = os.path.split(old_path)
if filepart.startswith('.'):
return old_path

base, ext = os.path.splitext(filepart)
base = re_junk.sub(' ', base)
base = re_spaces.sub(' ', base).strip()
if not base:
return old_path

return os.path.join(dirpart, base.title() + ext)

def titlecase(old_path, fun):
if not os.path.exists(old_path):
return

new_path = get_new_path(old_path)
if old_path == new_path:
return

fun(old_path, new_path)

def main():
parser = argparse.ArgumentParser(description='Rename files to "titlecased" and "sanitized".')
parser.add_argument('-n', '--dry-run', action='store_true', help='Print what would happen, don\'t rename')
parser.add_argument('paths', nargs='+')

args = parser.parse_args()
fun = print_rename if args.dry_run else do_rename

for path in args.paths:
titlecase(path, fun)

if __name__ == '__main__':
main()
`

Solution

-
I strongly oppose testing for file existence. It introduces a race condition: the path may exist at the time of test and disappear by the time of use; yes I am paranoid. Besides, it really impedes dry runs/unit testing - to try an interesting case you need to actually create a file. The pythonic way is to ask forgiveness, not permission:

try:
    os.rename(old_path, new_path)
except OSError:
    pass # or an error message


Notice that it would also take care of other failures of os.rename, such as new_path already exists or is too long; the directory is read-only, etc.

-
I am also not sure that "sanitization" is to be done unconditionally. A command line option would be nice.

-
Typically a debugging/diagnostic messages are sent to stderr. A quiet (or verbose) option is also desirable.

-
fun doesn't strike as a particularly good name.

Code Snippets

try:
    os.rename(old_path, new_path)
except OSError:
    pass # or an error message

Context

StackExchange Code Review Q#70024, answer score: 3

Revisions (0)

No revisions yet.