Spaces:
Running
Running
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 | |
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}" | |
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 | |
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""" | |
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""" | |
def offender(self): | |
index = [x is None for x in self.cause["got"]].index(True) | |
return index, self._master_name(index) | |
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""" | |
def offender(self): | |
index = [x is not None for x in self.cause["got"]].index(True) | |
return index, self._master_name(index) | |
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"] | |
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.""" | |