Skip to content
This repository was archived by the owner on Jan 28, 2019. It is now read-only.

Commit 586b83c

Browse files
authored
Merge pull request #157 from anthrotype/xml-declaration
add the default xml declaration in writeGlyphToString
2 parents baed4b4 + 864bb26 commit 586b83c

File tree

3 files changed

+56
-48
lines changed

3 files changed

+56
-48
lines changed

Lib/ufoLib/glifLib.py

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,14 @@
1616
from io import BytesIO, open
1717
from warnings import warn
1818
from collections import OrderedDict
19-
from fontTools.misc.py23 import tobytes, unicode
19+
from fontTools.misc.py23 import basestring, unicode
2020
from ufoLib.plistlib import PlistWriter, readPlist, writePlist
2121
from ufoLib.plistFromETree import readPlistFromTree
2222
from ufoLib.pointPen import AbstractPointPen, PointToSegmentPen
2323
from ufoLib.filenames import userNameToFileName
2424
from ufoLib.validators import isDictEnough, genericTypeValidator, colorValidator,\
2525
guidelinesValidator, anchorsValidator, identifierValidator, imageValidator, glyphLibValidator
2626

27-
try:
28-
basestring
29-
except NameError:
30-
basestring = str
31-
32-
try:
33-
unicode
34-
except NameError:
35-
unicode = str
36-
3727
from lxml import etree
3828

3929

@@ -388,7 +378,7 @@ def writeGlyph(self, glyphName, glyphObject=None, drawPointsFunc=None, formatVer
388378
if validate is None:
389379
validate = self._validateWrite
390380
self._purgeCachedGLIF(glyphName)
391-
data = writeGlyphToString(glyphName, glyphObject, drawPointsFunc, formatVersion=formatVersion, validate=validate)
381+
data = _writeGlyphToBytes(glyphName, glyphObject, drawPointsFunc, formatVersion=formatVersion, validate=validate)
392382
fileName = self.contents.get(glyphName)
393383
if fileName is None:
394384
if self._existingFileNames is None:
@@ -407,7 +397,7 @@ def writeGlyph(self, glyphName, glyphObject=None, drawPointsFunc=None, formatVer
407397
if data == oldData:
408398
return
409399
with open(path, "wb") as f:
410-
f.write(tobytes(data, encoding="utf-8"))
400+
f.write(data)
411401

412402
def deleteGlyph(self, glyphName):
413403
"""Permanently delete the glyph from the glyph set on disk. Will
@@ -560,34 +550,10 @@ def readGlyphFromString(aString, glyphObject=None, pointPen=None, formatVersions
560550
_readGlyphFromTree(tree, glyphObject, pointPen, formatVersions=formatVersions, validate=validate)
561551

562552

563-
def writeGlyphToString(glyphName, glyphObject=None, drawPointsFunc=None, formatVersion=2, validate=True):
564-
"""
565-
Return .glif data for a glyph as a UTF-8 encoded string.
566-
The 'glyphObject' argument can be any kind of object (even None);
567-
the writeGlyphToString() method will attempt to get the following
568-
attributes from it:
569-
"width" the advance width of the glyph
570-
"height" the advance height of the glyph
571-
"unicodes" a list of unicode values for this glyph
572-
"note" a string
573-
"lib" a dictionary containing custom data
574-
"image" a dictionary containing image data
575-
"guidelines" a list of guideline data dictionaries
576-
"anchors" a list of anchor data dictionaries
577-
578-
All attributes are optional: if 'glyphObject' doesn't
579-
have the attribute, it will simply be skipped.
580-
581-
To write outline data to the .glif file, writeGlyphToString() needs
582-
a function (any callable object actually) that will take one
583-
argument: an object that conforms to the PointPen protocol.
584-
The function will be called by writeGlyphToString(); it has to call the
585-
proper PointPen methods to transfer the outline to the .glif file.
586-
587-
The GLIF format version can be specified with the formatVersion argument.
588-
589-
``validate`` will validate the written data. It is set to ``True`` by default.
590-
"""
553+
def _writeGlyphToBytes(
554+
glyphName, glyphObject=None, drawPointsFunc=None, writer=None,
555+
formatVersion=2, validate=True):
556+
"""Return .glif data for a glyph as a UTF-8 encoded bytes string."""
591557
# start
592558
if validate and not isinstance(glyphName, basestring):
593559
raise GlifLibError("The glyph name is not properly formatted.")
@@ -627,9 +593,49 @@ def writeGlyphToString(glyphName, glyphObject=None, drawPointsFunc=None, formatV
627593
if getattr(glyphObject, "lib", None):
628594
_writeLib(glyphObject, root, validate)
629595
# return the text
630-
tree = etree.ElementTree(root)
631-
text = etree.tostring(root, encoding=unicode, pretty_print=True)
632-
return text
596+
data = etree.tostring(
597+
root, encoding="utf-8", xml_declaration=True, pretty_print=True
598+
)
599+
return data
600+
601+
602+
def writeGlyphToString(glyphName, glyphObject=None, drawPointsFunc=None, formatVersion=2, validate=True):
603+
"""
604+
Return .glif data for a glyph as a Unicode string (`unicode` in py2, `str`
605+
in py3). The XML declaration's encoding is always set to "UTF-8".
606+
The 'glyphObject' argument can be any kind of object (even None);
607+
the writeGlyphToString() method will attempt to get the following
608+
attributes from it:
609+
"width" the advance width of the glyph
610+
"height" the advance height of the glyph
611+
"unicodes" a list of unicode values for this glyph
612+
"note" a string
613+
"lib" a dictionary containing custom data
614+
"image" a dictionary containing image data
615+
"guidelines" a list of guideline data dictionaries
616+
"anchors" a list of anchor data dictionaries
617+
618+
All attributes are optional: if 'glyphObject' doesn't
619+
have the attribute, it will simply be skipped.
620+
621+
To write outline data to the .glif file, writeGlyphToString() needs
622+
a function (any callable object actually) that will take one
623+
argument: an object that conforms to the PointPen protocol.
624+
The function will be called by writeGlyphToString(); it has to call the
625+
proper PointPen methods to transfer the outline to the .glif file.
626+
627+
The GLIF format version can be specified with the formatVersion argument.
628+
629+
``validate`` will validate the written data. It is set to ``True`` by default.
630+
"""
631+
data = _writeGlyphToBytes(
632+
glyphName,
633+
glyphObject=glyphObject,
634+
drawPointsFunc=drawPointsFunc,
635+
formatVersion=formatVersion,
636+
validate=validate,
637+
)
638+
return data.decode("utf-8")
633639

634640

635641
def _writeAdvance(glyphObject, element, validate):

Lib/ufoLib/test/test_GLIF1.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import unittest
33
from ufoLib.glifLib import GlifLibError, readGlyphFromString, writeGlyphToString
44
from ufoLib.test.testSupport import Glyph, stripText
5+
from itertools import islice
56

67
try:
78
basestring
@@ -25,8 +26,8 @@ def pyToGLIF(self, py):
2526
glyph = Glyph()
2627
exec(py, {"glyph" : glyph, "pointPen" : glyph})
2728
glif = writeGlyphToString(glyph.name, glyphObject=glyph, drawPointsFunc=glyph.drawPoints, formatVersion=1, validate=True)
28-
glif = "\n".join(glif.splitlines())
29-
return glif
29+
# discard the first line containing the xml declaration
30+
return "\n".join(islice(glif.splitlines(), 1, None))
3031

3132
def glifToPy(self, glif):
3233
glif = stripText(glif)

Lib/ufoLib/test/test_GLIF2.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import unittest
33
from ufoLib.glifLib import GlifLibError, readGlyphFromString, writeGlyphToString
44
from ufoLib.test.testSupport import Glyph, stripText
5+
from itertools import islice
56

67
try:
78
basestring
@@ -25,8 +26,8 @@ def pyToGLIF(self, py):
2526
glyph = Glyph()
2627
exec(py, {"glyph" : glyph, "pointPen" : glyph})
2728
glif = writeGlyphToString(glyph.name, glyphObject=glyph, drawPointsFunc=glyph.drawPoints, formatVersion=2, validate=True)
28-
glif = "\n".join(glif.splitlines())
29-
return glif
29+
# discard the first line containing the xml declaration
30+
return "\n".join(islice(glif.splitlines(), 1, None))
3031

3132
def glifToPy(self, glif):
3233
glif = stripText(glif)

0 commit comments

Comments
 (0)