diff --git a/addons/base_automation/models/base_automation.py b/addons/base_automation/models/base_automation.py index 717b220273c..dafc746de29 100644 --- a/addons/base_automation/models/base_automation.py +++ b/addons/base_automation/models/base_automation.py @@ -498,7 +498,9 @@ class BaseAutomation(models.Model): """ Patch method `name` on `model`, unless it has been patched already. """ if model not in patched_models[name]: patched_models[name].add(model) - model._patch_method(name, method) + ModelClass = type(model) + method.origin = getattr(ModelClass, name) + setattr(ModelClass, name, method) # retrieve all actions, and patch their corresponding model for action_rule in self.with_context({}).search([]): diff --git a/addons/product/tests/test_variants.py b/addons/product/tests/test_variants.py index 095e9eebe78..0096a7d61c9 100644 --- a/addons/product/tests/test_variants.py +++ b/addons/product/tests/test_variants.py @@ -833,7 +833,7 @@ class TestVariantsArchive(ProductVariantsCommon): def unlink(self): raise Exception('just') - Product._patch_method('unlink', unlink) + self.patch(type(Product), 'unlink', unlink) variants_2x1 = self.template.product_variant_ids self._assert_2color_x_1size() @@ -855,8 +855,6 @@ class TestVariantsArchive(ProductVariantsCommon): archived_variants = self._get_archived_variants() self.assertFalse(archived_variants) - Product._revert_method('unlink') - def test_02_update_variant_archive_2_value(self): """We do the same operations on the template as in the previous tests, except we simulate that the variants can't be unlinked. @@ -868,7 +866,7 @@ class TestVariantsArchive(ProductVariantsCommon): def unlink(slef): raise Exception('just') - Product._patch_method('unlink', unlink) + self.patch(type(Product), 'unlink', unlink) variants_2x2 = self.template.product_variant_ids self._assert_2color_x_2size() @@ -924,8 +922,6 @@ class TestVariantsArchive(ProductVariantsCommon): self.assertEqual(archived_variants, variants_2x2) self._assert_2color_x_2size(archived_variants) - Product._revert_method('unlink') - @mute_logger('odoo.models.unlink') def test_03_update_variant_archive_3_value(self): self._remove_ptal_size() @@ -935,7 +931,7 @@ class TestVariantsArchive(ProductVariantsCommon): def unlink(slef): raise Exception('just') - Product._patch_method('unlink', unlink) + self.patch(type(Product), 'unlink', unlink) self._assert_2color_x_1size() archived_variants = self._get_archived_variants() @@ -983,14 +979,12 @@ class TestVariantsArchive(ProductVariantsCommon): archived_variants = self._get_archived_variants() self.assertEqual(archived_variants, variants_2x1 + variant_0x0) - Product._revert_method('unlink') - def test_04_from_to_single_values(self): Product = self.env['product.product'] def unlink(slef): raise Exception('just') - Product._patch_method('unlink', unlink) + self.patch(type(Product), 'unlink', unlink) # CASE: remove one value, line becoming single value variants_2x2 = self.template.product_variant_ids @@ -1027,8 +1021,6 @@ class TestVariantsArchive(ProductVariantsCommon): self._assert_2color_x_0size(archived_variants) self.assertEqual(archived_variants, variants_2x0) - Product._revert_method('unlink') - def test_name_search_dynamic_attributes(self): dynamic_attr = self.env['product.attribute'].create({ 'name': 'Dynamic', @@ -1079,7 +1071,7 @@ class TestVariantsArchive(ProductVariantsCommon): # Patch unlink method to force archiving instead deleting def unlink(self): self.active = False - Product._patch_method('unlink', unlink) + self.patch(type(Product), 'unlink', unlink) # Creating attributes pa_color = ProductAttribute.create({'sequence': 1, 'name': 'color', 'create_variant': 'dynamic'}) @@ -1184,8 +1176,6 @@ class TestVariantsArchive(ProductVariantsCommon): }) self.assertTrue(product_white.active) - Product._revert_method('unlink') - def test_set_barcode(self): tmpl = self.product.product_tmpl_id tmpl.barcode = '123' diff --git a/addons/test_mail/tests/test_mail_mail.py b/addons/test_mail/tests/test_mail_mail.py index b002fab7d01..19473e7b668 100644 --- a/addons/test_mail/tests/test_mail_mail.py +++ b/addons/test_mail/tests/test_mail_mail.py @@ -779,7 +779,8 @@ class TestMailMailRace(common.TransactionCase): # In practice, the update will wait the end of the send() transaction and set the notif as bounce, as expeced cr.execute("UPDATE mail_notification SET notification_status='bounce' WHERE id = %s", [notif.id]) return message['Message-Id'] - self.env['ir.mail_server']._patch_method('send_email', send_email) + + self.patch(self.registry['ir.mail_server'], 'send_email', send_email) mail.send() @@ -787,7 +788,6 @@ class TestMailMailRace(common.TransactionCase): self.assertEqual(notif.notification_status, 'sent') # some cleaning since we commited the cr - self.env['ir.mail_server']._revert_method('send_email') notif.unlink() mail.unlink() diff --git a/addons/test_mail/tests/test_message_track.py b/addons/test_mail/tests/test_message_track.py index 4aea07103f6..d0aa4ac0b52 100644 --- a/addons/test_mail/tests/test_message_track.py +++ b/addons/test_mail/tests/test_message_track.py @@ -222,14 +222,14 @@ class TestTracking(TestMailCommon): if 'name' in init_values and init_values['name'] == magic_code: return 'mail.mt_name_changed' return False - self.registry('mail.test.container')._patch_method('_track_subtype', _track_subtype) + self.patch(self.registry('mail.test.container'), '_track_subtype', _track_subtype) def _track_template(self, changes): res = {} if 'name' in changes: res['name'] = (mail_template, {'composition_mode': 'mass_mail'}) return res - self.registry('mail.test.container')._patch_method('_track_template', _track_template) + self.patch(self.registry('mail.test.container'), '_track_template', _track_template) cls = type(self.env['mail.test.container']) self.assertFalse(hasattr(getattr(cls, 'name'), 'track_visibility')) diff --git a/odoo/models.py b/odoo/models.py index b008e94eef5..e6d0daee6a7 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -3827,7 +3827,6 @@ class BaseModel(metaclass=MetaModel): parent_records._parent_store_update() @api.model_create_multi - @api.returns('self', lambda value: value.id) def create(self, vals_list): """ create(vals_list) -> records @@ -5008,44 +5007,6 @@ class BaseModel(metaclass=MetaModel): def _unregister_hook(self): """ Clean up what `~._register_hook` has done. """ - @classmethod - def _patch_method(cls, name, method): - """ Monkey-patch a method for all instances of this model. This replaces - the method called ``name`` by ``method`` in the given class. - The original method is then accessible via ``method.origin``, and it - can be restored with :meth:`~._revert_method`. - - Example:: - - def do_write(self, values): - # do stuff, and call the original method - return do_write.origin(self, values) - - # patch method write of model - model._patch_method('write', do_write) - - # this will call do_write - records = model.search([...]) - records.write(...) - - # restore the original method - model._revert_method('write') - """ - origin = getattr(cls, name) - method.origin = origin - # propagate decorators from origin to method, and apply api decorator - wrapped = api.propagate(origin, method) - wrapped.origin = origin - setattr(cls, name, wrapped) - - @classmethod - def _revert_method(cls, name): - """ Revert the original method called ``name`` in the given class. - See :meth:`~._patch_method`. - """ - method = getattr(cls, name) - setattr(cls, name, method.origin) - # # Instance creation #