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