changeset 65e6c8a59986 in trytond:default
details: https://hg.tryton.org/trytond?cmd=changeset&node=65e6c8a59986
description:
Include model, field and column in import data error message
issue11132
review381701002
diffstat:
CHANGELOG | 1 +
trytond/ir/message.xml | 11 +-
trytond/model/modelstorage.py | 210 +++++++-----
trytond/tests/import_data.py | 21 -
trytond/tests/test_importdata.py | 628 ++++++++++++++++----------------------
5 files changed, 393 insertions(+), 478 deletions(-)
diffs (1245 lines):
diff -r 3b5056ac4f06 -r 65e6c8a59986 CHANGELOG
--- a/CHANGELOG Sun Jan 30 01:42:23 2022 +0100
+++ b/CHANGELOG Sun Jan 30 12:58:51 2022 +0100
@@ -1,3 +1,4 @@
+* Include model, field and column in import data error message
* Support limit and offset to ModelSQL count search and search_count
* Apply view inheritance to board
* Add RPC view_get method to View
diff -r 3b5056ac4f06 -r 65e6c8a59986 trytond/ir/message.xml
--- a/trytond/ir/message.xml Sun Jan 30 01:42:23 2022 +0100
+++ b/trytond/ir/message.xml Sun Jan 30 12:58:51 2022 +0100
@@ -146,16 +146,19 @@
<field name="text">This record is part of the base
configuration.</field>
</record>
<record model="ir.message" id="msg_relation_not_found">
- <field name="text">Relation not found: "%(value)r" in
"%(model)s".</field>
+ <field name="text">Relation not found: %(value)r in "%(model)s"
(%(column)s).</field>
</record>
<record model="ir.message" id="msg_too_many_relations_found">
- <field name="text">Too many relations found: "%(value)r" in
"%(model)s".</field>
+ <field name="text">Too many relations found: %(value)r in
"%(model)s" (%(column)s).</field>
+ </record>
+ <record model="ir.message" id="msg_value_syntax_error">
+ <field name="text">Syntax error for value: %(value)r in
"%(field)s" of "%(model)s" (%(column)s).</field>
</record>
<record model="ir.message" id="msg_reference_syntax_error">
- <field name="text">Syntax error for reference: "%(value)r" in
"%(field)s".</field>
+ <field name="text">Syntax error for reference: %(value)r in
"%(field)s" of "%(model)s" (%(column)s).</field>
</record>
<record model="ir.message" id="msg_xml_id_syntax_error">
- <field name="text">Syntax error for XML id: "%(value)r" in
"%(field)s".</field>
+ <field name="text">Syntax error for XML id: %(value)r in
"%(field)s" of "%(model)s" (%(column)s).</field>
</record>
<record model="ir.message" id="msg_domain_validation_record">
<field name="text">The value for field "%(field)s" in "%(model)s"
is not valid according to its domain.</field>
diff -r 3b5056ac4f06 -r 65e6c8a59986 trytond/model/modelstorage.py
--- a/trytond/model/modelstorage.py Sun Jan 30 01:42:23 2022 +0100
+++ b/trytond/model/modelstorage.py Sun Jan 30 12:58:51 2022 +0100
@@ -4,6 +4,7 @@
import base64
import csv
import datetime
+import decimal
import random
import time
from collections import defaultdict
@@ -764,7 +765,7 @@
pool = Pool()
@lru_cache(maxsize=1000)
- def get_many2one(relation, value):
+ def get_many2one(relation, value, column):
if not value:
return None
Relation = pool.get(relation)
@@ -775,18 +776,19 @@
raise ImportDataError(gettext(
'ir.msg_relation_not_found',
value=value,
- model=relation))
+ **Relation.__names__()))
elif len(res) > 1:
raise ImportDataError(
gettext('ir.msg_too_many_relations_found',
value=value,
- model=relation))
+ column=column,
+ **Relation.__names__()))
else:
res = res[0].id
return res
@lru_cache(maxsize=1000)
- def get_many2many(relation, value):
+ def get_many2many(relation, value, column):
if not value:
return None
res = []
@@ -800,33 +802,36 @@
raise ImportDataError(
gettext('ir.msg_relation_not_found',
value=word,
- model=relation))
+ column=column,
+ **Relation.__names__()))
elif len(res2) > 1:
raise ImportDataError(
gettext('ir.msg_too_many_relations_found',
value=word,
- model=relation))
+ column=column,
+ **Relation.__names__()))
else:
res.extend(res2)
if len(res):
res = [('add', [x.id for x in res])]
return res
- def get_one2one(relation, value):
- return ('add', get_many2one(relation, value))
+ def get_one2one(relation, value, column):
+ return ('add', get_many2one(relation, value, column))
@lru_cache(maxsize=1000)
- def get_reference(value, field):
+ def get_reference(value, field, klass, column):
if not value:
return None
try:
relation, value = value.split(',', 1)
- except Exception:
+ Relation = pool.get(relation)
+ except (ValueError, KeyError) as e:
raise ImportDataError(
gettext('ir.msg_reference_syntax_error',
value=value,
- field=field))
- Relation = pool.get(relation)
+ column=column,
+ **klass.__names__(field))) from e
res = Relation.search([
('rec_name', '=', value),
], limit=2)
@@ -834,18 +839,19 @@
raise ImportDataError(gettext(
'ir.msg_relation_not_found',
value=value,
- model=relation))
+ **Relation.__names__()))
elif len(res) > 1:
raise ImportDataError(
gettext('ir.msg_too_many_relations_found',
value=value,
- model=relation))
+ column=column,
+ **Relation.__names__()))
else:
res = '%s,%s' % (relation, res[0].id)
return res
@lru_cache(maxsize=1000)
- def get_by_id(value, field, ftype):
+ def get_by_id(value, ftype, field, klass, column):
if not value:
return None
relation = None
@@ -855,11 +861,12 @@
elif ftype == 'reference':
try:
relation, value = value.split(',', 1)
- except Exception:
+ except ValueError as e:
raise ImportDataError(
gettext('ir.msg_reference_syntax_error',
value=value,
- field=field))
+ column=column,
+ **klass.__names__(field))) from e
value = [value]
else:
value = [value]
@@ -867,12 +874,13 @@
for word in value:
try:
module, xml_id = word.rsplit('.', 1)
- except Exception:
+ db_id = ModelData.get_id(module, xml_id)
+ except (ValueError, KeyError) as e:
raise ImportDataError(
gettext('ir.msg_xml_id_syntax_error',
value=word,
- field=field))
- db_id = ModelData.get_id(module, xml_id)
+ column=column,
+ **klass.__names__(field))) from e
res_ids.append(db_id)
if ftype == 'many2many' and res_ids:
return [('add', res_ids)]
@@ -889,6 +897,78 @@
create.append(row)
return id_
+ def convert(value, ftype, field, klass, column):
+ def convert_boolean(value):
+ if value.lower() == 'true':
+ return True
+ elif value.lower() == 'false':
+ return False
+ elif not value:
+ return False
+ else:
+ return bool(int(value))
+
+ def convert_integer(value):
+ if isinstance(value, int):
+ return value
+ elif value:
+ return int(value)
+
+ def convert_float(value):
+ if isinstance(value, float):
+ return value
+ elif value:
+ return float(value)
+
+ def convert_numeric(value):
+ if isinstance(value, Decimal):
+ return value
+ elif value:
+ return Decimal(value)
+
+ def convert_date(value):
+ if isinstance(value, datetime.date):
+ return value
+ elif value:
+ return datetime.datetime.strptime(value, '%Y-%m-%d').date()
+
+ def convert_datetime(value):
+ if isinstance(value, datetime.datetime):
+ return value
+ elif value:
+ return datetime.datetime.strptime(
+ value, '%Y-%m-%d %H:%M:%S')
+
+ def convert_timedelta(value):
+ if isinstance(value, datetime.timedelta):
+ return value
+ elif value:
+ try:
+ return float(value)
+ except ValueError:
+ hours, minutes, seconds = (
+ value.split(':') + ['00'])[:3]
+ return datetime.timedelta(
+ hours=int(hours), minutes=int(minutes),
+ seconds=float(seconds))
+
+ def convert_binary(value):
+ if not isinstance(value, bytes):
+ return base64.b64decode(value)
+ elif value:
+ return value
+
+ try:
+ return locals()['convert_%s' % ftype](value)
+ except KeyError:
+ return value
+ except (ValueError, TypeError, decimal.InvalidOperation) as e:
+ raise ImportDataError(
+ gettext('ir.msg_value_syntax_error',
+ value=value,
+ column=column,
+ **klass.__names__(field))) from e
+
def process_lines(data, prefix, fields_def, position=0, klass=cls):
line = data[position]
row = {}
@@ -903,95 +983,39 @@
% len(fields_names))
is_prefix_len = (len(field) == (prefix_len + 1))
value = line[i]
+ column = '/'.join(field)
if is_prefix_len and field[-1].endswith(':id'):
- ftype = fields_def[field[-1][:-3]]['type']
+ field_name = field[-1][:-3]
+ ftype = fields_def[field_name]['type']
row[field[0][:-3]] = get_by_id(
- value, '/'.join(field), ftype)
+ value, ftype, field_name, klass, column)
elif is_prefix_len and ':lang=' in field[-1]:
field_name, lang = field[-1].split(':lang=')
translate.setdefault(lang, {})[field_name] = value or False
elif is_prefix_len and prefix == field[:-1]:
- this_field_def = fields_def[field[-1]]
+ field_name = field[-1]
+ this_field_def = fields_def[field_name]
field_type = this_field_def['type']
res = None
- if field[-1] == 'id':
+ if field_name == 'id':
try:
res = int(value)
except ValueError:
- res = get_many2one(klass.__name__, value)
- elif field_type == 'boolean':
- if value.lower() == 'true':
- res = True
- elif value.lower() == 'false':
- res = False
- elif not value:
- res = False
- else:
- res = bool(int(value))
- elif field_type == 'integer':
- if isinstance(value, int):
- res = value
- elif value:
- res = int(value)
- else:
- res = None
- elif field_type == 'float':
- if isinstance(value, float):
- res = value
- elif value:
- res = float(value)
- else:
- res = None
- elif field_type == 'numeric':
- if isinstance(value, Decimal):
- res = value
- elif value:
- res = Decimal(value)
- else:
- res = None
- elif field_type == 'date':
- if isinstance(value, datetime.date):
- res = value
- elif value:
- res = datetime.datetime.strptime(
- value, '%Y-%m-%d').date()
- else:
- res = None
- elif field_type == 'datetime':
- if isinstance(value, datetime.datetime):
- res = value
- elif value:
- res = datetime.datetime.strptime(
- value, '%Y-%m-%d %H:%M:%S')
- else:
- res = None
- elif field_type == 'timedelta':
- if isinstance(value, datetime.timedelta):
- res = value
- elif value:
- try:
- res = float(value)
- except ValueError:
- hours, minutes, seconds = (
- value.split(':') + ['00'])[:3]
- res = datetime.timedelta(
- hours=int(hours), minutes=int(minutes),
- seconds=float(seconds))
- else:
- res = None
+ res = get_many2one(klass.__name__, value, column)
elif field_type == 'many2one':
- res = get_many2one(this_field_def['relation'], value)
+ res = get_many2one(
+ this_field_def['relation'], value, column)
elif field_type == 'many2many':
- res = get_many2many(this_field_def['relation'], value)
+ res = get_many2many(
+ this_field_def['relation'], value, column)
elif field_type == 'one2one':
- res = get_one2one(this_field_def['relation'], value)
+ res = get_one2one(
+ this_field_def['relation'], value, column)
elif field_type == 'reference':
- res = get_reference(value, '/'.join(field))
- elif (field_type == 'binary'
- and not isinstance(value, bytes)):
- res = base64.b64decode(value)
+ res = get_reference(value, field_name, klass, column)
else:
- res = value or None
+ res = convert(
+ value, field_type, field_name, klass, column)
row[field[-1]] = res
elif prefix == field[0:prefix_len]:
todo.add(field[prefix_len])
diff -r 3b5056ac4f06 -r 65e6c8a59986 trytond/tests/import_data.py
--- a/trytond/tests/import_data.py Sun Jan 30 01:42:23 2022 +0100
+++ b/trytond/tests/import_data.py Sun Jan 30 12:58:51 2022 +0100
@@ -17,36 +17,18 @@
integer = fields.Integer('Integer')
-class ImportDataIntegerRequired(ModelSQL):
- "Import Data Integer Required"
- __name__ = 'test.import_data.integer_required'
- integer = fields.Integer('Integer', required=True)
-
-
class ImportDataFloat(ModelSQL):
"Import Data Float"
__name__ = 'test.import_data.float'
float = fields.Float('Float')
-class ImportDataFloatRequired(ModelSQL):
- "Import Data Float Required"
- __name__ = 'test.import_data.float_required'
- float = fields.Float('Float', required=True)
-
-
class ImportDataNumeric(ModelSQL):
"Import Data Numeric"
__name__ = 'test.import_data.numeric'
numeric = fields.Numeric('Numeric')
-class ImportDataNumericRequired(ModelSQL):
- "Import Data Numeric Required"
- __name__ = 'test.import_data.numeric_required'
- numeric = fields.Numeric('Numeric', required=True)
-
-
class ImportDataChar(ModelSQL):
"Import Data Char"
__name__ = 'test.import_data.char'
@@ -166,11 +148,8 @@
Pool.register(
ImportDataBoolean,
ImportDataInteger,
- ImportDataIntegerRequired,
ImportDataFloat,
- ImportDataFloatRequired,
ImportDataNumeric,
- ImportDataNumericRequired,
ImportDataChar,
ImportDataText,
ImportDataDate,
diff -r 3b5056ac4f06 -r 65e6c8a59986 trytond/tests/test_importdata.py
--- a/trytond/tests/test_importdata.py Sun Jan 30 01:42:23 2022 +0100
+++ b/trytond/tests/test_importdata.py Sun Jan 30 12:58:51 2022 +0100
@@ -1,15 +1,13 @@
# -*- coding: utf-8 -*-
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
-import datetime
+import datetime as dt
import unittest
-from decimal import Decimal, InvalidOperation
+from decimal import Decimal
-from trytond.model.exceptions import (
- ImportDataError, RequiredValidationError, SelectionValidationError)
+from trytond.model.exceptions import ImportDataError
from trytond.pool import Pool
from trytond.tests.test_tryton import activate_module, with_transaction
-from trytond.transaction import Transaction
class ImportDataTestCase(unittest.TestCase):
@@ -25,26 +23,28 @@
pool = Pool()
Boolean = pool.get('test.import_data.boolean')
- self.assertEqual(Boolean.import_data(['boolean'],
- [['True']]), 1)
+ for value in ['True', '1', 'False', '0', '']:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Boolean.import_data(['boolean'], [[value]]), 1)
- self.assertEqual(Boolean.import_data(['boolean'],
- [['1']]), 1)
-
- self.assertEqual(Boolean.import_data(['boolean'],
- [['False']]), 1)
+ @with_transaction()
+ def test_boolean_many_rows(self):
+ "Test boolean many rows"
+ pool = Pool()
+ Boolean = pool.get('test.import_data.boolean')
- self.assertEqual(Boolean.import_data(['boolean'],
- [['0']]), 1)
-
- self.assertEqual(Boolean.import_data(['boolean'],
- [['']]), 1)
+ self.assertEqual(
+ Boolean.import_data(['boolean'], [['True'], ['False']]), 2)
- self.assertEqual(Boolean.import_data(['boolean'],
- [['True'], ['False']]), 2)
+ @with_transaction()
+ def test_boolean_invalid(self):
+ "Test boolean invalid value"
+ pool = Pool()
+ Boolean = pool.get('test.import_data.boolean')
- self.assertRaises(ValueError, Boolean.import_data,
- ['boolean'], [['foo']])
+ with self.assertRaises(ImportDataError):
+ Boolean.import_data(['boolean'], [['foo']])
@with_transaction()
def test_integer(self):
@@ -52,77 +52,30 @@
pool = Pool()
Integer = pool.get('test.import_data.integer')
- self.assertEqual(Integer.import_data(['integer'],
- [['1']]), 1)
-
- self.assertEqual(Integer.import_data(['integer'],
- [[0]]), 1)
-
- self.assertEqual(Integer.import_data(['integer'],
- [[1]]), 1)
-
- self.assertEqual(Integer.import_data(['integer'],
- [['-1']]), 1)
-
- self.assertEqual(Integer.import_data(['integer'],
- [['']]), 1)
-
- self.assertEqual(Integer.import_data(['integer'],
- [['1'], ['2']]), 2)
-
- self.assertRaises(ValueError, Integer.import_data,
- ['integer'], [['1.1']])
-
- self.assertRaises(ValueError, Integer.import_data,
- ['integer'], [['-1.1']])
-
- self.assertRaises(ValueError, Integer.import_data,
- ['integer'], [['foo']])
-
- self.assertEqual(Integer.import_data(['integer'],
- [['0']]), 1)
-
- self.assertEqual(Integer.import_data(['integer'],
- [[None]]), 1)
+ for value in ['1', '0', 0, 1, '-1', '', None]:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Integer.import_data(['integer'], [[value]]), 1)
@with_transaction()
- def test_integer_required(self):
- 'Test required integer'
+ def test_integer_many_rows(self):
+ "Test integer many rows"
pool = Pool()
- IntegerRequired = pool.get('test.import_data.integer_required')
- transaction = Transaction()
-
- self.assertEqual(IntegerRequired.import_data(['integer'],
- [['1']]), 1)
+ Integer = pool.get('test.import_data.integer')
- self.assertEqual(IntegerRequired.import_data(['integer'],
- [['-1']]), 1)
-
- with self.assertRaises(RequiredValidationError):
- IntegerRequired.import_data(['integer'], [['']])
- transaction.rollback()
-
- self.assertEqual(IntegerRequired.import_data(['integer'],
- [['1'], ['2']]), 2)
+ self.assertEqual(
+ Integer.import_data(['integer'], [['1'], ['2']]), 2)
- self.assertRaises(ValueError, IntegerRequired.import_data,
- ['integer'], [['1.1']])
-
- self.assertRaises(ValueError, IntegerRequired.import_data,
- ['integer'], [['-1.1']])
-
- self.assertRaises(ValueError, IntegerRequired.import_data,
- ['integer'], [['foo']])
+ @with_transaction()
+ def test_integer_invalid(self):
+ "Test integer invalid value"
+ pool = Pool()
+ Integer = pool.get('test.import_data.integer')
- self.assertEqual(IntegerRequired.import_data(['integer'],
- [['0']]), 1)
-
- self.assertEqual(IntegerRequired.import_data(['integer'],
- [[0]]), 1)
-
- with self.assertRaises(RequiredValidationError):
- IntegerRequired.import_data(['integer'], [[None]])
- transaction.rollback()
+ for value in ['1.1', '-1.1', 'foo']:
+ with self.subTest(value=value):
+ with self.assertRaises(ImportDataError):
+ Integer.import_data(['integer'], [[value]])
@with_transaction()
def test_float(self):
@@ -130,77 +83,20 @@
pool = Pool()
Float = pool.get('test.import_data.float')
- self.assertEqual(Float.import_data(['float'],
- [['1.1']]), 1)
-
- self.assertEqual(Float.import_data(['float'],
- [[0.0]]), 1)
-
- self.assertEqual(Float.import_data(['float'],
- [[1.1]]), 1)
-
- self.assertEqual(Float.import_data(['float'],
- [['-1.1']]), 1)
-
- self.assertEqual(Float.import_data(['float'],
- [['1']]), 1)
-
- self.assertEqual(Float.import_data(['float'],
- [['']]), 1)
-
- self.assertEqual(Float.import_data(['float'],
- [['1.1'], ['2.2']]), 2)
-
- self.assertRaises(ValueError, Float.import_data,
- ['float'], [['foo']])
-
- self.assertEqual(Float.import_data(['float'],
- [['0']]), 1)
-
- self.assertEqual(Float.import_data(['float'],
- [['0.0']]), 1)
-
- self.assertEqual(Float.import_data(['float'],
- [[None]]), 1)
+ for value in [
+ '1.1', 0.0, 1.1, '-1.1', '1', '', '1.1', '0', '0.0', None]:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Float.import_data(['float'], [[value]]), 1)
@with_transaction()
- def test_float_required(self):
- 'Test required float'
+ def test_float_invalid(self):
+ "Test float invalid value"
pool = Pool()
- FloatRequired = pool.get('test.import_data.float_required')
- transaction = Transaction()
-
- self.assertEqual(FloatRequired.import_data(['float'],
- [['1.1']]), 1)
-
- self.assertEqual(FloatRequired.import_data(['float'],
- [['-1.1']]), 1)
-
- self.assertEqual(FloatRequired.import_data(['float'],
- [['1']]), 1)
-
- with self.assertRaises(RequiredValidationError):
- FloatRequired.import_data(['float'], [['']])
- transaction.rollback()
+ Float = pool.get('test.import_data.float')
- self.assertEqual(FloatRequired.import_data(['float'],
- [['1.1'], ['2.2']]), 2)
-
- self.assertRaises(ValueError, FloatRequired.import_data,
- ['float'], [['foo']])
-
- self.assertEqual(FloatRequired.import_data(['float'],
- [['0']]), 1)
-
- self.assertEqual(FloatRequired.import_data(['float'],
- [['0.0']]), 1)
-
- self.assertEqual(FloatRequired.import_data(['float'],
- [[0.0]]), 1)
-
- with self.assertRaises(RequiredValidationError):
- FloatRequired.import_data(['float'], [[None]])
- transaction.rollback()
+ with self.assertRaises(ImportDataError):
+ Float.import_data(['float'], [['foo']])
@with_transaction()
def test_numeric(self):
@@ -208,77 +104,20 @@
pool = Pool()
Numeric = pool.get('test.import_data.numeric')
- self.assertEqual(Numeric.import_data(['numeric'],
- [['1.1']]), 1)
-
- self.assertEqual(Numeric.import_data(['numeric'],
- [[Decimal('0.0')]]), 1)
-
- self.assertEqual(Numeric.import_data(['numeric'],
- [[Decimal('1.1')]]), 1)
-
- self.assertEqual(Numeric.import_data(['numeric'],
- [['-1.1']]), 1)
-
- self.assertEqual(Numeric.import_data(['numeric'],
- [['1']]), 1)
-
- self.assertEqual(Numeric.import_data(['numeric'],
- [['']]), 1)
-
- self.assertEqual(Numeric.import_data(['numeric'],
- [['1.1'], ['2.2']]), 2)
-
- self.assertRaises(InvalidOperation, Numeric.import_data,
- ['numeric'], [['foo']])
-
- self.assertEqual(Numeric.import_data(['numeric'],
- [['0']]), 1)
-
- self.assertEqual(Numeric.import_data(['numeric'],
- [['0.0']]), 1)
-
- self.assertEqual(Numeric.import_data(['numeric'],
- [[None]]), 1)
+ for value in [
+ '1.1', Decimal('1.1'), '-1.1', '1',
+ Decimal('0.0'), '0', '0.0', '', None]:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Numeric.import_data(['numeric'], [[value]]), 1)
@with_transaction()
- def test_numeric_required(self):
- 'Test required numeric'
+ def test_numeric_invalid(self):
pool = Pool()
- NumericRequired = pool.get('test.import_data.numeric_required')
- transaction = Transaction()
-
- self.assertEqual(NumericRequired.import_data(['numeric'],
- [['1.1']]), 1)
-
- self.assertEqual(NumericRequired.import_data(['numeric'],
- [['-1.1']]), 1)
-
- self.assertEqual(NumericRequired.import_data(['numeric'],
- [['1']]), 1)
-
- with self.assertRaises(RequiredValidationError):
- NumericRequired.import_data(['numeric'], [['']])
- transaction.rollback()
+ Numeric = pool.get('test.import_data.numeric')
- self.assertEqual(NumericRequired.import_data(['numeric'],
- [['1.1'], ['2.2']]), 2)
-
- self.assertRaises(InvalidOperation,
- NumericRequired.import_data, ['numeric'], [['foo']])
-
- self.assertEqual(NumericRequired.import_data(['numeric'],
- [['0']]), 1)
-
- self.assertEqual(NumericRequired.import_data(['numeric'],
- [['0.0']]), 1)
-
- self.assertEqual(NumericRequired.import_data(['numeric'],
- [[Decimal('0.0')]]), 1)
-
- with self.assertRaises(RequiredValidationError):
- NumericRequired.import_data(['numeric'], [[None]])
- transaction.rollback()
+ with self.assertRaises(ImportDataError):
+ Numeric.import_data(['numeric'], [['foo']])
@with_transaction()
def test_char(self):
@@ -286,14 +125,19 @@
pool = Pool()
Char = pool.get('test.import_data.char')
- self.assertEqual(Char.import_data(['char'],
- [['test']]), 1)
+ for value in ['test', '']:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Char.import_data(['char'], [[value]]), 1)
- self.assertEqual(Char.import_data(['char'],
- [['']]), 1)
+ @with_transaction()
+ def test_char_many_rows(self):
+ "Test char many rows"
+ pool = Pool()
+ Char = pool.get('test.import_data.char')
- self.assertEqual(Char.import_data(['char'],
- [['test'], ['foo'], ['bar']]), 3)
+ self.assertEqual(
+ Char.import_data(['char'], [['test'], ['foo'], ['bar']]), 3)
@with_transaction()
def test_text(self):
@@ -301,14 +145,19 @@
pool = Pool()
Text = pool.get('test.import_data.text')
- self.assertEqual(Text.import_data(['text'],
- [['test']]), 1)
+ for value in ['test', '']:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Text.import_data(['text'], [[value]]), 1)
- self.assertEqual(Text.import_data(['text'],
- [['']]), 1)
+ @with_transaction()
+ def test_text_many_rows(self):
+ "Test text many rows"
+ pool = Pool()
+ Text = pool.get('test.import_data.text')
- self.assertEqual(Text.import_data(['text'],
- [['test'], ['foo'], ['bar']]), 3)
+ self.assertEqual(
+ Text.import_data(['text'], [['test'], ['foo'], ['bar']]), 3)
@with_transaction()
def test_date(self):
@@ -316,20 +165,28 @@
pool = Pool()
Date = pool.get('test.import_data.date')
- self.assertEqual(Date.import_data(['date'],
- [['2010-01-01']]), 1)
+ for value in ['2010-01-01', dt.date(2019, 3, 13), '']:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Date.import_data(['date'], [[value]]), 1)
- self.assertEqual(Date.import_data(['date'],
- [[datetime.date(2019, 3, 13)]]), 1)
+ @with_transaction()
+ def test_date_many_rows(self):
+ "Test date many rows"
+ pool = Pool()
+ Date = pool.get('test.import_data.date')
- self.assertEqual(Date.import_data(['date'],
- [['']]), 1)
+ self.assertEqual(
+ Date.import_data(['date'], [['2010-01-01'], ['2010-02-01']]), 2)
- self.assertEqual(Date.import_data(['date'],
- [['2010-01-01'], ['2010-02-01']]), 2)
+ @with_transaction()
+ def test_date_invalid(self):
+ "Test date invalid value"
+ pool = Pool()
+ Date = pool.get('test.import_data.date')
- self.assertRaises(ValueError, Date.import_data,
- ['date'], [['foo']])
+ with self.assertRaises(ImportDataError):
+ Date.import_data(['date'], [['foo']])
@with_transaction()
def test_datetime(self):
@@ -337,20 +194,31 @@
pool = Pool()
Datetime = pool.get('test.import_data.datetime')
- self.assertEqual(Datetime.import_data(['datetime'],
- [['2010-01-01 12:00:00']]), 1)
+ for value in [
+ '2010-01-01 12:00:00', dt.datetime(2019, 3, 13, 12, 0), '']:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Datetime.import_data(['datetime'], [[value]]), 1)
- self.assertEqual(Datetime.import_data(['datetime'],
- [[datetime.datetime(2019, 3, 13, 12, 0)]]), 1)
+ @with_transaction()
+ def test_datetime_many_rows(self):
+ "Test datetime many rows"
+ pool = Pool()
+ Datetime = pool.get('test.import_data.datetime')
- self.assertEqual(Datetime.import_data(['datetime'],
- [['']]), 1)
+ self.assertEqual(
+ Datetime.import_data(
+ ['datetime'], [
+ ['2010-01-01 12:00:00'], ['2010-01-01 13:30:00']]), 2)
- self.assertEqual(Datetime.import_data(['datetime'],
- [['2010-01-01 12:00:00'], ['2010-01-01 13:30:00']]), 2)
+ @with_transaction()
+ def test_datetime_invalid(self):
+ "Test datetime invalid value"
+ pool = Pool()
+ Datetime = pool.get('test.import_data.datetime')
- self.assertRaises(ValueError, Datetime.import_data,
- ['datetime'], [['foo']])
+ with self.assertRaises(ImportDataError):
+ Datetime.import_data(['datetime'], [['foo']])
@with_transaction()
def test_timedelta(self):
@@ -358,30 +226,23 @@
pool = Pool()
Timedelta = pool.get('test.import_data.timedelta')
- self.assertEqual(Timedelta.import_data(['timedelta'],
- [['00:00']]), 1)
-
- self.assertEqual(Timedelta.import_data(['timedelta'],
- [['0:00:00']]), 1)
-
- self.assertEqual(Timedelta.import_data(['timedelta'],
- [['01:00:00']]), 1)
-
- self.assertEqual(Timedelta.import_data(['timedelta'],
- [['36:00:00']]), 1)
+ for value in [
+ '00:00', '0:00:00', '01:00:00', '36:00:00', '0:00:00.0001',
+ dt.timedelta(
+ weeks=2, days=3, hours=8, minutes=50, seconds=30.45),
+ 30.45]:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Timedelta.import_data(['timedelta'], [[value]]), 1)
- self.assertEqual(Timedelta.import_data(['timedelta'],
- [['0:00:00.0001']]), 1)
+ @with_transaction()
+ def test_timedelta_invalid(self):
+ 'Test timedelta'
+ pool = Pool()
+ Timedelta = pool.get('test.import_data.timedelta')
- self.assertEqual(Timedelta.import_data(['timedelta'],
- [[datetime.timedelta(
- weeks=2, days=3, hours=8, minutes=50, seconds=30.45)]]), 1)
-
- self.assertEqual(Timedelta.import_data(['timedelta'],
- [[30.45]]), 1)
-
- self.assertRaises(ValueError, Timedelta.import_data,
- ['timedelta'], [['foo']])
+ with self.assertRaises(ImportDataError):
+ Timedelta.import_data(['timedelta'], [['foo']])
@with_transaction()
def test_selection(self):
@@ -389,100 +250,120 @@
pool = Pool()
Selection = pool.get('test.import_data.selection')
- self.assertEqual(Selection.import_data(['selection'],
- [['select1']]), 1)
-
- self.assertEqual(Selection.import_data(['selection'],
- [['']]), 1)
+ for value in ['select1', '']:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Selection.import_data(['selection'], [[value]]), 1)
- self.assertEqual(Selection.import_data(['selection'],
- [['select1'], ['select2']]), 2)
+ @with_transaction()
+ def test_selection_many_rows(self):
+ 'Test selection many rows'
+ pool = Pool()
+ Selection = pool.get('test.import_data.selection')
- with self.assertRaises(SelectionValidationError):
- Selection.import_data(['selection'], [['foo']])
+ self.assertEqual(
+ Selection.import_data(['selection'], [['select1'], ['select2']]),
+ 2)
@with_transaction()
def test_many2one(self):
'Test many2one'
pool = Pool()
Many2one = pool.get('test.import_data.many2one')
- transaction = Transaction()
- self.assertEqual(Many2one.import_data(['many2one'],
- [['Test']]), 1)
+ for value in ['Test', '']:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Many2one.import_data(['many2one'], [[value]]), 1)
- self.assertEqual(Many2one.import_data(['many2one:id'],
- [['tests.import_data_many2one_target_test']]), 1)
+ @with_transaction()
+ def test_many2one_id(self):
+ "Test many2one with id"
+ pool = Pool()
+ Many2one = pool.get('test.import_data.many2one')
- self.assertEqual(Many2one.import_data(['many2one'],
- [['']]), 1)
+ self.assertEqual(
+ Many2one.import_data(
+ ['many2one:id'], [['tests.import_data_many2one_target_test']]),
+ 1)
- self.assertEqual(Many2one.import_data(['many2one'],
- [['Test'], ['Test']]), 2)
+ @with_transaction()
+ def test_many2one_many_rows(self):
+ "Test many2one many rows"
+ pool = Pool()
+ Many2one = pool.get('test.import_data.many2one')
- with self.assertRaises(ImportDataError):
- Many2one.import_data(['many2one'], [['foo']])
- transaction.rollback()
+ self.assertEqual(
+ Many2one.import_data(['many2one'], [['Test'], ['Test']]), 2)
- with self.assertRaises(ImportDataError):
- Many2one.import_data(['many2one'], [['Duplicate']])
- transaction.rollback()
+ @with_transaction()
+ def test_many2one_invalid(self):
+ "Test many2one invalid value"
+ pool = Pool()
+ Many2one = pool.get('test.import_data.many2one')
- with self.assertRaises(ImportDataError):
- Many2one.import_data(['many2one:id'], [['foo']])
- transaction.rollback()
+ for value in ['foo', 'Duplicate']:
+ with self.subTest(value=value):
+ with self.assertRaises(ImportDataError):
+ Many2one.import_data(['many2one'], [[value]])
- with self.assertRaises(KeyError):
- Many2one.import_data(['many2one:id'], [['tests.foo']])
- transaction.rollback()
+ @with_transaction()
+ def test_many2one_id_invalid(self):
+ "Test many2one invalid id"
+ pool = Pool()
+ Many2one = pool.get('test.import_data.many2one')
+
+ for value in ['foo', 'tests.foo']:
+ with self.subTest(value=value):
+ with self.assertRaises(ImportDataError):
+ Many2one.import_data(['many2one:id'], [[value]])
@with_transaction()
def test_many2many(self):
'Test many2many'
pool = Pool()
Many2many = pool.get('test.import_data.many2many')
- transaction = Transaction()
-
- self.assertEqual(Many2many.import_data(['many2many'],
- [['Test 1']]), 1)
-
- self.assertEqual(Many2many.import_data(['many2many:id'],
- [['tests.import_data_many2many_target_test1']]), 1)
- self.assertEqual(Many2many.import_data(['many2many'],
- [['Test 1,Test 2']]), 1)
+ for value in [
+ 'Test 1', 'Test\\, comma', 'Test\\, comma,Test 1',
+ 'Test 1,Test 2', '']:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Many2many.import_data(['many2many'], [[value]]), 1)
- self.assertEqual(Many2many.import_data(['many2many:id'],
- [['tests.import_data_many2many_target_test1,'
- 'tests.import_data_many2many_target_test2']]), 1)
-
- self.assertEqual(Many2many.import_data(['many2many'],
- [['Test\\, comma']]), 1)
-
- self.assertEqual(Many2many.import_data(['many2many'],
- [['Test\\, comma,Test 1']]), 1)
+ @with_transaction()
+ def test_many2many_id(self):
+ "Test many2many with id"
+ pool = Pool()
+ Many2many = pool.get('test.import_data.many2many')
- self.assertEqual(Many2many.import_data(['many2many'],
- [['']]), 1)
+ for value in [
+ 'tests.import_data_many2many_target_test1',
+ 'tests.import_data_many2many_target_test1,'
+ 'tests.import_data_many2many_target_test2']:
+ with self.subTest(value=value):
+ self.assertEqual(
+ Many2many.import_data(['many2many:id'], [[value]]), 1)
- self.assertEqual(Many2many.import_data(['many2many'],
- [['Test 1'], ['Test 2']]), 2)
-
- with self.assertRaises(ImportDataError):
- Many2many.import_data(['many2many'], [['foo']])
- transaction.rollback()
+ @with_transaction()
+ def test_many2many_many_rows(self):
+ "Test many2many many rows"
+ pool = Pool()
+ Many2many = pool.get('test.import_data.many2many')
- with self.assertRaises(ImportDataError):
- Many2many.import_data(['many2many'], [['Test 1,foo']])
- transaction.rollback()
+ self.assertEqual(
+ Many2many.import_data(['many2many'], [['Test 1'], ['Test 2']]), 2)
- with self.assertRaises(ImportDataError):
- Many2many.import_data(['many2many'], [['Duplicate']])
- transaction.rollback()
+ @with_transaction()
+ def test_many2many_invalid(self):
+ "Test many2many invalid value"
+ pool = Pool()
+ Many2many = pool.get('test.import_data.many2many')
- with self.assertRaises(ImportDataError):
- Many2many.import_data(['many2many'], [['Test 1,Duplicate']])
- transaction.rollback()
+ for value in ['foo', 'Test 1,foo', 'Duplicate', 'Test 1,Duplicate']:
+ with self.subTest(value=value):
+ with self.assertRaises(ImportDataError):
+ Many2many.import_data(['many2many'], [[value]])
@with_transaction()
def test_one2many(self):
@@ -493,10 +374,22 @@
self.assertEqual(One2many.import_data(
['name', 'one2many/name'], [['Test', 'Test 1']]), 1)
+ @with_transaction()
+ def test_one2many_many_targets(self):
+ "Test one2many with many targets"
+ pool = Pool()
+ One2many = pool.get('test.import_data.one2many')
+
self.assertEqual(One2many.import_data(
['name', 'one2many/name'],
[['Test', 'Test 1'], ['', 'Test 2']]), 1)
+ @with_transaction()
+ def test_one2many_many_rows(self):
+ "Test one2many many rows"
+ pool = Pool()
+ One2many = pool.get('test.import_data.one2many')
+
self.assertEqual(One2many.import_data(
['name', 'one2many/name'],
[
@@ -509,14 +402,18 @@
'Test reference'
pool = Pool()
Reference = pool.get('test.import_data.reference')
- transaction = Transaction()
self.assertEqual(Reference.import_data(['reference'],
[['test.import_data.reference.selection,Test']]), 1)
reference, = Reference.search([])
self.assertEqual(reference.reference.__name__,
'test.import_data.reference.selection')
- transaction.rollback()
+
+ @with_transaction()
+ def test_reference_id(self):
+ "Test reference with id"
+ pool = Pool()
+ Reference = pool.get('test.import_data.reference')
self.assertEqual(Reference.import_data(['reference:id'],
[['test.import_data.reference.selection,'
@@ -524,13 +421,23 @@
reference, = Reference.search([])
self.assertEqual(reference.reference.__name__,
'test.import_data.reference.selection')
- transaction.rollback()
+
+ @with_transaction()
+ def test_reference_empty(self):
+ "Test reference empty"
+ pool = Pool()
+ Reference = pool.get('test.import_data.reference')
self.assertEqual(Reference.import_data(['reference'],
[['']]), 1)
reference, = Reference.search([])
self.assertEqual(reference.reference, None)
- transaction.rollback()
+
+ @with_transaction()
+ def test_reference_many_rows(self):
+ "Test reference many rows"
+ pool = Pool()
+ Reference = pool.get('test.import_data.reference')
self.assertEqual(Reference.import_data(['reference'],
[['test.import_data.reference.selection,Test'],
@@ -538,30 +445,31 @@
for reference in Reference.search([]):
self.assertEqual(reference.reference.__name__,
'test.import_data.reference.selection')
- transaction.rollback()
+
+ @with_transaction()
+ def test_reference_invalid(self):
+ "Test reference invalid value"
+ pool = Pool()
+ Reference = pool.get('test.import_data.reference')
- with self.assertRaises(ImportDataError):
- Reference.import_data(
- ['reference'], [['test.import_data.reference.selection,foo']])
- transaction.rollback()
+ for value in [
+ 'test.import_data.reference.selection,foo',
+ 'test.import_data.reference.selection,Duplicate',
+ 'test.import_data.reference.selection,test.foo']:
+ with self.subTest(value=value):
+ with self.assertRaises(ImportDataError):
+ Reference.import_data(['reference'], [[value]])
- with self.assertRaises(ImportDataError):
- Reference.import_data(
- ['reference'],
- [['test.import_data.reference.selection,Duplicate']])
- transaction.rollback()
+ @with_transaction()
+ def test_reference_id_invalid(self):
+ "Test reference invalid id"
+ pool = Pool()
+ Reference = pool.get('test.import_data.reference')
with self.assertRaises(ImportDataError):
Reference.import_data(
['reference:id'],
[['test.import_data.reference.selection,foo']])
- transaction.rollback()
-
- with self.assertRaises(KeyError):
- Reference.import_data(
- ['reference:id'],
- [['test.import_data.reference.selection,test.foo']])
- transaction.rollback()
@with_transaction()
def test_binary_bytes(self):