diff --git a/Lib/fontTools/__init__.py b/Lib/fontTools/__init__.py
index 60ea754f1..82ea0bd15 100644
--- a/Lib/fontTools/__init__.py
+++ b/Lib/fontTools/__init__.py
@@ -5,6 +5,6 @@ from fontTools.misc.loggingTools import configLogger
log = logging.getLogger(__name__)
-version = __version__ = "3.43.2.dev0"
+version = __version__ = "3.43.3.dev0"
__all__ = ["version", "log", "configLogger"]
diff --git a/Lib/fontTools/fontBuilder.py b/Lib/fontTools/fontBuilder.py
index 2498730c3..c6811f055 100644
--- a/Lib/fontTools/fontBuilder.py
+++ b/Lib/fontTools/fontBuilder.py
@@ -31,6 +31,7 @@ Here is how to build a minimal TTF:
from fontTools.fontBuilder import FontBuilder
from fontTools.pens.ttGlyphPen import TTGlyphPen
+
def drawTestGlyph(pen):
pen.moveTo((100, 100))
pen.lineTo((100, 1000))
@@ -38,35 +39,39 @@ def drawTestGlyph(pen):
pen.lineTo((500, 100))
pen.closePath()
-fb = FontBuilder(1024, isTTF=True)
-fb.setupGlyphOrder([".notdef", ".null", "A", "a"])
-fb.setupCharacterMap({65: "A", 97: "a"})
-advanceWidths = {".notdef": 600, "A": 600, "a": 600, ".null": 600}
+fb = FontBuilder(1024, isTTF=True)
+fb.setupGlyphOrder([".notdef", ".null", "space", "A", "a"])
+fb.setupCharacterMap({32: "space", 65: "A", 97: "a"})
+advanceWidths = {".notdef": 600, "space": 500, "A": 600, "a": 600, ".null": 0}
familyName = "HelloTestFont"
styleName = "TotallyNormal"
-nameStrings = dict(familyName=dict(en="HelloTestFont", nl="HalloTestFont"),
- styleName=dict(en="TotallyNormal", nl="TotaalNormaal"))
-nameStrings['psName'] = familyName + "-" + styleName
+version = "0.1"
+
+nameStrings = dict(
+ familyName=dict(en=familyName, nl="HalloTestFont"),
+ styleName=dict(en=styleName, nl="TotaalNormaal"),
+ uniqueFontIdentifier="fontBuilder: " + familyName + "." + styleName,
+ fullName=familyName + "-" + styleName,
+ psName=familyName + "-" + styleName,
+ version="Version " + version,
+)
pen = TTGlyphPen(None)
drawTestGlyph(pen)
glyph = pen.glyph()
-glyphs = {".notdef": glyph, "A": glyph, "a": glyph, ".null": glyph}
+glyphs = {".notdef": glyph, "space": glyph, "A": glyph, "a": glyph, ".null": glyph}
fb.setupGlyf(glyphs)
-
metrics = {}
glyphTable = fb.font["glyf"]
for gn, advanceWidth in advanceWidths.items():
metrics[gn] = (advanceWidth, glyphTable[gn].xMin)
fb.setupHorizontalMetrics(metrics)
-
-fb.setupHorizontalHeader(ascent=824, descent=200)
+fb.setupHorizontalHeader(ascent=824, descent=-200)
fb.setupNameTable(nameStrings)
-fb.setupOS2()
+fb.setupOS2(sTypoAscender=824, usWinAscent=824, usWinDescent=200)
fb.setupPost()
-
fb.save("test.ttf")
```
@@ -76,6 +81,7 @@ And here's how to build a minimal OTF:
from fontTools.fontBuilder import FontBuilder
from fontTools.pens.t2CharStringPen import T2CharStringPen
+
def drawTestGlyph(pen):
pen.moveTo((100, 100))
pen.lineTo((100, 1000))
@@ -83,35 +89,45 @@ def drawTestGlyph(pen):
pen.lineTo((500, 100))
pen.closePath()
-fb = FontBuilder(1024, isTTF=False)
-fb.setupGlyphOrder([".notdef", ".null", "A", "a"])
-fb.setupCharacterMap({65: "A", 97: "a"})
-advanceWidths = {".notdef": 600, "A": 600, "a": 600, ".null": 600}
+fb = FontBuilder(1024, isTTF=False)
+fb.setupGlyphOrder([".notdef", ".null", "space", "A", "a"])
+fb.setupCharacterMap({32: "space", 65: "A", 97: "a"})
+advanceWidths = {".notdef": 600, "space": 500, "A": 600, "a": 600, ".null": 0}
familyName = "HelloTestFont"
styleName = "TotallyNormal"
-nameStrings = dict(familyName=dict(en="HelloTestFont", nl="HalloTestFont"),
- styleName=dict(en="TotallyNormal", nl="TotaalNormaal"))
-nameStrings['psName'] = familyName + "-" + styleName
+version = "0.1"
+
+nameStrings = dict(
+ familyName=dict(en=familyName, nl="HalloTestFont"),
+ styleName=dict(en=styleName, nl="TotaalNormaal"),
+ uniqueFontIdentifier="fontBuilder: " + familyName + "." + styleName,
+ fullName=familyName + "-" + styleName,
+ psName=familyName + "-" + styleName,
+ version="Version " + version,
+)
pen = T2CharStringPen(600, None)
drawTestGlyph(pen)
charString = pen.getCharString()
-charStrings = {".notdef": charString, "A": charString, "a": charString, ".null": charString}
-fb.setupCFF(nameStrings['psName'], {"FullName": nameStrings['psName']}, charStrings, {})
-
+charStrings = {
+ ".notdef": charString,
+ "space": charString,
+ "A": charString,
+ "a": charString,
+ ".null": charString,
+}
+fb.setupCFF(nameStrings["psName"], {"FullName": nameStrings["psName"]}, charStrings, {})
lsb = {gn: cs.calcBounds(None)[0] for gn, cs in charStrings.items()}
metrics = {}
for gn, advanceWidth in advanceWidths.items():
metrics[gn] = (advanceWidth, lsb[gn])
fb.setupHorizontalMetrics(metrics)
-
fb.setupHorizontalHeader(ascent=824, descent=200)
fb.setupNameTable(nameStrings)
-fb.setupOS2()
+fb.setupOS2(sTypoAscender=824, usWinAscent=824, usWinDescent=200)
fb.setupPost()
-
fb.save("test.otf")
```
"""
diff --git a/Lib/fontTools/ufoLib/__init__.py b/Lib/fontTools/ufoLib/__init__.py
index 26b7ddd3e..4a1fa864d 100755
--- a/Lib/fontTools/ufoLib/__init__.py
+++ b/Lib/fontTools/ufoLib/__init__.py
@@ -1391,7 +1391,7 @@ class UFOWriter(UFOReader):
def _getGlyphSetFormatVersion1(self, validateRead, validateWrite, glyphNameToFileNameFunc=None):
from fontTools.ufoLib.glifLib import GlyphSet
- glyphSubFS = self.fs.makedir(DEFAULT_GLYPHS_DIRNAME, recreate=True),
+ glyphSubFS = self.fs.makedir(DEFAULT_GLYPHS_DIRNAME, recreate=True)
return GlyphSet(
glyphSubFS,
glyphNameToFileNameFunc=glyphNameToFileNameFunc,
diff --git a/Lib/fontTools/varLib/__init__.py b/Lib/fontTools/varLib/__init__.py
index 3677476d7..5a881495f 100644
--- a/Lib/fontTools/varLib/__init__.py
+++ b/Lib/fontTools/varLib/__init__.py
@@ -23,8 +23,7 @@ from __future__ import unicode_literals
from fontTools.misc.py23 import *
from fontTools.misc.fixedTools import otRound
from fontTools.misc.arrayTools import Vector
-from fontTools.ttLib import TTFont, newTable, TTLibError
-from fontTools.ttLib.tables._n_a_m_e import NameRecord
+from fontTools.ttLib import TTFont, newTable
from fontTools.ttLib.tables._f_v_a_r import Axis, NamedInstance
from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
from fontTools.ttLib.tables.ttProgram import Program
@@ -36,7 +35,7 @@ from fontTools.varLib.merger import VariationMerger
from fontTools.varLib.mvar import MVAR_ENTRIES
from fontTools.varLib.iup import iup_delta_optimize
from fontTools.varLib.featureVars import addFeatureVariations
-from fontTools.designspaceLib import DesignSpaceDocument, AxisDescriptor
+from fontTools.designspaceLib import DesignSpaceDocument
from collections import OrderedDict, namedtuple
import os.path
import logging
@@ -1017,9 +1016,6 @@ def main(args=None):
designspace_filename = options.designspace
finder = MasterFinder(options.master_finder)
- outfile = options.outfile
- if outfile is None:
- outfile = os.path.splitext(designspace_filename)[0] + '-VF.ttf'
vf, _, _ = build(
designspace_filename,
@@ -1028,6 +1024,11 @@ def main(args=None):
optimize=options.optimize
)
+ outfile = options.outfile
+ if outfile is None:
+ ext = "otf" if vf.sfntVersion == "OTTO" else "ttf"
+ outfile = os.path.splitext(designspace_filename)[0] + '-VF.' + ext
+
log.info("Saving variation font %s", outfile)
vf.save(outfile)
diff --git a/Lib/fontTools/varLib/cff.py b/Lib/fontTools/varLib/cff.py
old mode 100755
new mode 100644
index bcafdeee7..aaabf8573
--- a/Lib/fontTools/varLib/cff.py
+++ b/Lib/fontTools/varLib/cff.py
@@ -131,7 +131,7 @@ class MergeDictError(TypeError):
def conv_to_int(num):
- if num % 1 == 0:
+ if isinstance(num, float) and num.is_integer():
return int(num)
return num
@@ -198,17 +198,17 @@ def merge_PrivateDicts(top_dicts, vsindex_dict, var_model, fd_map):
pds.append(pd)
num_masters = len(pds)
for key, value in private_dict.rawDict.items():
+ dataList = []
if key not in pd_blend_fields:
continue
if isinstance(value, list):
try:
values = [pd.rawDict[key] for pd in pds]
except KeyError:
- del private_dict.rawDict[key]
print(
- b"Warning: {key} in default font Private dict is "
- b"missing from another font, and was "
- b"discarded.".format(key=key))
+ "Warning: {key} in default font Private dict is "
+ "missing from another font, and was "
+ "discarded.".format(key=key))
continue
try:
values = zip(*values)
@@ -227,7 +227,6 @@ def merge_PrivateDicts(top_dicts, vsindex_dict, var_model, fd_map):
and is converted finally to:
OtherBlues = [[-217, 17.0, 46.0], [-205, 0.0, 0.0]]
"""
- dataList = []
prev_val_list = [0] * num_masters
any_points_differ = False
for val_list in values:
@@ -237,8 +236,6 @@ def merge_PrivateDicts(top_dicts, vsindex_dict, var_model, fd_map):
any_points_differ = True
prev_val_list = val_list
deltas = sub_model.getDeltas(rel_list)
- # Convert numbers with no decimal part to an int.
- deltas = [conv_to_int(delta) for delta in deltas]
# For PrivateDict BlueValues, the default font
# values are absolute, not relative to the prior value.
deltas[0] = val_list[0]
@@ -253,6 +250,18 @@ def merge_PrivateDicts(top_dicts, vsindex_dict, var_model, fd_map):
dataList = sub_model.getDeltas(values)
else:
dataList = values[0]
+
+ # Convert numbers with no decimal part to an int
+ if isinstance(dataList, list):
+ for i, item in enumerate(dataList):
+ if isinstance(item, list):
+ for j, jtem in enumerate(item):
+ dataList[i][j] = conv_to_int(jtem)
+ else:
+ dataList[i] = conv_to_int(item)
+ else:
+ dataList = conv_to_int(dataList)
+
private_dict.rawDict[key] = dataList
@@ -270,7 +279,7 @@ def getfd_map(varFont, fonts_list):
num_regions = len(region_fonts)
topDict = default_font['CFF '].cff.topDictIndex[0]
if not hasattr(topDict, 'FDSelect'):
- # All glyphs reference only one FontDict.
+ # All glyphs reference only one FontDict.
# Map the FD index for regions to index 0.
fd_map[0] = {ri:0 for ri in range(num_regions)}
return fd_map
@@ -390,9 +399,9 @@ def merge_charstrings(glyphOrder, num_masters, top_dicts, masterModel):
# as we know it doesn't exist yet.
if vsindex != 0:
new_cs.program[:0] = [vsindex, 'vsindex']
-
+
# If there is no variation in any of the charstrings, then vsindex_dict
- # never gets built. This could still be needed if there is variation
+ # never gets built. This could still be needed if there is variation
# in the PrivatDict, so we will build the default data for vsindex = 0.
if not vsindex_dict:
key = (True,) * num_masters
diff --git a/Lib/fontTools/varLib/featureVars.py b/Lib/fontTools/varLib/featureVars.py
index d5793a560..0c6913d31 100644
--- a/Lib/fontTools/varLib/featureVars.py
+++ b/Lib/fontTools/varLib/featureVars.py
@@ -71,7 +71,7 @@ def overlayFeatureVariations(conditionalSubstitutions):
and rules with the same Box merged. The more specific rules appear earlier
in the resulting list. Moreover, instead of just a dictionary of substitutions,
a list of dictionaries is returned for substitutions corresponding to each
- uniq space, with each dictionary being identical to one of the input
+ unique space, with each dictionary being identical to one of the input
substitution dictionaries. These dictionaries are not merged to allow data
sharing when they are converted into font tables.
@@ -79,6 +79,7 @@ def overlayFeatureVariations(conditionalSubstitutions):
>>> condSubst = [
... # A list of (Region, Substitution) tuples.
... ([{"wght": (0.5, 1.0)}], {"dollar": "dollar.rvrn"}),
+ ... ([{"wght": (0.5, 1.0)}], {"dollar": "dollar.rvrn"}),
... ([{"wdth": (0.5, 1.0)}], {"cent": "cent.rvrn"}),
... ]
>>> from pprint import pprint
@@ -107,7 +108,8 @@ def overlayFeatureVariations(conditionalSubstitutions):
# rules for the same region.
merged = OrderedDict()
for key,value in reversed(conditionalSubstitutions):
- key = tuple(sorted(hashdict(cleanupBox(k)) for k in key))
+ key = tuple(sorted((hashdict(cleanupBox(k)) for k in key),
+ key=lambda d: tuple(sorted(d.items()))))
if key in merged:
merged[key].update(value)
else:
diff --git a/NEWS.rst b/NEWS.rst
index b7b1b5064..0105e42e9 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -1,3 +1,9 @@
+3.43.2 (released 2019-07-10)
+----------------------------
+
+- [featureVars] Fixed region-merging code on python3 (#1659).
+- [varLib.cff] Fixed merging of sparse PrivateDict items (#1653).
+
3.43.1 (released 2019-06-19)
----------------------------
diff --git a/Tests/otlLib/builder_test.py b/Tests/otlLib/builder_test.py
index 0829176c9..83f7c8286 100644
--- a/Tests/otlLib/builder_test.py
+++ b/Tests/otlLib/builder_test.py
@@ -3,1011 +3,1071 @@ from __future__ import unicode_literals
from fontTools.misc.testTools import getXML
from fontTools.otlLib import builder
from fontTools.ttLib.tables import otTables
-from itertools import chain
-import unittest
+import pytest
-class BuilderTest(unittest.TestCase):
- GLYPHS = (".notdef space zero one two three four five six "
- "A B C a b c grave acute cedilla f_f_i f_i c_t").split()
+class BuilderTest(object):
+ GLYPHS = (
+ ".notdef space zero one two three four five six "
+ "A B C a b c grave acute cedilla f_f_i f_i c_t"
+ ).split()
GLYPHMAP = {name: num for num, name in enumerate(GLYPHS)}
ANCHOR1 = builder.buildAnchor(11, -11)
ANCHOR2 = builder.buildAnchor(22, -22)
ANCHOR3 = builder.buildAnchor(33, -33)
- def __init__(self, methodName):
- unittest.TestCase.__init__(self, methodName)
- # Python 3 renamed assertRaisesRegexp to assertRaisesRegex,
- # and fires deprecation warnings if a program uses the old name.
- if not hasattr(self, "assertRaisesRegex"):
- self.assertRaisesRegex = self.assertRaisesRegexp
-
- @classmethod
- def setUpClass(cls):
- cls.maxDiff = None
-
def test_buildAnchor_format1(self):
anchor = builder.buildAnchor(23, 42)
- self.assertEqual(getXML(anchor.toXML),
- ['',
- ' ',
- ' ',
- ''])
+ assert getXML(anchor.toXML) == [
+ '',
+ ' ',
+ ' ',
+ "",
+ ]
def test_buildAnchor_format2(self):
anchor = builder.buildAnchor(23, 42, point=17)
- self.assertEqual(getXML(anchor.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(anchor.toXML) == [
+ '',
+ ' ',
+ ' ',
+ ' ',
+ "",
+ ]
def test_buildAnchor_format3(self):
anchor = builder.buildAnchor(
- 23, 42,
+ 23,
+ 42,
deviceX=builder.buildDevice({1: 1, 0: 0}),
- deviceY=builder.buildDevice({7: 7}))
- self.assertEqual(getXML(anchor.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ deviceY=builder.buildDevice({7: 7}),
+ )
+ assert getXML(anchor.toXML) == [
+ '',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ "",
+ ]
def test_buildAttachList(self):
- attachList = builder.buildAttachList({
- "zero": [23, 7], "one": [1],
- }, self.GLYPHMAP)
- self.assertEqual(getXML(attachList.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ attachList = builder.buildAttachList(
+ {"zero": [23, 7], "one": [1]}, self.GLYPHMAP
+ )
+ assert getXML(attachList.toXML) == [
+ "",
+ " ",
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ " ",
+ "",
+ ]
def test_buildAttachList_empty(self):
- self.assertIsNone(builder.buildAttachList({}, self.GLYPHMAP))
+ assert builder.buildAttachList({}, self.GLYPHMAP) is None
def test_buildAttachPoint(self):
attachPoint = builder.buildAttachPoint([7, 3])
- self.assertEqual(getXML(attachPoint.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(attachPoint.toXML) == [
+ "",
+ " ",
+ ' ',
+ ' ',
+ "",
+ ]
def test_buildAttachPoint_empty(self):
- self.assertIsNone(builder.buildAttachPoint([]))
+ assert builder.buildAttachPoint([]) is None
def test_buildAttachPoint_duplicate(self):
attachPoint = builder.buildAttachPoint([7, 3, 7])
- self.assertEqual(getXML(attachPoint.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ''])
-
+ assert getXML(attachPoint.toXML) == [
+ "",
+ " ",
+ ' ',
+ ' ',
+ "",
+ ]
def test_buildBaseArray(self):
anchor = builder.buildAnchor
- baseArray = builder.buildBaseArray({
- "a": {2: anchor(300, 80)},
- "c": {1: anchor(300, 80), 2: anchor(300, -20)}
- }, numMarkClasses=4, glyphMap=self.GLYPHMAP)
- self.assertEqual(getXML(baseArray.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ baseArray = builder.buildBaseArray(
+ {"a": {2: anchor(300, 80)}, "c": {1: anchor(300, 80), 2: anchor(300, -20)}},
+ numMarkClasses=4,
+ glyphMap=self.GLYPHMAP,
+ )
+ assert getXML(baseArray.toXML) == [
+ "",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ "",
+ ]
def test_buildBaseRecord(self):
a = builder.buildAnchor
rec = builder.buildBaseRecord([a(500, -20), None, a(300, -15)])
- self.assertEqual(getXML(rec.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(rec.toXML) == [
+ "",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ "",
+ ]
def test_buildCaretValueForCoord(self):
caret = builder.buildCaretValueForCoord(500)
- self.assertEqual(getXML(caret.toXML),
- ['',
- ' ',
- ''])
+ assert getXML(caret.toXML) == [
+ '',
+ ' ',
+ "",
+ ]
def test_buildCaretValueForPoint(self):
caret = builder.buildCaretValueForPoint(23)
- self.assertEqual(getXML(caret.toXML),
- ['',
- ' ',
- ''])
+ assert getXML(caret.toXML) == [
+ '',
+ ' ',
+ "",
+ ]
def test_buildComponentRecord(self):
a = builder.buildAnchor
rec = builder.buildComponentRecord([a(500, -20), None, a(300, -15)])
- self.assertEqual(getXML(rec.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(rec.toXML) == [
+ "",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ "",
+ ]
def test_buildComponentRecord_empty(self):
- self.assertIsNone(builder.buildComponentRecord([]))
+ assert builder.buildComponentRecord([]) is None
def test_buildComponentRecord_None(self):
- self.assertIsNone(builder.buildComponentRecord(None))
+ assert builder.buildComponentRecord(None) is None
def test_buildCoverage(self):
cov = builder.buildCoverage({"two", "four"}, {"two": 2, "four": 4})
- self.assertEqual(getXML(cov.toXML),
- ['',
- ' ',
- ' ',
- ''])
+ assert getXML(cov.toXML) == [
+ "",
+ ' ',
+ ' ',
+ "",
+ ]
def test_buildCursivePos(self):
- pos = builder.buildCursivePosSubtable({
- "two": (self.ANCHOR1, self.ANCHOR2),
- "four": (self.ANCHOR3, self.ANCHOR1)
- }, self.GLYPHMAP)
- self.assertEqual(getXML(pos.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ pos = builder.buildCursivePosSubtable(
+ {"two": (self.ANCHOR1, self.ANCHOR2), "four": (self.ANCHOR3, self.ANCHOR1)},
+ self.GLYPHMAP,
+ )
+ assert getXML(pos.toXML) == [
+ '',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ "",
+ ]
def test_buildDevice_format1(self):
- device = builder.buildDevice({1:1, 0:0})
- self.assertEqual(getXML(device.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ device = builder.buildDevice({1: 1, 0: 0})
+ assert getXML(device.toXML) == [
+ "",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ "",
+ ]
def test_buildDevice_format2(self):
- device = builder.buildDevice({2:2, 0:1, 1:0})
- self.assertEqual(getXML(device.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ device = builder.buildDevice({2: 2, 0: 1, 1: 0})
+ assert getXML(device.toXML) == [
+ "",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ "",
+ ]
def test_buildDevice_format3(self):
- device = builder.buildDevice({5:3, 1:77})
- self.assertEqual(getXML(device.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ device = builder.buildDevice({5: 3, 1: 77})
+ assert getXML(device.toXML) == [
+ "",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ "",
+ ]
def test_buildLigatureArray(self):
anchor = builder.buildAnchor
- ligatureArray = builder.buildLigatureArray({
- "f_i": [{2: anchor(300, -20)}, {}],
- "c_t": [{}, {1: anchor(500, 350), 2: anchor(1300, -20)}]
- }, numMarkClasses=4, glyphMap=self.GLYPHMAP)
- self.assertEqual(getXML(ligatureArray.toXML),
- ['',
- ' ',
- ' ', # f_i
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ ligatureArray = builder.buildLigatureArray(
+ {
+ "f_i": [{2: anchor(300, -20)}, {}],
+ "c_t": [{}, {1: anchor(500, 350), 2: anchor(1300, -20)}],
+ },
+ numMarkClasses=4,
+ glyphMap=self.GLYPHMAP,
+ )
+ assert getXML(ligatureArray.toXML) == [
+ "",
+ " ",
+ ' ', # f_i
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ " ",
+ "",
+ ]
def test_buildLigatureAttach(self):
anchor = builder.buildAnchor
- attach = builder.buildLigatureAttach([
- [anchor(500, -10), None],
- [None, anchor(300, -20), None]])
- self.assertEqual(getXML(attach.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ attach = builder.buildLigatureAttach(
+ [[anchor(500, -10), None], [None, anchor(300, -20), None]]
+ )
+ assert getXML(attach.toXML) == [
+ "",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ "",
+ ]
def test_buildLigatureAttach_emptyComponents(self):
attach = builder.buildLigatureAttach([[], None])
- self.assertEqual(getXML(attach.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(attach.toXML) == [
+ "",
+ " ",
+ ' ',
+ ' ',
+ "",
+ ]
def test_buildLigatureAttach_noComponents(self):
attach = builder.buildLigatureAttach([])
- self.assertEqual(getXML(attach.toXML),
- ['',
- ' ',
- ''])
+ assert getXML(attach.toXML) == [
+ "",
+ " ",
+ "",
+ ]
def test_buildLigCaretList(self):
carets = builder.buildLigCaretList(
- {"f_f_i": [300, 600]}, {"c_t": [42]}, self.GLYPHMAP)
- self.assertEqual(getXML(carets.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ {"f_f_i": [300, 600]}, {"c_t": [42]}, self.GLYPHMAP
+ )
+ assert getXML(carets.toXML) == [
+ "",
+ " ",
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ " ",
+ "",
+ ]
def test_buildLigCaretList_bothCoordsAndPointsForSameGlyph(self):
carets = builder.buildLigCaretList(
- {"f_f_i": [300]}, {"f_f_i": [7]}, self.GLYPHMAP)
- self.assertEqual(getXML(carets.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ {"f_f_i": [300]}, {"f_f_i": [7]}, self.GLYPHMAP
+ )
+ assert getXML(carets.toXML) == [
+ "",
+ " ",
+ ' ',
+ " ",
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ " ",
+ "",
+ ]
def test_buildLigCaretList_empty(self):
- self.assertIsNone(builder.buildLigCaretList({}, {}, self.GLYPHMAP))
+ assert builder.buildLigCaretList({}, {}, self.GLYPHMAP) is None
def test_buildLigCaretList_None(self):
- self.assertIsNone(builder.buildLigCaretList(None, None, self.GLYPHMAP))
+ assert builder.buildLigCaretList(None, None, self.GLYPHMAP) is None
def test_buildLigGlyph_coords(self):
lig = builder.buildLigGlyph([500, 800], None)
- self.assertEqual(getXML(lig.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(lig.toXML) == [
+ "",
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ "",
+ ]
def test_buildLigGlyph_empty(self):
- self.assertIsNone(builder.buildLigGlyph([], []))
+ assert builder.buildLigGlyph([], []) is None
def test_buildLigGlyph_None(self):
- self.assertIsNone(builder.buildLigGlyph(None, None))
+ assert builder.buildLigGlyph(None, None) is None
def test_buildLigGlyph_points(self):
lig = builder.buildLigGlyph(None, [2])
- self.assertEqual(getXML(lig.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(lig.toXML) == [
+ "",
+ " ",
+ ' ',
+ ' ',
+ " ",
+ "",
+ ]
def test_buildLookup(self):
s1 = builder.buildSingleSubstSubtable({"one": "two"})
s2 = builder.buildSingleSubstSubtable({"three": "four"})
lookup = builder.buildLookup([s1, s2], flags=7)
- self.assertEqual(getXML(lookup.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(lookup.toXML) == [
+ "",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ "",
+ ]
def test_buildLookup_badFlags(self):
s = builder.buildSingleSubstSubtable({"one": "two"})
- self.assertRaisesRegex(
- AssertionError, "if markFilterSet is None, "
- "flags must not set LOOKUP_FLAG_USE_MARK_FILTERING_SET; "
- "flags=0x0010",
- builder.buildLookup, [s],
- builder.LOOKUP_FLAG_USE_MARK_FILTERING_SET, None)
- self.assertRaisesRegex(
- AssertionError, "if markFilterSet is not None, "
- "flags must set LOOKUP_FLAG_USE_MARK_FILTERING_SET; "
- "flags=0x0004",
- builder.buildLookup, [s],
- builder.LOOKUP_FLAG_IGNORE_LIGATURES, 777)
+ with pytest.raises(
+ AssertionError,
+ match=(
+ "if markFilterSet is None, flags must not set "
+ "LOOKUP_FLAG_USE_MARK_FILTERING_SET; flags=0x0010"
+ ),
+ ) as excinfo:
+ builder.buildLookup([s], builder.LOOKUP_FLAG_USE_MARK_FILTERING_SET, None)
+ with pytest.raises(
+ AssertionError,
+ match=(
+ "if markFilterSet is not None, flags must set "
+ "LOOKUP_FLAG_USE_MARK_FILTERING_SET; flags=0x0004"
+ ),
+ ) as excinfo:
+ builder.buildLookup([s], builder.LOOKUP_FLAG_IGNORE_LIGATURES, 777)
def test_buildLookup_conflictingSubtableTypes(self):
s1 = builder.buildSingleSubstSubtable({"one": "two"})
s2 = builder.buildAlternateSubstSubtable({"one": ["two", "three"]})
- self.assertRaisesRegex(
- AssertionError, "all subtables must have the same LookupType",
- builder.buildLookup, [s1, s2])
+ with pytest.raises(
+ AssertionError, match="all subtables must have the same LookupType"
+ ) as excinfo:
+ builder.buildLookup([s1, s2])
def test_buildLookup_noSubtables(self):
- self.assertIsNone(builder.buildLookup([]))
- self.assertIsNone(builder.buildLookup(None))
- self.assertIsNone(builder.buildLookup([None]))
- self.assertIsNone(builder.buildLookup([None, None]))
+ assert builder.buildLookup([]) is None
+ assert builder.buildLookup(None) is None
+ assert builder.buildLookup([None]) is None
+ assert builder.buildLookup([None, None]) is None
def test_buildLookup_markFilterSet(self):
s = builder.buildSingleSubstSubtable({"one": "two"})
- flags = (builder.LOOKUP_FLAG_RIGHT_TO_LEFT |
- builder.LOOKUP_FLAG_USE_MARK_FILTERING_SET)
+ flags = (
+ builder.LOOKUP_FLAG_RIGHT_TO_LEFT
+ | builder.LOOKUP_FLAG_USE_MARK_FILTERING_SET
+ )
lookup = builder.buildLookup([s], flags, markFilterSet=999)
- self.assertEqual(getXML(lookup.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(lookup.toXML) == [
+ "",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ "",
+ ]
def test_buildMarkArray(self):
- markArray = builder.buildMarkArray({
- "acute": (7, builder.buildAnchor(300, 800)),
- "grave": (2, builder.buildAnchor(10, 80))
- }, self.GLYPHMAP)
- self.assertLess(self.GLYPHMAP["grave"], self.GLYPHMAP["acute"])
- self.assertEqual(getXML(markArray.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ markArray = builder.buildMarkArray(
+ {
+ "acute": (7, builder.buildAnchor(300, 800)),
+ "grave": (2, builder.buildAnchor(10, 80)),
+ },
+ self.GLYPHMAP,
+ )
+ assert self.GLYPHMAP["grave"] < self.GLYPHMAP["acute"]
+ assert getXML(markArray.toXML) == [
+ "",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ "",
+ ]
def test_buildMarkBasePosSubtable(self):
anchor = builder.buildAnchor
marks = {
"acute": (0, anchor(300, 700)),
"cedilla": (1, anchor(300, -100)),
- "grave": (0, anchor(300, 700))
+ "grave": (0, anchor(300, 700)),
}
bases = {
# Make sure we can handle missing entries.
"A": {}, # no entry for any markClass
"B": {0: anchor(500, 900)}, # only markClass 0 specified
"C": {1: anchor(500, -10)}, # only markClass 1 specified
-
"a": {0: anchor(500, 400), 1: anchor(500, -20)},
- "b": {0: anchor(500, 800), 1: anchor(500, -20)}
+ "b": {0: anchor(500, 800), 1: anchor(500, -20)},
}
table = builder.buildMarkBasePosSubtable(marks, bases, self.GLYPHMAP)
- self.assertEqual(getXML(table.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ', # grave
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ', # acute
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ', # cedilla
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ', # A
- ' ',
- ' ',
- ' ',
- ' ', # B
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ', # C
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ', # a
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ', # b
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(table.toXML) == [
+ '',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ " ",
+ " ",
+ ' ', # grave
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ', # acute
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ', # cedilla
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ' ', # A
+ ' ',
+ ' ',
+ " ",
+ ' ', # B
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ ' ', # C
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ', # a
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ', # b
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ " ",
+ "",
+ ]
def test_buildMarkGlyphSetsDef(self):
marksets = builder.buildMarkGlyphSetsDef(
- [{"acute", "grave"}, {"cedilla", "grave"}], self.GLYPHMAP)
- self.assertEqual(getXML(marksets.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ [{"acute", "grave"}, {"cedilla", "grave"}], self.GLYPHMAP
+ )
+ assert getXML(marksets.toXML) == [
+ "",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ "",
+ ]
def test_buildMarkGlyphSetsDef_empty(self):
- self.assertIsNone(builder.buildMarkGlyphSetsDef([], self.GLYPHMAP))
+ assert builder.buildMarkGlyphSetsDef([], self.GLYPHMAP) is None
def test_buildMarkGlyphSetsDef_None(self):
- self.assertIsNone(builder.buildMarkGlyphSetsDef(None, self.GLYPHMAP))
+ assert builder.buildMarkGlyphSetsDef(None, self.GLYPHMAP) is None
def test_buildMarkLigPosSubtable(self):
anchor = builder.buildAnchor
marks = {
"acute": (0, anchor(300, 700)),
"cedilla": (1, anchor(300, -100)),
- "grave": (0, anchor(300, 700))
+ "grave": (0, anchor(300, 700)),
}
bases = {
"f_i": [{}, {0: anchor(200, 400)}], # nothing on f; only 1 on i
"c_t": [
- {0: anchor(500, 600), 1: anchor(500, -20)}, # c
- {0: anchor(1300, 800), 1: anchor(1300, -20)} # t
- ]
+ {0: anchor(500, 600), 1: anchor(500, -20)}, # c
+ {0: anchor(1300, 800), 1: anchor(1300, -20)}, # t
+ ],
}
table = builder.buildMarkLigPosSubtable(marks, bases, self.GLYPHMAP)
- self.assertEqual(getXML(table.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(table.toXML) == [
+ '',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ ' ',
+ " ",
+ " ",
+ " ",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ " ",
+ " ",
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ " ",
+ " ",
+ "",
+ ]
def test_buildMarkRecord(self):
rec = builder.buildMarkRecord(17, builder.buildAnchor(500, -20))
- self.assertEqual(getXML(rec.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(rec.toXML) == [
+ "",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ "",
+ ]
def test_buildMark2Record(self):
a = builder.buildAnchor
rec = builder.buildMark2Record([a(500, -20), None, a(300, -15)])
- self.assertEqual(getXML(rec.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ assert getXML(rec.toXML) == [
+ "",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ "",
+ ]
def test_buildPairPosClassesSubtable(self):
d20 = builder.buildValue({"XPlacement": -20})
d50 = builder.buildValue({"XPlacement": -50})
d0 = builder.buildValue({})
d8020 = builder.buildValue({"XPlacement": -80, "YPlacement": -20})
- subtable = builder.buildPairPosClassesSubtable({
- (tuple("A",), tuple(["zero"])): (d0, d50),
- (tuple("A",), tuple(["one", "two"])): (None, d20),
- (tuple(["B", "C"]), tuple(["zero"])): (d8020, d50),
- }, self.GLYPHMAP)
- self.assertEqual(getXML(subtable.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ subtable = builder.buildPairPosClassesSubtable(
+ {
+ (tuple("A"), tuple(["zero"])): (d0, d50),
+ (tuple("A"), tuple(["one", "two"])): (None, d20),
+ (tuple(["B", "C"]), tuple(["zero"])): (d8020, d50),
+ },
+ self.GLYPHMAP,
+ )
+ assert getXML(subtable.toXML) == [
+ '',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ " ",
+ " ",
+ "",
+ ]
def test_buildPairPosGlyphs(self):
d50 = builder.buildValue({"XPlacement": -50})
d8020 = builder.buildValue({"XPlacement": -80, "YPlacement": -20})
- subtables = builder.buildPairPosGlyphs({
- ("A", "zero"): (None, d50),
- ("A", "one"): (d8020, d50),
- }, self.GLYPHMAP)
- self.assertEqual(sum([getXML(t.toXML) for t in subtables], []),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- '',
- '',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ subtables = builder.buildPairPosGlyphs(
+ {("A", "zero"): (None, d50), ("A", "one"): (d8020, d50)}, self.GLYPHMAP
+ )
+ assert sum([getXML(t.toXML) for t in subtables], []) == [
+ '',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ "",
+ '',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ "",
+ ]
def test_buildPairPosGlyphsSubtable(self):
d20 = builder.buildValue({"XPlacement": -20})
d50 = builder.buildValue({"XPlacement": -50})
d0 = builder.buildValue({})
d8020 = builder.buildValue({"XPlacement": -80, "YPlacement": -20})
- subtable = builder.buildPairPosGlyphsSubtable({
- ("A", "zero"): (d0, d50),
- ("A", "one"): (None, d20),
- ("B", "five"): (d8020, d50),
- }, self.GLYPHMAP)
- self.assertEqual(getXML(subtable.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ subtable = builder.buildPairPosGlyphsSubtable(
+ {
+ ("A", "zero"): (d0, d50),
+ ("A", "one"): (None, d20),
+ ("B", "five"): (d8020, d50),
+ },
+ self.GLYPHMAP,
+ )
+ assert getXML(subtable.toXML) == [
+ '',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ " ",
+ "",
+ ]
def test_buildSinglePos(self):
- subtables = builder.buildSinglePos({
- "one": builder.buildValue({"XPlacement": 500}),
- "two": builder.buildValue({"XPlacement": 500}),
- "three": builder.buildValue({"XPlacement": 200}),
- "four": builder.buildValue({"XPlacement": 400}),
- "five": builder.buildValue({"XPlacement": 500}),
- "six": builder.buildValue({"YPlacement": -6}),
- }, self.GLYPHMAP)
- self.assertEqual(sum([getXML(t.toXML) for t in subtables], []),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- '',
- '',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ subtables = builder.buildSinglePos(
+ {
+ "one": builder.buildValue({"XPlacement": 500}),
+ "two": builder.buildValue({"XPlacement": 500}),
+ "three": builder.buildValue({"XPlacement": 200}),
+ "four": builder.buildValue({"XPlacement": 400}),
+ "five": builder.buildValue({"XPlacement": 500}),
+ "six": builder.buildValue({"YPlacement": -6}),
+ },
+ self.GLYPHMAP,
+ )
+ assert sum([getXML(t.toXML) for t in subtables], []) == [
+ '',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ ' ',
+ "",
+ '',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ "",
+ ]
def test_buildSinglePos_ValueFormat0(self):
- subtables = builder.buildSinglePos({
- "zero": builder.buildValue({})
- }, self.GLYPHMAP)
- self.assertEqual(sum([getXML(t.toXML) for t in subtables], []),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ subtables = builder.buildSinglePos(
+ {"zero": builder.buildValue({})}, self.GLYPHMAP
+ )
+ assert sum([getXML(t.toXML) for t in subtables], []) == [
+ '',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ "",
+ ]
def test_buildSinglePosSubtable_format1(self):
- subtable = builder.buildSinglePosSubtable({
- "one": builder.buildValue({"XPlacement": 777}),
- "two": builder.buildValue({"XPlacement": 777}),
- }, self.GLYPHMAP)
- self.assertEqual(getXML(subtable.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ subtable = builder.buildSinglePosSubtable(
+ {
+ "one": builder.buildValue({"XPlacement": 777}),
+ "two": builder.buildValue({"XPlacement": 777}),
+ },
+ self.GLYPHMAP,
+ )
+ assert getXML(subtable.toXML) == [
+ '',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ "",
+ ]
def test_buildSinglePosSubtable_format2(self):
- subtable = builder.buildSinglePosSubtable({
- "one": builder.buildValue({"XPlacement": 777}),
- "two": builder.buildValue({"YPlacement": -888}),
- }, self.GLYPHMAP)
- self.assertEqual(getXML(subtable.toXML),
- ['',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ' ',
- ''])
+ subtable = builder.buildSinglePosSubtable(
+ {
+ "one": builder.buildValue({"XPlacement": 777}),
+ "two": builder.buildValue({"YPlacement": -888}),
+ },
+ self.GLYPHMAP,
+ )
+ assert getXML(subtable.toXML) == [
+ '',
+ " ",
+ ' ',
+ ' ',
+ " ",
+ ' ',
+ " ",
+ ' ',
+ ' ',
+ "",
+ ]
def test_buildValue(self):
value = builder.buildValue({"XPlacement": 7, "YPlacement": 23})
func = lambda writer, font: value.toXML(writer, font, valueName="Val")
- self.assertEqual(getXML(func),
- [''])
+ assert getXML(func) == ['']
def test_getLigatureKey(self):
components = lambda s: [tuple(word) for word in s.split()]
c = components("fi fl ff ffi fff")
c.sort(key=builder._getLigatureKey)
- self.assertEqual(c, components("fff ffi ff fi fl"))
+ assert c == components("fff ffi ff fi fl")
def test_getSinglePosValueKey(self):
- device = builder.buildDevice({10:1, 11:3})
+ device = builder.buildDevice({10: 1, 11: 3})
a1 = builder.buildValue({"XPlacement": 500, "XPlaDevice": device})
a2 = builder.buildValue({"XPlacement": 500, "XPlaDevice": device})
b = builder.buildValue({"XPlacement": 500})
keyA1 = builder._getSinglePosValueKey(a1)
keyA2 = builder._getSinglePosValueKey(a1)
keyB = builder._getSinglePosValueKey(b)
- self.assertEqual(keyA1, keyA2)
- self.assertEqual(hash(keyA1), hash(keyA2))
- self.assertNotEqual(keyA1, keyB)
- self.assertNotEqual(hash(keyA1), hash(keyB))
+ assert keyA1 == keyA2
+ assert hash(keyA1) == hash(keyA2)
+ assert keyA1 != keyB
+ assert hash(keyA1) != hash(keyB)
-class ClassDefBuilderTest(unittest.TestCase):
+class ClassDefBuilderTest(object):
def test_build_usingClass0(self):
b = builder.ClassDefBuilder(useClass0=True)
b.add({"aa", "bb"})
@@ -1015,14 +1075,8 @@ class ClassDefBuilderTest(unittest.TestCase):
b.add({"c"})
b.add({"e", "f", "g", "h"})
cdef = b.build()
- self.assertIsInstance(cdef, otTables.ClassDef)
- self.assertEqual(cdef.classDefs, {
- "a": 2,
- "b": 2,
- "c": 3,
- "aa": 1,
- "bb": 1
- })
+ assert isinstance(cdef, otTables.ClassDef)
+ assert cdef.classDefs == {"a": 2, "b": 2, "c": 3, "aa": 1, "bb": 1}
def test_build_notUsingClass0(self):
b = builder.ClassDefBuilder(useClass0=False)
@@ -1030,30 +1084,31 @@ class ClassDefBuilderTest(unittest.TestCase):
b.add({"c"})
b.add({"e", "f", "g", "h"})
cdef = b.build()
- self.assertIsInstance(cdef, otTables.ClassDef)
- self.assertEqual(cdef.classDefs, {
+ assert isinstance(cdef, otTables.ClassDef)
+ assert cdef.classDefs == {
"a": 2,
"b": 2,
"c": 3,
"e": 1,
"f": 1,
"g": 1,
- "h": 1
- })
+ "h": 1,
+ }
def test_canAdd(self):
b = builder.ClassDefBuilder(useClass0=True)
b.add({"a", "b", "c", "d"})
b.add({"e", "f"})
- self.assertTrue(b.canAdd({"a", "b", "c", "d"}))
- self.assertTrue(b.canAdd({"e", "f"}))
- self.assertTrue(b.canAdd({"g", "h", "i"}))
- self.assertFalse(b.canAdd({"b", "c", "d"}))
- self.assertFalse(b.canAdd({"a", "b", "c", "d", "e", "f"}))
- self.assertFalse(b.canAdd({"d", "e", "f"}))
- self.assertFalse(b.canAdd({"f"}))
+ assert b.canAdd({"a", "b", "c", "d"})
+ assert b.canAdd({"e", "f"})
+ assert b.canAdd({"g", "h", "i"})
+ assert not b.canAdd({"b", "c", "d"})
+ assert not b.canAdd({"a", "b", "c", "d", "e", "f"})
+ assert not b.canAdd({"d", "e", "f"})
+ assert not b.canAdd({"f"})
if __name__ == "__main__":
import sys
- sys.exit(unittest.main())
+
+ sys.exit(pytest.main(sys.argv))
diff --git a/Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w0.00.ttx b/Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w0.00.ttx
index 577315845..f6568fd83 100644
--- a/Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w0.00.ttx
+++ b/Tests/varLib/data/master_sparse_cff2/MasterSet_Kanji-w0.00.ttx
@@ -374,6 +374,7 @@
+
diff --git a/Tests/varLib/data/test_results/BuildTestCFF2.ttx b/Tests/varLib/data/test_results/BuildTestCFF2.ttx
index 91b83fc01..290445250 100644
--- a/Tests/varLib/data/test_results/BuildTestCFF2.ttx
+++ b/Tests/varLib/data/test_results/BuildTestCFF2.ttx
@@ -86,10 +86,10 @@
-
+
-
+
diff --git a/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx b/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx
index 5ded5b915..26bd7ba74 100644
--- a/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx
+++ b/Tests/varLib/data/test_results/TestNonMarkingCFF2.ttx
@@ -31,10 +31,10 @@
-
+
-
+
diff --git a/Tests/varLib/data/test_results/TestSparseCFF2VF.ttx b/Tests/varLib/data/test_results/TestSparseCFF2VF.ttx
index 442ae91e6..f05f62f74 100644
--- a/Tests/varLib/data/test_results/TestSparseCFF2VF.ttx
+++ b/Tests/varLib/data/test_results/TestSparseCFF2VF.ttx
@@ -132,6 +132,7 @@
+
diff --git a/requirements.txt b/requirements.txt
index 8e1fe6ed5..5b6368986 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,3 +9,7 @@ munkres==1.0.12; platform_python_implementation == "PyPy" and python_version < '
munkres==1.1.2; platform_python_implementation == "PyPy" and python_version >= '3.5'
zopfli==0.1.6
fs==2.4.8
+# lxml 4.4.0 breaks OrderedDict attributes in python < 3.6 so we pin to previous version
+# https://bugs.launchpad.net/lxml/+bug/1838252
+lxml==4.3.5; python_version < '3.6' # pyup: ignore
+lxml==4.4.0; python_version >= '3.6'
diff --git a/setup.cfg b/setup.cfg
index eec867f2a..4de4b9b4c 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 3.43.2.dev0
+current_version = 3.43.3.dev0
commit = True
tag = False
tag_name = {new_version}
diff --git a/setup.py b/setup.py
index cb1c83666..be091d3a8 100755
--- a/setup.py
+++ b/setup.py
@@ -352,7 +352,7 @@ def find_data_files(manpath="share/man"):
setup(
name="fonttools",
- version="3.43.2.dev0",
+ version="3.43.3.dev0",
description="Tools to manipulate font files",
author="Just van Rossum",
author_email="just@letterror.com",