Add expectContentsFile parameter to GlyphSet
For use when reading existing UFOs, to comply with the specification stating that a contents.plist file must exist in a glyph set. Closes https://github.com/fonttools/fonttools/issues/2111.
This commit is contained in:
parent
26d06342f9
commit
8d2a3ae6d2
@ -683,7 +683,13 @@ class UFOReader(_UFOBaseIO):
|
|||||||
# this will already have been raised during __init__
|
# this will already have been raised during __init__
|
||||||
raise UFOLibError("The default layer is not defined in layercontents.plist.")
|
raise UFOLibError("The default layer is not defined in layercontents.plist.")
|
||||||
|
|
||||||
def getGlyphSet(self, layerName=None, validateRead=None, validateWrite=None):
|
def getGlyphSet(
|
||||||
|
self,
|
||||||
|
layerName=None,
|
||||||
|
validateRead=None,
|
||||||
|
validateWrite=None,
|
||||||
|
expectContentsFile=False
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Return the GlyphSet associated with the
|
Return the GlyphSet associated with the
|
||||||
glyphs directory mapped to layerName
|
glyphs directory mapped to layerName
|
||||||
@ -695,6 +701,10 @@ class UFOReader(_UFOBaseIO):
|
|||||||
class's validate value, can be overridden.
|
class's validate value, can be overridden.
|
||||||
``validateWrite`` will validate the written data, by default it is set to the
|
``validateWrite`` will validate the written data, by default it is set to the
|
||||||
class's validate value, can be overridden.
|
class's validate value, can be overridden.
|
||||||
|
``expectContentsFile`` will raise a GlifLibError if a contents.plist file is
|
||||||
|
not found on the glyph set file system. This should be set to ``True`` if you
|
||||||
|
are reading an existing UFO and ``False`` if you use ``getGlyphSet`` to create
|
||||||
|
a fresh glyph set.
|
||||||
"""
|
"""
|
||||||
from fontTools.ufoLib.glifLib import GlyphSet
|
from fontTools.ufoLib.glifLib import GlyphSet
|
||||||
|
|
||||||
@ -723,6 +733,7 @@ class UFOReader(_UFOBaseIO):
|
|||||||
ufoFormatVersion=self._formatVersion,
|
ufoFormatVersion=self._formatVersion,
|
||||||
validateRead=validateRead,
|
validateRead=validateRead,
|
||||||
validateWrite=validateWrite,
|
validateWrite=validateWrite,
|
||||||
|
expectContentsFile=expectContentsFile
|
||||||
)
|
)
|
||||||
|
|
||||||
def getCharacterMapping(self, layerName=None, validate=None):
|
def getCharacterMapping(self, layerName=None, validate=None):
|
||||||
@ -1422,7 +1433,15 @@ class UFOWriter(UFOReader):
|
|||||||
raise UFOLibError("Could not locate a glyph set directory for the layer named %s." % layerName)
|
raise UFOLibError("Could not locate a glyph set directory for the layer named %s." % layerName)
|
||||||
return foundDirectory
|
return foundDirectory
|
||||||
|
|
||||||
def getGlyphSet(self, layerName=None, defaultLayer=True, glyphNameToFileNameFunc=None, validateRead=None, validateWrite=None):
|
def getGlyphSet(
|
||||||
|
self,
|
||||||
|
layerName=None,
|
||||||
|
defaultLayer=True,
|
||||||
|
glyphNameToFileNameFunc=None,
|
||||||
|
validateRead=None,
|
||||||
|
validateWrite=None,
|
||||||
|
expectContentsFile=False,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Return the GlyphSet object associated with the
|
Return the GlyphSet object associated with the
|
||||||
appropriate glyph directory in the .ufo.
|
appropriate glyph directory in the .ufo.
|
||||||
@ -1435,6 +1454,10 @@ class UFOWriter(UFOReader):
|
|||||||
class's validate value, can be overridden.
|
class's validate value, can be overridden.
|
||||||
``validateWrte`` will validate the written data, by default it is set to the
|
``validateWrte`` will validate the written data, by default it is set to the
|
||||||
class's validate value, can be overridden.
|
class's validate value, can be overridden.
|
||||||
|
``expectContentsFile`` will raise a GlifLibError if a contents.plist file is
|
||||||
|
not found on the glyph set file system. This should be set to ``True`` if you
|
||||||
|
are reading an existing UFO and ``False`` if you use ``getGlyphSet`` to create
|
||||||
|
a fresh glyph set.
|
||||||
"""
|
"""
|
||||||
if validateRead is None:
|
if validateRead is None:
|
||||||
validateRead = self._validate
|
validateRead = self._validate
|
||||||
@ -1459,7 +1482,12 @@ class UFOWriter(UFOReader):
|
|||||||
raise UFOLibError("A layer name must be provided for non-default layers.")
|
raise UFOLibError("A layer name must be provided for non-default layers.")
|
||||||
# move along to format specific writing
|
# move along to format specific writing
|
||||||
if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
|
if self._formatVersion < UFOFormatVersion.FORMAT_3_0:
|
||||||
return self._getDefaultGlyphSet(validateRead, validateWrite, glyphNameToFileNameFunc=glyphNameToFileNameFunc)
|
return self._getDefaultGlyphSet(
|
||||||
|
validateRead,
|
||||||
|
validateWrite,
|
||||||
|
glyphNameToFileNameFunc=glyphNameToFileNameFunc,
|
||||||
|
expectContentsFile=expectContentsFile
|
||||||
|
)
|
||||||
elif self._formatVersion.major == UFOFormatVersion.FORMAT_3_0.major:
|
elif self._formatVersion.major == UFOFormatVersion.FORMAT_3_0.major:
|
||||||
return self._getGlyphSetFormatVersion3(
|
return self._getGlyphSetFormatVersion3(
|
||||||
validateRead,
|
validateRead,
|
||||||
@ -1467,11 +1495,18 @@ class UFOWriter(UFOReader):
|
|||||||
layerName=layerName,
|
layerName=layerName,
|
||||||
defaultLayer=defaultLayer,
|
defaultLayer=defaultLayer,
|
||||||
glyphNameToFileNameFunc=glyphNameToFileNameFunc,
|
glyphNameToFileNameFunc=glyphNameToFileNameFunc,
|
||||||
|
expectContentsFile=expectContentsFile,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(self._formatVersion)
|
raise NotImplementedError(self._formatVersion)
|
||||||
|
|
||||||
def _getDefaultGlyphSet(self, validateRead, validateWrite, glyphNameToFileNameFunc=None):
|
def _getDefaultGlyphSet(
|
||||||
|
self,
|
||||||
|
validateRead,
|
||||||
|
validateWrite,
|
||||||
|
glyphNameToFileNameFunc=None,
|
||||||
|
expectContentsFile=False,
|
||||||
|
):
|
||||||
from fontTools.ufoLib.glifLib import GlyphSet
|
from fontTools.ufoLib.glifLib import GlyphSet
|
||||||
|
|
||||||
glyphSubFS = self.fs.makedir(DEFAULT_GLYPHS_DIRNAME, recreate=True)
|
glyphSubFS = self.fs.makedir(DEFAULT_GLYPHS_DIRNAME, recreate=True)
|
||||||
@ -1481,6 +1516,7 @@ class UFOWriter(UFOReader):
|
|||||||
ufoFormatVersion=self._formatVersion,
|
ufoFormatVersion=self._formatVersion,
|
||||||
validateRead=validateRead,
|
validateRead=validateRead,
|
||||||
validateWrite=validateWrite,
|
validateWrite=validateWrite,
|
||||||
|
expectContentsFile=expectContentsFile,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _getGlyphSetFormatVersion3(
|
def _getGlyphSetFormatVersion3(
|
||||||
@ -1490,6 +1526,7 @@ class UFOWriter(UFOReader):
|
|||||||
layerName=None,
|
layerName=None,
|
||||||
defaultLayer=True,
|
defaultLayer=True,
|
||||||
glyphNameToFileNameFunc=None,
|
glyphNameToFileNameFunc=None,
|
||||||
|
expectContentsFile=False,
|
||||||
):
|
):
|
||||||
from fontTools.ufoLib.glifLib import GlyphSet
|
from fontTools.ufoLib.glifLib import GlyphSet
|
||||||
|
|
||||||
@ -1529,6 +1566,7 @@ class UFOWriter(UFOReader):
|
|||||||
ufoFormatVersion=self._formatVersion,
|
ufoFormatVersion=self._formatVersion,
|
||||||
validateRead=validateRead,
|
validateRead=validateRead,
|
||||||
validateWrite=validateWrite,
|
validateWrite=validateWrite,
|
||||||
|
expectContentsFile=expectContentsFile,
|
||||||
)
|
)
|
||||||
|
|
||||||
def renameGlyphSet(self, layerName, newLayerName, defaultLayer=False):
|
def renameGlyphSet(self, layerName, newLayerName, defaultLayer=False):
|
||||||
|
@ -135,6 +135,7 @@ class GlyphSet(_UFOBaseIO):
|
|||||||
ufoFormatVersion=None,
|
ufoFormatVersion=None,
|
||||||
validateRead=True,
|
validateRead=True,
|
||||||
validateWrite=True,
|
validateWrite=True,
|
||||||
|
expectContentsFile=False,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
'path' should be a path (string) to an existing local directory, or
|
'path' should be a path (string) to an existing local directory, or
|
||||||
@ -191,6 +192,8 @@ class GlyphSet(_UFOBaseIO):
|
|||||||
self.fs = filesystem
|
self.fs = filesystem
|
||||||
# if glyphSet contains no 'contents.plist', we consider it empty
|
# if glyphSet contains no 'contents.plist', we consider it empty
|
||||||
self._havePreviousFile = filesystem.exists(CONTENTS_FILENAME)
|
self._havePreviousFile = filesystem.exists(CONTENTS_FILENAME)
|
||||||
|
if expectContentsFile and not self._havePreviousFile:
|
||||||
|
raise GlifLibError(f"{CONTENTS_FILENAME} is missing.")
|
||||||
# attribute kept for backward compatibility
|
# attribute kept for backward compatibility
|
||||||
self.ufoFormatVersion = ufoFormatVersion.major
|
self.ufoFormatVersion = ufoFormatVersion.major
|
||||||
self.ufoFormatVersionTuple = ufoFormatVersion
|
self.ufoFormatVersionTuple = ufoFormatVersion
|
||||||
|
@ -3940,6 +3940,26 @@ class UFO3WriteLayersTestCase(unittest.TestCase):
|
|||||||
result = list(writer.getGlyphSet("layer 2", defaultLayer=False).keys())
|
result = list(writer.getGlyphSet("layer 2", defaultLayer=False).keys())
|
||||||
self.assertEqual(expected, result)
|
self.assertEqual(expected, result)
|
||||||
|
|
||||||
|
def testGetGlyphSetNoContents(self):
|
||||||
|
self.makeUFO()
|
||||||
|
os.remove(os.path.join(self.ufoPath, "glyphs.layer 1", "contents.plist"))
|
||||||
|
|
||||||
|
reader = UFOReader(self.ufoPath, validate=True)
|
||||||
|
with self.assertRaises(GlifLibError):
|
||||||
|
reader.getGlyphSet("layer 1", expectContentsFile=True)
|
||||||
|
|
||||||
|
writer = UFOWriter(self.ufoPath, validate=True)
|
||||||
|
with self.assertRaises(GlifLibError):
|
||||||
|
writer.getGlyphSet("layer 1", defaultLayer=False, expectContentsFile=True)
|
||||||
|
|
||||||
|
# There's a separate code path for < v3 UFOs.
|
||||||
|
with open(os.path.join(self.ufoPath, "metainfo.plist"), "wb") as f:
|
||||||
|
plistlib.dump(dict(creator="test", formatVersion=2), f)
|
||||||
|
os.remove(os.path.join(self.ufoPath, "glyphs", "contents.plist"))
|
||||||
|
writer = UFOWriter(self.ufoPath, validate=True, formatVersion=2)
|
||||||
|
with self.assertRaises(GlifLibError):
|
||||||
|
writer.getGlyphSet(expectContentsFile=True)
|
||||||
|
|
||||||
# make a new font with two layers
|
# make a new font with two layers
|
||||||
|
|
||||||
def testNewFontOneLayer(self):
|
def testNewFontOneLayer(self):
|
||||||
|
@ -54,6 +54,16 @@ class GlyphSetTests(unittest.TestCase):
|
|||||||
added, removed,
|
added, removed,
|
||||||
"%s.glif file differs after round tripping" % glyphName)
|
"%s.glif file differs after round tripping" % glyphName)
|
||||||
|
|
||||||
|
def testContentsExist(self):
|
||||||
|
with self.assertRaises(GlifLibError):
|
||||||
|
GlyphSet(
|
||||||
|
self.dstDir,
|
||||||
|
ufoFormatVersion=2,
|
||||||
|
validateRead=True,
|
||||||
|
validateWrite=True,
|
||||||
|
expectContentsFile=True,
|
||||||
|
)
|
||||||
|
|
||||||
def testRebuildContents(self):
|
def testRebuildContents(self):
|
||||||
gset = GlyphSet(GLYPHSETDIR, validateRead=True, validateWrite=True)
|
gset = GlyphSet(GLYPHSETDIR, validateRead=True, validateWrite=True)
|
||||||
contents = gset.contents
|
contents = gset.contents
|
||||||
|
Loading…
x
Reference in New Issue
Block a user