diff --git a/.gitignore b/.gitignore index afeef5372..388cdac76 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ htmlcov/ # OSX Finder .DS_Store +.pytest_cache diff --git a/Doc/source/designspaceLib/readme.rst b/Doc/source/designspaceLib/readme.rst index 139122273..614705ca0 100644 --- a/Doc/source/designspaceLib/readme.rst +++ b/Doc/source/designspaceLib/readme.rst @@ -129,6 +129,8 @@ Attributes - ``path``: string. Absolute path to the source file, calculated from the document path and the string in the filename attr. MutatorMath + Varlib. + ``layer``: string. The name of the layer in the source to look for + outline data. Defaults to ``None`` which means the foreground layer. - ``font``: Any Python object. Optional. Points to a representation of this source font that is loaded in memory, as a Python object (e.g. a ``defcon.Font`` or a ``fontTools.ttFont.TTFont``). The default @@ -538,6 +540,9 @@ Attributes - ``filename``: required, string. A path to the source file, relative to the root path of this document. The path can be at the same level as the document or lower. +- ``layer``: optional, string. The name of the layer in the source file. + If no layer is given assume it is the foreground layer. The layer names + should follow the conventions layed out in the .. _http://unifiedfontobject.org/versions/ufo3/layercontents.plist/ .. 31-lib-element: diff --git a/Lib/fontTools/designspaceLib/__init__.py b/Lib/fontTools/designspaceLib/__init__.py index 0e1b5e1a7..3be15e33b 100644 --- a/Lib/fontTools/designspaceLib/__init__.py +++ b/Lib/fontTools/designspaceLib/__init__.py @@ -114,7 +114,7 @@ class SimpleDescriptor(object): class SourceDescriptor(SimpleDescriptor): """Simple container for data related to the source""" flavor = "source" - _attrs = ['filename', 'path', 'name', + _attrs = ['filename', 'path', 'name', 'layerName', 'location', 'copyLib', 'copyGroups', 'copyFeatures', 'muteKerning', 'muteInfo', @@ -142,6 +142,7 @@ class SourceDescriptor(SimpleDescriptor): self.name = None self.location = None + self.layerName = None self.copyLib = False self.copyInfo = False self.copyGroups = False @@ -567,6 +568,8 @@ class BaseDocWriter(object): sourceElement.attrib['familyname'] = sourceObject.familyName if sourceObject.styleName is not None: sourceElement.attrib['stylename'] = sourceObject.styleName + if sourceObject.layerName is not None: + sourceElement.attrib['layer'] = sourceObject.layerName if sourceObject.copyLib: libElement = ET.Element('lib') libElement.attrib['copy'] = "1" @@ -769,6 +772,7 @@ class BaseDocReader(object): # Look at all locations and collect the axis names and values # assumptions: # look for the default value on an axis from a master location + # Needs deprecation warning allLocations = [] minima = {} maxima = {} @@ -822,6 +826,9 @@ class BaseDocReader(object): if styleName is not None: sourceObject.styleName = styleName sourceObject.location = self.locationFromElement(sourceElement) + layerName = sourceElement.attrib.get('layer') + if layerName is not None: + sourceObject.layerName = layerName for libElement in sourceElement.findall('.lib'): if libElement.attrib.get('copy') == '1': sourceObject.copyLib = True diff --git a/Tests/designspaceLib/data/test.designspace b/Tests/designspaceLib/data/test.designspace index e91aad1e4..43116deb2 100644 --- a/Tests/designspaceLib/data/test.designspace +++ b/Tests/designspaceLib/data/test.designspace @@ -38,6 +38,12 @@ + + + + + + diff --git a/Tests/designspaceLib/designspace_test.py b/Tests/designspaceLib/designspace_test.py index 210be8123..f352d410b 100644 --- a/Tests/designspaceLib/designspace_test.py +++ b/Tests/designspaceLib/designspace_test.py @@ -57,6 +57,19 @@ def test_fill_document(tmpdir): s2.familyName = "MasterFamilyName" s2.styleName = "MasterStyleNameTwo" doc.addSource(s2) + # add master 3 from a different layer + s3 = SourceDescriptor() + s3.filename = os.path.relpath(masterPath2, os.path.dirname(testDocPath)) + s3.name = "master.ufo2" + s3.copyLib = False + s3.copyInfo = False + s3.copyFeatures = False + s3.muteKerning = False + s3.layerName = "supports" + s3.location = dict(weight=1000) + s3.familyName = "MasterFamilyName" + s3.styleName = "Supports" + doc.addSource(s3) # add instance 1 i1 = InstanceDescriptor() i1.filename = os.path.relpath(instancePath1, os.path.dirname(testDocPath)) @@ -788,98 +801,100 @@ def __removeAxesFromDesignSpace(path): f.close() -@pytest.fixture -def invalid_designspace(): - p = "testCheck.designspace" - __removeAxesFromDesignSpace(p) - yield p +# @pytest.fixture +# def invalid_designspace(): +# p = "testCheck.designspace" +# __removeAxesFromDesignSpace(p) +# yield p -@pytest.mark.xfail(reason="The check method requires MutatorMath") -def test_check(invalid_designspace, tmpdir): - tmpdir = str(tmpdir) - # check if the checks are checking - testDocPath = os.path.join(tmpdir, invalid_designspace) - masterPath1 = os.path.join(tmpdir, "masters", "masterTest1.ufo") - masterPath2 = os.path.join(tmpdir, "masters", "masterTest2.ufo") - instancePath1 = os.path.join(tmpdir, "instances", "instanceTest1.ufo") - instancePath2 = os.path.join(tmpdir, "instances", "instanceTest2.ufo") +# #@pytest.mark.xfail(reason="The check method requires MutatorMath") +# def test_check(invalid_designspace, tmpdir): +# tmpdir = str(tmpdir) +# # check if the checks are checking +# testDocPath = os.path.join(tmpdir, invalid_designspace) +# masterPath1 = os.path.join(tmpdir, "masters", "masterTest1.ufo") +# masterPath2 = os.path.join(tmpdir, "masters", "masterTest2.ufo") +# instancePath1 = os.path.join(tmpdir, "instances", "instanceTest1.ufo") +# instancePath2 = os.path.join(tmpdir, "instances", "instanceTest2.ufo") - # no default selected - doc = DesignSpaceDocument() - # add master 1 - s1 = SourceDescriptor() - s1.path = masterPath1 - s1.name = "master.ufo1" - s1.location = dict(snap=0, pop=10) - s1.familyName = "MasterFamilyName" - s1.styleName = "MasterStyleNameOne" - doc.addSource(s1) - # add master 2 - s2 = SourceDescriptor() - s2.path = masterPath2 - s2.name = "master.ufo2" - s2.location = dict(snap=1000, pop=20) - s2.familyName = "MasterFamilyName" - s2.styleName = "MasterStyleNameTwo" - doc.addSource(s2) - doc.checkAxes() - doc.getAxisOrder() == ['snap', 'pop'] - assert doc.default == None - doc.checkDefault() - assert doc.default.name == 'master.ufo1' +# # no default selected +# doc = DesignSpaceDocument() +# # add master 1 +# s1 = SourceDescriptor() +# s1.path = masterPath1 +# s1.name = "master.ufo1" +# s1.location = dict(snap=0, pop=10) +# s1.familyName = "MasterFamilyName" +# s1.styleName = "MasterStyleNameOne" +# doc.addSource(s1) +# # add master 2 +# s2 = SourceDescriptor() +# s2.path = masterPath2 +# s2.name = "master.ufo2" +# s2.location = dict(snap=1000, pop=20) +# s2.familyName = "MasterFamilyName" +# s2.styleName = "MasterStyleNameTwo" +# doc.addSource(s2) +# doc.checkAxes() +# doc.getAxisOrder() == ['snap', 'pop'] +# assert doc.default == None +# doc.checkDefault() +# assert doc.default.name == 'master.ufo1' - # default selected - doc = DesignSpaceDocument() - # add master 1 - s1 = SourceDescriptor() - s1.path = masterPath1 - s1.name = "master.ufo1" - s1.location = dict(snap=0, pop=10) - s1.familyName = "MasterFamilyName" - s1.styleName = "MasterStyleNameOne" - doc.addSource(s1) - # add master 2 - s2 = SourceDescriptor() - s2.path = masterPath2 - s2.name = "master.ufo2" - s2.copyInfo = True - s2.location = dict(snap=1000, pop=20) - s2.familyName = "MasterFamilyName" - s2.styleName = "MasterStyleNameTwo" - doc.addSource(s2) - doc.checkAxes() - assert doc.getAxisOrder() == ['snap', 'pop'] - assert doc.default == None - doc.checkDefault() - assert doc.default.name == 'master.ufo2' +# # default selected +# doc = DesignSpaceDocument() +# # add master 1 +# s1 = SourceDescriptor() +# s1.path = masterPath1 +# s1.name = "master.ufo1" +# s1.location = dict(snap=0, pop=10) +# s1.familyName = "MasterFamilyName" +# s1.styleName = "MasterStyleNameOne" +# doc.addSource(s1) +# # add master 2 +# s2 = SourceDescriptor() +# s2.path = masterPath2 +# s2.name = "master.ufo2" +# s2.copyInfo = True +# s2.location = dict(snap=1000, pop=20) +# s2.familyName = "MasterFamilyName" +# s2.styleName = "MasterStyleNameTwo" +# doc.addSource(s2) +# doc.checkAxes() +# assert doc.getAxisOrder() == ['snap', 'pop'] +# assert doc.default == None +# doc.checkDefault() +# assert doc.default.name == 'master.ufo2' + +# # generate a doc without axes, save and read again +# doc = DesignSpaceDocument() +# # add master 1 +# s1 = SourceDescriptor() +# s1.path = masterPath1 +# s1.name = "master.ufo1" +# s1.location = dict(snap=0, pop=10) +# s1.familyName = "MasterFamilyName" +# s1.styleName = "MasterStyleNameOne" +# doc.addSource(s1) +# # add master 2 +# s2 = SourceDescriptor() +# s2.path = masterPath2 +# s2.name = "master.ufo2" +# s2.location = dict(snap=1000, pop=20) +# s2.familyName = "MasterFamilyName" +# s2.styleName = "MasterStyleNameTwo" +# doc.addSource(s2) +# doc.checkAxes() +# doc.write(testDocPath) +# __removeAxesFromDesignSpace(testDocPath) + +# new = DesignSpaceDocument() +# new.read(testDocPath) +# assert len(new.axes) == 2 +# new.checkAxes() +# assert len(new.axes) == 2 +# assert print([a.name for a in new.axes]) == ['snap', 'pop'] +# new.write(testDocPath) - # generate a doc without axes, save and read again - doc = DesignSpaceDocument() - # add master 1 - s1 = SourceDescriptor() - s1.path = masterPath1 - s1.name = "master.ufo1" - s1.location = dict(snap=0, pop=10) - s1.familyName = "MasterFamilyName" - s1.styleName = "MasterStyleNameOne" - doc.addSource(s1) - # add master 2 - s2 = SourceDescriptor() - s2.path = masterPath2 - s2.name = "master.ufo2" - s2.location = dict(snap=1000, pop=20) - s2.familyName = "MasterFamilyName" - s2.styleName = "MasterStyleNameTwo" - doc.addSource(s2) - doc.checkAxes() - doc.write(testDocPath) - __removeAxesFromDesignSpace(testDocPath) - new = DesignSpaceDocument() - new.read(testDocPath) - assert len(new.axes) == 2 - new.checkAxes() - assert len(new.axes) == 2 - assert print([a.name for a in new.axes]) == ['snap', 'pop'] - new.write(testDocPath)