diff --git a/Lib/fontTools/varLib/errors.py b/Lib/fontTools/varLib/errors.py index 5840070f7..f9cd9fbe4 100644 --- a/Lib/fontTools/varLib/errors.py +++ b/Lib/fontTools/varLib/errors.py @@ -12,7 +12,7 @@ class VarLibValidationError(VarLibError): class VarLibMergeError(VarLibError): """Raised when input data cannot be merged into a variable font.""" - def __init__(self, merger, **kwargs): + def __init__(self, merger=None, **kwargs): self.merger = merger if not kwargs: kwargs = {} @@ -28,17 +28,17 @@ class VarLibMergeError(VarLibError): return self.__doc__ def _master_name(self, ix): - ttf = self.merger.ttfs[ix] - if ( - "name" in ttf - and ttf["name"].getDebugName(1) - and ttf["name"].getDebugName(2) - ): - return ttf["name"].getDebugName(1) + " " + ttf["name"].getDebugName(2) - elif hasattr(ttf.reader, "file") and hasattr(ttf.reader.file, "name"): - return ttf.reader.file.name - else: - return "master number %i" % ix + if self.merger is not None: + ttf = self.merger.ttfs[ix] + if ( + "name" in ttf + and ttf["name"].getDebugName(1) + and ttf["name"].getDebugName(2) + ): + return ttf["name"].getDebugName(1) + " " + ttf["name"].getDebugName(2) + elif hasattr(ttf.reader, "file") and hasattr(ttf.reader.file, "name"): + return ttf.reader.file.name + return f"master number {ix}" @property def offender(self): @@ -76,7 +76,7 @@ class ShouldBeConstant(VarLibMergeError): @property def details(self): - if self.stack[0] != ".FeatureCount": + if self.stack[0] != ".FeatureCount" or self.merger is None: return super().details offender_index, offender = self.offender bad_ttf = self.merger.ttfs[offender_index] diff --git a/Lib/fontTools/varLib/merger.py b/Lib/fontTools/varLib/merger.py index 29a662fa6..77d2ea7ef 100644 --- a/Lib/fontTools/varLib/merger.py +++ b/Lib/fontTools/varLib/merger.py @@ -143,7 +143,7 @@ class AligningMerger(Merger): def merge(merger, self, lst): if self is None: if not allNone(lst): - raise NotANone(self, expected=None, got=lst) + raise NotANone(merger, expected=None, got=lst) return lst = [l.classDefs for l in lst] @@ -156,7 +156,7 @@ def merge(merger, self, lst): for k in allKeys: allValues = nonNone(l.get(k) for l in lst) if not allEqual(allValues): - raise ShouldBeConstant(self, expected=allValues[0], got=lst, stack=["." + k]) + raise ShouldBeConstant(merger, expected=allValues[0], got=lst, stack=["." + k]) if not allValues: self[k] = None else: @@ -193,7 +193,7 @@ def _merge_GlyphOrders(font, lst, values_lst=None, default=None): order = sorted(combined, key=sortKey) # Make sure all input glyphsets were in proper order if not all(sorted(vs, key=sortKey) == vs for vs in lst): - raise InconsistentGlyphOrder(self) + raise InconsistentGlyphOrder() del combined paddedValues = None @@ -208,7 +208,7 @@ def _merge_GlyphOrders(font, lst, values_lst=None, default=None): for dict_set in dict_sets] return order, padded -def _Lookup_SinglePos_get_effective_value(subtables, glyph): +def _Lookup_SinglePos_get_effective_value(merger, subtables, glyph): for self in subtables: if self is None or \ type(self) != ot.SinglePos or \ @@ -220,10 +220,10 @@ def _Lookup_SinglePos_get_effective_value(subtables, glyph): elif self.Format == 2: return self.Value[self.Coverage.glyphs.index(glyph)] else: - raise UnsupportedFormat(self, subtable="single positioning lookup") + raise UnsupportedFormat(merger, subtable="single positioning lookup") return None -def _Lookup_PairPos_get_effective_value_pair(subtables, firstGlyph, secondGlyph): +def _Lookup_PairPos_get_effective_value_pair(merger, subtables, firstGlyph, secondGlyph): for self in subtables: if self is None or \ type(self) != ot.PairPos or \ @@ -242,14 +242,14 @@ def _Lookup_PairPos_get_effective_value_pair(subtables, firstGlyph, secondGlyph) klass2 = self.ClassDef2.classDefs.get(secondGlyph, 0) return self.Class1Record[klass1].Class2Record[klass2] else: - raise UnsupportedFormat(self, subtable="pair positioning lookup") + raise UnsupportedFormat(merger, subtable="pair positioning lookup") return None @AligningMerger.merger(ot.SinglePos) def merge(merger, self, lst): self.ValueFormat = valueFormat = reduce(int.__or__, [l.ValueFormat for l in lst], 0) if not (len(lst) == 1 or (valueFormat & ~0xF == 0)): - raise UnsupportedFormat(self, subtable="single positioning lookup") + raise UnsupportedFormat(merger, subtable="single positioning lookup") # If all have same coverage table and all are format 1, coverageGlyphs = self.Coverage.glyphs @@ -279,7 +279,7 @@ def merge(merger, self, lst): # Note!!! This *might* result in behavior change if ValueFormat2-zeroedness # is different between used subtable and current subtable! # TODO(behdad) Check and warn if that happens? - v = _Lookup_SinglePos_get_effective_value(merger.lookup_subtables[i], glyph) + v = _Lookup_SinglePos_get_effective_value(merger, merger.lookup_subtables[i], glyph) if v is None: v = otBase.ValueRecord(valueFormat) values[j] = v @@ -315,7 +315,9 @@ def merge(merger, self, lst): if values[j] is not None: vpair = values[j] else: - vpair = _Lookup_PairPos_get_effective_value_pair(merger.lookup_subtables[i], self._firstGlyph, glyph) + vpair = _Lookup_PairPos_get_effective_value_pair( + merger, merger.lookup_subtables[i], self._firstGlyph, glyph + ) if vpair is None: v1, v2 = None, None else: @@ -518,7 +520,7 @@ def merge(merger, self, lst): elif self.Format == 2: _PairPosFormat2_merge(self, lst, merger) else: - raise UnsupportedFormat(self, subtable="pair positioning lookup") + raise UnsupportedFormat(merger, subtable="pair positioning lookup") del merger.valueFormat1, merger.valueFormat2 @@ -584,8 +586,7 @@ def _MarkBasePosFormat1_merge(self, lst, merger, Mark='Mark', Base='Base'): # input masters. if not allEqual(allClasses): - raise allClasses(self, allClasses) - rec = None + raise ShouldBeConstant(merger, expected=allClasses[0], got=allClasses) else: rec = ot.MarkRecord() rec.Class = allClasses[0] @@ -633,7 +634,8 @@ def _MarkBasePosFormat1_merge(self, lst, merger, Mark='Mark', Base='Base'): @AligningMerger.merger(ot.MarkBasePos) def merge(merger, self, lst): if not allEqualTo(self.Format, (l.Format for l in lst)): - raise InconsistentFormats(self, + raise InconsistentFormats( + merger, subtable="mark-to-base positioning lookup", expected=self.Format, got=[l.Format for l in lst] @@ -641,12 +643,13 @@ def merge(merger, self, lst): if self.Format == 1: _MarkBasePosFormat1_merge(self, lst, merger) else: - raise UnsupportedFormat(self, subtable="mark-to-base positioning lookup") + raise UnsupportedFormat(merger, subtable="mark-to-base positioning lookup") @AligningMerger.merger(ot.MarkMarkPos) def merge(merger, self, lst): if not allEqualTo(self.Format, (l.Format for l in lst)): - raise InconsistentFormats(self, + raise InconsistentFormats( + merger, subtable="mark-to-mark positioning lookup", expected=self.Format, got=[l.Format for l in lst] @@ -654,7 +657,7 @@ def merge(merger, self, lst): if self.Format == 1: _MarkBasePosFormat1_merge(self, lst, merger, 'Mark1', 'Mark2') else: - raise UnsupportedFormat(self, subtable="mark-to-mark positioning lookup") + raise UnsupportedFormat(merger, subtable="mark-to-mark positioning lookup") def _PairSet_flatten(lst, font): self = ot.PairSet() @@ -780,12 +783,13 @@ def merge(merger, self, lst): continue if sts[0].__class__.__name__.startswith('Extension'): if not allEqual([st.__class__ for st in sts]): - raise InconsistentExtensions(self, + raise InconsistentExtensions( + merger, expected="Extension", got=[st.__class__.__name__ for st in sts] ) if not allEqual([st.ExtensionLookupType for st in sts]): - raise InconsistentExtensions(self) + raise InconsistentExtensions(merger) l.LookupType = sts[0].ExtensionLookupType new_sts = [st.ExtSubTable for st in sts] del sts[:] @@ -1035,7 +1039,7 @@ def buildVarDevTable(store_builder, master_values): @VariationMerger.merger(ot.BaseCoord) def merge(merger, self, lst): if self.Format != 1: - raise UnsupportedFormat(self, subtable="a baseline coordinate") + raise UnsupportedFormat(merger, subtable="a baseline coordinate") self.Coordinate, DeviceTable = buildVarDevTable(merger.store_builder, [a.Coordinate for a in lst]) if DeviceTable: self.Format = 3 @@ -1044,7 +1048,7 @@ def merge(merger, self, lst): @VariationMerger.merger(ot.CaretValue) def merge(merger, self, lst): if self.Format != 1: - raise UnsupportedFormat(self, subtable="a caret") + raise UnsupportedFormat(merger, subtable="a caret") self.Coordinate, DeviceTable = buildVarDevTable(merger.store_builder, [a.Coordinate for a in lst]) if DeviceTable: self.Format = 3 @@ -1053,7 +1057,7 @@ def merge(merger, self, lst): @VariationMerger.merger(ot.Anchor) def merge(merger, self, lst): if self.Format != 1: - raise UnsupportedFormat(self, subtable="an anchor") + raise UnsupportedFormat(merger, subtable="an anchor") self.XCoordinate, XDeviceTable = buildVarDevTable(merger.store_builder, [a.XCoordinate for a in lst]) self.YCoordinate, YDeviceTable = buildVarDevTable(merger.store_builder, [a.YCoordinate for a in lst]) if XDeviceTable or YDeviceTable: