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