Skip to main content

FontLift Python bindings and CLI powered by PyO3

Project description

fontlift

Install, uninstall, list, and clean up fonts on macOS and Windows — from the command line, from Rust, or from Python.

Made by FontLab https://www.fontlab.com/


What fontlift does

A font is not just a file. To make a font usable by applications, the OS must be told about it: on macOS that means a Core Text registration, on Windows a registry entry plus a GDI call. fontlift handles that mechanics so you don't have to.

Operation What it does
install Copy the font file to the OS font directory, register it. Apps see it immediately.
uninstall Remove the OS registration. File stays on disk.
remove Unregister and delete the file.
list Enumerate every face the OS currently knows about.
cleanup Prune stale registrations + clear font caches.
doctor Find interrupted operations and resume them.

Platform support

Platform Status Install location (user) Install location (system) Admin needed for system?
macOS 12+ Full ~/Library/Fonts/ /Library/Fonts/ sudo
Windows 10 1809+ Full %LOCALAPPDATA%\Microsoft\Windows\Fonts\ C:\Windows\Fonts\ Administrator
Windows 7–10 pre-1809 System scope only C:\Windows\Fonts\ Administrator
Linux Planned ~/.local/share/fonts/ /usr/share/fonts/

macOS detail: Core Text picks up the font immediately after installation — no reboot, no log-out. /System/Library/Fonts/ is managed by macOS and protected by SIP; fontlift never touches it.

Windows detail: Installation writes both a registry entry under HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts (user scope) or HKLM\... (system scope) and calls AddFontResourceW + WM_FONTCHANGE so running apps can use the font right away. Without the registry entry the font disappears after the next reboot.


Font formats

Extension Format Notes
.ttf TrueType Single face. Most common format.
.otf OpenType Single face. PostScript or TrueType outlines.
.ttc / .otc Collection Multiple faces in one file (e.g. CJK families).
.woff / .woff2 Web Open Font Compressed for the web; system support varies.
.dfont Mac data-fork suitcase Legacy macOS format.

CLI quick start

# Install a font for the current user (no admin needed)
fontlift install MyFont.otf

# Install an entire directory of fonts
fontlift install ~/Downloads/InterFamily/

# Install system-wide for all users (requires sudo / admin)
fontlift install --admin MyFont.otf

# List all installed fonts (one path per line, sorted, deduped)
fontlift list
fontlift list --name          # PostScript names instead of paths
fontlift list --path --name   # path::PostScriptName pairs
fontlift list --json          # machine-readable JSON

# Uninstall (keeps the file on disk)
fontlift uninstall ~/Library/Fonts/MyFont.otf
fontlift uninstall --name HelveticaNeue-Bold

# Remove (uninstall + delete the file)
fontlift remove ~/Library/Fonts/OldFont.otf
fontlift remove --name OldFont-Regular

# Prune stale registrations and clear caches
fontlift cleanup
fontlift cleanup --prune-only   # registrations only
fontlift cleanup --cache-only   # caches only
fontlift cleanup --admin        # include system scope

# Preview any operation without changing anything
fontlift --dry-run install MyFont.otf

# Check for and recover interrupted operations
fontlift doctor
fontlift doctor --preview

# Shell completions
fontlift completions bash >> ~/.bashrc
fontlift completions zsh  > ~/.zsh/completions/_fontlift
fontlift completions fish > ~/.config/fish/completions/fontlift.fish

Global flags work with every subcommand:

Flag Effect
--dry-run Print what would happen, change nothing
--quiet / -q Suppress all non-error output
--verbose / -v Show resolved paths, scope choices, extra detail
--json / -j Machine-readable JSON output

Validation

Before installing, fontlift can run an out-of-process validator to catch malformed font files. The validator runs in a separate process so a corrupt font cannot crash fontlift itself.

fontlift install MyFont.ttf                                 # normal (64 MB, 5 s)
fontlift install --validation-strictness lenient Big.ttf    # 128 MB, 10 s
fontlift install --validation-strictness paranoid Untrusted.ttf  # 32 MB, 2 s
fontlift install --no-validate QuickTest.ttf                # skip entirely

Python

import fontlift

# One-shot helpers
fontlift.install("MyFont.ttf")                    # user scope, no admin
fontlift.install("MyFont.ttf", admin=True)        # system scope
fontlift.uninstall("MyFont.ttf")
fontlift.uninstall(name="HelveticaNeue-Bold")     # by PostScript name
fontlift.remove("OldFont.ttf")
fontlift.cleanup(prune=True, cache=True)
fontlift.cleanup(admin=True)                      # system scope

# List all installed fonts
for font in fontlift.list_fonts():
    # font is a dict; key fields:
    # postscript_name, full_name, family_name, style, path, scope
    print(f"{font['family_name']} {font['style']}{font['path']}")

# Reusable manager (one platform connection, multiple operations)
mgr = fontlift.FontliftManager()
mgr.install_font("/tmp/MyFont.ttf")
faces = mgr.list_fonts()
mgr.cleanup(prune=True, cache=True)

The Python package is a thin wrapper around the fontlift._native PyO3 extension. Build it with maturin develop (development) or maturin build --release (wheel for distribution).


Rust library

use fontlift_core::{FontManager, FontScope, FontliftFontSource};
use fontlift_platform_mac::MacFontManager; // or WinFontManager on Windows

let manager = MacFontManager::new();
let source = FontliftFontSource::new("MyFont.ttf".into())
    .with_scope(Some(FontScope::User));

manager.install_font(&source)?;

for face in manager.list_installed_fonts()? {
    println!("{}: {} {}", face.source.path.display(), face.family_name, face.style);
}

Crate layout

fontlift/
├── core/            fontlift-core       types, traits, validation, journal
├── platform-mac/    fontlift-platform-mac   Core Text implementation
├── platform-win/    fontlift-platform-win   Registry + GDI implementation
├── cli/             fontlift-cli        clap-based CLI
├── python/          fontlift-python     PyO3 bindings
└── validator/       fontlift-validator  out-of-process font parser helper

fontlift-core defines FontManager, FontError, FontScope, and the shared data types. Platform crates implement FontManager with real OS calls. The CLI and Python bindings delegate to whichever platform crate is compiled in.


Building

# Prerequisites: Rust 1.75+, platform SDK (Xcode CLT on macOS, VS Build Tools on Windows)

# Full workspace build + tests
./build.sh --test

# Rust only
cargo build --workspace
cargo test --workspace
cargo clippy --workspace -- -D warnings

# Python wheel (requires maturin)
maturin develop -m python/Cargo.toml          # editable install for dev
maturin build  -m python/Cargo.toml --release # distributable wheel → dist/

Environment variables

Variable Effect Default
FONTLIFT_OVERRIDE_USER_LIBRARY Override per-user font directory Platform default
FONTLIFT_OVERRIDE_SYSTEM_LIBRARY Override system font directory Platform default
FONTLIFT_DRY_RUN Simulate all operations false
FONTLIFT_ALLOW_SYSTEM Permit system-scope writes false
FONTLIFT_LOG_LEVEL trace/debug/info/warn/error info
FONTLIFT_JOURNAL_PATH Override crash-recovery journal location Platform default
RUST_LOG Standard env_logger filter

Error types

Error Meaning
FontNotFound File does not exist at the given path
InvalidFormat File exists but is not a supported font format
RegistrationFailed OS refused to register the font
SystemFontProtection Path is in a system-managed font directory
PermissionDenied Process lacks the required privileges
AlreadyInstalled A font with that path is already registered
UnsupportedOperation Feature not available on this platform

Roadmap

  • Linux support (fontconfig + fc-cache)
  • Variable font metadata extraction
  • GUI via testypf integration

License

Apache License 2.0 — see LICENSE.

See CHANGELOG.md for version history.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fontlift-5.0.15-cp312-cp312-macosx_11_0_arm64.whl (377.5 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

File details

Details for the file fontlift-5.0.15-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

  • Download URL: fontlift-5.0.15-cp312-cp312-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 377.5 kB
  • Tags: CPython 3.12, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for fontlift-5.0.15-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 5af9bab10e3817647c33c4a5361d1cfb4e62874e4291537566fe1ebc6c4b81af
MD5 14e8b6c2da7c1594a98fd0f7e3d4d0f5
BLAKE2b-256 f3822b443ac70ff545c3e247aebcd6ce608e927cccb73114c0f13294ba7adeb5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page