🌎 Eli Heuer’s Blog

Building a TTF to UFO Converter with Argparse

January 23, 2018

If you have used command line software before you are probably familiar with flags, for example --help for help or -v for version. In this tutorial, I will demonstrate using the module Argparse to add flags to a Python script.

The script will convert a TTF font file to a UFO directory, UFO is an XML based format used for uncompiled fonts. To start, open a terminal and navigate to a directory where you want to work. To keep dependencies contained, make a virtual environment by entering the following commands:

python3 -m venv venv
source venv/bin/activate

Runnging source venv/bin/activate activates the virtual environment, to deactivate just type deactivate. Now that we are in the venv we need to install the packages needed for the script, argparse, defcon and, ufo-extractor:

ufo-extractor: Extracts UFO files from defcon font objects.

defcon: Creates a Python object from a given TTF.

argparse: Command line interface tool, gets input and output location.

Install these dependencies with pip:

pip install --upgrade ufo-extractor defcon argparse

Now we have everything installed and are ready to write the script, in any directory, make a new Python file and open it with a text editor (I'm using Vim here):

touch ttf-to-ufo.py
vi ttf-to-ufo.py

Now start the script by importing argparse, make a new argparse object called parser and call parser.parse_args().

import argparse

parser = argparse.ArgumentParser()

Save the script an run it from the command line:

python3 ttf-to-ufo.py

Nothing happens... try running it with a --help flag:

python3 ttf-to-ufo.py --help

usage: test.py [-h]

optional arguments:
-h, --help  show this help message and exit

It works, great. Help is the only built-in flag that works without additional code, so let’s add -i for input path and -o for output path:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("-i", help = "input file path")
parser.add_argument("-o", help = "output file path")
args = parser.parse_args()

print('inputfile:', args.i)
print('outputfile:', args.o)

Now if we run the script with a help flag again, we should get something like this:

python3 ttf-to-ufo.py --help

usage: test.py [-h] [-i I] [-o O]

optional arguments:
-h, --help  show this help message and exit
-i I        input file path
-o O        output file path

Next, let’s try using the flags, replace ~/.fonts/test.ttf with the path to a TTF you want to use:

python3 ttf-to-ufo.py -i ~/.fonts/test.ttf -o test.ufo
inputfile: /home/user/.fonts/test.ttf
outputfile: test.ufo

Now import defcon and ufo-extractor. Please note that even though ufo-extractor is imported with pip install ufo-extractor, it needs to be imported in python with import extractor, confusing, I know. Move the argparse code into a function that returns args and move the script part into a conditional statement. if __name__ == "__main__": tells Python to only run the script part when you are running the script from the command line, and ignore it if you are importing create_arg_parser into another Python program:

import argparse
import defcon
import extractor

def create_arg_parser():
    parser = argparse.ArgumentParser()
    parser.add_argument("-i", help = "input filename")
    parser.add_argument("-o", help = "output filename")
    args = parser.parse_args()
    return args

if __name__ == "__main__":
    args = create_arg_parser()
    ttf_path = args.i
    ufo_path = args.o
    print('ttf_path: ', ttf_path)
    print('ufo_path:', ufo_path)
    # Make UFO
    print('Generating UFO...', ufo_path)
    ufo = defcon.Font()
    extractor.extractUFO(ttf_path, ufo)

If you run this script with -i and -o a UFO directory should be generated. If you don’t give a full file path for -o and just enter a file name like this test.ufo, a ufo directory will be created in the same directory as the script:

python3 ttf-to-ufo.py -i ~/.fonts/test.ttf -o ~/test.ufo
ttf_path:  /home/eli/.fonts/test.ttf
ufo_path: /home/eli/test.ufo
Generating UFO... /home/eli/test.ufo