Rename files to titlecased 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('{} -&gt; {}'.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()


Unit tests:

#!/usr/bin/env python

import unittest

from titlecase import get_new_path


class TestTitleCase(unittest.TestCase):
    def test_hello(self):
        self.assertEqual('Hello', get_new_path('hello'))

    def test_hello_txt(self):
        self.assertEqual('Hello.txt', get_new_path('hello.txt'))

    def test_hello_there_txt_dotted(self):
        self.assertEqual('Hello There.txt', get_new_path('hello.there.txt'))

    def test_hello_there(self):
        self.assertEqual('Hello There', get_new_path('hello there'))

    def test_hello__there(self):
        self.assertEqual('Hello There', get_new_path('hello  there'))

    def test_dot(self):
        self.assertEqual('.', get_new_path('.'))

    def test_dotdot(self):
        self.assertEqual('..', get_new_path('..'))

    def test_subdir(self):
        self.assertEqual('some/path/File.txt', get_new_path('some/path/file.txt'))

    def test_subdir_nobasename(self):
        self.assertEqual('some/path/.txt', get_new_path('some/path/.txt'))

    def test_subdir_dotdot(self):
        self.assertEqual('../path/File.txt', get_new_path('../path/file.txt'))

    def test_subdir_dotdot_in_middle(self):
        self.assertEqual('some/../path/File.txt', get_new_path('some/../path/file.txt'))


if __name__ == '__main__':
    unittest.main()


Is there a better way I missed? Anything to improve?
Better names maybe? Interesting unit test cases I missed?

(This script (along with some other utility scripts) is on GitHub.)
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.