summaryrefslogtreecommitdiffstats
path: root/contrib/python/fonttools/fontTools/varLib/errors.py
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/python/fonttools/fontTools/varLib/errors.py')
-rw-r--r--contrib/python/fonttools/fontTools/varLib/errors.py219
1 files changed, 219 insertions, 0 deletions
diff --git a/contrib/python/fonttools/fontTools/varLib/errors.py b/contrib/python/fonttools/fontTools/varLib/errors.py
new file mode 100644
index 00000000000..4f30f901bab
--- /dev/null
+++ b/contrib/python/fonttools/fontTools/varLib/errors.py
@@ -0,0 +1,219 @@
+import textwrap
+
+
+class VarLibError(Exception):
+ """Base exception for the varLib module."""
+
+
+class VarLibValidationError(VarLibError):
+ """Raised when input data is invalid from varLib's point of view."""
+
+
+class VarLibMergeError(VarLibError):
+ """Raised when input data cannot be merged into a variable font."""
+
+ def __init__(self, merger=None, **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):
+ if self.merger is not None:
+ ttf = self.merger.ttfs[ix]
+ if "name" in ttf and ttf["name"].getBestFullName():
+ return ttf["name"].getBestFullName()
+ 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):
+ if "expected" in self.cause and "got" in self.cause:
+ index = [x == self.cause["expected"] for x in self.cause["got"]].index(
+ False
+ )
+ master_name = self._master_name(index)
+ if "location" in self.cause:
+ master_name = f"{master_name} ({self.cause['location']})"
+ return index, master_name
+ 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']!r}, instead saw {got!r}\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):
+ basic_message = super().details
+
+ if self.stack[0] != ".FeatureCount" or self.merger is None:
+ return basic_message
+
+ assert self.stack[0] == ".FeatureCount"
+ offender_index, _ = self.offender
+ bad_ttf = self.merger.ttfs[offender_index]
+ good_ttf = next(
+ ttf
+ for ttf in self.merger.ttfs
+ if self.stack[-1] in ttf
+ and ttf[self.stack[-1]].table.FeatureList.FeatureCount
+ == self.cause["expected"]
+ )
+
+ 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 basic_message + (
+ "\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):
+ index = [x is None for x in self.cause["got"]].index(True)
+ return index, self._master_name(index)
+
+ @property
+ def details(self):
+ cause, stack = self.cause, self.stack
+ return f"{stack[0]}=={cause['got']}\n"
+
+
+class NotANone(VarLibMergeError):
+ """one of the values in a list was not empty when it should have been"""
+
+ @property
+ def offender(self):
+ index = [x is not None for x in self.cause["got"]].index(True)
+ return index, self._master_name(index)
+
+ @property
+ def details(self):
+ cause, stack = self.cause, self.stack
+ 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 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"""
+
+ def __init__(self, merger=None, **kwargs):
+ super().__init__(merger, **kwargs)
+ if not self.stack:
+ self.stack = [".Format"]
+
+ @property
+ def reason(self):
+ s = self.__doc__ % self.cause["subtable"]
+ if "value" in self.cause:
+ s += f" ({self.cause['value']!r})"
+ return s
+
+
+class InconsistentFormats(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):
+ error_msg = (
+ f"For the Private Dict key '{key}', the default font value list:"
+ f"\n\t{value}\nhad a different number of values than a region font:"
+ )
+ for region_value in values:
+ error_msg += f"\n\t{region_value}"
+ self.args = (error_msg,)
+
+
+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 = (
+ f"Glyph '{glyph_name}': '{point_type}' at point index {pt_index} in "
+ f"master index {m_index} differs from the default font point type "
+ f"'{default_type}'"
+ )
+ 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."""