def run_ufolib_import_validation(self): """ ufoLib UFOReader.getLayerNames method validates the layercontents.plist file :return: (list) list of test failure Result objects """ res = Result(self.testpath) ss = StdStreamer(self.ufopath) if ( file_exists(self.testpath) is False ): # should only meet this condition if not a mandatory file (runner.py checks) res.test_failed = False ss.stream_result(res) return self.test_fail_list try: # read layercontents.plist with ufoLib - the ufoLib library performs type validations on values on read ufolib_reader = UFOReader(self.ufopath, validate=True) ufolib_reader.getLayerNames() res.test_failed = False ss.stream_result(res) except Exception as e: if ( self.testpath in self.mandatory_filepaths_list ): # if part of mandatory file spec for UFO version, fail early res.test_failed = True res.exit_failure = True # fail early b/c it is mandatory part of spec else: res.test_failed = ( True ) # fail the test, but wait to report until all other tests complete res.test_long_stdstream_string = ( self.testpath + " failed ufoLib import test with error: " + str(e) ) self.test_fail_list.append(res) ss.stream_result(res) return self.test_fail_list
def reloadLayers(self, layerData): """ Reload the layers. This should not be called externally. """ reader = UFOReader(self.font.path, validate=self.font.ufoLibReadValidate) # handle the layers currentLayerOrder = self.layerOrder for layerName, l in layerData.get("layers", {}).items(): # new layer if layerName not in currentLayerOrder: glyphSet = reader.getGlyphSet(layerName, validateRead=self.ufoLibReadValidate, validateWrite=self.font.ufoLibWriteValidate) self.newLayer(layerName, glyphSet) # get the layer layer = self[layerName] # reload the layer info if l.get("info"): layer.color = None layer.lib.clear() layer._glyphSet.readLayerInfo(layer) self._stampLayerInfoDataState(layer) # reload the glyphs glyphNames = l.get("glyphNames", []) if glyphNames: layer.reloadGlyphs(glyphNames) # handle the order if layerData.get("order", False): newLayerOrder = reader.getLayerNames() for layerName in self.layerOrder: if layerName not in newLayerOrder: newLayerOrder.append(layerName) self.layerOrder = newLayerOrder # handle the default layer if layerData.get("default", False): newDefaultLayerName = reader.getDefaultLayerName() self.defaultLayer = self[newDefaultLayerName]
def run_ufolib_import_validation(self): """ ufoLib UFOReader.readMetaInfo method validates the UFO version number. This method adds validation for expected reverse URL name scheme in :return: (list) list of test failure Result objects """ res = Result(self.testpath) ss = StdStreamer(self.ufopath) if ( file_exists(self.testpath) is False ): # fail test, exit early if file is missing res.test_failed = True res.exit_failure = True res.test_long_stdstream_string = ( "metainfo.plist is not available on the path " + self.testpath ) ss.stream_result(res) try: ufolib_reader = UFOReader(self.ufopath, validate=True) ufolib_reader.readMetaInfo() res.test_failed = False ss.stream_result(res) except Exception as e: res.test_failed = True res.exit_failure = True res.test_long_stdstream_string = ( self.testpath + " failed ufoLib import test with error: " + str(e) ) self.test_fail_list.append(res) ss.stream_result(res) return self.test_fail_list
def test_pointCollector(): ufoPath = getFontPath("MutatorSansBoldWideMutated.ufo") reader = UFOReader(ufoPath) glyphSet = reader.getGlyphSet() pen = PointCollector(glyphSet) glyphSet["B"].draw(pen) assert len(pen.points) == 38 assert len(pen.tags) == 38 assert pen.contours == [3, 37] assert pen.tags[:12] == [1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1] pen = PointCollector(glyphSet, decompose=False) glyphSet["Aacute"].draw(pen) assert len(pen.points) == 0 assert pen.contours == [] assert pen.components == [("A", (1, 0, 0, 1, 0, 0)), ("acute", (1, 0, 0, 1, 484, 20))] pen = PointCollector(glyphSet, decompose=True) glyphSet["Aacute"].draw(pen) assert len(pen.points) == 20 assert pen.contours == [3, 7, 11, 15, 19] assert pen.components == [] pen = PointCollector(glyphSet) glyphSet["O"].draw(pen) assert len(pen.points) == 28 assert pen.contours == [13, 27]
def read(cls, reader: UFOReader, lazy: bool = True) -> LayerSet: """Instantiates a LayerSet object from a :class:`fontTools.ufoLib.UFOReader`. Args: path: The path to the UFO to load. lazy: If True, load glyphs, data files and images as they are accessed. If False, load everything up front. """ layers: dict[str, Layer] = {} defaultLayer = None defaultLayerName = reader.getDefaultLayerName() for layerName in reader.getLayerNames(): isDefault = layerName == defaultLayerName if isDefault or not lazy: layer = cls._loadLayer(reader, layerName, lazy, isDefault) if isDefault: defaultLayer = layer layers[layerName] = layer else: layers[layerName] = _LAYER_NOT_LOADED assert defaultLayer is not None self = cls(layers=layers, defaultLayer=defaultLayer) if lazy: self._reader = reader return self
def save(self, writer, saveAs=False, progressBar=None): """ Save data. This method should not be called externally. Subclasses may override this method to implement custom saving behavior. """ if saveAs: font = self.font if font is not None and font.path is not None and os.path.exists(font.path): reader = UFOReader(font.path, validate=False) readerDataDirectoryListing = reader.getDataDirectoryListing() for fileName, data in self._data.items(): path = "%s/%s" % ("data", fileName) if data["data"] is not None or fileName not in readerDataDirectoryListing: continue writer.copyFromReader(reader, path, path) for fileName in self._scheduledForDeletion: # instead of trying to maintain a list of in UFO # vs. in memory, simply skip and move on when # something can't be deleted because it isn't # in the UFO. writer.removePath("%s/%s" % ("data", fileName), force=True) self._scheduledForDeletion.clear() for fileName, data in self._data.items(): if not data["dirty"]: continue writer.writeBytesToPath("%s/%s" % ("data", fileName), data["data"]) data["dirty"] = False data["onDisk"] = True data["onDiskModTime"] = writer.getFileModificationTime("%s/%s" % ("data", fileName)) self.dirty = False
def run_ufolib_import_validation(self): """ ufoLib UFOReader.readLib method validates the lib.plist file :return: (list) list of test failure Result objects """ res = Result(self.testpath) ss = StdStreamer(self.ufopath) if file_exists(self.testpath) is False: res.test_failed = ( False ) # not a mandatory file in UFO spec, test passes if missing ss.stream_result(res) return self.test_fail_list try: # read lib.plist with ufoLib - the ufoLib library performs type validations on values on read ufolib_reader = UFOReader(self.ufopath, validate=True) ufolib_reader.readLib() res.test_failed = False ss.stream_result(res) except Exception as e: res.test_failed = True res.test_long_stdstream_string = ( self.testpath + " failed ufoLib import test with error: " + str(e) ) ss.stream_result(res) self.test_fail_list.append(res) return self.test_fail_list
def test_ufoCharacterMapping_glyphNames(): ufoPath = getFontPath("MutatorSansBoldWideMutated.ufo") reader = UFOReader(ufoPath) cmap, revCmap, anchors = fetchCharacterMappingAndAnchors( reader.getGlyphSet(), ufoPath, ["A"]) assert cmap[0x0041] == "A" assert revCmap["A"] == [0x0041] assert anchors == {"A": [("top", 645, 815)]}
def test_getUpdateInfo(tmpdir): ufoSource = getFontPath("MutatorSansBoldWideMutated.ufo") ufoPath = shutil.copytree(ufoSource, tmpdir / "test.ufo") reader = UFOReader(ufoPath, validate=False) glyphSet = reader.getGlyphSet() cmap, unicodes, anchors = fetchCharacterMappingAndAnchors(glyphSet, ufoPath) state = UFOState(reader, glyphSet, getUnicodesAndAnchors=lambda: (unicodes, anchors)) feaPath = pathlib.Path(reader.fs.getsyspath("/features.fea")) feaPath.touch() state = state.newState() (needsFeaturesUpdate, needsGlyphUpdate, needsInfoUpdate, needsCmapUpdate, needsLibUpdate) = state.getUpdateInfo() assert needsFeaturesUpdate assert not needsGlyphUpdate assert not needsInfoUpdate assert not needsCmapUpdate infoPath = pathlib.Path(reader.fs.getsyspath("/fontinfo.plist")) infoPath.touch() state = state.newState() (needsFeaturesUpdate, needsGlyphUpdate, needsInfoUpdate, needsCmapUpdate, needsLibUpdate) = state.getUpdateInfo() assert not needsFeaturesUpdate assert not needsGlyphUpdate assert needsInfoUpdate assert not needsCmapUpdate glyph = Glyph("A", None) ppen = RecordingPointPen() glyphSet.readGlyph("A", glyph, ppen) glyph.anchors[0]["x"] = 123 glyphSet.writeGlyph("A", glyph, ppen.replay) state = state.newState() (needsFeaturesUpdate, needsGlyphUpdate, needsInfoUpdate, needsCmapUpdate, needsLibUpdate) = state.getUpdateInfo() assert needsFeaturesUpdate assert needsGlyphUpdate assert not needsInfoUpdate assert not needsCmapUpdate glyph = Glyph("A", None) ppen = RecordingPointPen() glyphSet.readGlyph("A", glyph, ppen) glyph.unicodes = [123] glyphSet.writeGlyph("A", glyph, ppen.replay) state = state.newState() (needsFeaturesUpdate, needsGlyphUpdate, needsInfoUpdate, needsCmapUpdate, needsLibUpdate) = state.getUpdateInfo() assert not needsFeaturesUpdate assert needsGlyphUpdate assert not needsInfoUpdate assert needsCmapUpdate
def __getitem__(self, fileName): if self._data[fileName]["data"] is None: path = self.font.path reader = UFOReader(path, validate=False) path = "%s/%s" % ("data", fileName) data = reader.readBytesFromPath(path) onDiskModTime = reader.getFileModificationTime(path) self._data[fileName] = _dataDict(data=data, onDisk=True, onDiskModTime=onDiskModTime) return self._data[fileName]["data"]
def testUFO2(self): self.makeUFO(formatVersion=2) reader = UFOReader(self.ufoPath, validate=True) kerning = reader.readKerning() self.assertEqual(self.expectedKerning, kerning) groups = reader.readGroups() self.assertEqual(self.expectedGroups, groups) info = TestInfoObject() reader.readInfo(info)
def extractIncludedFeatureFiles(ufoPath, reader=None): if isinstance(ufoPath, str): ufoPath = pathlib.Path(ufoPath) if reader is None: reader = UFOReader(ufoPath, validate=False) mainFeatures = reader.readFeatures() if not mainFeatures: return () return sorted(set(_extractIncludedFeatureFiles(mainFeatures, [ufoPath.parent])))
def test_pointCollectorQuad(): ufoPath = getFontPath("QuadTest-Regular.ufo") reader = UFOReader(ufoPath) glyphSet = reader.getGlyphSet() pen = PointCollector(glyphSet) glyphSet["a"].draw(pen) assert len(pen.points) == 4 assert len(pen.tags) == 4 assert pen.contours == [3] assert pen.tags == [0, 0, 0, 0]
def __getitem__(self, fileName): d = self._data[fileName] if d["data"] is None: path = self.font.path reader = UFOReader(path, validate=False) data = reader.readImage(fileName, validate=self.ufoLibReadValidate) d["data"] = data d["digest"] = _makeDigest(data) d["onDisk"] = True d["onDiskModTime"] = reader.getFileModificationTime("%s/%s" % ("images", fileName)) return d["data"]
def open(cls, path, lazy=True, validate=True): reader = UFOReader(path, validate=validate) self = cls.read(reader, lazy=lazy) self._path = path self._fileStructure = reader.fileStructure if lazy: # keep the reader around so we can close it when done self._reader = reader else: reader.close() return self
def testRead(self): originalData = dict(fontInfoVersion1) self._writeInfoToPlist(originalData) infoObject = TestInfoObject() reader = UFOReader(self.dstDir, validate=True) reader.readInfo(infoObject) for attr in dir(infoObject): if attr not in fontInfoVersion2: continue originalValue = fontInfoVersion2[attr] readValue = getattr(infoObject, attr) self.assertEqual(originalValue, readValue)
def _fontSaveWasCompleted(self): """ When saving a UFOZ, the underlying ZipFS object is closed. The objects then stored in layer._glyphSet contain references to a closed, and therefore unusable, filesystem. To remedy this, after the save is completed this method will be called and new GlyphSet objects will be created and assigned to the layers. """ reader = UFOReader(self.font.path, validate=self.font.ufoLibReadValidate) if reader.fileStructure is UFOFileStructure.ZIP: for layerName in self.layerOrder: layer = self[layerName] layer._glyphSet = reader.getGlyphSet(layerName=layerName, validateRead=self.ufoLibReadValidate)
def test_readMetaInfo_errors(ufo_path): (ufo_path / "metainfo.plist").unlink() with pytest.raises(UFOLibError, match="'metainfo.plist' is missing"): UFOReader(ufo_path) (ufo_path / "metainfo.plist").write_bytes(plistlib.dumps({})) with pytest.raises(UFOLibError, match="Missing required formatVersion"): UFOReader(ufo_path) (ufo_path / "metainfo.plist").write_bytes(plistlib.dumps([])) with pytest.raises(UFOLibError, match="metainfo.plist is not properly formatted"): UFOReader(ufo_path)
def save(self, writer, removeUnreferencedImages=False, saveAs=False, progressBar=None): """ Save images. This method should not be called externally. Subclasses may override this method to implement custom saving behavior. """ if removeUnreferencedImages: self.disableNotifications() for fileName in self.unreferencedFileNames: del self[fileName] self.enableNotifications() if saveAs: font = self.font if font is not None and font.path is not None and os.path.exists( font.path): reader = UFOReader(font.path, validate=False) readerImageNames = reader.getImageDirectoryListing( validate=self.ufoLibReadValidate) for fileName, data in self._data.items(): if data["data"] is not None or fileName not in readerImageNames: continue writer.copyImageFromReader( reader, fileName, fileName, validate=self.ufoLibWriteValidate) for fileName in self._scheduledForDeletion: try: writer.removeImage(fileName, validate=self.ufoLibWriteValidate) except UFOLibError: # this will be raised if the file doesn't exist. # instead of trying to maintain a list of in UFO # vs. in memory, simply fail and move on when # something can't be deleted because it isn't # in the UFO. pass self._scheduledForDeletion.clear() for fileName, data in self._data.items(): if not data["dirty"]: continue writer.writeImage(fileName, data["data"], validate=self.ufoLibWriteValidate) data["dirty"] = False data["onDisk"] = True data["onDiskModTime"] = writer.getFileModificationTime( "%s/%s" % ("images", fileName)) self.dirty = False
def testFontStyleConversion(self): fontStyle1To2 = { 64: "regular", 1: "italic", 32: "bold", 33: "bold italic" } for old, new in list(fontStyle1To2.items()): info = dict(fontInfoVersion1) info["fontStyle"] = old self._writeInfoToPlist(info) reader = UFOReader(self.dstDir, validate=True) infoObject = TestInfoObject() reader.readInfo(infoObject) self.assertEqual(new, infoObject.styleMapStyleName)
def testFontStyleConversion(self): fontStyle1To2 = { 64 : "regular", 1 : "italic", 32 : "bold", 33 : "bold italic" } for old, new in list(fontStyle1To2.items()): info = dict(fontInfoVersion1) info["fontStyle"] = old self._writeInfoToPlist(info) reader = UFOReader(self.dstDir, validate=True) infoObject = TestInfoObject() reader.readInfo(infoObject) self.assertEqual(new, infoObject.styleMapStyleName)
def test_testForExternalChanges_modify_on_disk_and_scan(self): path = makeTestFontCopy() font = Font(path) reader = UFOReader(path) # d = font.data["com.typesupply.defcon.test.file"] font.data["com.typesupply.defcon.test.file"] filePath = os.path.join(path, "data", "com.typesupply.defcon.test.file") f = open(filePath, "wb") f.write(b"blah") f.close() reader = UFOReader(path) self.assertEqual(font.data.testForExternalChanges(reader), (["com.typesupply.defcon.test.file"], [], [])) tearDownTestFontCopy()
def _fontSaveWasCompleted(self): """ When saving a UFOZ, the underlying ZipFS object is closed. The objects then stored in layer._glyphSet contain references to a closed, and therefore unusable, filesystem. To remedy this, after the save is completed this method will be called and new GlyphSet objects will be created and assigned to the layers. """ reader = UFOReader(self.font.path, validate=self.font.ufoLibReadValidate) if reader.fileStructure is UFOFileStructure.ZIP: for layerName in self.layerOrder: layer = self[layerName] layer._glyphSet = reader.getGlyphSet( layerName=layerName, validateRead=self.ufoLibReadValidate)
def test_ufoCharacterMapping(): ufoPath = getFontPath("MutatorSansBoldWideMutated.ufo") reader = UFOReader(ufoPath) cmap, revCmap, anchors = fetchCharacterMappingAndAnchors( reader.getGlyphSet(), ufoPath) assert cmap[0x0041] == "A" assert revCmap["A"] == [0x0041] # MutatorSansBoldWideMutated.ufo/glyphs/A_.glif contains a commented-out <unicode> # tag, that must not be parsed, as well as a commented-out <anchor>. assert 0x1234 not in cmap assert anchors == { "A": [("top", 645, 815)], "E": [("top", 582.5, 815)], "macroncmb": [("_top", 0, 815)] }
def test_testForExternalChanges_change_layer_order(self): path = getTestFontPath("TestExternalEditing.ufo") path = makeTestFontCopy(path) shutil.copytree(os.path.join(path, "glyphs"), os.path.join(path, "glyphs.test")) with open(os.path.join(path, "layercontents.plist"), "rb") as f: contents = load(f) contents.append(("test", "glyphs.test")) with open(os.path.join(path, "layercontents.plist"), "wb") as f: dump(contents, f) font = Font(path) with open(os.path.join(path, "layercontents.plist"), "rb") as f: contents = load(f) contents.reverse() with open(os.path.join(path, "layercontents.plist"), "wb") as f: dump(contents, f) reader = UFOReader(path) self.assertEqual( font.layers.testForExternalChanges(reader), { "deleted": [], "added": [], "modified": {}, "defaultLayer": False, "order": True }) tearDownTestFontCopy(font.path)
def test_testForExternalChanges_change_layer_order(self): for ufo in (u"TestExternalEditing.ufo", u"TestExternalEditing.ufoz"): path = getTestFontPath(ufo) path = makeTestFontCopy(path) fileSystem = openTestFontAsFileSystem(path) fs.copy.copy_dir(fileSystem, "glyphs", fileSystem, "glyphs.test") with fileSystem.open(u"layercontents.plist", "rb") as f: contents = load(f) contents.append(("test", "glyphs.test")) with fileSystem.open(u"layercontents.plist", "wb") as f: dump(contents, f) closeTestFontAsFileSystem(fileSystem, path) with Font(path) as font: fileSystem = openTestFontAsFileSystem(path) with fileSystem.open(u"layercontents.plist", "rb") as f: contents = load(f) contents.reverse() with fileSystem.open(u"layercontents.plist", "wb") as f: dump(contents, f) closeTestFontAsFileSystem(fileSystem, path) with UFOReader(path) as reader: self.assertEqual(font.layers.testForExternalChanges(reader), {"deleted": [], "added": [], "modified": {}, "defaultLayer": False, "order": True}) tearDownTestFontCopy(font.path)
def _fontSaveWasCompleted(self): """ On saving a UFO, the underlying fs object is closed. The objects then stored in layer._glyphSet contain references to a closed, and therefore unusable, filesystem. To remedy this, after the save is completed this method will be called and new GlyphSet objects will be created and assigned to the layers. """ font = self.font font.close() font._reader = reader = UFOReader(font.path, validate=font.ufoLibReadValidate) defaultLayerName = self._defaultLayerName for layerName in self.layerOrder: layer = self[layerName] if reader.formatVersionTuple < (3, 0): # ufo2 or less has not layers # map only to the default layer to the ufo2 glyphSet # set all all other layers internal _glyphSet object to None if defaultLayerName == layerName: glyphSet = reader.getGlyphSet( validateRead=self.ufoLibReadValidate) else: glyphSet = None else: # we do have layers and the must be available after a save action glyphSet = reader.getGlyphSet( layerName=layerName, validateRead=self.ufoLibReadValidate) layer._glyphSet = glyphSet
def test_testForExternalChanges_change_default_layer(self): for ufo in (u"TestExternalEditing.ufo", u"TestExternalEditing.ufoz"): path = getTestFontPath(ufo) path = makeTestFontCopy(path) fileSystem = openTestFontAsFileSystem(path) fs.copy.copy_dir(fileSystem, "glyphs", fileSystem, "glyphs.test") contents = [("foo", "glyphs"), ("test", "glyphs.test")] with fileSystem.open(u"layercontents.plist", "wb") as f: dump(contents, f) closeTestFontAsFileSystem(fileSystem, path) font = Font(path) fileSystem = openTestFontAsFileSystem(path) contents = [("foo", "glyphs.test"), ("test", "glyphs")] with fileSystem.open(u"layercontents.plist", "wb") as f: dump(contents, f) closeTestFontAsFileSystem(fileSystem, path) reader = UFOReader(path) self.assertEqual( font.layers.testForExternalChanges(reader), { "deleted": [], "added": [], "modified": {}, "defaultLayer": True, "order": False }) tearDownTestFontCopy(font.path)
def open(cls, path: PathLike, lazy: bool = True, validate: bool = True,) -> "Font": """Instantiates a new Font object from a path to a UFO. Args: path: The path to the UFO to load. lazy: If True, load glyphs, data files and images as they are accessed. If False, load everything up front. validate: If True, enable UFO data model validation during loading. If False, load whatever is deserializable. """ reader = UFOReader(path, validate=validate) self = cls.read(reader, lazy=lazy) self._path = path if not lazy: reader.close() return self
def reloadLayers(self, layerData): """ Reload the layers. This should not be called externally. """ with UFOReader(self.font.path, validate=self.font.ufoLibReadValidate) as reader: # handle the layers currentLayerOrder = self.layerOrder for layerName, l in layerData.get("layers", {}).items(): # new layer if layerName not in currentLayerOrder: glyphSet = reader.getGlyphSet(layerName, validateRead=self.ufoLibReadValidate, validateWrite=self.font.ufoLibWriteValidate) self.newLayer(layerName, glyphSet) # get the layer layer = self[layerName] # reload the layer info if l.get("info"): layer.color = None layer.lib.clear() layer._glyphSet.readLayerInfo(layer) self._stampLayerInfoDataState(layer) # reload the glyphs glyphNames = l.get("glyphNames", []) if glyphNames: layer.reloadGlyphs(glyphNames) # handle the order if layerData.get("order", False): newLayerOrder = reader.getLayerNames() for layerName in self.layerOrder: if layerName not in newLayerOrder: newLayerOrder.append(layerName) self.layerOrder = newLayerOrder # handle the default layer if layerData.get("default", False): newDefaultLayerName = reader.getDefaultLayerName() self.defaultLayer = self[newDefaultLayerName]
def test_testForExternalChanges_remove_a_layer(self): for ufo in (u"TestExternalEditing.ufo", u"TestExternalEditing.ufoz"): path = getTestFontPath(ufo) path = makeTestFontCopy(path) fileSystem = openTestFontAsFileSystem(path) fs.copy.copy_dir(fileSystem, "glyphs", fileSystem, "glyphs.test") with fileSystem.open(u"layercontents.plist", "rb") as f: contents = load(f) contents.append(("test", "glyphs.test")) with fileSystem.open(u"layercontents.plist", "wb") as f: dump(contents, f) closeTestFontAsFileSystem(fileSystem, path) font = Font(path) fileSystem = openTestFontAsFileSystem(path) fileSystem.removetree(u"glyphs.test") with fileSystem.open(u"layercontents.plist", "rb") as f: contents = load(f) del contents[-1] with fileSystem.open(u"layercontents.plist", "wb") as f: dump(contents, f) closeTestFontAsFileSystem(fileSystem, path) reader = UFOReader(path) self.assertEqual( font.layers.testForExternalChanges(reader)["deleted"], ["test"]) tearDownTestFontCopy(font.path)
def test_formatVersionTuple(ufo_path): reader = UFOReader(ufo_path) assert reader.formatVersionTuple == (3, 0) assert reader.formatVersionTuple.major == 3 assert reader.formatVersionTuple.minor == 0 assert str(reader.formatVersionTuple) == "3.0"
def _font_is_ufo(path): from fontTools.ufoLib import UFOReader from fontTools.ufoLib.errors import UFOLibError try: UFOReader(path, validate=False) return True except (UFOLibError, KeyError, TypeError): return False
def testCases(path): reader = UFOReader(path) expectedFileStructure = fileStructure if fileStructure is None: expectedFileStructure = UFOFileStructure.PACKAGE else: expectedFileStructure = UFOFileStructure(fileStructure) self.assertEqual(reader.fileStructure, expectedFileStructure)
def testWidthNameConversion(self): widthName1To2 = { "Ultra-condensed" : 1, "Extra-condensed" : 2, "Condensed" : 3, "Semi-condensed" : 4, "Medium (normal)" : 5, "Semi-expanded" : 6, "Expanded" : 7, "Extra-expanded" : 8, "Ultra-expanded" : 9 } for old, new in list(widthName1To2.items()): info = dict(fontInfoVersion1) info["widthName"] = old self._writeInfoToPlist(info) reader = UFOReader(self.dstDir, validate=True) infoObject = TestInfoObject() reader.readInfo(infoObject) self.assertEqual(new, infoObject.openTypeOS2WidthClass)
def save(self, writer, removeUnreferencedImages=False, saveAs=False, progressBar=None): """ Save images. This method should not be called externally. Subclasses may override this method to implement custom saving behavior. """ if removeUnreferencedImages: self.disableNotifications() for fileName in self.unreferencedFileNames: del self[fileName] self.enableNotifications() if saveAs: font = self.font if font is not None and font.path is not None and os.path.exists(font.path): reader = UFOReader(font.path, validate=False) readerImageNames = reader.getImageDirectoryListing(validate=self.ufoLibReadValidate) for fileName, data in self._data.items(): if data["data"] is not None or fileName not in readerImageNames: continue writer.copyImageFromReader(reader, fileName, fileName, validate=self.ufoLibWriteValidate) for fileName in self._scheduledForDeletion: try: writer.removeImage(fileName, validate=self.ufoLibWriteValidate) except UFOLibError: # this will be raised if the file doesn't exist. # instead of trying to maintain a list of in UFO # vs. in memory, simply fail and move on when # something can't be deleted because it isn't # in the UFO. pass self._scheduledForDeletion.clear() for fileName, data in self._data.items(): if not data["dirty"]: continue writer.writeImage(fileName, data["data"], validate=self.ufoLibWriteValidate) data["dirty"] = False data["onDisk"] = True data["onDiskModTime"] = writer.getFileModificationTime("%s/%s" % ("images", fileName)) self.dirty = False