base.py 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. # Copyright 2013 Google, Inc. All Rights Reserved.
  2. #
  3. # Google Author(s): Behdad Esfahbod, Roozbeh Pournader
  4. from fontTools.ttLib.tables.DefaultTable import DefaultTable
  5. import logging
  6. log = logging.getLogger("fontTools.merge")
  7. def add_method(*clazzes, **kwargs):
  8. """Returns a decorator function that adds a new method to one or
  9. more classes."""
  10. allowDefault = kwargs.get("allowDefaultTable", False)
  11. def wrapper(method):
  12. done = []
  13. for clazz in clazzes:
  14. if clazz in done:
  15. continue # Support multiple names of a clazz
  16. done.append(clazz)
  17. assert allowDefault or clazz != DefaultTable, "Oops, table class not found."
  18. assert (
  19. method.__name__ not in clazz.__dict__
  20. ), "Oops, class '%s' has method '%s'." % (clazz.__name__, method.__name__)
  21. setattr(clazz, method.__name__, method)
  22. return None
  23. return wrapper
  24. def mergeObjects(lst):
  25. lst = [item for item in lst if item is not NotImplemented]
  26. if not lst:
  27. return NotImplemented
  28. lst = [item for item in lst if item is not None]
  29. if not lst:
  30. return None
  31. clazz = lst[0].__class__
  32. assert all(type(item) == clazz for item in lst), lst
  33. logic = clazz.mergeMap
  34. returnTable = clazz()
  35. returnDict = {}
  36. allKeys = set.union(set(), *(vars(table).keys() for table in lst))
  37. for key in allKeys:
  38. try:
  39. mergeLogic = logic[key]
  40. except KeyError:
  41. try:
  42. mergeLogic = logic["*"]
  43. except KeyError:
  44. raise Exception(
  45. "Don't know how to merge key %s of class %s" % (key, clazz.__name__)
  46. )
  47. if mergeLogic is NotImplemented:
  48. continue
  49. value = mergeLogic(getattr(table, key, NotImplemented) for table in lst)
  50. if value is not NotImplemented:
  51. returnDict[key] = value
  52. returnTable.__dict__ = returnDict
  53. return returnTable
  54. @add_method(DefaultTable, allowDefaultTable=True)
  55. def merge(self, m, tables):
  56. if not hasattr(self, "mergeMap"):
  57. log.info("Don't know how to merge '%s'.", self.tableTag)
  58. return NotImplemented
  59. logic = self.mergeMap
  60. if isinstance(logic, dict):
  61. return m.mergeObjects(self, self.mergeMap, tables)
  62. else:
  63. return logic(tables)