noconflict.py

Go to the documentation of this file.
00001 import inspect, types, __builtin__
00002 
00003 ############## preliminary: two utility functions #####################
00004 
00005 def skip_redundant(iterable, skipset=None):
00006     "Redundant items are repeated items or items in the original skipset."
00007     if skipset is None: skipset = set()
00008     for item in iterable:
00009         if item not in skipset:
00010             skipset.add(item)
00011             yield item
00012 
00013 
00014 def remove_redundant(metaclasses):
00015     skipset = set([types.ClassType])
00016     for meta in metaclasses: # determines the metaclasses to be skipped
00017         skipset.update(inspect.getmro(meta)[1:])
00018     return tuple(skip_redundant(metaclasses, skipset))
00019 
00020 ##################################################################
00021 ## now the core of the module: two mutually recursive functions ##
00022 ##################################################################
00023 
00024 memoized_metaclasses_map = {}
00025 
00026 ##
00027 # Not intended to be used outside of this module, unless you know
00028 #  what you are doing.
00029 def get_noconflict_metaclass(bases, left_metas, right_metas):
00030     # make tuple of needed metaclasses in specified priority order
00031     metas = left_metas + tuple(map(type, bases)) + right_metas
00032     needed_metas = remove_redundant(metas)
00033 
00034     # return existing confict-solving meta, if any
00035     if needed_metas in memoized_metaclasses_map:
00036         return memoized_metaclasses_map[needed_metas]
00037     # nope: compute, memoize and return needed conflict-solving meta
00038     elif not needed_metas:         # wee, a trivial case, happy us
00039         meta = type
00040     elif len(needed_metas) == 1: # another trivial case
00041         meta = needed_metas[0]
00042     # check for recursion, can happen i.e. for Zope ExtensionClasses
00043     elif needed_metas == bases: 
00044         raise TypeError("Incompatible root metatypes", needed_metas)
00045     else: # gotta work ...
00046         metaname = '_' + ''.join([m.__name__ for m in needed_metas])
00047         meta = classmaker()(metaname, needed_metas, {})
00048     memoized_metaclasses_map[needed_metas] = meta
00049     return meta
00050 
00051 def classmaker(left_metas=(), right_metas=()):
00052     def make_class(name, bases, adict):
00053         metaclass = get_noconflict_metaclass(bases, left_metas, right_metas)
00054         return metaclass(name, bases, adict)
00055     return make_class
00056 
00057 if (__name__ == '__main__'):
00058     from vyperlogix.misc import ObjectTypeName
00059 
00060     class M_A(type):
00061         pass
00062     class M_B(type):
00063         pass
00064     class A(object):
00065         __metaclass__=M_A
00066     class B(object):
00067         __metaclass__=M_B
00068     #from noconflict import classmaker
00069     class C(A,B):
00070         __metaclass__=classmaker()
00071     print ObjectTypeName._typeName(C)
00072     
00073 

© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved; If you reference this document or any part of this document you must use the citation verbatim (including the link) "© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved."

Notice: This source code contained in this document is NOT open source and is NOT being distributed as open source.

122,241 lines of code and growing...