Skip to content

Commit

Permalink
Font close second attempt (#269)
Browse files Browse the repository at this point in the history
* adding font.close + with statement support (context manager)
* use with statement or close() in tests so files get closed properly, fixing Windows test failures
* remove a few py2 things
* fix deprecated method
* test on a copy
* close UFOreaders and UFOWriters
* fix deprecated warning getbytes, setbytes
  • Loading branch information
typemytype committed May 27, 2020
1 parent 7cf8e47 commit c0484e1
Show file tree
Hide file tree
Showing 17 changed files with 564 additions and 552 deletions.
4 changes: 1 addition & 3 deletions Lib/defcon/objects/color.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from fontTools.misc.py23 import basestring


class Color(str):

Expand All @@ -17,7 +15,7 @@ class Color(str):

def __new__(self, value):
# convert from string
if isinstance(value, basestring):
if isinstance(value, str):
value = _stringToSequence(value)
r, g, b, a = value
# validate the values
Expand Down
16 changes: 8 additions & 8 deletions Lib/defcon/objects/dataSet.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def _set_fileNames(self, fileNames):
def __getitem__(self, fileName):
if self._data[fileName]["data"] is None:
path = self.font.path
reader = UFOReader(path, validate=False)
reader = self.font._reader
path = "%s/%s" % ("data", fileName)
data = reader.readBytesFromPath(path)
onDiskModTime = reader.getFileModificationTime(path)
Expand Down Expand Up @@ -110,13 +110,13 @@ def save(self, writer, saveAs=False, progressBar=None):
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)
with UFOReader(font.path, validate=False) as reader:
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
Expand Down
268 changes: 145 additions & 123 deletions Lib/defcon/objects/font.py

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions Lib/defcon/objects/glyph.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import absolute_import
import weakref
from warnings import warn
from fontTools.misc.py23 import basestring
from fontTools.misc.arrayTools import unionRect
from defcon.objects.base import BaseObject
from defcon.objects.contour import Contour
Expand Down Expand Up @@ -1035,7 +1034,7 @@ def _get_note(self):

def _set_note(self, value):
if value is not None:
assert isinstance(value, basestring)
assert isinstance(value, str)
oldValue = self._note
if oldValue != value:
self._note = value
Expand Down
20 changes: 9 additions & 11 deletions Lib/defcon/objects/imageSet.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import hashlib
import weakref
from defcon.objects.base import BaseObject
from fontTools.misc.py23 import unicode
from fontTools.ufoLib import UFOReader, UFOLibError
from fontTools.ufoLib.filenames import (
userNameToFileName, illegalCharacters, reservedFileNames, maxFileNameLength
Expand Down Expand Up @@ -114,8 +113,7 @@ def __contains__(self, fileName):
def __getitem__(self, fileName):
d = self._data[fileName]
if d["data"] is None:
path = self.font.path
reader = UFOReader(path, validate=False)
reader = self.font._reader
data = reader.readImage(fileName, validate=self.ufoLibReadValidate)
d["data"] = data
d["digest"] = _makeDigest(data)
Expand Down Expand Up @@ -186,12 +184,12 @@ def save(self, writer, removeUnreferencedImages=False, saveAs=False, progressBar
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)
with UFOReader(font.path, validate=False) as reader:
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)
Expand Down Expand Up @@ -220,7 +218,7 @@ def makeFileName(self, fileName):
"""
Make a file system legal version of **fileName**.
"""
fileName = unicode(fileName)
fileName = str(fileName)
suffix = ""
if fileName.lower().endswith(".png"):
suffix = fileName[-4:]
Expand Down Expand Up @@ -392,7 +390,7 @@ def fileNameValidator(value):
True
"""
# must be a unicode
if not isinstance(value, unicode):
if not isinstance(value, str):
return False
# must not be longer then the max fileName length
if len(value) > maxFileNameLength:
Expand Down
12 changes: 2 additions & 10 deletions Lib/defcon/objects/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import weakref
from fontTools.ufoLib import UFOFileStructure
from fontTools.misc.arrayTools import unionRect
from fontTools.misc.py23 import tounicode
from defcon.objects.base import BaseObject
from defcon.objects.glyph import Glyph
from defcon.objects.lib import Lib
Expand Down Expand Up @@ -295,7 +294,7 @@ def keys(self):
# name

def _set_name(self, value):
value = tounicode(value)
value = str(value)
oldName = self._name
if oldName != value:
self._name = value
Expand Down Expand Up @@ -586,14 +585,7 @@ def testForExternalChanges(self, reader):
"""
Test for external changes. This should not be called externally.
"""
# if the file structure is UFOZ, the established layer._glyphSet
# references data that was available at the time layer._glyphSet
# was created. therefore, it will not see any changes. To remedy
# this, create an object with the data that is available right now
# and assign it to the layer. this gives the same functionality
# as seen with a regular UFO.
if reader.fileStructure is UFOFileStructure.ZIP:
self._glyphSet = reader.getGlyphSet(layerName=self.name, validateRead=self.ufoLibReadValidate)
self._glyphSet = reader.getGlyphSet(layerName=self.name, validateRead=self.ufoLibReadValidate)
glyphSet = self._glyphSet
if glyphSet is None:
return [], [], []
Expand Down
66 changes: 34 additions & 32 deletions Lib/defcon/objects/layerSet.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,9 @@ def _fontSaveWasCompleted(self):
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)
font = self.font
font.close()
font._reader = reader = UFOReader(font.path, validate=font.ufoLibReadValidate)
if reader.fileStructure is UFOFileStructure.ZIP:
for layerName in self.layerOrder:
layer = self[layerName]
Expand Down Expand Up @@ -434,37 +436,37 @@ 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]
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]

# -----------------------------
# Serialization/Deserialization
Expand Down
3 changes: 1 addition & 2 deletions Lib/defcon/objects/uniData.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import weakref
import unicodedata
from fontTools.agl import AGL2UV
from fontTools.misc.py23 import basestring, range
from defcon.tools import unicodeTools
from defcon.objects.base import BaseDictObject

Expand Down Expand Up @@ -574,7 +573,7 @@ def _flattenSortResult(self, result):
def _sortRecurse(self, blocks, sortMethod, ascending, allowPseudoUnicode, function):
if not blocks:
return []
if not isinstance(list(blocks)[0], basestring):
if not isinstance(list(blocks)[0], str):
sortedBlocks = []
for block in blocks:
block = self._sortRecurse(block, sortMethod, ascending, allowPseudoUnicode, function)
Expand Down

0 comments on commit c0484e1

Please sign in to comment.