[IMP] models: model extension may not change kind (abstract, model or transient)

This prevents a model extension from:
 - changing an abstract model to a non-abstract one,
 - changing a transient model to a non-transient one or vice-versa.
This commit is contained in:
Raphael Collet
2016-07-01 16:01:04 +02:00
parent bc2a06c019
commit 4ee6adf4b2
+31 -1
View File
@@ -307,7 +307,8 @@ class BaseModel(object):
__metaclass__ = MetaModel
_auto = False # don't create any database backend
_register = False # not visible in ORM registry
_transient = False # not transient
_abstract = True # whether model is abstract
_transient = False # whether model is transient
_name = None
_columns = {}
@@ -624,6 +625,8 @@ class BaseModel(object):
if name not in pool:
raise TypeError("Model %r does not exist in registry." % name)
ModelClass = type(pool[name])
ModelClass._build_model_check_base(cls)
check_parent = ModelClass._build_model_check_parent
else:
ModelClass = type(name, (BaseModel,), {
'_name': name,
@@ -633,6 +636,7 @@ class BaseModel(object):
'_fields': {}, # populated in _setup_base()
'_defaults': {}, # populated in _setup_base()
})
check_parent = cls._build_model_check_parent
# determine all the classes the model should inherit from
bases = LastOrderedSet([cls])
@@ -644,6 +648,7 @@ class BaseModel(object):
for base in parent_class.__bases__:
bases.add(base)
else:
check_parent(cls, parent_class)
bases.add(parent_class)
parent_class._inherit_children.add(name)
ModelClass.__bases__ = tuple(bases)
@@ -656,6 +661,29 @@ class BaseModel(object):
model.__init__(pool, cr)
return model
@classmethod
def _build_model_check_base(model_class, cls):
""" Check whether ``model_class`` can be extended with ``cls``. """
if model_class._abstract and not cls._abstract:
msg = ("%s transforms the abstract model %r into a non-abstract model. "
"That class should either inherit from AbstractModel, or set a different '_name'.")
raise TypeError(msg % (cls, model_class._name))
if model_class._transient != cls._transient:
if model_class._transient:
msg = ("%s transforms the transient model %r into a non-transient model. "
"That class should either inherit from TransientModel, or set a different '_name'.")
else:
msg = ("%s transforms the model %r into a transient model. "
"That class should either inherit from Model, or set a different '_name'.")
raise TypeError(msg % (cls, model_class._name))
@classmethod
def _build_model_check_parent(model_class, cls, parent_class):
""" Check whether ``model_class`` can inherit from ``parent_class``. """
if model_class._abstract and not parent_class._abstract:
msg = ("In %s, the abstract model %r cannot inherit from the non-abstract model %r.")
raise TypeError(msg % (cls, model_class._name, parent_class._name))
@classmethod
def _build_model_attributes(cls, pool):
""" Initialize base model attributes. """
@@ -6252,6 +6280,7 @@ class Model(AbstractModel):
"""
_auto = True # automatically create database backend
_register = False # not visible in ORM registry, meant to be python-inherited only
_abstract = False # not abstract
_transient = False # not transient
class TransientModel(Model):
@@ -6264,6 +6293,7 @@ class TransientModel(Model):
"""
_auto = True # automatically create database backend
_register = False # not visible in ORM registry, meant to be python-inherited only
_abstract = False # not abstract
_transient = True # transient
def itemgetter_tuple(items):