diff --git a/odoo/addons/base/models/ir_fields.py b/odoo/addons/base/models/ir_fields.py index 80f3ce31513..8dc639b2ee1 100644 --- a/odoo/addons/base/models/ir_fields.py +++ b/odoo/addons/base/models/ir_fields.py @@ -24,7 +24,6 @@ class ImportWarning(Warning): class ConversionNotFound(ValueError): pass - class IrFieldsConverter(models.AbstractModel): _name = 'ir.fields.converter' _description = 'Fields Converter' @@ -113,6 +112,8 @@ class IrFieldsConverter(models.AbstractModel): # uniform handling w = ImportWarning(w) log(field, w) + except (UnicodeEncodeError, UnicodeDecodeError) as e: + log(field, ValueError(str(e))) except ValueError as e: if import_file_context: # if the error is linked to a matching error, the error is a tuple diff --git a/odoo/addons/test_impex/ir.model.access.csv b/odoo/addons/test_impex/ir.model.access.csv index e051b726705..a901be2bf30 100644 --- a/odoo/addons/test_impex/ir.model.access.csv +++ b/odoo/addons/test_impex/ir.model.access.csv @@ -26,3 +26,5 @@ access_export_one2many_recursive,access_export_one2many_recursive,model_export_o access_export_unique,access_export_unique,model_export_unique,,1,1,1,1 access_export_inherits_parent,access_export_inherits_parent,model_export_inherits_parent,,1,1,1,1 access_export_inherits_child,access_export_inherits_child,model_export_inherits_child,,1,1,1,1 +access_export_m2o_str,access_export_m2o_str,model_export_m2o_str,,1,1,1,1 +access_export_m2o_str_child,access_export_m2o_str_child,model_export_m2o_str_child,,1,1,1,1 diff --git a/odoo/addons/test_impex/models.py b/odoo/addons/test_impex/models.py index 685cec9b80e..9a2fdf40392 100644 --- a/odoo/addons/test_impex/models.py +++ b/odoo/addons/test_impex/models.py @@ -174,3 +174,13 @@ class InheritsChild(models.Model): parent_id = fields.Many2one('export.inherits.parent', required=True, ondelete='cascade') value = fields.Integer() + +class Many2String(models.Model): + _name = _description = 'export.m2o.str' + + child_id = fields.Many2one('export.m2o.str.child') + +class ChidToString(models.Model): + _name = _description = 'export.m2o.str.child' + + name = fields.Char() diff --git a/odoo/addons/test_impex/tests/test_load.py b/odoo/addons/test_impex/tests/test_load.py index bc989799532..daf53f2b4e2 100644 --- a/odoo/addons/test_impex/tests/test_load.py +++ b/odoo/addons/test_impex/tests/test_load.py @@ -737,6 +737,20 @@ class test_m2o(ImporterCase): self.assertFalse(result['messages']) self.assertEqual(len(result['ids']), 1) +class TestInvalidStrings(ImporterCase): + model_name = 'export.m2o.str' + + @mute_logger('odoo.sql_db') + def test_fail_unpaired_surrogate(self): + result = self.import_(['child_id'], [['\uddff']]) + self.assertTrue(result['messages']) + self.assertIn('surrogates', result['messages'][0]['message']) + + @mute_logger('odoo.sql_db') + def test_fail_nul(self): + result = self.import_(['child_id'], [['\x00']]) + self.assertTrue(result['messages']) + self.assertIn('NUL', result['messages'][0]['message']) class test_m2m(ImporterCase): model_name = 'export.many2many' diff --git a/odoo/models.py b/odoo/models.py index 06bb0698f28..a920d1f192b 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -1312,13 +1312,14 @@ class BaseModel(metaclass=MetaModel): exc_vals = dict(base, record=record, field=field_name) record = dict(base, type=type, record=record, field=field, message=str(exception.args[0]) % exc_vals) - # ensure to add field_name to the exception. Used in import to concatenate multiple errors in the same block if len(exception.args) > 1: - if not exception.args[1]: - exception.args = (exception.args[0], {'field_name': field_name}) - else: - exception.args[1]['field_name'] = field_name - record.update(exception.args[1]) + info = {} + if exception.args[1] and isinstance(exception.args[1], dict): + info = exception.args[1] + # ensure field_name is added to the exception. Used in import to + # concatenate multiple errors in the same block + info['field_name'] = field_name + record.update(info) log(record) stream = CountingStream(records)