unstale

pypi / fonttools

fonttools

What changed in fonttools 4, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-21.

13 breaking2 security1 deprecations6 new APIs and options6 behavior and defaults1 tooling49 fixes and other

See which of these apply to your code, ranked, in your agent:

npx @unstale/cli init

@unstale/cli 0.2.2 on npm

fonttools 478 changes

Breaking changes 13

  • Bounds-checks count and offSize on read, raising TTLibError instead of allocating huge lazy lists.

    4.67.0release notes

  • Fixes format 2 compilation edge cases, rejects glyph IDs above 65535 in formats 2 and 4, splits long format 14 default UVS ranges, and round-trips empty formats 12 and 13.

    4.67.0release notes

  • Prefers the Windows English name over the Mac name.

    4.67.0release notes

  • Raises NotImplementedError for an all-off-curve cubic contour, which the point pen protocol cannot express.

    4.67.0release notes

  • Rejects in-place union with |=.

    4.67.0release notes

  • Raises ValueError instead of IndexError for a truncated path command.

    4.67.0release notes

  • Updates the variation-store binary format; VARC fonts built with earlier fontTools versions must be rebuilt.

    4.67.0release notes

  • When splitting a DesignSpace v5 document with makeNames=True, explicitly set family and style names take precedence over names computed from STAT labels in all languages; an instance with its own style name no longer gets a PostScript name made from…

    4.66.1release notes

  • Decompiling a format 4 subtable with an idRangeOffset outside glyphIndexArray now raises TTLibError instead of silently mapping to the wrong glyph or raising a bare AssertionError.

    4.66.1release notes

  • Entity resolution is disabled altogether on lxml 5.0 and later to prevent crafted DTDs from reading local files into parsed XML content.

    4.66.0release notes

  • Python 3.10 support is dropped; fontTools now requires Python 3.11 or later.

    4.66.0release notes

  • When unicodedata2 is used, version 18.0.0 is required.

    4.66.0release notes

  • The instancer rejects pinning or restricting axes referenced by VARC components.

    4.66.0release notes

Security 2

  • Expansion of format 4 segments and format 12/13 groups is bounded; out-of-range, inverted, overlapping, and missing-glyph groups are handled without unbounded expansion.

    4.66.0release notes

  • Escapes axis names and tags in emitted designspace snippets to prevent crafted fonts from injecting markup.

    4.66.0release notes

Deprecations 1

  • This module now only re-exports enum.StrEnum and is deprecated.

    4.66.0release notes

New APIs and options 6

  • Adds a keyword-only argument to support decreasing design-space axis mappings.

    4.67.0release notes

  • Adds support for instancing variable COLRv1 fonts.

    4.67.0release notes

  • Allows requesting an axis's original range on VARC fonts.

    4.67.0release notes

  • A new axisCount element provides the axis count when gvar data is processed without fvar.

    4.66.0release notes

  • The new languages attribute contains all language tags in a LanguageStatement; language remains the first tag.

    4.66.0release notes

  • Static VARC fonts can omit fvar while retaining gvar or CFF2 component-internal variation data; hidden axes are addressed by index, and gvar supports compilation, decompilation, and TTX round-tripping without fvar.

    4.66.0release notes

Behavior and default changes 6

  • Accepts flattened per-region vector tuples.

    4.67.0release notes

  • Supports merging fonts that both have a MATH table.

    4.67.0release notes

  • Warns when a source or instance is dropped because it lies outside the document's own axes.

    4.67.0release notes

  • Warns when a source or instance is dropped because it lies outside the document's own axes.

    4.67.0release notes

  • feaLib supports listing multiple language tags; following rules and lookup references are registered under every listed language, and dflt cannot be combined with other tags.

    4.66.0release notes

  • When --flavor is omitted, pyftsubset preserves the input font's WOFF or WOFF2 flavor; use --flavor=none to force uncompressed output.

    4.66.0release notes

Tooling 1

  • Support for Python 3.15 is explicitly tested and declared.

    4.66.0release notes

Fixes and other changes 49

  • Omitted range attributes on a DesignSpace v5 axis subset are taken from the parent axis.

    4.67.0release notes

  • Corrects BCP 47 tags for some Mac and Windows language IDs.

    4.67.0release notes

  • Deleting a CFF dict attribute now actually removes it.

    4.67.0release notes

  • Reads CFF font names as Latin-1, matching how they are written.

    4.67.0release notes

  • Preserves operands when a blend has zero regions.

    4.67.0release notes

  • Normalizes mapped-axis bounds and rule conditions from their original values.

    4.67.0release notes

  • Keeps glyph metrics after probing a missing attribute.

    4.67.0release notes

  • Rejects duplicate use of a mark class in one anchor list, handles value records with all-NULL devices, and pads a short OS/2 Vendor with spaces.

    4.67.0release notes

  • Invalid BASE, UnicodeRange, name, STAT location, and OS/2 Vendor inputs now raise FeatureLibError with a source location instead of a bare Python error.

    4.67.0release notes

  • Fixes size, ssXX, and cvXX FeatureParams in FeatureVariations alternate feature tables so they compile and round-trip.

    4.67.0release notes

  • Adding rvrn shifts lookup indices inside existing FeatureVariations; null offsets are handled and substitution records stay sorted after merging.

    4.67.0release notes

  • The subsetter handles a null GDEF variation store.

    4.67.0release notes

  • The instancer CLI raises ValueError with a missing fvar table message for a static font instead of a bare KeyError.

    4.67.0release notes

  • Folds, removes, or remaps MATH VariationIndex devices when instancing, subsetting the GDEF store, or optimizing it.

    4.67.0release notes

  • Fixes tokenizing escaped parentheses in PostScript strings.

    4.67.0release notes

  • Preserves the direction of the remaining axis when decomposing a transform whose first column is zero.

    4.67.0release notes

  • Closes owned input streams when parsing fails.

    4.67.0release notes

  • Handles empty packed deltas when this setting is enabled.

    4.67.0release notes

  • Avoids a crash on a format 2.0 table with numGlyphs set to 0.

    4.67.0release notes

  • Recursive decompilation fully decodes lazily loaded ligatures, SinglePos, and PairPos arrays, preventing corruption or assertions on lazy fonts.

    4.67.0release notes

  • Passes the all-off-curve None sentinel through.

    4.67.0release notes

  • Scales per-glyph VORG origins, fixes VARC scaling for static fonts and condition variations, and avoids mutating the shared default CFF FontMatrix.

    4.67.0release notes

  • Fixes compiling a Silf table decompiled from binary.

    4.67.0release notes

  • Returns NotImplemented for unsupported types.

    4.67.0release notes

  • Fixes cubic off-curve detection across contour starts.

    4.67.0release notes

  • Computes glyph width lazily for glyf variable fonts without HVAR, making width correct before drawing.

    4.67.0release notes

  • Fixes component conditions, implicit scaleY import, reported coordinates after axis resets, and inherited coordinates when drawing CFF2 components.

    4.67.0release notes

  • Applies VVAR vertical-origin deltas to VORG and uses OpenType rounding for instanced advances and vertical origins.

    4.67.0release notes

  • Keeps a universal FeatureVariations record when pinning removes its last condition but other axes remain.

    4.67.0release notes

  • Preserves ppem Device corrections in GDEF, BASE, GPOS, and JSTF instead of asserting on them.

    4.67.0release notes

  • Respects designspace source layers and fixes --json output with SciPy.

    4.67.0release notes

  • Raises ValueError with a missing fvar table message for a static font instead of a bare KeyError.

    4.67.0release notes

  • Recomputes numRecs and numRatios when compiling.

    4.67.0release notes

  • Preserves minorVersion when copying flavor data.

    4.67.0release notes

  • Can be called more than once.

    4.67.0release notes

  • Compiling succeeds when the lowest glyph ID in a lead-byte row is 32768 or higher, instead of failing with struct.error.

    4.66.1release notes

  • The instancer no longer culls avar2 ranges for component-internal variations that can reach outside font-level ranges.

    4.66.0release notes

  • The VarStore is always recompiled when saving, preventing stale data when a font is modified in place after an earlier save.

    4.66.0release notes

  • Its type annotation and documentation now correctly specify that it holds a SourceDescriptor, not a source name.

    4.66.0release notes

  • A STAT table block missing ElidedFallbackName or ElidedFallbackNameID now raises FeatureLibError instead of UnboundLocalError.

    4.66.0release notes

  • Collinear vertical lines are treated as parallel, avoiding ZeroDivisionError.

    4.66.0release notes

  • Repeated script/language pairs within a feature block no longer replace the language system's lookups with a fresh copy of the defaults.

    4.66.0release notes

  • Preserves exact endpoints when splitting a cubic curve.

    4.66.0release notes

  • Preserves exact endpoints when splitting a quadratic curve.

    4.66.0release notes

  • Inconsistent WOFF table, metadata, or private-data lengths raise TTLibError instead of AssertionError, including under python -O.

    4.66.0release notes

  • Bundled script, script extension, block, and bidi-mirroring tables are updated to Unicode 18.0.0.

    4.66.0release notes

  • Merge reports incompatible unitsPerEm values by name and includes the input values instead of raising a bare assertion.

    4.66.0release notes

  • The instancer fixes stale VARC axis references after removing an unrelated axis.

    4.66.0release notes

  • Drawing VARC components with a negated condition (format 5) no longer raises AttributeError.

    4.66.0release notes