diff options
Diffstat (limited to 'Lib/fontTools/varLib/errors.py')
-rw-r--r-- | Lib/fontTools/varLib/errors.py | 157 |
1 files changed, 154 insertions, 3 deletions
diff --git a/Lib/fontTools/varLib/errors.py b/Lib/fontTools/varLib/errors.py index b73f1886..5840070f 100644 --- a/Lib/fontTools/varLib/errors.py +++ b/Lib/fontTools/varLib/errors.py @@ -1,3 +1,6 @@ +import textwrap + + class VarLibError(Exception): """Base exception for the varLib module.""" @@ -9,8 +12,144 @@ class VarLibValidationError(VarLibError): class VarLibMergeError(VarLibError): """Raised when input data cannot be merged into a variable font.""" + def __init__(self, merger, **kwargs): + self.merger = merger + if not kwargs: + kwargs = {} + if "stack" in kwargs: + self.stack = kwargs["stack"] + del kwargs["stack"] + else: + self.stack = [] + self.cause = kwargs + + @property + def reason(self): + 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 + + @property + def offender(self): + if "expected" in self.cause and "got" in self.cause: + index = [x == self.cause["expected"] for x in self.cause["got"]].index( + False + ) + return index, self._master_name(index) + return None, None + + @property + def details(self): + if "expected" in self.cause and "got" in self.cause: + offender_index, offender = self.offender + got = self.cause["got"][offender_index] + return f"Expected to see {self.stack[0]}=={self.cause['expected']}, instead saw {got}\n" + return "" + + def __str__(self): + offender_index, offender = self.offender + location = "" + if offender: + location = f"\n\nThe problem is likely to be in {offender}:\n" + context = "".join(reversed(self.stack)) + basic = textwrap.fill( + f"Couldn't merge the fonts, because {self.reason}. " + f"This happened while performing the following operation: {context}", + width=78, + ) + return "\n\n" + basic + location + self.details + + +class ShouldBeConstant(VarLibMergeError): + """some values were different, but should have been the same""" + + @property + def details(self): + if self.stack[0] != ".FeatureCount": + return super().details + offender_index, offender = self.offender + bad_ttf = self.merger.ttfs[offender_index] + good_ttf = self.merger.ttfs[offender_index - 1] + + good_features = [ + x.FeatureTag + for x in good_ttf[self.stack[-1]].table.FeatureList.FeatureRecord + ] + bad_features = [ + x.FeatureTag + for x in bad_ttf[self.stack[-1]].table.FeatureList.FeatureRecord + ] + return ( + "\nIncompatible features between masters.\n" + f"Expected: {', '.join(good_features)}.\n" + f"Got: {', '.join(bad_features)}.\n" + ) + + +class FoundANone(VarLibMergeError): + """one of the values in a list was empty when it shouldn't have been""" + + @property + def offender(self): + cause = self.argv[0] + index = [x is None for x in cause["got"]].index(True) + return index, self._master_name(index) + + @property + def details(self): + cause, stack = self.args[0], self.args[1:] + return f"{stack[0]}=={cause['got']}\n" + + +class MismatchedTypes(VarLibMergeError): + """data had inconsistent types""" + + +class LengthsDiffer(VarLibMergeError): + """a list of objects had inconsistent lengths""" -class VarLibCFFDictMergeError(VarLibMergeError): + +class KeysDiffer(VarLibMergeError): + """a list of objects had different keys""" + + +class InconsistentGlyphOrder(VarLibMergeError): + """the glyph order was inconsistent between masters""" + + +class InconsistentExtensions(VarLibMergeError): + """the masters use extension lookups in inconsistent ways""" + + +class UnsupportedFormat(VarLibMergeError): + """an OpenType subtable (%s) had a format I didn't expect""" + + @property + def reason(self): + cause, stack = self.args[0], self.args[1:] + return self.__doc__ % cause["subtable"] + + +class UnsupportedFormat(UnsupportedFormat): + """an OpenType subtable (%s) had inconsistent formats between masters""" + + +class VarLibCFFMergeError(VarLibError): + pass + + +class VarLibCFFDictMergeError(VarLibCFFMergeError): """Raised when a CFF PrivateDict cannot be merged.""" def __init__(self, key, value, values): @@ -23,8 +162,8 @@ class VarLibCFFDictMergeError(VarLibMergeError): self.args = (error_msg,) -class VarLibCFFPointTypeMergeError(VarLibMergeError): - """Raised when a CFF glyph cannot be merged.""" +class VarLibCFFPointTypeMergeError(VarLibCFFMergeError): + """Raised when a CFF glyph cannot be merged because of point type differences.""" def __init__(self, point_type, pt_index, m_index, default_type, glyph_name): error_msg = ( @@ -35,5 +174,17 @@ class VarLibCFFPointTypeMergeError(VarLibMergeError): self.args = (error_msg,) +class VarLibCFFHintTypeMergeError(VarLibCFFMergeError): + """Raised when a CFF glyph cannot be merged because of hint type differences.""" + + def __init__(self, hint_type, cmd_index, m_index, default_type, glyph_name): + error_msg = ( + f"Glyph '{glyph_name}': '{hint_type}' at index {cmd_index} in " + f"master index {m_index} differs from the default font hint type " + f"'{default_type}'" + ) + self.args = (error_msg,) + + class VariationModelError(VarLibError): """Raised when a variation model is faulty.""" |