Python wrapper for OpenType Sanitizer, also known as just "OTS". It is similar to and partially based on ots-python, but builds OTS as a Python C Extension (instead of as an executable and calling through subprocess as ots-python does).
NOTE: Although this package is similar to ots-python, it is not a drop-in replacement for it, as the Python API is different.
The project builds pip-installable wheels for Python 3.10, 3.11, 3.12, 3.13, or 3.14 under Mac or Linux. It is possible this project will build and run with other Pythons and other operating systems, but it has only been tested with the listed configurations.
If you just want to use pyots, you can simply run python -m pip install -U pyots (in one of the supported platforms/Python versions) which will install pre-built, compiled, ready-to-use Python wheels. Then you can skip down to the Use section.
If you'd like to tinker with the pyots code, you will want to get your local setup ready:
- clone this repo
- run
python setup.py downloadto download the OTS source (which is not included in this project). You can modify theversionvalue insetup.cfgunder[download]to specify a different version of OTS. You'll also need to change thesha256hash value that corresponds to the OTS tar.xz package. Note that this scheme has some limitations: OTS sources older than 8.1.3 might not build correctly since they used different build systems. Also, versions newer than the one specified in this repo might require adjustments in order to build correctly. What can we say, we're dependent onots... - to build and install
pyotsafter downloading OTS, you can runpython setup.py installorpython -m pip install . - while iterating changes, you will want to delete the temporary
buildandsrc/ots/buildfolders.
There is a test suite defined for exercising the Python extension. It makes use (and assumes the presence of) the downloaded OTS library source's test font data in src/ots so ensure you have run python setup.py download and have the ots folder under src. Invoke the tests with python -m pytest.
If you wish to run tests comparing results from ots-python against pyots, be sure to python -m pip install opentype-sanitizer first, otherwise that set of tests will be skipped.
Simplest case:
import pyots
result = pyots.sanitize('/path/to/font/file.ttf')result is an OTSResult object with 3 attributes:
sanitizedBoolean indicating whether the file was successfully sanitizedmodifiedBoolean indicating whether the file was modified* during sanitizationmessagesTuple of message strings generated during sanitization (may be empty)
- Note: currently the back-end OTS code can modify fonts that are successfully sanitized, even when no changes are performed. Thus
modifiedcan sometimes be True whensanitizedis True. Usually the modification is only to the modification date and related checksums. Thus, it might be possible to devise a better detection of modification, i.e. ignoringhead.modifiedand other inconsequential modifications, but that was out-of-scope for this work.
# sanitize a folder of fonts. Print messages for any that were not successfully sanitized.
import pyots
from pathlib import Path
for filename in Path("src/ots/tests/fonts/good").rglob("*"):
result = pyots.sanitize(filename.absolute())
if not result.sanitized:
print(f'{filename}:\n{", ".join([m for m in result.messages])}')- Specify keyword
output=<path_to_output_file>to thesanitize()command and the sanitized file will be saved to that location - Use
quiet=Trueforsanitize()to suppress messages - Specify
font_index=<index_in_TTC>when sanitizing a Collection (OTC/TTC) file and you want to sanitize only a particular index within the Collection (otherwise all will be sanitized per OTS's default behavior)