summaryrefslogtreecommitdiff
path: root/odoo
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2020-04-07 13:51:30 +0000
committerRaphael Collet <rco@odoo.com>2020-05-18 09:51:43 +0000
commitea3e39506a2b360545ec0cd1d3235e69ad16ea6c (patch)
tree9d103c7a40911c988e1a3cbecfd8d6a76a3a9a85 /odoo
parent2e56191c8b86d05bbce17790de8a4732c0478013 (diff)
[IMP] models: use slots for BaseModel
This restricts the attributes of a BaseModel instance to `env`, `_ids` and `_prefetch_ids`. This way, one can only assign fields on a record; other assignments are programming errors. This also reduces the memory footprint of records from 168 to 64 bytes (-62%), and makes their instanciation faster. closes odoo/odoo#51075 Related: odoo/enterprise#10529 Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
Diffstat (limited to 'odoo')
-rw-r--r--odoo/addons/base/models/qweb.py1
-rw-r--r--odoo/addons/base/models/res_config.py2
-rw-r--r--odoo/addons/test_new_api/tests/test_attributes.py19
-rw-r--r--odoo/models.py11
4 files changed, 15 insertions, 18 deletions
diff --git a/odoo/addons/base/models/qweb.py b/odoo/addons/base/models/qweb.py
index 464cb7a166e..6a099e810bc 100644
--- a/odoo/addons/base/models/qweb.py
+++ b/odoo/addons/base/models/qweb.py
@@ -234,6 +234,7 @@ class frozendict(dict):
class QWeb(object):
+ __slots__ = ()
_void_elements = frozenset([
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen',
diff --git a/odoo/addons/base/models/res_config.py b/odoo/addons/base/models/res_config.py
index a03a70a2ec6..1cba371e188 100644
--- a/odoo/addons/base/models/res_config.py
+++ b/odoo/addons/base/models/res_config.py
@@ -14,6 +14,8 @@ _logger = logging.getLogger(__name__)
class ResConfigModuleInstallationMixin(object):
+ __slots__ = ()
+
@api.model
def _install_modules(self, modules):
""" Install the requested modules.
diff --git a/odoo/addons/test_new_api/tests/test_attributes.py b/odoo/addons/test_new_api/tests/test_attributes.py
index 94a048f2554..27853d9a16e 100644
--- a/odoo/addons/test_new_api/tests/test_attributes.py
+++ b/odoo/addons/test_new_api/tests/test_attributes.py
@@ -1,25 +1,12 @@
# -*- coding: utf-8 -*-
from odoo.tests import common
-ANSWER_TO_ULTIMATE_QUESTION = 42
class TestAttributes(common.TransactionCase):
- def test_we_can_add_attributes(self):
+ def test_we_cannot_add_attributes(self):
Model = self.env['test_new_api.category']
instance = Model.create({'name': 'Foo'})
- # assign an unknown attribute
- instance.unknown = ANSWER_TO_ULTIMATE_QUESTION
-
- # Does the attribute exist in the instance of the model ?
- self.assertTrue(hasattr(instance, 'unknown'))
-
- # Is it the right type ?
- self.assertIsInstance(instance.unknown, int)
-
- # Is it the right value, in case of, we don't know ;-)
- self.assertEqual(instance.unknown, ANSWER_TO_ULTIMATE_QUESTION)
-
- # We are paranoiac !
- self.assertEqual(getattr(instance, 'unknown'), ANSWER_TO_ULTIMATE_QUESTION)
+ with self.assertRaises(AttributeError):
+ instance.unknown = 42
diff --git a/odoo/models.py b/odoo/models.py
index 43f477fb1c2..15758441afa 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -53,7 +53,7 @@ from . import api
from . import tools
from .exceptions import AccessError, MissingError, ValidationError, UserError
from .osv.query import Query
-from .tools import frozendict, lazy_classproperty, lazy_property, ormcache, \
+from .tools import frozendict, lazy_classproperty, ormcache, \
Collector, LastOrderedSet, OrderedSet, IterableGenerator, \
groupby, unique
from .tools.config import config
@@ -151,6 +151,10 @@ class MetaModel(api.Meta):
module_to_models = defaultdict(list)
+ def __new__(meta, name, bases, attrs):
+ attrs.setdefault('__slots__', ())
+ return super().__new__(meta, name, bases, attrs)
+
def __init__(self, name, bases, attrs):
if not self._register:
self._register = True
@@ -253,6 +257,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
To create a class that should not be instantiated,
the :attr:`~odoo.models.BaseModel._register` attribute may be set to False.
"""
+ __slots__ = ['env', '_ids', '_prefetch_ids']
_auto = False
"""Whether a database table should be created (default: ``True``).
@@ -5607,7 +5612,7 @@ Record ids: %(records)s
# Cache and recomputation management
#
- @lazy_property
+ @property
def _cache(self):
""" Return the cache of ``self``, mapping field names to values. """
return RecordCache(self)
@@ -6226,6 +6231,8 @@ collections.Sequence.register(BaseModel)
class RecordCache(MutableMapping):
""" A mapping from field names to values, to read and update the cache of a record. """
+ __slots__ = ['_record']
+
def __init__(self, record):
assert len(record) == 1, "Unexpected RecordCache(%s)" % record
self._record = record