diff options
Diffstat (limited to 'Tests/designspaceLib/designspace_test.py')
-rw-r--r-- | Tests/designspaceLib/designspace_test.py | 401 |
1 files changed, 260 insertions, 141 deletions
diff --git a/Tests/designspaceLib/designspace_test.py b/Tests/designspaceLib/designspace_test.py index ee2d19e6..ceddfd10 100644 --- a/Tests/designspaceLib/designspace_test.py +++ b/Tests/designspaceLib/designspace_test.py @@ -1,12 +1,15 @@ # coding=utf-8 import os +from pathlib import Path import re +import shutil import pytest from fontTools import ttLib from fontTools.designspaceLib import ( AxisDescriptor, + AxisMappingDescriptor, AxisLabelDescriptor, DesignSpaceDocument, DesignSpaceDocumentError, @@ -21,20 +24,22 @@ from fontTools.designspaceLib import ( from fontTools.designspaceLib.types import Range from fontTools.misc import plistlib +from .fixtures import datadir + def _axesAsDict(axes): """ - Make the axis data we have available in + Make the axis data we have available in """ axesDict = {} for axisDescriptor in axes: d = { - 'name': axisDescriptor.name, - 'tag': axisDescriptor.tag, - 'minimum': axisDescriptor.minimum, - 'maximum': axisDescriptor.maximum, - 'default': axisDescriptor.default, - 'map': axisDescriptor.map, + "name": axisDescriptor.name, + "tag": axisDescriptor.tag, + "minimum": axisDescriptor.minimum, + "maximum": axisDescriptor.maximum, + "default": axisDescriptor.default, + "map": axisDescriptor.map, } axesDict[axisDescriptor.name] = d return axesDict @@ -72,8 +77,8 @@ def test_fill_document(tmpdir): a1.name = "weight" a1.tag = "wght" # note: just to test the element language, not an actual label name recommendations. - a1.labelNames[u'fa-IR'] = u"قطر" - a1.labelNames[u'en'] = u"Wéíght" + a1.labelNames["fa-IR"] = "قطر" + a1.labelNames["en"] = "Wéíght" doc.addAxis(a1) a2 = AxisDescriptor() a2.minimum = 0 @@ -83,7 +88,7 @@ def test_fill_document(tmpdir): a2.tag = "wdth" a2.map = [(0.0, 10.0), (15.0, 20.0), (401.0, 66.0), (1000.0, 990.0)] a2.hidden = True - a2.labelNames[u'fr'] = u"Chasse" + a2.labelNames["fr"] = "Chasse" doc.addAxis(a2) # add master 1 @@ -131,18 +136,22 @@ def test_fill_document(tmpdir): i1.familyName = "InstanceFamilyName" i1.styleName = "InstanceStyleName" i1.name = "instance.ufo1" - i1.location = dict(weight=500, spooky=666) # this adds a dimension that is not defined. + i1.location = dict( + weight=500, spooky=666 + ) # this adds a dimension that is not defined. i1.postScriptFontName = "InstancePostscriptName" i1.styleMapFamilyName = "InstanceStyleMapFamilyName" i1.styleMapStyleName = "InstanceStyleMapStyleName" i1.localisedStyleName = dict(fr="Demigras", ja="半ば") i1.localisedFamilyName = dict(fr="Montserrat", ja="モンセラート") i1.localisedStyleMapStyleName = dict(de="Standard") - i1.localisedStyleMapFamilyName = dict(de="Montserrat Halbfett", ja="モンセラート SemiBold") + i1.localisedStyleMapFamilyName = dict( + de="Montserrat Halbfett", ja="モンセラート SemiBold" + ) glyphData = dict(name="arrow", mute=True, unicodes=[0x123, 0x124, 0x125]) - i1.glyphs['arrow'] = glyphData - i1.lib['com.coolDesignspaceApp.binaryData'] = plistlib.Data(b'<binary gunk>') - i1.lib['com.coolDesignspaceApp.specimenText'] = "Hamburgerwhatever" + i1.glyphs["arrow"] = glyphData + i1.lib["com.coolDesignspaceApp.binaryData"] = plistlib.Data(b"<binary gunk>") + i1.lib["com.coolDesignspaceApp.specimenText"] = "Hamburgerwhatever" doc.addInstance(i1) # add instance 2 i2 = InstanceDescriptor() @@ -151,46 +160,51 @@ def test_fill_document(tmpdir): i2.styleName = "InstanceStyleName" i2.name = "instance.ufo2" # anisotropic location - i2.location = dict(weight=500, width=(400,300)) + i2.location = dict(weight=500, width=(400, 300)) i2.postScriptFontName = "InstancePostscriptName" i2.styleMapFamilyName = "InstanceStyleMapFamilyName" i2.styleMapStyleName = "InstanceStyleMapStyleName" - glyphMasters = [dict(font="master.ufo1", glyphName="BB", location=dict(width=20,weight=20)), dict(font="master.ufo2", glyphName="CC", location=dict(width=900,weight=900))] + glyphMasters = [ + dict(font="master.ufo1", glyphName="BB", location=dict(width=20, weight=20)), + dict(font="master.ufo2", glyphName="CC", location=dict(width=900, weight=900)), + ] glyphData = dict(name="arrow", unicodes=[101, 201, 301]) - glyphData['masters'] = glyphMasters - glyphData['note'] = "A note about this glyph" - glyphData['instanceLocation'] = dict(width=100, weight=120) - i2.glyphs['arrow'] = glyphData - i2.glyphs['arrow2'] = dict(mute=False) + glyphData["masters"] = glyphMasters + glyphData["note"] = "A note about this glyph" + glyphData["instanceLocation"] = dict(width=100, weight=120) + i2.glyphs["arrow"] = glyphData + i2.glyphs["arrow2"] = dict(mute=False) doc.addInstance(i2) doc.filename = "suggestedFileName.designspace" - doc.lib['com.coolDesignspaceApp.previewSize'] = 30 + doc.lib["com.coolDesignspaceApp.previewSize"] = 30 # write some rules r1 = RuleDescriptor() r1.name = "named.rule.1" - r1.conditionSets.append([ - dict(name='axisName_a', minimum=0, maximum=1), - dict(name='axisName_b', minimum=2, maximum=3) - ]) + r1.conditionSets.append( + [ + dict(name="axisName_a", minimum=0, maximum=1), + dict(name="axisName_b", minimum=2, maximum=3), + ] + ) r1.subs.append(("a", "a.alt")) doc.addRule(r1) # write the document; without an explicit format it will be 5.0 by default doc.write(testDocPath5) assert os.path.exists(testDocPath5) - assert_equals_test_file(testDocPath5, 'data/test_v5_original.designspace') + assert_equals_test_file(testDocPath5, "data/test_v5_original.designspace") # write again with an explicit format = 4.1 doc.formatVersion = "4.1" doc.write(testDocPath) assert os.path.exists(testDocPath) - assert_equals_test_file(testDocPath, 'data/test_v4_original.designspace') + assert_equals_test_file(testDocPath, "data/test_v4_original.designspace") # import it again new = DesignSpaceDocument() new.read(testDocPath) - assert new.default.location == {'width': 20.0, 'weight': 0.0} - assert new.filename == 'test_v4.designspace' + assert new.default.location == {"width": 20.0, "weight": 0.0} + assert new.filename == "test_v4.designspace" assert new.lib == doc.lib assert new.instances[0].lib == doc.instances[0].lib @@ -240,10 +254,10 @@ def test_unicodes(tmpdir): i1.name = "instance.ufo1" i1.location = dict(weight=500) glyphData = dict(name="arrow", mute=True, unicodes=[100, 200, 300]) - i1.glyphs['arrow'] = glyphData + i1.glyphs["arrow"] = glyphData doc.addInstance(i1) # now we have sources and instances, but no axes yet. - doc.axes = [] # clear the axes + doc.axes = [] # clear the axes # write some axes a1 = AxisDescriptor() a1.minimum = 0 @@ -260,13 +274,13 @@ def test_unicodes(tmpdir): new.read(testDocPath) new.write(testDocPath2) # compare the file contents - with open(testDocPath, 'r', encoding='utf-8') as f1: + with open(testDocPath, "r", encoding="utf-8") as f1: t1 = f1.read() - with open(testDocPath2, 'r', encoding='utf-8') as f2: + with open(testDocPath2, "r", encoding="utf-8") as f2: t2 = f2.read() assert t1 == t2 # check the unicode values read from the document - assert new.instances[0].glyphs['arrow']['unicodes'] == [100,200,300] + assert new.instances[0].glyphs["arrow"]["unicodes"] == [100, 200, 300] def test_localisedNames(tmpdir): @@ -299,20 +313,22 @@ def test_localisedNames(tmpdir): i1.styleMapFamilyName = "Montserrat SemiBold" i1.styleMapStyleName = "Regular" i1.setFamilyName("Montserrat", "fr") - i1.setFamilyName(u"モンセラート", "ja") + i1.setFamilyName("モンセラート", "ja") i1.setStyleName("Demigras", "fr") - i1.setStyleName(u"半ば", "ja") - i1.setStyleMapStyleName(u"Standard", "de") + i1.setStyleName("半ば", "ja") + i1.setStyleMapStyleName("Standard", "de") i1.setStyleMapFamilyName("Montserrat Halbfett", "de") - i1.setStyleMapFamilyName(u"モンセラート SemiBold", "ja") + i1.setStyleMapFamilyName("モンセラート SemiBold", "ja") i1.name = "instance.ufo1" - i1.location = dict(weight=500, spooky=666) # this adds a dimension that is not defined. + i1.location = dict( + weight=500, spooky=666 + ) # this adds a dimension that is not defined. i1.postScriptFontName = "InstancePostscriptName" glyphData = dict(name="arrow", mute=True, unicodes=[0x123]) - i1.glyphs['arrow'] = glyphData + i1.glyphs["arrow"] = glyphData doc.addInstance(i1) # now we have sources and instances, but no axes yet. - doc.axes = [] # clear the axes + doc.axes = [] # clear the axes # write some axes a1 = AxisDescriptor() a1.minimum = 0 @@ -321,8 +337,8 @@ def test_localisedNames(tmpdir): a1.name = "weight" a1.tag = "wght" # note: just to test the element language, not an actual label name recommendations. - a1.labelNames[u'fa-IR'] = u"قطر" - a1.labelNames[u'en'] = u"Wéíght" + a1.labelNames["fa-IR"] = "قطر" + a1.labelNames["en"] = "Wéíght" doc.addAxis(a1) a2 = AxisDescriptor() a2.minimum = 0 @@ -331,7 +347,7 @@ def test_localisedNames(tmpdir): a2.name = "width" a2.tag = "wdth" a2.map = [(0.0, 10.0), (401.0, 66.0), (1000.0, 990.0)] - a2.labelNames[u'fr'] = u"Poids" + a2.labelNames["fr"] = "Poids" doc.addAxis(a2) # add an axis that is not part of any location to see if that works a3 = AxisDescriptor() @@ -341,14 +357,16 @@ def test_localisedNames(tmpdir): a3.name = "spooky" a3.tag = "spok" a3.map = [(0.0, 10.0), (401.0, 66.0), (1000.0, 990.0)] - #doc.addAxis(a3) # uncomment this line to test the effects of default axes values + # doc.addAxis(a3) # uncomment this line to test the effects of default axes values # write some rules r1 = RuleDescriptor() r1.name = "named.rule.1" - r1.conditionSets.append([ - dict(name='weight', minimum=200, maximum=500), - dict(name='width', minimum=0, maximum=150) - ]) + r1.conditionSets.append( + [ + dict(name="weight", minimum=200, maximum=500), + dict(name="width", minimum=0, maximum=150), + ] + ) r1.subs.append(("a", "a.alt")) doc.addRule(r1) # write the document @@ -358,9 +376,9 @@ def test_localisedNames(tmpdir): new = DesignSpaceDocument() new.read(testDocPath) new.write(testDocPath2) - with open(testDocPath, 'r', encoding='utf-8') as f1: + with open(testDocPath, "r", encoding="utf-8") as f1: t1 = f1.read() - with open(testDocPath2, 'r', encoding='utf-8') as f2: + with open(testDocPath2, "r", encoding="utf-8") as f2: t2 = f2.read() assert t1 == t2 @@ -378,7 +396,7 @@ def test_handleNoAxes(tmpdir): # Case 1: No axes element in the document, but there are sources and instances doc = DesignSpaceDocument() - for name, value in [('One', 1),('Two', 2),('Three', 3)]: + for name, value in [("One", 1), ("Two", 2), ("Three", 3)]: a = AxisDescriptor() a.minimum = 0 a.maximum = 1000 @@ -417,7 +435,7 @@ def test_handleNoAxes(tmpdir): i1.familyName = "InstanceFamilyName" i1.styleName = "InstanceStyleName" i1.name = "instance.ufo1" - i1.location = dict(axisNameOne=(-1000,500), axisNameTwo=100) + i1.location = dict(axisNameOne=(-1000, 500), axisNameTwo=100) i1.postScriptFontName = "InstancePostscriptName" i1.styleMapFamilyName = "InstanceStyleMapFamilyName" i1.styleMapStyleName = "InstanceStyleMapStyleName" @@ -428,6 +446,7 @@ def test_handleNoAxes(tmpdir): verify.read(testDocPath) verify.write(testDocPath2) + def test_pathNameResolve(tmpdir): tmpdir = str(tmpdir) # test how descriptor.path and descriptor.filename are resolved @@ -499,7 +518,9 @@ def test_pathNameResolve(tmpdir): verify.read(testDocPath3) assert verify.sources[0].filename == "../somewhere/over/the/rainbow.ufo" # make the absolute path for filename so we can see if it matches the path - p = os.path.abspath(os.path.join(os.path.dirname(testDocPath3), verify.sources[0].filename)) + p = os.path.abspath( + os.path.join(os.path.dirname(testDocPath3), verify.sources[0].filename) + ) assert verify.sources[0].path == posix(p) # Case 4: the filename points to one file, the path points to another. The path takes precedence. @@ -529,7 +550,7 @@ def test_pathNameResolve(tmpdir): s.familyName = "MasterFamilyName" s.styleName = "MasterStyleNameOne" doc.addSource(s) - doc.write(testDocPath5) # so that the document has a path + doc.write(testDocPath5) # so that the document has a path doc.updateFilenameFromPath() assert doc.sources[0].filename == "masters/masterTest1.ufo" @@ -543,7 +564,7 @@ def test_pathNameResolve(tmpdir): s.location = dict(weight=0) s.familyName = "MasterFamilyName" s.styleName = "MasterStyleNameOne" - doc.write(testDocPath5) # so that the document has a path + doc.write(testDocPath5) # so that the document has a path doc.addSource(s) assert doc.sources[0].filename == "../somewhere/over/the/rainbow.ufo" doc.updateFilenameFromPath(force=True) @@ -561,21 +582,22 @@ def test_normalise1(): a1.name = "axisName_a" a1.tag = "TAGA" doc.addAxis(a1) - assert doc.normalizeLocation(dict(axisName_a=0)) == {'axisName_a': 0.0} - assert doc.normalizeLocation(dict(axisName_a=1000)) == {'axisName_a': 1.0} + assert doc.normalizeLocation(dict(axisName_a=0)) == {"axisName_a": 0.0} + assert doc.normalizeLocation(dict(axisName_a=1000)) == {"axisName_a": 1.0} # clipping beyond max values: - assert doc.normalizeLocation(dict(axisName_a=1001)) == {'axisName_a': 1.0} - assert doc.normalizeLocation(dict(axisName_a=500)) == {'axisName_a': 0.5} - assert doc.normalizeLocation(dict(axisName_a=-1000)) == {'axisName_a': -1.0} - assert doc.normalizeLocation(dict(axisName_a=-1001)) == {'axisName_a': -1.0} + assert doc.normalizeLocation(dict(axisName_a=1001)) == {"axisName_a": 1.0} + assert doc.normalizeLocation(dict(axisName_a=500)) == {"axisName_a": 0.5} + assert doc.normalizeLocation(dict(axisName_a=-1000)) == {"axisName_a": -1.0} + assert doc.normalizeLocation(dict(axisName_a=-1001)) == {"axisName_a": -1.0} # anisotropic coordinates normalise to isotropic - assert doc.normalizeLocation(dict(axisName_a=(1000, -1000))) == {'axisName_a': 1.0} + assert doc.normalizeLocation(dict(axisName_a=(1000, -1000))) == {"axisName_a": 1.0} doc.normalize() r = [] for axis in doc.axes: r.append((axis.name, axis.minimum, axis.default, axis.maximum)) r.sort() - assert r == [('axisName_a', -1.0, 0.0, 1.0)] + assert r == [("axisName_a", -1.0, 0.0, 1.0)] + def test_normalise2(): # normalisation with minimum > 0 @@ -587,22 +609,25 @@ def test_normalise2(): a2.default = 100 a2.name = "axisName_b" doc.addAxis(a2) - assert doc.normalizeLocation(dict(axisName_b=0)) == {'axisName_b': 0.0} - assert doc.normalizeLocation(dict(axisName_b=1000)) == {'axisName_b': 1.0} + assert doc.normalizeLocation(dict(axisName_b=0)) == {"axisName_b": 0.0} + assert doc.normalizeLocation(dict(axisName_b=1000)) == {"axisName_b": 1.0} # clipping beyond max values: - assert doc.normalizeLocation(dict(axisName_b=1001)) == {'axisName_b': 1.0} - assert doc.normalizeLocation(dict(axisName_b=500)) == {'axisName_b': 0.4444444444444444} - assert doc.normalizeLocation(dict(axisName_b=-1000)) == {'axisName_b': 0.0} - assert doc.normalizeLocation(dict(axisName_b=-1001)) == {'axisName_b': 0.0} + assert doc.normalizeLocation(dict(axisName_b=1001)) == {"axisName_b": 1.0} + assert doc.normalizeLocation(dict(axisName_b=500)) == { + "axisName_b": 0.4444444444444444 + } + assert doc.normalizeLocation(dict(axisName_b=-1000)) == {"axisName_b": 0.0} + assert doc.normalizeLocation(dict(axisName_b=-1001)) == {"axisName_b": 0.0} # anisotropic coordinates normalise to isotropic - assert doc.normalizeLocation(dict(axisName_b=(1000,-1000))) == {'axisName_b': 1.0} - assert doc.normalizeLocation(dict(axisName_b=1001)) == {'axisName_b': 1.0} + assert doc.normalizeLocation(dict(axisName_b=(1000, -1000))) == {"axisName_b": 1.0} + assert doc.normalizeLocation(dict(axisName_b=1001)) == {"axisName_b": 1.0} doc.normalize() r = [] for axis in doc.axes: r.append((axis.name, axis.minimum, axis.default, axis.maximum)) r.sort() - assert r == [('axisName_b', 0.0, 0.0, 1.0)] + assert r == [("axisName_b", 0.0, 0.0, 1.0)] + def test_normalise3(): # normalisation of negative values, with default == maximum @@ -614,16 +639,17 @@ def test_normalise3(): a3.default = 0 a3.name = "ccc" doc.addAxis(a3) - assert doc.normalizeLocation(dict(ccc=0)) == {'ccc': 0.0} - assert doc.normalizeLocation(dict(ccc=1)) == {'ccc': 0.0} - assert doc.normalizeLocation(dict(ccc=-1000)) == {'ccc': -1.0} - assert doc.normalizeLocation(dict(ccc=-1001)) == {'ccc': -1.0} + assert doc.normalizeLocation(dict(ccc=0)) == {"ccc": 0.0} + assert doc.normalizeLocation(dict(ccc=1)) == {"ccc": 0.0} + assert doc.normalizeLocation(dict(ccc=-1000)) == {"ccc": -1.0} + assert doc.normalizeLocation(dict(ccc=-1001)) == {"ccc": -1.0} doc.normalize() r = [] for axis in doc.axes: r.append((axis.name, axis.minimum, axis.default, axis.maximum)) r.sort() - assert r == [('ccc', -1.0, 0.0, 0.0)] + assert r == [("ccc", -1.0, 0.0, 0.0)] + def test_normalise4(): # normalisation with a map @@ -634,14 +660,15 @@ def test_normalise4(): a4.maximum = 1000 a4.default = 0 a4.name = "ddd" - a4.map = [(0,100), (300, 500), (600, 500), (1000,900)] + a4.map = [(0, 100), (300, 500), (600, 500), (1000, 900)] doc.addAxis(a4) doc.normalize() r = [] for axis in doc.axes: r.append((axis.name, axis.map)) r.sort() - assert r == [('ddd', [(0, 0.0), (300, 0.5), (600, 0.5), (1000, 1.0)])] + assert r == [("ddd", [(0, 0.0), (300, 0.5), (600, 0.5), (1000, 1.0)])] + def test_axisMapping(): # note: because designspance lib does not do any actual @@ -653,68 +680,113 @@ def test_axisMapping(): a4.maximum = 1000 a4.default = 0 a4.name = "ddd" - a4.map = [(0,100), (300, 500), (600, 500), (1000,900)] + a4.map = [(0, 100), (300, 500), (600, 500), (1000, 900)] doc.addAxis(a4) doc.normalize() r = [] for axis in doc.axes: r.append((axis.name, axis.map)) r.sort() - assert r == [('ddd', [(0, 0.0), (300, 0.5), (600, 0.5), (1000, 1.0)])] + assert r == [("ddd", [(0, 0.0), (300, 0.5), (600, 0.5), (1000, 1.0)])] + + +def test_axisMappingsRoundtrip(tmpdir): + # tests of axisMappings in a document, roundtripping. + + tmpdir = str(tmpdir) + srcDocPath = (Path(__file__) / "../data/test_avar2.designspace").resolve() + testDocPath = os.path.join(tmpdir, "test_avar2.designspace") + shutil.copy(srcDocPath, testDocPath) + testDocPath2 = os.path.join(tmpdir, "test_avar2_roundtrip.designspace") + doc = DesignSpaceDocument() + doc.read(testDocPath) + assert doc.axisMappings + assert len(doc.axisMappings) == 1 + assert doc.axisMappings[0].inputLocation == {"Justify": -100.0, "Width": 100.0} + + # This is a bit of a hack, but it's the only way to make sure + # that the save works on Windows if the tempdir and the data + # dir are on different drives. + for descriptor in doc.sources + doc.instances: + descriptor.path = None + + doc.write(testDocPath2) + # verify these results + doc2 = DesignSpaceDocument() + doc2.read(testDocPath2) + assert [mapping.inputLocation for mapping in doc.axisMappings] == [ + mapping.inputLocation for mapping in doc2.axisMappings + ] + assert [mapping.outputLocation for mapping in doc.axisMappings] == [ + mapping.outputLocation for mapping in doc2.axisMappings + ] + def test_rulesConditions(tmpdir): # tests of rules, conditionsets and conditions r1 = RuleDescriptor() r1.name = "named.rule.1" - r1.conditionSets.append([ - dict(name='axisName_a', minimum=0, maximum=1000), - dict(name='axisName_b', minimum=0, maximum=3000) - ]) + r1.conditionSets.append( + [ + dict(name="axisName_a", minimum=0, maximum=1000), + dict(name="axisName_b", minimum=0, maximum=3000), + ] + ) r1.subs.append(("a", "a.alt")) - assert evaluateRule(r1, dict(axisName_a = 500, axisName_b = 0)) == True - assert evaluateRule(r1, dict(axisName_a = 0, axisName_b = 0)) == True - assert evaluateRule(r1, dict(axisName_a = 1000, axisName_b = 0)) == True - assert evaluateRule(r1, dict(axisName_a = 1000, axisName_b = -100)) == False - assert evaluateRule(r1, dict(axisName_a = 1000.0001, axisName_b = 0)) == False - assert evaluateRule(r1, dict(axisName_a = -0.0001, axisName_b = 0)) == False - assert evaluateRule(r1, dict(axisName_a = -100, axisName_b = 0)) == False - assert processRules([r1], dict(axisName_a = 500, axisName_b = 0), ["a", "b", "c"]) == ['a.alt', 'b', 'c'] - assert processRules([r1], dict(axisName_a = 500, axisName_b = 0), ["a.alt", "b", "c"]) == ['a.alt', 'b', 'c'] - assert processRules([r1], dict(axisName_a = 2000, axisName_b = 0), ["a", "b", "c"]) == ['a', 'b', 'c'] + assert evaluateRule(r1, dict(axisName_a=500, axisName_b=0)) == True + assert evaluateRule(r1, dict(axisName_a=0, axisName_b=0)) == True + assert evaluateRule(r1, dict(axisName_a=1000, axisName_b=0)) == True + assert evaluateRule(r1, dict(axisName_a=1000, axisName_b=-100)) == False + assert evaluateRule(r1, dict(axisName_a=1000.0001, axisName_b=0)) == False + assert evaluateRule(r1, dict(axisName_a=-0.0001, axisName_b=0)) == False + assert evaluateRule(r1, dict(axisName_a=-100, axisName_b=0)) == False + assert processRules([r1], dict(axisName_a=500, axisName_b=0), ["a", "b", "c"]) == [ + "a.alt", + "b", + "c", + ] + assert processRules( + [r1], dict(axisName_a=500, axisName_b=0), ["a.alt", "b", "c"] + ) == ["a.alt", "b", "c"] + assert processRules([r1], dict(axisName_a=2000, axisName_b=0), ["a", "b", "c"]) == [ + "a", + "b", + "c", + ] # rule with only a maximum r2 = RuleDescriptor() r2.name = "named.rule.2" - r2.conditionSets.append([dict(name='axisName_a', maximum=500)]) + r2.conditionSets.append([dict(name="axisName_a", maximum=500)]) r2.subs.append(("b", "b.alt")) - assert evaluateRule(r2, dict(axisName_a = 0)) == True - assert evaluateRule(r2, dict(axisName_a = -500)) == True - assert evaluateRule(r2, dict(axisName_a = 1000)) == False + assert evaluateRule(r2, dict(axisName_a=0)) == True + assert evaluateRule(r2, dict(axisName_a=-500)) == True + assert evaluateRule(r2, dict(axisName_a=1000)) == False # rule with only a minimum r3 = RuleDescriptor() r3.name = "named.rule.3" - r3.conditionSets.append([dict(name='axisName_a', minimum=500)]) + r3.conditionSets.append([dict(name="axisName_a", minimum=500)]) r3.subs.append(("c", "c.alt")) - assert evaluateRule(r3, dict(axisName_a = 0)) == False - assert evaluateRule(r3, dict(axisName_a = 1000)) == True - assert evaluateRule(r3, dict(axisName_a = 1000)) == True + assert evaluateRule(r3, dict(axisName_a=0)) == False + assert evaluateRule(r3, dict(axisName_a=1000)) == True + assert evaluateRule(r3, dict(axisName_a=1000)) == True # rule with only a minimum, maximum in separate conditions r4 = RuleDescriptor() r4.name = "named.rule.4" - r4.conditionSets.append([ - dict(name='axisName_a', minimum=500), - dict(name='axisName_b', maximum=500) - ]) + r4.conditionSets.append( + [dict(name="axisName_a", minimum=500), dict(name="axisName_b", maximum=500)] + ) r4.subs.append(("c", "c.alt")) - assert evaluateRule(r4, dict(axisName_a = 1000, axisName_b = 0)) == True - assert evaluateRule(r4, dict(axisName_a = 0, axisName_b = 0)) == False - assert evaluateRule(r4, dict(axisName_a = 1000, axisName_b = 1000)) == False + assert evaluateRule(r4, dict(axisName_a=1000, axisName_b=0)) == True + assert evaluateRule(r4, dict(axisName_a=0, axisName_b=0)) == False + assert evaluateRule(r4, dict(axisName_a=1000, axisName_b=1000)) == False + def test_rulesDocument(tmpdir): # tests of rules in a document, roundtripping. @@ -739,26 +811,51 @@ def test_rulesDocument(tmpdir): doc.addAxis(b1) r1 = RuleDescriptor() r1.name = "named.rule.1" - r1.conditionSets.append([ - dict(name='axisName_a', minimum=0, maximum=1000), - dict(name='axisName_b', minimum=0, maximum=3000) - ]) + r1.conditionSets.append( + [ + dict(name="axisName_a", minimum=0, maximum=1000), + dict(name="axisName_b", minimum=0, maximum=3000), + ] + ) r1.subs.append(("a", "a.alt")) # rule with minium and maximum doc.addRule(r1) assert len(doc.rules) == 1 assert len(doc.rules[0].conditionSets) == 1 assert len(doc.rules[0].conditionSets[0]) == 2 - assert _axesAsDict(doc.axes) == {'axisName_a': {'map': [], 'name': 'axisName_a', 'default': 0, 'minimum': 0, 'maximum': 1000, 'tag': 'TAGA'}, 'axisName_b': {'map': [], 'name': 'axisName_b', 'default': 2000, 'minimum': 2000, 'maximum': 3000, 'tag': 'TAGB'}} - assert doc.rules[0].conditionSets == [[ - {'minimum': 0, 'maximum': 1000, 'name': 'axisName_a'}, - {'minimum': 0, 'maximum': 3000, 'name': 'axisName_b'}]] - assert doc.rules[0].subs == [('a', 'a.alt')] + assert _axesAsDict(doc.axes) == { + "axisName_a": { + "map": [], + "name": "axisName_a", + "default": 0, + "minimum": 0, + "maximum": 1000, + "tag": "TAGA", + }, + "axisName_b": { + "map": [], + "name": "axisName_b", + "default": 2000, + "minimum": 2000, + "maximum": 3000, + "tag": "TAGB", + }, + } + assert doc.rules[0].conditionSets == [ + [ + {"minimum": 0, "maximum": 1000, "name": "axisName_a"}, + {"minimum": 0, "maximum": 3000, "name": "axisName_b"}, + ] + ] + assert doc.rules[0].subs == [("a", "a.alt")] doc.normalize() - assert doc.rules[0].name == 'named.rule.1' - assert doc.rules[0].conditionSets == [[ - {'minimum': 0.0, 'maximum': 1.0, 'name': 'axisName_a'}, - {'minimum': 0.0, 'maximum': 1.0, 'name': 'axisName_b'}]] + assert doc.rules[0].name == "named.rule.1" + assert doc.rules[0].conditionSets == [ + [ + {"minimum": 0.0, "maximum": 1.0, "name": "axisName_a"}, + {"minimum": 0.0, "maximum": 1.0, "name": "axisName_b"}, + ] + ] # still one conditionset assert len(doc.rules[0].conditionSets) == 1 doc.write(testDocPath) @@ -778,17 +875,22 @@ def test_rulesDocument(tmpdir): assert len(doc3.rules) == 1 assert len(doc3.rules[0].conditionSets) == 2 + def _addUnwrappedCondition(path): # only for testing, so we can make an invalid designspace file # older designspace files may have conditions that are not wrapped in a conditionset # These can be read into a new conditionset. - with open(path, 'r', encoding='utf-8') as f: + with open(path, "r", encoding="utf-8") as f: d = f.read() print(d) - d = d.replace('<rule name="named.rule.1">', '<rule name="named.rule.1">\n\t<condition maximum="22" minimum="33" name="axisName_a" />') - with open(path, 'w', encoding='utf-8') as f: + d = d.replace( + '<rule name="named.rule.1">', + '<rule name="named.rule.1">\n\t<condition maximum="22" minimum="33" name="axisName_a" />', + ) + with open(path, "w", encoding="utf-8") as f: f.write(d) + def test_documentLib(tmpdir): # roundtrip test of the document lib with some nested data tmpdir = str(tmpdir) @@ -801,7 +903,7 @@ def test_documentLib(tmpdir): a1.maximum = 1000 a1.default = 0 doc.addAxis(a1) - dummyData = dict(a=123, b=u"äbc", c=[1,2,3], d={'a':123}) + dummyData = dict(a=123, b="äbc", c=[1, 2, 3], d={"a": 123}) dummyKey = "org.fontTools.designspaceLib" doc.lib = {dummyKey: dummyData} doc.write(testDocPath1) @@ -855,17 +957,15 @@ def test_updatePaths(tmpdir): def test_read_with_path_object(): - import pathlib - source = (pathlib.Path(__file__) / "../data/test_v4_original.designspace").resolve() + source = (Path(__file__) / "../data/test_v4_original.designspace").resolve() assert source.exists() doc = DesignSpaceDocument() doc.read(source) def test_with_with_path_object(tmpdir): - import pathlib tmpdir = str(tmpdir) - dest = pathlib.Path(tmpdir) / "test_v4_original.designspace" + dest = Path(tmpdir) / "test_v4_original.designspace" doc = DesignSpaceDocument() doc.write(dest) assert dest.exists() @@ -934,7 +1034,6 @@ def test_findDefault_axis_mapping(): def test_loadSourceFonts(): - def opener(path): font = ttLib.TTFont() font.importXML(path) @@ -945,7 +1044,7 @@ def test_loadSourceFonts(): os.path.dirname(os.path.dirname(__file__)), "varLib", "data", - "SparseMasters.designspace" + "SparseMasters.designspace", ) designspace = DesignSpaceDocument.fromfile(path) @@ -976,7 +1075,7 @@ def test_addAxisDescriptor(): ds = DesignSpaceDocument() axis = ds.addAxisDescriptor( - name="Weight", tag="wght", minimum=100, default=400, maximum=900 + name="Weight", tag="wght", minimum=100, default=400, maximum=900 ) assert ds.axes[0] is axis @@ -988,6 +1087,19 @@ def test_addAxisDescriptor(): assert axis.maximum == 900 +def test_addAxisDescriptor(): + ds = DesignSpaceDocument() + + mapping = ds.addAxisMappingDescriptor( + inputLocation={"weight": 900, "width": 150}, outputLocation={"weight": 870} + ) + + assert ds.axisMappings[0] is mapping + assert isinstance(mapping, AxisMappingDescriptor) + assert mapping.inputLocation == {"weight": 900, "width": 150} + assert mapping.outputLocation == {"weight": 870} + + def test_addSourceDescriptor(): ds = DesignSpaceDocument() @@ -1003,10 +1115,10 @@ def test_addInstanceDescriptor(): ds = DesignSpaceDocument() instance = ds.addInstanceDescriptor( - name="TestInstance", - location={"Weight": 400}, - styleName="Regular", - styleMapStyleName="regular", + name="TestInstance", + location={"Weight": 400}, + styleName="Regular", + styleMapStyleName="regular", ) assert ds.instances[0] is instance @@ -1064,3 +1176,10 @@ def test_Range_post_init(): assert r.minimum == -1 assert r.maximum == 2 assert r.default == -1 + + +def test_get_axes(datadir: Path) -> None: + ds = DesignSpaceDocument.fromfile(datadir / "test_v5.designspace") + + assert ds.getAxis("Width") is ds.getAxisByTag("wdth") + assert ds.getAxis("Italic") is ds.getAxisByTag("ital") |