[FIX] core: apply post-constraints only if necessary
This is a followup of commit bc2bb5e03c2b32d4ee1b0597ea5889c17d2b0e0e When a module is updated, a constraint application may (temporarily) fail because the existing data does not respect the constraint, this is OK and can be fixed through hooks/migration scripts and was handled by the aforementioned commit. However when updating multiple modules, it is possible that an inheriting module will try to re-apply the failed constraint and succeed, if that is the case, when processing the `post_constraints` an already-existing constraint will be applied and raise an error. To fix this, a check is made before trying to apply the constraint, to verify that it is not already in _constraint_queue, if it is not, then we may attempt to apply it, if it is in the queue, then we may safely ignore it as it will be applied further down the registry cycle. closes odoo/odoo#55725 X-original-commit: 5225b9ce5178302af05b63029fb184e27b781815 Signed-off-by: Adrian Torres (adt) <adt@odoo.com>
This commit is contained in:
@@ -333,20 +333,27 @@ class Registry(Mapping):
|
||||
def post_constraint(self, func, *args, **kwargs):
|
||||
""" Call the given function, and delay it if it fails during an upgrade. """
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
if (func, args, kwargs) not in self._constraint_queue:
|
||||
# Module A may try to apply a constraint and fail but another module B inheriting
|
||||
# from Module A may try to reapply the same constraint and succeed, however the
|
||||
# constraint would already be in the _constraint_queue and would be executed again
|
||||
# at the end of the registry cycle, this would fail (already-existing constraint)
|
||||
# and generate an error, therefore a constraint should only be applied if it's
|
||||
# not already marked as "to be applied".
|
||||
func(*args, **kwargs)
|
||||
except Exception as e:
|
||||
if self._is_install:
|
||||
_schema.error(*e.args)
|
||||
else:
|
||||
_schema.info(*e.args)
|
||||
self._constraint_queue.append(partial(func, *args, **kwargs))
|
||||
self._constraint_queue.append((func, args, kwargs))
|
||||
|
||||
def finalize_constraints(self):
|
||||
""" Call the delayed functions from above. """
|
||||
while self._constraint_queue:
|
||||
func = self._constraint_queue.popleft()
|
||||
func, args, kwargs = self._constraint_queue.popleft()
|
||||
try:
|
||||
func()
|
||||
func(*args, **kwargs)
|
||||
except Exception as e:
|
||||
_schema.error(*e.args)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user