init: Convert input checking asserts into proper exceptions

Also fix the avar output mapping check to allow values greater than OR
EQUAL to the preceeding values.
This commit is contained in:
Nikolaus Waxweiler 2020-02-11 13:51:52 +00:00 committed by Nikolaus Waxweiler
parent 8f7a796bd3
commit c5c30588b5

View File

@ -79,7 +79,12 @@ def _add_fvar(font, axes, instances):
coordinates = instance.location
if "en" not in instance.localisedStyleName:
assert instance.styleName
if not instance.styleName:
raise VarLibValidationError(
f"Instance at location '{coordinates}' must have a default English "
"style name ('stylename' attribute on the instance element or a "
"stylename element with an 'xml:lang=\"en\"' attribute)."
)
localisedStyleName = dict(instance.localisedStyleName)
localisedStyleName["en"] = tounicode(instance.styleName)
else:
@ -135,20 +140,32 @@ def _add_avar(font, axes):
# Current avar requirements. We don't have to enforce
# these on the designer and can deduce some ourselves,
# but for now just enforce them.
assert axis.minimum == min(keys)
assert axis.maximum == max(keys)
assert axis.default in keys
# No duplicates
assert len(set(keys)) == len(keys), (
f"{axis.tag} axis: All axis mapping input='...' "
"values must be unique, but we found duplicates."
if axis.minimum != min(keys):
raise VarLibValidationError(
f"Axis '{axis.name}': there must be a mapping for the axis minimum "
f"value {axis.minimum} and it must be the lowest input mapping value."
)
assert len(set(vals)) == len(vals), (
f"{axis.tag} axis: All axis mapping output='...' "
"values must be unique, but we found duplicates."
if axis.maximum != max(keys):
raise VarLibValidationError(
f"Axis '{axis.name}': there must be a mapping for the axis maximum "
f"value {axis.maximum} and it must be the highest input mapping value."
)
if axis.default not in keys:
raise VarLibValidationError(
f"Axis '{axis.name}': there must be a mapping for the axis default "
f"value {axis.default}."
)
# No duplicate input values (output values can be >= their preceeding value).
if len(set(keys)) != len(keys):
raise VarLibValidationError(
f"Axis '{axis.name}': All axis mapping input='...' values must be "
"unique, but we found duplicates."
)
# Ascending values
assert sorted(vals) == vals
if sorted(vals) != vals:
raise VarLibValidationError(
f"Axis '{axis.name}': mapping output values must be in ascending order."
)
keys_triple = (axis.minimum, axis.default, axis.maximum)
vals_triple = tuple(axis.map_forward(v) for v in keys_triple)
@ -212,8 +229,8 @@ def _add_stat(font, axes):
def _add_gvar(font, masterModel, master_ttfs, tolerance=0.5, optimize=True):
assert tolerance >= 0
if tolerance < 0:
raise ValueError("`tolerance` must be a positive number.")
log.info("Generating gvar")
assert "gvar" not in font
@ -704,6 +721,7 @@ def load_designspace(designspace):
raise VarLibValidationError("Designspace must have at least one source.")
instances = ds.instances
# TODO: Use fontTools.designspaceLib.tagForAxisName instead.
standard_axis_map = OrderedDict([
('weight', ('wght', {'en': u'Weight'})),
('width', ('wdth', {'en': u'Width'})),
@ -713,11 +731,15 @@ def load_designspace(designspace):
])
# Setup axes
if not ds.axes:
raise VarLibValidationError(f"Designspace must have at least one axis.")
axes = OrderedDict()
for axis in ds.axes:
for axis_index, axis in enumerate(ds.axes):
axis_name = axis.name
if not axis_name:
assert axis.tag is not None
if not axis.tag:
raise VarLibValidationError(f"Axis at index {axis_index} needs a tag.")
axis_name = axis.name = axis.tag
if axis_name in standard_axis_map:
@ -726,7 +748,8 @@ def load_designspace(designspace):
if not axis.labelNames:
axis.labelNames.update(standard_axis_map[axis_name][1])
else:
assert axis.tag is not None
if not axis.tag:
raise VarLibValidationError(f"Axis at index {axis_index} needs a tag.")
if not axis.labelNames:
axis.labelNames["en"] = tounicode(axis_name)
@ -737,15 +760,28 @@ def load_designspace(designspace):
for obj in masters+instances:
obj_name = obj.name or obj.styleName or ''
loc = obj.location
if loc is None:
raise VarLibValidationError(
f"Source or instance '{obj_name}' has no location."
)
for axis_name in loc.keys():
assert axis_name in axes, "Location axis '%s' unknown for '%s'." % (axis_name, obj_name)
if axis_name not in axes:
raise VarLibValidationError(
f"Location axis '{axis_name}' unknown for '{obj_name}'."
)
for axis_name,axis in axes.items():
if axis_name not in loc:
# NOTE: `axis.default` is always user-space, but `obj.location` always design-space.
loc[axis_name] = axis.map_forward(axis.default)
else:
v = axis.map_backward(loc[axis_name])
assert axis.minimum <= v <= axis.maximum, "Location for axis '%s' (mapped to %s) out of range for '%s' [%s..%s]" % (axis_name, v, obj_name, axis.minimum, axis.maximum)
if not (axis.minimum <= v <= axis.maximum):
raise VarLibValidationError(
f"Source or instance '{obj_name}' has out-of-range location "
f"for axis '{axis_name}': is mapped to {v} but must be in "
f"mapped range [{axis.minimum}..{axis.maximum}] (NOTE: all "
"values are in user-space)."
)
# Normalize master locations
@ -766,9 +802,15 @@ def load_designspace(designspace):
base_idx = None
for i,m in enumerate(normalized_master_locs):
if all(v == 0 for v in m.values()):
assert base_idx is None
if base_idx is not None:
raise VarLibValidationError(
"More than one base master found in Designspace."
)
base_idx = i
assert base_idx is not None, "Base master not found; no master at default location?"
if base_idx is None:
raise VarLibValidationError(
"Base master not found; no master at default location?"
)
log.info("Index of base master: %s", base_idx)
return _DesignSpaceData(