I'm learing Python by writing a program to solve some housekeeping I do weekly, namely renaming PDF files according to rules given in a text file.
My end goal is to have idiomatic Python, with full test coverage. I have done some refactoring, and written a couple of tests. Ideally I would have done TDD from the beginning, but I find it challenging to write tests since I don't know Python that well yet.
The PDF documents can be named with two patterns:
xx.pdf
xx-y.pdf
They are stored in the folder ./test relative to the script root.
The text file Instruments.txt contains the following pattern:
01 SopranoCn 02 SoloCn 03 RepianoCn ... 18 Percussion 20 AllParts ...
The whole purpose is to rename files like this:
xx.pdf (01.pdf) --> xx_{instrument_name}.pdf (01_SopranoCn.pdf) xx-y.pdf (02-1.pdf) --> xx_{instrument_name}{part_number}.pdf (02_SoloCn1.pdf)
The y-argument is optional, and can be added to any instrument.
Here's the whole source:
"""
Invoke with "python notesort.py <path to folder>".
A list of instrument numbers with corresponding instrument names
must be available in the root folder of the script.
"""
# Standard library imports
import os
FOLDER = './test'
def create_instrument_map():
"""Create a dictionary mapping each prefix
to the corresponding instrument name."""
with open('Instruments.txt') as instrument_file:
return {
line.split()[0]: line.split()[1] for line in instrument_file
}
def rename_files_with_instrument_name(instrument_map):
"""Rename PDF files in folder based on the root of
the original file name."""
for filename in os.listdir(FOLDER):
root, extension = os.path.splitext(filename)
if not extension.endswith('.pdf'):
continue
try:
if root[2]:
if root[:2] in instrument_map:
new_file_name = '{prefix}_'\
'{instrument_name}'\
'{part_number}'\
'{extension}'.format(
prefix=root[:2],
instrument_name=instrument_map[root[:2]],
part_number=root[3],
extension=extension)
except:
if root in instrument_map:
new_file_name = '{prefix}_{instrument_name}{extension}'.format(
prefix=root,
instrument_name=instrument_map[root],
extension=extension)
old_path = os.path.join(FOLDER, filename)
new_path = os.path.join(FOLDER, new_file_name)
os.rename(old_path, new_path)
print 'Renamed', filename, '-->', new_file_name
if __name__ == '__main__':
instrument_map = create_instrument_map()
rename_files_with_instrument_name(instrument_map)
I have started to write some tests for it, but I find it difficult to test rename_files_with_instrument_name
. I do not have any experience writing tests, but I see the benefit and want to practise writing them.
These are the tests I have so far:
import unittest
from notesort import create_instrument_map
class TestNoteSort(unittest.TestCase):
def test_create_instrument_map_creates_soprano_cornet(self):
instrument_map = create_instrument_map()
self.assertEqual(instrument_map['01'], 'SopranoCn')
def test_create_instrument_map_soprano_not_solo(self):
instrument_map = create_instrument_map()
self.assertNotEqual(instrument_map['01'], 'SoloCn')
if __name__ == '__main__':
unittest.main()
Please feel free to make comments on any part of my implementation. No need to be easy on me, even if I'm a beginner.
I am especially interested in how I can get further with testing, and also how to refactor rename_files_with_instrument_name
.