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 def wrapper(method): 17 done = [] 18 for clazz in clazzes: 19 if clazz in done: continue # Support multiple names of a clazz 20 done.append(clazz) 21 assert allowDefault or clazz != DefaultTable, 'Oops, table class not found.' 22 assert method.__name__ not in clazz.__dict__, \ 23 "Oops, class '%s' has method '%s'." % (clazz.__name__, method.__name__) 24 setattr(clazz, method.__name__, method) 25 return None 26 return wrapper 27 28def mergeObjects(lst): 29 lst = [item for item in lst if item is not NotImplemented] 30 if not lst: 31 return NotImplemented 32 lst = [item for item in lst if item is not None] 33 if not lst: 34 return None 35 36 clazz = lst[0].__class__ 37 assert all(type(item) == clazz for item in lst), lst 38 39 logic = clazz.mergeMap 40 returnTable = clazz() 41 returnDict = {} 42 43 allKeys = set.union(set(), *(vars(table).keys() for table in lst)) 44 for key in allKeys: 45 try: 46 mergeLogic = logic[key] 47 except KeyError: 48 try: 49 mergeLogic = logic['*'] 50 except KeyError: 51 raise Exception("Don't know how to merge key %s of class %s" % 52 (key, clazz.__name__)) 53 if mergeLogic is NotImplemented: 54 continue 55 value = mergeLogic(getattr(table, key, NotImplemented) for table in lst) 56 if value is not NotImplemented: 57 returnDict[key] = value 58 59 returnTable.__dict__ = returnDict 60 61 return returnTable 62 63@add_method(DefaultTable, allowDefaultTable=True) 64def merge(self, m, tables): 65 if not hasattr(self, 'mergeMap'): 66 log.info("Don't know how to merge '%s'.", self.tableTag) 67 return NotImplemented 68 69 logic = self.mergeMap 70 71 if isinstance(logic, dict): 72 return m.mergeObjects(self, self.mergeMap, tables) 73 else: 74 return logic(tables) 75 76 77