CLI tool for modifying font family names in OpenType/TrueType fonts
Project description
fontnome
fontnome is a Python CLI tool for modifying font family names in OpenType and TrueType fonts. It manipulates specific nameID fields in the font's name table while preserving all other font data intact.
Installation
Install from PyPI:
pip install fontnome
Or using uv:
uv pip install fontnome
For development:
git clone https://github.com/twardoch/fontnome
cd fontnome
uv pip install -e ".[dev]"
Why fontnome?
When working with fonts, you often need to:
- Rename font families for testing or deployment
- Add version suffixes or timestamps to track iterations
- Create customized font builds with modified names
- Manage font naming across different platforms
fontnome makes these operations safe, predictable, and scriptable. It handles the complexity of OpenType name tables, ensuring that all relevant nameID fields are updated consistently.
Quick Start
# View current font family name
fontnome view MyFont.ttf
# Rename font family
fontnome new MyFont.ttf --new_family="Custom Font"
# Add timestamp (updates on each run)
fontnome timestamp MyFont.ttf
# Add suffix
fontnome suffix MyFont.ttf --suffix=" Beta"
# Find and replace in name
fontnome replace MyFont.ttf --find="Regular" --replace="Modified"
Core Concepts
Two Name Types
fontnome operates on two distinct naming concepts:
-
family_name: Human-readable display name (e.g., "My Font Family")
- Read from: nameID 16 (Typographic Family) → 21 (WWS Family) → 1 (Font Family)
- Written to: nameIDs 1, 4, 16, 18, 21
-
family_slug: ASCII-safe PostScript identifier (e.g., "MyFontFamily")
- Read from: nameID 25 (Variations PostScript Name Prefix) → 6 (PostScript name, before first hyphen)
- Written to: nameIDs 6, 20, 25 (with spaces removed)
SLUG_RULE
Slug generation converts any string to a PostScript-compatible identifier:
- Keeps only printable ASCII characters (codes 33-126)
- Removes these 10 forbidden characters:
[](){}<>/% - Removes all spaces
Example: "My Font [Beta]" → "MyFontBeta"
TIME_RULE
Timestamps are generated as lowercase base-36 Unix timestamps for compact, sortable identifiers.
Example: "t51r1v" (represents a specific Unix timestamp)
Safe File Writing
All operations use a safe writing pattern:
- Write to temporary file
- Optionally create backup of original
- Atomically move temporary file to final location
This prevents data loss and ensures you never end up with corrupted fonts.
Commands
All commands support short aliases (single letter) for faster typing.
view (v) - Display font family name
fontnome view <input_path> [--long]
fontnome v <input_path> [--long]
Parameters:
input_path: Input font file (.ttf, .otf)--long: Show path prefix in output (optional)
Examples:
$ fontnome view MyFont.ttf
My Font Family
$ fontnome v MyFont.ttf --long
MyFont.ttf:My Font Family
new (n) - Set new family name
fontnome new <input_path> --new_family=<name> [--output_path=<mode>]
fontnome n <input_path> --new_family=<name> [--output_path=<mode>]
Parameters:
input_path: Input font filenew_family: New family name to setoutput_path: Output mode (see Output Modes section)
Operation:
- Sets
new_family_nameto the provided value - Generates
new_family_slugusing SLUG_RULE - Updates all relevant nameID fields
Examples:
# Replace input file
$ fontnome new MyFont.ttf --new_family="Custom Font"
# Save to new file
$ fontnome n MyFont.ttf --new_family="Test" --output_path="output.ttf"
# Create backup before replacing
$ fontnome n MyFont.ttf --new_family="Production" --output_path="1"
replace (r) - Find and replace in family name
fontnome replace <input_path> --find=<text> --replace=<text> [--output_path=<mode>]
fontnome r <input_path> --find=<text> --replace=<text> [--output_path=<mode>]
Parameters:
input_path: Input font filefind: Text to findreplace: Text to replace withoutput_path: Output mode (optional)
Operation:
- Reads current
family_nameandfamily_slug - Replaces
findwithreplaceinfamily_name - Converts both to slugs and replaces in
family_slug - Updates all relevant nameID fields
Examples:
$ fontnome replace MyFont.ttf --find="Draft" --replace="Final"
$ fontnome r MyFont.ttf --find="v1" --replace="v2"
suffix (s) - Append suffix to family name
fontnome suffix <input_path> --suffix=<text> [--output_path=<mode>]
fontnome s <input_path> --suffix=<text> [--output_path=<mode>]
Parameters:
input_path: Input font filesuffix: Suffix to appendoutput_path: Output mode (optional)
Operation:
- Reads current
family_nameandfamily_slug - Appends
suffixtofamily_name - Appends slug-converted suffix to
family_slug
Examples:
$ fontnome suffix MyFont.ttf --suffix=" Beta"
$ fontnome s MyFont.ttf --suffix=" v2.0"
prefix (p) - Prepend prefix to family name
fontnome prefix <input_path> --prefix=<text> [--output_path=<mode>]
fontnome p <input_path> --prefix=<text> [--output_path=<mode>]
Parameters:
input_path: Input font fileprefix: Prefix to prependoutput_path: Output mode (optional)
Operation:
- Reads current
family_nameandfamily_slug - Prepends
prefixtofamily_name - Prepends slug-converted prefix to
family_slug
Examples:
$ fontnome prefix MyFont.ttf --prefix="Draft "
$ fontnome p MyFont.ttf --prefix="Test "
timestamp (t) - Append timestamp suffix
fontnome timestamp <input_path> [--separator=<text>] [--replace_timestamp] [--output_path=<mode>]
fontnome t <input_path> [--separator=<text>] [--replace_timestamp] [--output_path=<mode>]
Parameters:
input_path: Input font fileseparator: Separator before timestamp (default:" tX")replace_timestamp: Remove old timestamp before adding new (default:True)output_path: Output mode (optional)
Operation:
- Reads current
family_nameandfamily_slug - If
replace_timestamp=Trueand using default separator:- Removes
tXand everything after fromfamily_name - Removes
tXand everything after fromfamily_slug
- Removes
- Generates new timestamp using TIME_RULE
- Appends
separator + timestamptofamily_name - Appends slug-converted suffix to
family_slug
Examples:
# Default: replaces old timestamp on each run
$ fontnome timestamp MyFont.ttf
# First run: "My Font" → "My Font tXt51r1v"
# Second run: "My Font tXt51r1v" → "My Font tXt51r2a"
# Keep accumulating timestamps
$ fontnome t MyFont.ttf --replace_timestamp=False
# Use custom separator
$ fontnome t MyFont.ttf --separator="-"
Output Modes
All commands (except view) support flexible output handling via --output_path:
Mode "0" (default)
Replace input file safely:
fontnome new MyFont.ttf --new_family="Test" # --output_path="0" implied
Mode "1"
Create backup with timestamp, then replace input:
fontnome new MyFont.ttf --new_family="Test" --output_path="1"
# Creates: MyFont--t51r1v.ttf (backup)
# Updates: MyFont.ttf (modified)
Mode "2"
Save to timestamped output file, keep original:
fontnome new MyFont.ttf --new_family="Test" --output_path="2"
# Keeps: MyFont.ttf (original)
# Creates: MyFont--t51r1v.ttf (modified)
Explicit Path
Save to specific file:
fontnome new MyFont.ttf --new_family="Test" --output_path="Output.ttf"
# Keeps: MyFont.ttf (original)
# Creates: Output.ttf (modified)
Verbose Logging
Enable debug logging for troubleshooting:
fontnome --verbose view MyFont.ttf
fontnome --verbose new MyFont.ttf --new_family="Test"
Technical Details
Platform/Encoding Priority
When reading name records, fontnome tries:
- Windows English:
(platformID=3, platEncID=1, langID=0x409) - Mac Roman fallback:
(platformID=1, platEncID=0, langID=0)
nameID Field Mapping
family_name operations update:
- nameID 1: Font Family name (legacy)
- nameID 4: Full font name
- nameID 16: Typographic Family name
- nameID 18: Typographic Subfamily name
- nameID 21: WWS Family Name
family_slug operations update (no spaces):
- nameID 6: PostScript name
- nameID 20: PostScript CID findfont name
- nameID 25: Variations PostScript Name Prefix
Reference Code
The implementation is based on fonttools patterns. Reference code studied:
vendors/fonttools/Snippets/rename-fonts.pyvendors/fonttools/Lib/fontTools/varLib/instancer/names.py
Note: The vendors/ directory contains reference code only. fontnome uses the fonttools package from PyPI.
Requirements
- Python 3.12+
- fonttools >= 4.50.0
- fire >= 0.6.0
- loguru >= 0.7.0
Development
# Clone repository
git clone https://github.com/twardoch/fontnome
cd fontnome
# Create virtual environment
uv venv --python 3.12
source .venv/bin/activate # or `.venv\Scripts\activate` on Windows
# Install in development mode
uv pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Run linting
ruff check src/
ruff format src/
# Run comprehensive test suite
./test.sh
Testing
fontnome includes comprehensive tests:
# Unit tests
pytest tests/test_utils.py -v # Slug and timestamp functions
pytest tests/test_core.py -v # Font name operations
# All tests with coverage
pytest tests/ --cov=fontnome --cov-report=html
# Functional tests (via test.sh)
./test.sh
Test coverage: 93-95% on core modules (utils.py, core.py).
License
Apache License 2.0
Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
Links
- PyPI: https://pypi.org/project/fontnome/
- GitHub: https://github.com/twardoch/fontnome
- Issues: https://github.com/twardoch/fontnome/issues
Credits
Created by Adam Twardoch
Based on fonttools by Just van Rossum and contributors.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fontnome-1.0.2.tar.gz.
File metadata
- Download URL: fontnome-1.0.2.tar.gz
- Upload date:
- Size: 333.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3908f0c821e1dc1dbca7949befc3ee84f6ea1e60cf7b11586b0e5be8eaa160c1
|
|
| MD5 |
af0a8c479b17fd09da4d3e1634046b9b
|
|
| BLAKE2b-256 |
81f11867f1d594a35051fe237404d53f17e07ba84983a7d641155e9d8f56b261
|
File details
Details for the file fontnome-1.0.2-py3-none-any.whl.
File metadata
- Download URL: fontnome-1.0.2-py3-none-any.whl
- Upload date:
- Size: 15.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
68a324429b5ec4aeb38df9a4bcce9a9849692d88c0925225d62f3fd6468c97e4
|
|
| MD5 |
36a1531ce0fa4518173b3d9c93b0cf5a
|
|
| BLAKE2b-256 |
d148c97de4468bd9754c5242a11ce8b4eed3866ab422e080cbd6f1d00dd23aa4
|