Repository: fonttools/fonttools

Issue:
[instancer] --update-name-tables unnecessarily strict?
In order to update the name tables, the instancer looks in the STAT table and expects to see an entry for every axis and every axis value which is being instantiated. I wonder if this is overly strict; my feeling is that if there is an axis which doesn't affect style naming at all, it does not need to be in the STAT table, and therefore the instancer should be able to ignore that axis when it comes to generating the style names. But maybe there is a good reason for this behaviour.


Discussion:
> an axis which doesn't affect style naming at all

IIUC, are you suggesting that if an axis is not defined in STAT it should be ignored when updating the name table?
I thought STAT requires that all fvar axes have a corresponding design axis.

> In a font with an 'fvar' table, this value must be greater than or equal to the axisCount value in the 'fvar' table.

https://learn.microsoft.com/en-us/typography/opentype/spec/stat#style-attributes-header
OK. But the same argument applies for axis values.
if STAT doesn't contain some axis values at the new desired default location, the update_name_table method would not know what to put there. Should it skip those and leave them emtpy? Or make something up based on the coordianate value itself? The safest was to expect them all to be there. /cc @m4rc1e the author of the code
> Should it skip those and leave them emtpy?

I suppose one way to see it would be that if there any values listed for an axis, then trying to instantiate the name table for a value which is not listed (e.g. "wght=650") should fail, because we're expecting a name but there isn't a valid one; but if the axis is listed but there are no axis values, then it's an axis which doesn't affect naming so just ignore it.
> if the axis is listed but there are no axis values, then it's an axis which doesn't affect naming so just ignore it.

I see what you mean now, makes sense. I'm fine with relaxing it that way.
Agree with relaxing if there are no axis values.

Resolving patch:
diff --git a/Lib/fontTools/varLib/instancer/names.py b/Lib/fontTools/varLib/instancer/names.py
--- a/Lib/fontTools/varLib/instancer/names.py
+++ b/Lib/fontTools/varLib/instancer/names.py
@@ -134,6 +134,14 @@ def updateNameTable(varfont, axisLimits):
 def checkAxisValuesExist(stat, axisValues, axisCoords):
     seen = set()
     designAxes = stat.DesignAxisRecord.Axis
+    hasValues = set()
+    for value in stat.AxisValueArray.AxisValue:
+        if value.Format in (1, 2, 3):
+            hasValues.add(designAxes[value.AxisIndex].AxisTag)
+        elif value.Format == 4:
+            for rec in value.AxisValueRecord:
+                hasValues.add(designAxes[rec.AxisIndex].AxisTag)
+
     for axisValueTable in axisValues:
         axisValueFormat = axisValueTable.Format
         if axisValueTable.Format in (1, 2, 3):
@@ -150,7 +158,7 @@ def checkAxisValuesExist(stat, axisValues, axisCoords):
                 if axisTag in axisCoords and rec.Value == axisCoords[axisTag]:
                     seen.add(axisTag)
 
-    missingAxes = set(axisCoords) - seen
+    missingAxes = (set(axisCoords) - seen) & hasValues
     if missingAxes:
         missing = ", ".join(f"'{i}': {axisCoords[i]}" for i in missingAxes)
         raise ValueError(f"Cannot find Axis Values {{{missing}}}")


Test patch:
diff --git a/Tests/varLib/instancer/names_test.py b/Tests/varLib/instancer/names_test.py
--- a/Tests/varLib/instancer/names_test.py
+++ b/Tests/varLib/instancer/names_test.py
@@ -333,3 +333,21 @@ def test_updateNameTable_existing_subfamily_name_is_not_regular(varfont):
     instancer.names.updateNameTable(varfont, {"wght": 100})
     expected = {(2, 3, 1, 0x409): "Regular", (17, 3, 1, 0x409): "Thin"}
     _test_name_records(varfont, expected, isNonRIBBI=True)
+
+
+def test_name_irrelevant_axes(varfont):
+    # Cannot update name table if not on a named axis value location
+    with pytest.raises(ValueError) as excinfo:
+        location = {"wght": 400, "wdth": 90}
+        instance = instancer.instantiateVariableFont(
+            varfont, location, updateFontNames=True
+        )
+    assert "Cannot find Axis Values" in str(excinfo.value)
+
+    # Now let's make the wdth axis "irrelevant" to naming (no axis values)
+    varfont["STAT"].table.AxisValueArray.AxisValue.pop(6)
+    varfont["STAT"].table.AxisValueArray.AxisValue.pop(4)
+    location = {"wght": 400, "wdth": 90}
+    instance = instancer.instantiateVariableFont(
+        varfont, location, updateFontNames=True
+    )