Python comes with batteries included – it has (almost) everything you need out-of-the-box. Distributions of Python include modules from the Python Standard Library, which provide a wide range of tools for common problems in everyday programming – for example file system access, numerical and mathematical functions, unicode text processing, dealing with dates and calendars, reading / writing multiple data formats, serving web pages, generating random numbers, and a lot more.

This page shows selected examples of useful functions available in various standard modules. Follow the links to the official documentation of each module for more information.

os

The os module contains functions that deal with the file system.

import os
os.listdir

Lists the contents of a folder:

>>> os.listdir('/myFolder')
os.walk

Recursively lists the contents of a folder and all its subfolders:

aFolder = '/myFolder'
for path, folders, files in os.walk(aFolder):
    print(path)
    print(folders)
    print(files)
    print('-'*30)
os.getcwd

Returns the folder where the current script is running (current working directory):

>>> os.getcwd()
os.mkdir

Creates a new folder:

newFolder = "/Users/myUsername/Desktop/test"
os.mkdir(newFolder)
os.makedirs

Creates a folder and all parent folders in a given path:

newFolder2 = "/Users/myUsername/Desktop/test2/aSubfolder"
os.makedirs(newFolder2)
os.rename

Renames a folder or file:

oldFile = "/Users/myUsername/Desktop/image.png"
newFile = "/Users/myUsername/Desktop/imageNew.png"
os.rename(oldFile, newFile)
os.remove

Removes a file:

filePath = "/Users/myUsername/Desktop/test3/image.png"
os.remove(filePath)
os.rmdir

Removes an empty folder:

os.rmdir(newFolderName)

To remove a folder and everything inside it, use shutil.rmtree (see below).

shutil

The shutil module offers functions to copy and remove collections of files.

import shutil
copytree

Copies a folder and all its contents to a given path, creating missing parent folders.

srcFolder = "/Users/myUsername/Desktop/test1"
dstFolder = "/Users/myUsername/Desktop/backup/test1"
shutil.copytree(srcFolder, dstFolder)
rmtree

Delete a folder and all its contents.

shutil.rmtree(srcFolder)

os.path

The os.path module contains functions for manipulating file and folder names.

os.path.exists

Checks if a file or folder exists, returns a bool:

>>> os.path.exists('/myFile.png')
os.path.basename

Returns the file name for a given path, without the parent folder:

>>> filePath = "/Users/myUsername/Desktop/test3/image.png"
>>> os.path.basename(filePath)
image.png
os.path.dirname

Returns the parent folder for a given file path:

os.path.dirname(filePath)
/Users/myUsername/Desktop/test3
os.path.split

Splits a given file path into parent folder and file name:

folder, fileName = os.path.split(filePath)
os.path.splitext

Splits a file path into root and extension:

>>> os.path.splitext(filePath)
('/Users/myUsername/Desktop/test3/image', '.png')

glob

The glob module finds all file or folder names matching a specified pattern.

The example script below returns a list of all UFO files in a given folder:

>>> import glob
>>> glob.glob('/aFolder/*.ufo')

random

The random module provides functions to generate pseudo-random numbers, make random choices, etc.

from random import random, randint, choice # ... etc.
random

Returns a random float between 0.0 and 1.0:

>>> for i in range(5):
...     random()
0.1440220412035288
0.6030806336013335
0.23406747728785426
0.12986516342850718
0.5555918432876255
randint

Returns a random int between two given integers:

>>> for i in range(5):
...     randint(10, 70)
17
59
27
40
34
uniform

Returns a random float between two given numbers:

>>> for i in range(5):
...     uniform(0.2, 12)
9.377996146219418
11.67729261822652
9.499059365948389
5.330554497768862
8.164767529218107
choice

Returns one randomly selected item from a given list.

>>> fruits = ['apple', 'orange', 'banana', 'lemon', 'strawberry']
>>> for i in range(5):
...    choice(fruits)
lemon
banana
strawberry
orange
orange
shuffle

Shuffles the items of a given list in place.

for i in range(5):
    shuffle(fruits)
    print(fruits
['apple', 'banana', 'orange', 'lemon', 'strawberry']
['strawberry', 'lemon', 'banana', 'apple', 'orange']
['apple', 'lemon', 'strawberry', 'orange', 'banana']
['apple', 'banana', 'orange', 'lemon', 'strawberry']
['lemon', 'banana', 'apple', 'orange', 'strawberry']
seed

Initializes the random number generator.

from random import random, seed
seed(3)
print(random())

The result of this script will always be:

0.32383276483316237

This makes it possible to reproduce random values generated with a script!

math

The math module provides several mathematical functions and constants.

from math import *
sqrt

Returns the square root of a number.

>>> sqrt(81)
9.0
floor

Returns the largest integer which is less than or equal to a given number.

>>> floor(4.80)
4
ceil

Returns the smallest integer which is greater than or equal to a given number.

>>> ceil(4.80)
5
pi

The mathematical constant π (pi).

>>> from math import pi
>>> pi
3.141592653589793
sin, cos, tan, etc.

Return the sine, cosine, tangent etc. for a given angle.

The DrawBot script below shows an example of vector math, using cos and sin to calculate new coordinates from an origin point, angle and distance.

from math import sin, cos

x1, y1 = 100, 100
distance = 800
angle = 60

x2 = x1 + distance * sin(radians(angle))
y2 = y1 + distance * cos(radians(angle))

stroke(1, 0, 0)
line((x1, y1), (x2, y2))

Here’s another example of vector math, using the trigonometric functions hypot (hypothenuse) and atan2 (arc tangent) to calculate the distance and angle between two points.

from math import hypot, atan2

x1, y1 = 100, 100
x2, y2 = 500, 480

distance = hypot(x2 - x1, y2 - y1)
angle = degrees(atan2(y2 - y1, x2 - x1))
  • use radians() to convert angles in degrees to radians
  • use degrees() to convert angles in radians to degrees

datetime

The datetime module supplies classes for manipulating dates and times.

>>> import datetime
>>> now = datetime.datetime.now()
>>> now
2020-03-19 09:19:24.797088

Date objects support a strftime(format) method to create a string representation of time and date using format codes. For example:

>>> now.strftime("%x %X")
>>> now.strftime("%d %B %Y %H:%M %A")
03/19/2020 09:19:24
19 March 2020 09:19 Thursday 079

See strftime() and strptime() Behavior for the full set of format codes available.

colorsys

The colorsys module contains functions to convert color values between different color systems (RGB, YIQ, HLS, HSV).

The DrawBot script below uses colorsys to produce a range of hues.

from colorsys import hsv_to_rgb

size(600, 120)

steps = 15
w = width() / steps
x = y = 0

for i in range(steps):
    hue = i * 1.0 / steps
    R, G, B = hsv_to_rgb(hue, 1.0, 1.0)
    fill(R, G, B)
    rect(x, y, w, height())
    x += w

zipfile

The zipfile module provides tools to create, read, write, append, and list a ZIP file.

Create a zip file from a given folder
import os
from zipfile import ZipFile
  
folder = 'someFolder'
zipPath = os.path.join(os.path.dirname(folder), 'myZipFile.zip')
  
with ZipFile(zipPath, 'w') as myZip:
    for root, dirs, files in os.walk(folder):
        for fileName in files:
            filePath = os.path.join(root, fileName)
            myZip.write(filePath, os.path.relpath(filePath, folder))
Expand the contents of a zip file into a folder
from zipfile import ZipFile 
  
zipPath = 'myZipFile.zip'
dstPath = '/someFolder'
  
with ZipFile(zipPath, 'r') as myZip: 
    myZip.extractall(dstPath)

subprocess

The subprocess module allows you to run new processes, for example to execute command-line tools from a script.

The script below converts a VFB font to UFO by calling a locally installed vfb2ufo.

import subprocess

cmds = ['/usr/local/bin/vfb2ufo', '/aFolder/myFont.vfb']

p = subprocess.Popen(cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)

output, errors = p.communicate()

print(output)

xml.etree.ElementTree

The xml.etree.ElementTree module implements a simple API for parsing and creating XML data.

Parse an XML file
import xml.etree.ElementTree as ET
xmlPath = '/aFolder/myFont.ufo/glyphs/a.glif'
tree = ET.parse(xmlPath)
Get root tag and attributes
root = tree.getroot()
print(root.tag, root.attrib)
glyph {'name': 'a', 'format': '2'}
Get all children of an element
for child in root:
    print(child.tag, child.attrib)
advance {'width': '475'}
unicode {'hex': '0061'}
outline {}
lib {}
Find all children with a given tag
for elem in root.findall('outline'):
    print(elem.tag)
Iterate recursively over all sub-trees
for elem in root.iter('point'):
    print(elem.tag)
Find element and set a value for an attribute
root.find('advance').attrib['width'] = 700
Save changes to XML file
tree.write(xmlPath)

string

The string module contains some useful lists of characters:

>>> import string
>>> string.ascii_lowercase
abcdefghijklmnopqrstuvwxyz
>>> string.ascii_uppercase
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>> string.digits
0123456789
>>> string.punctuation
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

json

The json module provides tools for reading and writing JSON files.

json.loads

Loads data from a JSON file into a dictionary.

import json

jsonPath = 'somedata.json'

with open(jsonPath, 'r', encoding='utf-8') as f:
    data = json.loads(f.read())

print(data)
json.dumps

Encodes a Python object hierarchy into JSON format.

The example below also saves a .json file at a given path.

fontinfo = {
    'familyName' : 'My Font',
    'versionMajor' : 1,
    'versionMinor' : 3,
    'openTypeNameDesignerURL' : 'http://mywebsite.com/',
}

jsonPath = 'fontinfo.json'

with open(jsonPath, 'w', encoding='utf-8') as f:
    data = json.dumps(fontinfo)
    f.write(data)

plistlib

The plistlib module provides an interface for reading and writing the property list files used by macOS.

Property lists are also used by the UFOUnified Font Object. A cross-platform, cross-application, human-readable, future-proof format for storing font data. format to store various kinds of metadata, for example fontinfo.plist, kerning.plist, groups.plist, etc.

plistlib.load

Loads data from a .plist file into a dictionary.

import plistlib

plistPath = 'somedata.plist'

with open(plistPath, 'rb') as f:
    data = plistlib.load(f)

print(data)
plistlib.dump

Write an object to a .plist file.

fontinfo = {
  'familyName' : 'My Font',
  'versionMajor' : 1,
  'versionMinor' : 3,
  'openTypeNameDesignerURL' : 'http://mywebsite.com/',
}

plistPath = 'fontinfo.plist'

with open(plistPath, 'wb') as f:
    plistlib.dump(fontinfo, f)

difflib

The difflib module provides classes and functions for comparing sequences. It can be used to show the differences between two versions of a text-based file – such as two .glif files, as in the example below.

import difflib

glifPath1 = 'myFont1.ufo/glyphs/a.glif'
with open(glifPath1, 'r') as f:
    glifSrc1 = f.readlines()

glifPath2 = 'myFont2.ufo/glyphs/a.glif'
with open(glifPath2, 'r') as f:
    glifSrc2 = f.readlines()

uniDiff = difflib.unified_diff(glifSrc1, glifSrc2)
print(''.join(list(uniDiff)))
--- 
+++ 
@@ -1,18 +1,12 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <glyph name="a" format="2">
-  <advance width="500"/>
+  <advance width="514.9054171954316"/>
   <outline>
     <contour>
       <point x="152.70780456852776" y="609.2342163705584" type="line"/>
       <point x="65.2954473350253" y="245.02359612944178" type="line"/>
-      <point x="334.9054171954316" y="151.91108819796978" type="line"/>
+      <point x="434.9054171954316" y="151.91108819796978" type="line"/>
       <point x="423.27093908629433" y="603.8090894670054" type="line"/>
     </contour>
   </outline>
-  <lib>
-    <dict>
-      <key>public.markColor</key>
-      <string>0,1,0,1</string>
-    </dict>
-  </lib>
 </glyph>

Several diff modes are available, including an HTML diff with colors.

D = difflib.HtmlDiff()
html = D.make_file(glifSrc1, glifSrc2)
print(html)

You can use difflib to compute the differences between GLIF files. For example:

import difflib
import vanilla
from mojo.UI import CodeEditor

glyph = CurrentGlyph()

before = glyph.dumpToGLIF()

for contour in glyph:
    contour.autoStartSegment()

after = glyph.dumpToGLIF()

D = difflib.Differ()
diff = D.compare(before.split('\n'), after.split('\n'))
diffText = '\n'.join(diff)

w = vanilla.Window((800, 400), minSize=(300, 400))
w.e = CodeEditor((0, 0, 0, 0), diffText, readOnly=True, lexer="xml")
w.open()

More standard modules

The Python Standard Library includes many other modules – see the documentation for more information about each module.

Last edited on 01/09/2021