summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2014-04-29 00:44:04 -0400
committerSimon Charette <charette.s@gmail.com>2014-04-29 10:55:36 -0400
commitf02f20a7395fe6681cfcae1c52d4bab68f6aa0d5 (patch)
tree2fce0b0b6ca19cae991a8a2afbe7209c1768f375
parent62bbfba3aa96011a374f935d2c2176e5c2c90b85 (diff)
[1.7.x] Use the new implementation of `six.with_metaclass`.
No more `NewBase` horrors. Thanks to bendavis78 for his work on merging this into six. Backport of a2340ac6d6 from master
-rw-r--r--django/db/models/base.py12
-rw-r--r--django/utils/six.py16
2 files changed, 16 insertions, 12 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 968174e78c..f156643eed 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -62,19 +62,9 @@ class ModelBase(type):
def __new__(cls, name, bases, attrs):
super_new = super(ModelBase, cls).__new__
- # six.with_metaclass() inserts an extra class called 'NewBase' in the
- # inheritance tree: Model -> NewBase -> object. But the initialization
- # should be executed only once for a given model class.
-
- # attrs will never be empty for classes declared in the standard way
- # (ie. with the `class` keyword). This is quite robust.
- if name == 'NewBase' and attrs == {}:
- return super_new(cls, name, bases, attrs)
-
# Also ensure initialization is only performed for subclasses of Model
# (excluding Model class itself).
- parents = [b for b in bases if isinstance(b, ModelBase) and
- not (b.__name__ == 'NewBase' and b.__mro__ == (b, object))]
+ parents = [b for b in bases if isinstance(b, ModelBase)]
if not parents:
return super_new(cls, name, bases, attrs)
diff --git a/django/utils/six.py b/django/utils/six.py
index dd171aa42f..bf94a83000 100644
--- a/django/utils/six.py
+++ b/django/utils/six.py
@@ -628,7 +628,21 @@ _add_doc(reraise, """Reraise an exception.""")
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
- return meta("NewBase", bases, {})
+ # This requires a bit of explanation: the basic idea is to make a
+ # dummy metaclass for one level of class instantiation that replaces
+ # itself with the actual metaclass. Because of internal type checks
+ # we also need to make sure that we downgrade the custom metaclass
+ # for one level to something closer to type (that's why __call__ and
+ # __init__ comes back from type etc.).
+ class metaclass(meta):
+ __call__ = type.__call__
+ __init__ = type.__init__
+ def __new__(cls, name, this_bases, d):
+ if this_bases is None:
+ return type.__new__(cls, name, (), d)
+ return meta(name, bases, d)
+ return metaclass('temporary_class', None, {})
+
def add_metaclass(metaclass):
"""Class decorator for creating a class with a metaclass."""