Add registry for custom table packer/unpacker classes (#2055)

* Add custom table packer/unpacker registry

* fix documentation for getTableClass(): it will never return None

* add unregisterCustomTableClass(), mostly for testing
This commit is contained in:
Just van Rossum 2020-09-09 11:35:06 +02:00 committed by GitHub
parent a41005077d
commit 9064e53c7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 3 deletions

View File

@ -830,10 +830,48 @@ def getTableModule(tag):
return getattr(tables, pyTag)
def getTableClass(tag):
"""Fetch the packer/unpacker class for a table.
Return None when no class is found.
# Registry for custom table packer/unpacker classes. Keys are table
# tags, values are (moduleName, className) tuples.
# See registerCustomTableClass() and getCustomTableClass()
_customTableRegistry = {}
def registerCustomTableClass(tag, moduleName, className=None):
"""Register a custom packer/unpacker class for a table.
The 'moduleName' must be an importable module. If no 'className'
is given, it is derived from the tag, for example it will be
table_C_U_S_T_ for a 'CUST' tag.
The registered table class should be a subclass of
fontTools.ttLib.tables.DefaultTable.DefaultTable
"""
if className is None:
className = "table_" + tagToIdentifier(tag)
_customTableRegistry[tag] = (moduleName, className)
def unregisterCustomTableClass(tag):
"""Unregister the custom packer/unpacker class for a table."""
del _customTableRegistry[tag]
def getCustomTableClass(tag):
"""Return the custom table class for tag, if one has been registered
with 'registerCustomTableClass()'. Else return None.
"""
if tag not in _customTableRegistry:
return None
import importlib
moduleName, className = _customTableRegistry[tag]
module = importlib.import_module(moduleName)
return getattr(module, className)
def getTableClass(tag):
"""Fetch the packer/unpacker class for a table."""
tableClass = getCustomTableClass(tag)
if tableClass is not None:
return tableClass
module = getTableModule(tag)
if module is None:
from .tables.DefaultTable import DefaultTable

View File

@ -0,0 +1,48 @@
import io
from fontTools.ttLib import TTFont, newTable, registerCustomTableClass, unregisterCustomTableClass
from fontTools.ttLib.tables.DefaultTable import DefaultTable
class CustomTableClass(DefaultTable):
def decompile(self, data, ttFont):
self.numbers = list(data)
def compile(self, ttFont):
return bytes(self.numbers)
# not testing XML read/write
table_C_U_S_T_ = CustomTableClass # alias for testing
TABLETAG = "CUST"
def test_registerCustomTableClass():
font = TTFont()
font[TABLETAG] = newTable(TABLETAG)
font[TABLETAG].data = b"\x00\x01\xff"
f = io.BytesIO()
font.save(f)
f.seek(0)
assert font[TABLETAG].data == b"\x00\x01\xff"
registerCustomTableClass(TABLETAG, "ttFont_test", "CustomTableClass")
try:
font = TTFont(f)
assert font[TABLETAG].numbers == [0, 1, 255]
assert font[TABLETAG].compile(font) == b"\x00\x01\xff"
finally:
unregisterCustomTableClass(TABLETAG)
def test_registerCustomTableClassStandardName():
registerCustomTableClass(TABLETAG, "ttFont_test")
try:
font = TTFont()
font[TABLETAG] = newTable(TABLETAG)
font[TABLETAG].numbers = [4, 5, 6]
assert font[TABLETAG].compile(font) == b"\x04\x05\x06"
finally:
unregisterCustomTableClass(TABLETAG)