mirror of
https://github.com/gryf/pygtktalog.git
synced 2026-03-26 22:03:30 +01:00
* Updated pygtkmvc to 1.2.2.
This commit is contained in:
65
src/gtkmvc/support/noconflict.py
Normal file
65
src/gtkmvc/support/noconflict.py
Normal file
@@ -0,0 +1,65 @@
|
||||
# Author: Michele Simionato <michelesimionato@libero.it>
|
||||
# Copyright (C) 2004 by Michele Simionato
|
||||
# License: Python License (version not specified)
|
||||
# Last Updated: 2nd of March 2007, 10:23 GMT
|
||||
#
|
||||
# Any serious user of metaclasses has been bitten at least once by
|
||||
# the infamous metaclass/metatype conflict. This script contains a
|
||||
# general recipe to solve the problem, as well as some theory and
|
||||
# some examples.
|
||||
|
||||
|
||||
import inspect, types, __builtin__
|
||||
|
||||
############## preliminary: two utility functions #####################
|
||||
|
||||
def skip_redundant(iterable, skipset=None):
|
||||
"Redundant items are repeated items or items in the original skipset."
|
||||
if skipset is None: skipset = set()
|
||||
for item in iterable:
|
||||
if item not in skipset:
|
||||
skipset.add(item)
|
||||
yield item
|
||||
|
||||
|
||||
def remove_redundant(metaclasses):
|
||||
skipset = set([types.ClassType])
|
||||
for meta in metaclasses: # determines the metaclasses to be skipped
|
||||
skipset.update(inspect.getmro(meta)[1:])
|
||||
return tuple(skip_redundant(metaclasses, skipset))
|
||||
|
||||
##################################################################
|
||||
## now the core of the module: two mutually recursive functions ##
|
||||
##################################################################
|
||||
|
||||
memoized_metaclasses_map = {}
|
||||
|
||||
def get_noconflict_metaclass(bases, left_metas, right_metas):
|
||||
"""Not intended to be used outside of this module, unless you know
|
||||
what you are doing."""
|
||||
# make tuple of needed metaclasses in specified priority order
|
||||
metas = left_metas + tuple(map(type, bases)) + right_metas
|
||||
needed_metas = remove_redundant(metas)
|
||||
|
||||
# return existing confict-solving meta, if any
|
||||
if needed_metas in memoized_metaclasses_map:
|
||||
return memoized_metaclasses_map[needed_metas]
|
||||
# nope: compute, memoize and return needed conflict-solving meta
|
||||
elif not needed_metas: # wee, a trivial case, happy us
|
||||
meta = type
|
||||
elif len(needed_metas) == 1: # another trivial case
|
||||
meta = needed_metas[0]
|
||||
# check for recursion, can happen i.e. for Zope ExtensionClasses
|
||||
elif needed_metas == bases:
|
||||
raise TypeError("Incompatible root metatypes", needed_metas)
|
||||
else: # gotta work ...
|
||||
metaname = '_' + ''.join([m.__name__ for m in needed_metas])
|
||||
meta = classmaker()(metaname, needed_metas, {})
|
||||
memoized_metaclasses_map[needed_metas] = meta
|
||||
return meta
|
||||
|
||||
def classmaker(left_metas=(), right_metas=()):
|
||||
def make_class(name, bases, adict):
|
||||
metaclass = get_noconflict_metaclass(bases, left_metas, right_metas)
|
||||
return metaclass(name, bases, adict)
|
||||
return make_class
|
||||
Reference in New Issue
Block a user