[IMP] core: optimize model._setup_base()

Simplify the code to retrieve fields on a class.
Simplify the class attribute that lists the class' proper fields.
Optimize `model._add_inherited_fields()`.
Optimize `resolve_mro` by using classes instead of recordsets.

This saves 3.5% of the total installation time.

X-original-commit: 89ab71905cb6c5d3beda5eac357f8592e31aaef8
This commit is contained in:
Raphael Collet
2020-04-03 11:40:27 +00:00
parent b491ca0bb3
commit f694caac41
2 changed files with 48 additions and 36 deletions
+7 -6
View File
@@ -55,12 +55,13 @@ def resolve_mro(model, name, predicate):
(the ones that appear in the registry) are ignored.
"""
result = []
for cls in type(model).__mro__:
if not getattr(cls, 'pool', None) and name in cls.__dict__:
value = cls.__dict__[name]
if not predicate(value):
break
result.append(value)
for cls in model._model_classes:
value = cls.__dict__.get(name, Default)
if value is Default:
continue
if not predicate(value):
break
result.append(value)
return result
+41 -30
View File
@@ -2575,28 +2575,31 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
@api.model
def _add_inherited_fields(self):
""" Determine inherited fields. """
# determine candidate inherited fields
fields = {}
for parent_model, parent_field in self._inherits.items():
parent = self.env[parent_model]
for name, field in parent._fields.items():
if not self._inherits:
return
# determine which fields can be inherited
to_inherit = {
name: (parent_fname, field)
for parent_model_name, parent_fname in self._inherits.items()
for name, field in self.env[parent_model_name]._fields.items()
}
# add inherited fields that are not redefined locally
for name, (parent_fname, field) in to_inherit.items():
if name not in self._fields:
# inherited fields are implemented as related fields, with the
# following specific properties:
# - reading inherited fields should not bypass access rights
# - copy inherited fields iff their original field is copied
fields[name] = field.new(
self._add_field(name, field.new(
inherited=True,
inherited_field=field,
related=(parent_field, name),
related=(parent_fname, name),
related_sudo=False,
copy=field.copy,
readonly=field.readonly,
)
# add inherited fields that are not redefined locally
for name, field in fields.items():
if name not in self._fields:
self._add_field(name, field)
))
@api.model
def _inherits_check(self):
@@ -2628,8 +2631,9 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
""" Prepare the setup of the model. """
cls = type(self)
cls._setup_done = False
# a model's base structure depends on its mro (without registry classes)
cls._model_cache_key = tuple(c for c in cls.mro() if getattr(c, 'pool', None) is None)
# the classes that define this model's base fields and methods
cls._model_classes = tuple(c for c in cls.mro() if getattr(c, 'pool', None) is None)
# reset those attributes on the model's class for _setup_fields() below
for attr in ('_rec_name', '_active_name'):
@@ -2647,8 +2651,9 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# 1. determine the proper fields of the model: the fields defined on the
# class and magic fields, not the inherited or custom ones
cls0 = cls.pool.model_cache.get(cls._model_cache_key)
if cls0 and cls0._model_cache_key == cls._model_cache_key:
cls0 = cls.pool.model_cache.get(cls._model_classes)
if cls0 and cls0._model_classes == cls._model_classes:
# cls0 is either a model class from another registry, or cls itself.
# The point is that it has the same base classes. We retrieve stuff
# from cls0 to optimize the setup of cls. cls0 is guaranteed to be
@@ -2656,18 +2661,24 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# therefore two registries are never set up at the same time.
# remove fields that are not proper to cls
for name in OrderedSet(cls._fields) - cls0._proper_fields:
for name in set(cls._fields).difference(cls0._model_fields):
delattr(cls, name)
cls._fields.pop(name, None)
# collect proper fields on cls0, and add them on cls
for name in cls0._proper_fields:
field = cls0._fields[name]
# regular fields are shared, while related fields are setup from scratch
if not field.related:
self._add_field(name, field)
else:
self._add_field(name, field.new(**field.args))
cls._proper_fields = OrderedSet(cls._fields)
del cls._fields[name]
if cls0 is cls:
# simply reset up fields
for name, field in cls._fields.items():
field.setup_base(self, name)
else:
# collect proper fields on cls0, and add them on cls
for name in cls0._model_fields:
field = cls0._fields[name]
# regular fields are shared, while related fields are setup from scratch
if not field.related:
self._add_field(name, field)
else:
self._add_field(name, field.new(**field.args))
cls._model_fields = list(cls._fields)
else:
# retrieve fields from parent classes, and duplicate them on cls to
@@ -2680,9 +2691,9 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
if not any(field.args.get(k) for k in ('automatic', 'manual', 'inherited')):
self._add_field(name, field.new())
self._add_magic_fields()
cls._proper_fields = OrderedSet(cls._fields)
cls._model_fields = list(cls._fields)
cls.pool.model_cache[cls._model_cache_key] = cls
cls.pool.model_cache[cls._model_classes] = cls
# 2. add manual fields
if self.pool._init_modules: