Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using mptt.models.MPTTModel and nani.models.TranslatableModel, #39

Closed
Natim opened this issue Sep 13, 2011 · 1 comment
Closed

Using mptt.models.MPTTModel and nani.models.TranslatableModel, #39

Natim opened this issue Sep 13, 2011 · 1 comment

Comments

@Natim
Copy link

Natim commented Sep 13, 2011

Trying to use both inherance raise this error

TypeError: Error when calling the metaclass bases metaclass conflict: 
  the metaclass of a derived class must be a (non-strict) subclass of the
  metaclasses of all its bases
@Natim
Copy link
Author

Natim commented Sep 13, 2011

The solution is describe here : http://code.activestate.com/recipes/204197-solving-the-metaclass-conflict/

Create the file noconflict.py (that may be added to django-nani) with this content :

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

Then in your model use this :

from mptt.models import MPTTModel
from nani.models import TranslatableModel, TranslatedFields
from noconflict import classmaker

class Section(TranslatableModel, MPTTModel):
    __metaclass__ = classmaker()

....

Enjoy !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant