[MERGE] convert BaseModel and expression to the new API

This commit is contained in:
Raphael Collet
2016-06-16 16:53:22 +02:00
18 changed files with 1700 additions and 2826 deletions
+1 -1
View File
@@ -363,7 +363,7 @@ class AccountAssetAsset(models.Model):
if default is None:
default = {}
default['name'] = self.name + _(' (copy)')
return super(AccountAssetAsset, self).copy_data(default)[0]
return super(AccountAssetAsset, self).copy_data(default)
@api.multi
def _compute_entries(self, date, group_entries=False):
+1 -1
View File
@@ -501,7 +501,7 @@ class ir_import(orm.TransientModel):
def _convert_import_data(self, record, fields, options, context=None):
""" Extracts the input browse_record and fields list (with
``False``-y placeholders for fields to *not* import) into a
format Model.import_data can use: a fields list without holes
format Model.load can use: a fields list without holes
and the precisely matching data matrix
:param browse_record record:
+1 -1
View File
@@ -358,7 +358,7 @@ class test_preview(TransactionCase):
class test_convert_import_data(TransactionCase):
""" Tests conversion of base_import.import input into data which
can be fed to Model.import_data
can be fed to Model.load
"""
def test_all(self):
Import = self.registry('base_import.import')
+4 -3
View File
@@ -65,11 +65,12 @@ class Users(models.Model):
self.env['mail.channel'].search([('group_ids', 'in', user_group_ids)])._subscribe_users()
return write_res
def copy_data(self, *args, **kwargs):
data = super(Users, self).copy_data(*args, **kwargs)
@api.multi
def copy_data(self, default=None):
data = super(Users, self).copy_data(default)[0]
if data and data.get('alias_name'):
data['alias_name'] = data['login']
return data
return [data]
def _create_welcome_message(self):
self.ensure_one()
+2 -2
View File
@@ -316,12 +316,12 @@ class ResConfigInstaller(models.TransientModel, ResConfigModuleInstallationMixin
return dict(defaults, **dict.fromkeys(self.already_installed(), True))
@api.model
def fields_get(self, fields=None, write_access=True, attributes=None):
def fields_get(self, fields=None, attributes=None):
""" If an addon is already installed, set it to readonly as
res.config.installer doesn't handle uninstallations of already
installed addons
"""
fields = super(ResConfigInstaller, self).fields_get(fields, write_access=write_access, attributes=attributes)
fields = super(ResConfigInstaller, self).fields_get(fields, attributes=attributes)
for name in self.already_installed():
if name not in fields:
+2 -2
View File
@@ -876,8 +876,8 @@ class UsersView(models.Model):
values[f] = selected and selected[-1] or False
@api.model
def fields_get(self, allfields=None, write_access=True, attributes=None):
res = super(UsersView, self).fields_get(allfields=allfields, write_access=write_access, attributes=attributes)
def fields_get(self, allfields=None, attributes=None):
res = super(UsersView, self).fields_get(allfields, attributes=attributes)
# add reified groups fields
if not self.env.user._is_admin():
return res
+16
View File
@@ -400,6 +400,10 @@ class TestPartnerRecursion(TransactionCase):
self.p2 = res_partner.create({'name': 'Elmtree Child 1', 'parent_id': self.p1.id})
self.p3 = res_partner.create({'name': 'Elmtree Grand-Child 1.1', 'parent_id': self.p2.id})
def test_100_res_partner_recursion(self):
self.assertTrue(self.p3._check_recursion())
self.assertTrue((self.p1 + self.p2 + self.p3)._check_recursion())
# split 101, 102, 103 tests to force SQL rollback between them
def test_101_res_partner_recursion(self):
@@ -511,3 +515,15 @@ class TestGroups(TransactionCase):
groups = all_groups.search([('full_name', 'in', ['Administration / Access Rights','Contact Creation'])])
self.assertTrue(groups, "did not match search for 'Administration / Access Rights' and 'Contact Creation'")
def test_res_group_recursion(self):
# four groups with no cycle, check them all together
a = self.env['res.groups'].create({'name': 'A'})
b = self.env['res.groups'].create({'name': 'B'})
c = self.env['res.groups'].create({'name': 'G', 'implied_ids': [(6, 0, (a + b).ids)]})
d = self.env['res.groups'].create({'name': 'D', 'implied_ids': [(6, 0, c.ids)]})
self.assertTrue((a + b + c + d)._check_m2m_recursion('implied_ids'))
# create a cycle and check
a.implied_ids = d
self.assertFalse(a._check_m2m_recursion('implied_ids'))
+1 -1
View File
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
from . import test_export, test_import, test_load
from . import test_export, test_load
@@ -1,877 +0,0 @@
# -*- coding: utf-8 -*-
import openerp.modules.registry
import openerp
from openerp.tests import common
from openerp.tools.misc import mute_logger
def ok(n):
""" Successful import of ``n`` records
:param int n: number of records which should have been imported
"""
return n, 0, 0, 0
def error(row, message, record=None, **kwargs):
""" Failed import of the record ``record`` at line ``row``, with the error
message ``message``
:param str message:
:param dict record:
"""
return (
-1, dict(record or {}, **kwargs),
"Line %d : %s" % (row, message),
'')
def values(seq, field='value'):
return [item[field] for item in seq]
class ImporterCase(common.TransactionCase):
model_name = False
def __init__(self, *args, **kwargs):
super(ImporterCase, self).__init__(*args, **kwargs)
self.model = None
def setUp(self):
super(ImporterCase, self).setUp()
self.model = self.registry(self.model_name)
def import_(self, fields, rows, context=None):
return self.model.import_data(
self.cr, openerp.SUPERUSER_ID, fields, rows, context=context)
def read(self, fields=('value',), domain=(), context=None):
return self.model.read(
self.cr, openerp.SUPERUSER_ID,
self.model.search(self.cr, openerp.SUPERUSER_ID, domain, context=context),
fields=fields, context=context)
def browse(self, domain=(), context=None):
return self.model.browse(
self.cr, openerp.SUPERUSER_ID,
self.model.search(self.cr, openerp.SUPERUSER_ID, domain, context=context),
context=context)
def xid(self, record):
ModelData = self.registry('ir.model.data')
ids = ModelData.search(
self.cr, openerp.SUPERUSER_ID,
[('model', '=', record._name), ('res_id', '=', record.id)])
if ids:
d = ModelData.read(
self.cr, openerp.SUPERUSER_ID, ids, ['name', 'module'])[0]
if d['module']:
return '%s.%s' % (d['module'], d['name'])
return d['name']
name = record.name_get()[0][1]
# fix dotted name_get results, otherwise xid lookups blow up
name = name.replace('.', '-')
ModelData.create(self.cr, openerp.SUPERUSER_ID, {
'name': name,
'model': record._name,
'res_id': record.id,
'module': '__test__'
})
return '__test__.' + name
class test_ids_stuff(ImporterCase):
model_name = 'export.integer'
def test_create_with_id(self):
self.assertEqual(
self.import_(['.id', 'value'], [['42', '36']]),
error(1, u"Unknown database identifier '42'"))
def test_create_with_xid(self):
self.assertEqual(
self.import_(['id', 'value'], [['somexmlid', '42']]),
ok(1))
self.assertEqual(
'somexmlid',
self.xid(self.browse()[0]))
def test_update_with_id(self):
id = self.model.create(self.cr, openerp.SUPERUSER_ID, {'value': 36})
self.assertEqual(
36,
self.model.browse(self.cr, openerp.SUPERUSER_ID, id).value)
self.assertEqual(
self.import_(['.id', 'value'], [[str(id), '42']]),
ok(1))
self.assertEqual(
[42], # updated value to imported
values(self.read()))
def test_update_with_xid(self):
self.import_(['id', 'value'], [['somexmlid', '36']])
self.assertEqual([36], values(self.read()))
self.import_(['id', 'value'], [['somexmlid', '1234567']])
self.assertEqual([1234567], values(self.read()))
def test_wrong_format(self):
self.assertEqual(
self.import_(['value'], [['50%']]),
error(1, u"'50%' does not seem to be an integer for field 'unknown'"))
class test_boolean_field(ImporterCase):
model_name = 'export.boolean'
def test_empty(self):
self.assertEqual(
self.import_(['value'], []),
ok(0))
def test_exported(self):
self.assertEqual(
self.import_(['value'], [
['False'],
['True'],
]),
ok(2))
records = self.read()
self.assertEqual([
False,
True,
], values(records))
def test_falses(self):
self.assertEqual(
self.import_(['value'], [
[u'0'],
[u'no'],
[u'false'],
[u'FALSE'],
[u''],
]),
ok(5))
self.assertEqual([
False,
False,
False,
False,
False,
],
values(self.read()))
def test_trues(self):
self.assertEqual(
self.import_(['value'], [
['off'],
['None'],
['nil'],
['()'],
['f'],
['#f'],
# Problem: OpenOffice (and probably excel) output localized booleans
['VRAI'],
[u'OFF'],
[u'是的'],
['!&%#${}'],
['%(field)s'],
]),
ok(11))
self.assertEqual(
[True] * 11,
values(self.read()))
class test_integer_field(ImporterCase):
model_name = 'export.integer'
def test_none(self):
self.assertEqual(
self.import_(['value'], []),
ok(0))
def test_empty(self):
self.assertEqual(
self.import_(['value'], [['']]),
ok(1))
self.assertEqual(
[False],
values(self.read()))
def test_zero(self):
self.assertEqual(
self.import_(['value'], [['0']]),
ok(1))
self.assertEqual(
self.import_(['value'], [['-0']]),
ok(1))
self.assertEqual([False, False], values(self.read()))
def test_positives(self):
self.assertEqual(
self.import_(['value'], [
['1'],
['42'],
[str(2**31-1)],
['12345678']
]),
ok(4))
self.assertEqual([
1, 42, 2**31-1, 12345678
], values(self.read()))
def test_negatives(self):
self.assertEqual(
self.import_(['value'], [
['-1'],
['-42'],
[str(-(2**31 - 1))],
[str(-(2**31))],
['-12345678']
]),
ok(5))
self.assertEqual([
-1, -42, -(2**31 - 1), -(2**31), -12345678
], values(self.read()))
@mute_logger('openerp.sql_db')
def test_out_of_range(self):
self.assertEqual(
self.import_(['value'], [[str(2**31)]]),
error(1, "integer out of range\n"))
# auto-rollbacks if error is in process_liness, but not during
# ir.model.data write. Can differentiate because former ends lines
# error lines with "!"
self.cr.rollback()
self.assertEqual(
self.import_(['value'], [[str(-2**32)]]),
error(1, "integer out of range\n"))
def test_nonsense(self):
self.assertEqual(
self.import_(['value'], [['zorglub']]),
error(1, u"'zorglub' does not seem to be an integer for field 'unknown'"))
class test_float_field(ImporterCase):
model_name = 'export.float'
def test_none(self):
self.assertEqual(
self.import_(['value'], []),
ok(0))
def test_empty(self):
self.assertEqual(
self.import_(['value'], [['']]),
ok(1))
self.assertEqual(
[False],
values(self.read()))
def test_zero(self):
self.assertEqual(
self.import_(['value'], [['0']]),
ok(1))
self.assertEqual(
self.import_(['value'], [['-0']]),
ok(1))
self.assertEqual([False, False], values(self.read()))
def test_positives(self):
self.assertEqual(
self.import_(['value'], [
['1'],
['42'],
[str(2**31-1)],
['12345678'],
[str(2**33)],
['0.000001'],
]),
ok(6))
self.assertEqual([
1, 42, 2**31-1, 12345678, 2.0**33, .000001
], values(self.read()))
def test_negatives(self):
self.assertEqual(
self.import_(['value'], [
['-1'],
['-42'],
[str(-2**31 + 1)],
[str(-2**31)],
['-12345678'],
[str(-2**33)],
['-0.000001'],
]),
ok(7))
self.assertEqual([
-1, -42, -(2**31 - 1), -(2**31), -12345678, -2.0**33, -.000001
], values(self.read()))
def test_nonsense(self):
self.assertEqual(
self.import_(['value'], [['foobar']]),
error(1, u"'foobar' does not seem to be a number for field 'unknown'"))
class test_string_field(ImporterCase):
model_name = 'export.string.bounded'
def test_empty(self):
self.assertEqual(
self.import_(['value'], [['']]),
ok(1))
self.assertEqual([False], values(self.read()))
def test_imported(self):
self.assertEqual(
self.import_(['value'], [
[u'foobar'],
[u'foobarbaz'],
[u'Með suð í eyrum við spilum endalaust'],
[u"People 'get' types. They use them all the time. Telling "
u"someone he can't pound a nail with a banana doesn't much "
u"surprise him."]
]),
ok(4))
self.assertEqual([
u"foobar",
u"foobarbaz",
u"Með suð í eyrum ",
u"People 'get' typ",
], values(self.read()))
class test_unbound_string_field(ImporterCase):
model_name = 'export.string'
def test_imported(self):
self.assertEqual(
self.import_(['value'], [
[u'í dag viðrar vel til loftárása'],
# ackbar.jpg
[u"If they ask you about fun, you tell them – fun is a filthy"
u" parasite"]
]),
ok(2))
self.assertEqual([
u"í dag viðrar vel til loftárása",
u"If they ask you about fun, you tell them – fun is a filthy parasite"
], values(self.read()))
class test_text(ImporterCase):
model_name = 'export.text'
def test_empty(self):
self.assertEqual(
self.import_(['value'], [['']]),
ok(1))
self.assertEqual([False], values(self.read()))
def test_imported(self):
s = (u"Breiðskífa er notað um útgefna hljómplötu sem inniheldur "
u"stúdíóupptökur frá einum flytjanda. Breiðskífur eru oftast "
u"milli 25-80 mínútur og er lengd þeirra oft miðuð við 33⅓ "
u"snúninga 12 tommu vínylplötur (sem geta verið allt að 30 mín "
u"hvor hlið).\n\nBreiðskífur eru stundum tvöfaldar og eru þær þá"
u" gefnar út á tveimur geisladiskum eða tveimur vínylplötum.")
self.assertEqual(
self.import_(['value'], [[s]]),
ok(1))
self.assertEqual([s], values(self.read()))
class test_selection(ImporterCase):
model_name = 'export.selection'
translations_fr = [
("Qux", "toto"),
("Bar", "titi"),
("Foo", "tete"),
]
def test_imported(self):
self.assertEqual(
self.import_(['value'], [
['Qux'],
['Bar'],
['Foo'],
['2'],
]),
ok(4))
self.assertEqual([3, 2, 1, 2], values(self.read()))
def test_imported_translated(self):
self.registry('res.lang').load_lang(self.cr, openerp.SUPERUSER_ID, 'fr_FR')
Translations = self.registry('ir.translation')
for source, value in self.translations_fr:
Translations.create(self.cr, openerp.SUPERUSER_ID, {
'name': 'export.selection,value',
'lang': 'fr_FR',
'type': 'selection',
'src': source,
'value': value
})
self.assertEqual(
self.import_(['value'], [
['toto'],
['tete'],
['titi'],
], context={'lang': 'fr_FR'}),
ok(3))
self.assertEqual([3, 1, 2], values(self.read()))
self.assertEqual(
self.import_(['value'], [['Foo']], context={'lang': 'fr_FR'}),
ok(1))
def test_invalid(self):
self.assertEqual(
self.import_(['value'], [['Baz']]),
error(1, u"Value 'Baz' not found in selection field 'unknown'"))
self.cr.rollback()
self.assertEqual(
self.import_(['value'], [[42]]),
error(1, u"Value '42' not found in selection field 'unknown'"))
class test_selection_function(ImporterCase):
model_name = 'export.selection.function'
translations_fr = [
("Corge", "toto"),
("Grault", "titi"),
("Wheee", "tete"),
("Moog", "tutu"),
]
def test_imported(self):
""" import uses fields_get, so translates import label (may or may not
be good news) *and* serializes the selection function to reverse it:
import does not actually know that the selection field uses a function
"""
# NOTE: conflict between a value and a label => ?
self.assertEqual(
self.import_(['value'], [
['3'],
["Grault"],
]),
ok(2))
self.assertEqual(
[3, 1],
values(self.read()))
def test_translated(self):
""" Expects output of selection function returns translated labels
"""
self.registry('res.lang').load_lang(self.cr, openerp.SUPERUSER_ID, 'fr_FR')
Translations = self.registry('ir.translation')
for source, value in self.translations_fr:
Translations.create(self.cr, openerp.SUPERUSER_ID, {
'name': 'export.selection,value',
'lang': 'fr_FR',
'type': 'selection',
'src': source,
'value': value
})
self.assertEqual(
self.import_(['value'], [
['toto'],
['tete'],
], context={'lang': 'fr_FR'}),
ok(2))
self.assertEqual(
self.import_(['value'], [['Wheee']], context={'lang': 'fr_FR'}),
ok(1))
class test_m2o(ImporterCase):
model_name = 'export.many2one'
def test_by_name(self):
# create integer objects
integer_id1 = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
integer_id2 = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 36})
# get its name
name1 = dict(self.registry('export.integer').name_get(
self.cr, openerp.SUPERUSER_ID,[integer_id1]))[integer_id1]
name2 = dict(self.registry('export.integer').name_get(
self.cr, openerp.SUPERUSER_ID,[integer_id2]))[integer_id2]
self.assertEqual(
self.import_(['value'], [
# import by name_get
[name1],
[name1],
[name2],
]),
ok(3))
# correct ids assigned to corresponding records
self.assertEqual([
(integer_id1, name1),
(integer_id1, name1),
(integer_id2, name2),],
values(self.read()))
def test_by_xid(self):
ExportInteger = self.registry('export.integer')
integer_id = ExportInteger.create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
xid = self.xid(ExportInteger.browse(
self.cr, openerp.SUPERUSER_ID, [integer_id])[0])
self.assertEqual(
self.import_(['value/id'], [[xid]]),
ok(1))
b = self.browse()
self.assertEqual(42, b[0].value.value)
def test_by_id(self):
integer_id = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
self.assertEqual(
self.import_(['value/.id'], [[integer_id]]),
ok(1))
b = self.browse()
self.assertEqual(42, b[0].value.value)
def test_by_names(self):
integer_id1 = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
integer_id2 = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
name1 = dict(self.registry('export.integer').name_get(
self.cr, openerp.SUPERUSER_ID,[integer_id1]))[integer_id1]
name2 = dict(self.registry('export.integer').name_get(
self.cr, openerp.SUPERUSER_ID,[integer_id2]))[integer_id2]
# names should be the same
self.assertEqual(name1, name2)
self.assertEqual(
self.import_(['value'], [[name2]]),
ok(1))
self.assertEqual([
(integer_id1, name1)
], values(self.read()))
def test_fail_by_implicit_id(self):
""" Can't implicitly import records by id
"""
# create integer objects
integer_id1 = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 42})
integer_id2 = self.registry('export.integer').create(
self.cr, openerp.SUPERUSER_ID, {'value': 36})
self.assertEqual(
self.import_(['value'], [
# import by id, without specifying it
[integer_id1],
[integer_id2],
[integer_id1],
]),
error(1, u"No matching record found for name '%s' in field 'unknown'" % integer_id1))
def test_sub_field(self):
""" Does not implicitly create the record, does not warn that you can't
import m2o subfields (at all)...
"""
self.assertEqual(
self.import_(['value/value'], [['42']]),
error(1, u"Can not create Many-To-One records indirectly, import the field separately"))
def test_fail_noids(self):
self.assertEqual(
self.import_(['value'], [['nameisnoexist:3']]),
error(1, u"No matching record found for name 'nameisnoexist:3' in field 'unknown'"))
self.cr.rollback()
self.assertEqual(
self.import_(['value/id'], [['noxidhere']]),
error(1, u"No matching record found for external id 'noxidhere' in field 'unknown'"))
self.cr.rollback()
self.assertEqual(
self.import_(['value/.id'], [[66]]),
error(1, u"No matching record found for database id '66' in field 'unknown'"))
class test_m2m(ImporterCase):
model_name = 'export.many2many'
# apparently, one and only thing which works is a
# csv_internal_sep-separated list of ids, xids, or names (depending if
# m2m/.id, m2m/id or m2m[/anythingelse]
def test_ids(self):
id1 = self.registry('export.many2many.other').create(
self.cr, openerp.SUPERUSER_ID, {'value': 3, 'str': 'record0'})
id2 = self.registry('export.many2many.other').create(
self.cr, openerp.SUPERUSER_ID, {'value': 44, 'str': 'record1'})
id3 = self.registry('export.many2many.other').create(
self.cr, openerp.SUPERUSER_ID, {'value': 84, 'str': 'record2'})
id4 = self.registry('export.many2many.other').create(
self.cr, openerp.SUPERUSER_ID, {'value': 9, 'str': 'record3'})
id5 = self.registry('export.many2many.other').create(
self.cr, openerp.SUPERUSER_ID, {'value': 99, 'str': 'record4'})
self.assertEqual(
self.import_(['value/.id'], [
['%d,%d' % (id1, id2)],
['%d,%d,%d' % (id1, id3, id4)],
['%d,%d,%d' % (id1, id2, id3)],
['%d' % id5]
]),
ok(4))
ids = lambda records: [record.id for record in records]
b = self.browse()
self.assertEqual(ids(b[0].value), [id1, id2])
self.assertEqual(values(b[0].value), [3, 44])
self.assertEqual(ids(b[2].value), [id1, id2, id3])
self.assertEqual(values(b[2].value), [3, 44, 84])
def test_noids(self):
self.assertEqual(
self.import_(['value/.id'], [['42']]),
error(1, u"No matching record found for database id '42' in field 'unknown'"))
def test_xids(self):
M2O_o = self.registry('export.many2many.other')
id1 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 3, 'str': 'record0'})
id2 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 44, 'str': 'record1'})
id3 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 84, 'str': 'record2'})
id4 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 9, 'str': 'record3'})
records = M2O_o.browse(self.cr, openerp.SUPERUSER_ID, [id1, id2, id3, id4])
self.assertEqual(
self.import_(['value/id'], [
['%s,%s' % (self.xid(records[0]), self.xid(records[1]))],
['%s' % self.xid(records[3])],
['%s,%s' % (self.xid(records[2]), self.xid(records[1]))],
]),
ok(3))
b = self.browse()
self.assertEqual(values(b[0].value), [3, 44])
self.assertEqual(values(b[2].value), [44, 84])
def test_noxids(self):
self.assertEqual(
self.import_(['value/id'], [['noxidforthat']]),
error(1, u"No matching record found for external id 'noxidforthat' in field 'unknown'"))
def test_names(self):
M2O_o = self.registry('export.many2many.other')
id1 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 3, 'str': 'record0'})
id2 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 44, 'str': 'record1'})
id3 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 84, 'str': 'record2'})
id4 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 9, 'str': 'record3'})
records = M2O_o.browse(self.cr, openerp.SUPERUSER_ID, [id1, id2, id3, id4])
name = lambda record: record.name_get()[0][1]
self.assertEqual(
self.import_(['value'], [
['%s,%s' % (name(records[1]), name(records[2]))],
['%s,%s,%s' % (name(records[0]), name(records[1]), name(records[2]))],
['%s,%s' % (name(records[0]), name(records[3]))],
]),
ok(3))
b = self.browse()
self.assertEqual(values(b[1].value), [3, 44, 84])
self.assertEqual(values(b[2].value), [3, 9])
def test_nonames(self):
self.assertEqual(
self.import_(['value'], [['wherethem2mhavenonames']]),
error(1, u"No matching record found for name 'wherethem2mhavenonames' in field 'unknown'"))
def test_import_to_existing(self):
M2O_o = self.registry('export.many2many.other')
id1 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 3, 'str': 'record0'})
id2 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 44, 'str': 'record1'})
id3 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 84, 'str': 'record2'})
id4 = M2O_o.create(self.cr, openerp.SUPERUSER_ID, {'value': 9, 'str': 'record3'})
xid = 'myxid'
self.assertEqual(
self.import_(['id', 'value/.id'], [[xid, '%d,%d' % (id1, id2)]]),
ok(1))
self.assertEqual(
self.import_(['id', 'value/.id'], [[xid, '%d,%d' % (id3, id4)]]),
ok(1))
b = self.browse()
self.assertEqual(len(b), 1)
# TODO: replacement of existing m2m values is correct?
self.assertEqual(values(b[0].value), [84, 9])
class test_o2m(ImporterCase):
model_name = 'export.one2many'
def test_name_get(self):
s = u'Java is a DSL for taking large XML files and converting them to' \
u' stack traces'
self.assertEqual(
self.import_(
['const', 'value'],
[['5', s]]),
error(1, u"No matching record found for name '%s' in field 'unknown'" % s))
def test_single(self):
self.assertEqual(
self.import_(['const', 'value/value'], [
['5', '63']
]),
ok(1))
(b,) = self.browse()
self.assertEqual(b.const, 5)
self.assertEqual(values(b.value), [63])
def test_multicore(self):
self.assertEqual(
self.import_(['const', 'value/value'], [
['5', '63'],
['6', '64'],
]),
ok(2))
b1, b2 = self.browse()
self.assertEqual(b1.const, 5)
self.assertEqual(values(b1.value), [63])
self.assertEqual(b2.const, 6)
self.assertEqual(values(b2.value), [64])
def test_multisub(self):
self.assertEqual(
self.import_(['const', 'value/value'], [
['5', '63'],
['', '64'],
['', '65'],
['', '66'],
]),
ok(4))
(b,) = self.browse()
self.assertEqual(values(b.value), [63, 64, 65, 66])
def test_multi_subfields(self):
self.assertEqual(
self.import_(['value/str', 'const', 'value/value'], [
['this', '5', '63'],
['is', '', '64'],
['the', '', '65'],
['rhythm', '', '66'],
]),
ok(4))
(b,) = self.browse()
self.assertEqual(values(b.value), [63, 64, 65, 66])
self.assertEqual(
values(b.value, 'str'),
'this is the rhythm'.split())
def test_link_inline(self):
id1 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Bf', 'value': 109
})
id2 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Me', 'value': 262
})
try:
self.import_(['const', 'value/.id'], [
['42', '%d,%d' % (id1, id2)]
])
except ValueError, e:
# should be Exception(Database ID doesn't exist: export.one2many.child : $id1,$id2)
self.assertIs(type(e), ValueError)
self.assertEqual(
e.args[0],
"invalid literal for int() with base 10: '%d,%d'" % (id1, id2))
def test_link(self):
id1 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Bf', 'value': 109
})
id2 = self.registry('export.one2many.child').create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Me', 'value': 262
})
self.assertEqual(
self.import_(['const', 'value/.id'], [
['42', str(id1)],
['', str(id2)],
]),
ok(2))
[b] = self.browse()
self.assertEqual(b.const, 42)
# automatically forces link between core record and o2ms
self.assertEqual(values(b.value), [109, 262])
self.assertEqual(values(b.value, field='parent_id'), [b, b])
def test_link_2(self):
O2M_c = self.registry('export.one2many.child')
id1 = O2M_c.create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Bf', 'value': 109
})
id2 = O2M_c.create(self.cr, openerp.SUPERUSER_ID, {
'str': 'Me', 'value': 262
})
self.assertEqual(
self.import_(['const', 'value/.id', 'value/value'], [
['42', str(id1), '1'],
['', str(id2), '2'],
]),
ok(2))
[b] = self.browse()
self.assertEqual(b.const, 42)
self.assertEqual(values(b.value), [1, 2])
self.assertEqual(values(b.value, field='parent_id'), [b, b])
class test_o2m_multiple(ImporterCase):
model_name = 'export.one2many.multiple'
def test_multi_mixed(self):
self.assertEqual(
self.import_(['const', 'child1/value', 'child2/value'], [
['5', '11', '21'],
['', '12', '22'],
['', '13', '23'],
['', '14', ''],
]),
ok(4))
[b] = self.browse()
self.assertEqual(values(b.child1), [11, 12, 13, 14])
self.assertEqual(values(b.child2), [21, 22, 23])
def test_multi(self):
self.assertEqual(
self.import_(['const', 'child1/value', 'child2/value'], [
['5', '11', '21'],
['', '12', ''],
['', '13', ''],
['', '14', ''],
['', '', '22'],
['', '', '23'],
]),
ok(6))
[b] = self.browse()
self.assertEqual(values(b.child1), [11, 12, 13, 14])
self.assertEqual(values(b.child2), [21, 22, 23])
def test_multi_fullsplit(self):
self.assertEqual(
self.import_(['const', 'child1/value', 'child2/value'], [
['5', '11', ''],
['', '12', ''],
['', '13', ''],
['', '14', ''],
['', '', '21'],
['', '', '22'],
['', '', '23'],
]),
ok(7))
[b] = self.browse()
self.assertEqual(b.const, 5)
self.assertEqual(values(b.child1), [11, 12, 13, 14])
self.assertEqual(values(b.child2), [21, 22, 23])
# function, related, reference: written to db as-is...
# => function uses @type for value coercion/conversion
+4
View File
@@ -248,6 +248,10 @@ class MixedModel(models.Model):
lang = fields.Selection(string='Language', selection='_get_lang')
reference = fields.Reference(string='Related Document',
selection='_reference_models')
comment1 = fields.Html(sanitize=False)
comment2 = fields.Html(sanitize=True, strip_classes=False)
comment3 = fields.Html(sanitize=True, strip_classes=True)
comment4 = fields.Html(sanitize=True, strip_style=True)
@api.one
def _compute_now(self):
@@ -125,15 +125,15 @@ class TestHtmlField(common.TransactionCase):
def setUp(self):
super(TestHtmlField, self).setUp()
self.partner = self.registry('res.partner')
self.model = self.env['test_new_api.mixed']
def test_00_sanitize(self):
cr, uid, context = self.cr, self.uid, {}
old_columns = self.partner._columns
self.partner._columns = dict(old_columns)
self.partner._columns.update({
'comment': fields.html('Secure Html', sanitize=False),
})
self.assertEqual(self.model._fields['comment1'].sanitize, False)
self.assertEqual(self.model._fields['comment2'].sanitize, True)
self.assertEqual(self.model._fields['comment2'].strip_classes, False)
self.assertEqual(self.model._fields['comment3'].sanitize, True)
self.assertEqual(self.model._fields['comment3'].strip_classes, True)
some_ugly_html = """<p>Oops this should maybe be sanitized
% if object.some_field and not object.oriented:
<table>
@@ -151,40 +151,22 @@ class TestHtmlField(common.TransactionCase):
<p>Youpie</p>
%endif"""
pid = self.partner.create(cr, uid, {
'name': 'Raoul Poilvache',
'comment': some_ugly_html,
}, context=context)
partner = self.partner.browse(cr, uid, pid, context=context)
self.assertEqual(partner.comment, some_ugly_html, 'Error in HTML field: content was sanitized but field has sanitize=False')
self.partner._columns.update({
'comment': fields.html('Unsecure Html', sanitize=True, strip_classes=False),
record = self.model.create({
'comment1': some_ugly_html,
'comment2': some_ugly_html,
'comment3': some_ugly_html,
'comment4': some_ugly_html,
})
self.partner.write(cr, uid, [pid], {
'comment': some_ugly_html,
}, context=context)
partner = self.partner.browse(cr, uid, pid, context=context)
# classes are kept
self.assertIn('<tr class="', partner.comment)
self.partner._columns.update({
'comment': fields.html('Unsecure Html', sanitize=True, strip_classes=True),
})
self.partner.write(cr, uid, [pid], {
'comment': some_ugly_html,
}, context=context)
partner = self.partner.browse(cr, uid, pid, context=context)
self.assertEqual(record.comment1, some_ugly_html, 'Error in HTML field: content was sanitized but field has sanitize=False')
self.assertIn('<tr class="', record.comment2)
# sanitize should have closed tags left open in the original html
self.assertIn('</table>', partner.comment, 'Error in HTML field: content does not seem to have been sanitized despise sanitize=True')
self.assertIn('</td>', partner.comment, 'Error in HTML field: content does not seem to have been sanitized despise sanitize=True')
self.assertIn('<tr style="', partner.comment, 'Style attr should not have been stripped')
self.assertIn('</table>', record.comment3, 'Error in HTML field: content does not seem to have been sanitized despise sanitize=True')
self.assertIn('</td>', record.comment3, 'Error in HTML field: content does not seem to have been sanitized despise sanitize=True')
self.assertIn('<tr style="', record.comment3, 'Style attr should not have been stripped')
# sanitize does not keep classes if asked to
self.assertNotIn('<tr class="', partner.comment)
self.assertNotIn('<tr class="', record.comment3)
self.partner._columns['comment'] = fields.html('Stripped Html', sanitize=True, strip_style=True)
self.partner.write(cr, uid, [pid], {'comment': some_ugly_html}, context=context)
partner = self.partner.browse(cr, uid, pid, context=context)
self.assertNotIn('<tr style="', partner.comment, 'Style attr should have been stripped')
self.partner._columns = old_columns
self.assertNotIn('<tr style="', record.comment4, 'Style attr should have been stripped')
+22 -11
View File
@@ -45,11 +45,9 @@ __all__ = [
]
import logging
import operator
from inspect import currentframe, getargspec
from collections import defaultdict, MutableMapping
from collections import defaultdict, Mapping
from contextlib import contextmanager
from inspect import currentframe, getargspec
from pprint import pformat
from weakref import WeakSet
from werkzeug.local import Local, release_local
@@ -293,10 +291,10 @@ def get_upgrade(method):
return upgrade
elif model == 'self':
return lambda self, *args, **kwargs: self.browse(args[0])
else:
elif model:
return lambda self, *args, **kwargs: self.env[model].browse(args[0])
else:
return lambda self, *args, **kwargs: args[0]
return lambda self, *args, **kwargs: args[0]
def get_aggregate(method):
@@ -309,10 +307,10 @@ def get_aggregate(method):
model, _, _ = spec
if model == 'self':
return lambda self, value: sum(value, self.browse())
else:
elif model:
return lambda self, value: sum(value, self.env[model].browse())
else:
return lambda self, value: value
return lambda self, value: value
def get_context_split(method):
@@ -813,7 +811,7 @@ def expected(decorator, func):
class Environment(object):
class Environment(Mapping):
""" An environment wraps data for ORM records:
- :attr:`cr`, the current database cursor;
@@ -871,6 +869,10 @@ class Environment(object):
envs.add(self)
return self
#
# Mapping methods
#
def __contains__(self, model_name):
""" Test whether the given model exists. """
return model_name in self.registry
@@ -887,6 +889,15 @@ class Environment(object):
""" Return the size of the model registry. """
return len(self.registry)
def __eq__(self, other):
return self is other
def __ne__(self, other):
return self is not other
def __hash__(self):
return object.__hash__(self)
def __call__(self, cr=None, user=None, context=None):
""" Return an environment based on ``self`` with modified parameters.
+1550 -1792
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -357,7 +357,7 @@ def init_models(models, cr, context):
model._auto_end()
cr.commit()
for _, func, args in sorted(context['todo'], key=itemgetter(0)):
func(cr, *args)
func(*args)
if models:
models[0].recompute()
cr.commit()
+64 -69
View File
@@ -423,7 +423,6 @@ def select_from_where(cr, select_field, from_table, where_field, where_ids, wher
res.extend([r[0] for r in cr.fetchall()])
return res
def select_distinct_from_where_not_null(cr, select_field, from_table):
cr.execute('SELECT distinct("%s") FROM "%s" where "%s" is not null' % (select_field, from_table, select_field))
return [r[0] for r in cr.fetchall()]
@@ -611,6 +610,7 @@ def create_substitution_leaf(leaf, new_elements, new_model=None, internal=False)
new_leaf = ExtendedLeaf(new_elements, new_model, join_context=new_join_context, internal=internal)
return new_leaf
class expression(object):
""" Parse a domain expression
Use a real polish notation
@@ -618,12 +618,12 @@ class expression(object):
For more info: http://christophe-simonis-at-tiny.blogspot.com/2008/08/new-new-domain-notation.html
"""
def __init__(self, cr, uid, exp, table, context):
def __init__(self, domain, model):
""" Initialize expression object and automatically parse the expression
right after initialization.
:param exp: expression (using domain ('foo', '=', 'bar' format))
:param table: root model
:param domain: expression (using domain ('foo', '=', 'bar' format))
:param model: root model
:attr list result: list that will hold the result of the parsing
as a list of ExtendedLeaf
@@ -633,15 +633,15 @@ class expression(object):
:attr list expression: the domain expression, that will be normalized
and prepared
"""
self._unaccent = get_unaccent_wrapper(cr)
self._unaccent = get_unaccent_wrapper(model._cr)
self.joins = []
self.root_model = table
self.root_model = model
# normalize and prepare the expression for parsing
self.expression = distribute_not(normalize_domain(exp))
self.expression = distribute_not(normalize_domain(domain))
# parse the domain expression
self.parse(cr, uid, context=context)
self.parse()
# ----------------------------------------
# Leafs management
@@ -663,7 +663,7 @@ class expression(object):
# Parsing
# ----------------------------------------
def parse(self, cr, uid, context):
def parse(self):
""" Transform the leaves of the expression
The principle is to pop elements from a leaf stack one at a time.
@@ -685,8 +685,9 @@ class expression(object):
:var obj comodel: relational model of field (field.comodel)
(res_partner.bank_ids -> res.partner.bank)
"""
cr, uid, context = self.root_model.env.args
def to_ids(value, comodel, context=None, limit=None):
def to_ids(value, comodel):
""" Normalize a single id or name, or a list of those, into a list of ids
:param {int,long,basestring,list,tuple} value:
if int, long -> return [value]
@@ -703,11 +704,14 @@ class expression(object):
elif isinstance(value, (int, long)):
return [value]
if names:
name_get_list = [name_get[0] for name in names for name_get in comodel.name_search(cr, uid, name, [], 'ilike', context=context, limit=limit)]
return list(set(name_get_list))
return list({
rid
for name in names
for rid, rname in comodel.name_search(name, [], 'ilike', limit=None)
})
return list(value)
def child_of_domain(left, ids, left_model, parent=None, prefix='', context=None):
def child_of_domain(left, ids, left_model, parent=None, prefix=''):
""" Return a domain implementing the child_of operator for [(left,child_of,ids)],
either as a range using the parent_left/right tree lookup fields
(when available), or as an expanded [(left,in,child_ids)] """
@@ -715,46 +719,43 @@ class expression(object):
return FALSE_DOMAIN
if left_model._parent_store and (not left_model.pool._init):
# TODO: Improve where joins are implemented for many with '.', replace by:
# doms += ['&',(prefix+'.parent_left','<',o.parent_right),(prefix+'.parent_left','>=',o.parent_left)]
# doms += ['&',(prefix+'.parent_left','<',rec.parent_right),(prefix+'.parent_left','>=',rec.parent_left)]
doms = []
for o in left_model.browse(cr, uid, ids, context=context):
for rec in left_model.browse(ids):
if doms:
doms.insert(0, OR_OPERATOR)
doms += [AND_OPERATOR, ('parent_left', '<', o.parent_right), ('parent_left', '>=', o.parent_left)]
doms += [AND_OPERATOR, ('parent_left', '<', rec.parent_right), ('parent_left', '>=', rec.parent_left)]
if prefix:
return [(left, 'in', left_model.search(cr, uid, doms, context=context))]
return [(left, 'in', left_model.search(doms).ids)]
return doms
else:
def recursive_children(ids, model, parent_field):
if not ids:
return []
ids2 = model.search(cr, uid, [(parent_field, 'in', ids)], context=context)
return ids + recursive_children(ids2, model, parent_field)
return [(left, 'in', recursive_children(ids, left_model, parent or left_model._parent_name))]
parent_name = parent or left_model._parent_name
child_ids = set(ids)
while ids:
ids = left_model.search([(parent_name, 'in', ids)]).ids
child_ids.update(ids)
return [(left, 'in', list(child_ids))]
def parent_of_domain(left, ids, left_model, parent=None, prefix='', context=None):
def parent_of_domain(left, ids, left_model, parent=None, prefix=''):
""" Return a domain implementing the parent_of operator for [(left,parent_of,ids)],
either as a range using the parent_left/right tree lookup fields
(when available), or as an expanded [(left,in,parent_ids)] """
if left_model._parent_store and (not left_model.pool._init):
doms = []
for node in left_model.browse(cr, uid, ids, context=context):
for rec in left_model.browse(ids):
if doms:
doms.insert(0, OR_OPERATOR)
doms += [AND_OPERATOR, ('parent_right', '>', node.parent_left), ('parent_left', '<=', node.parent_left)]
doms += [AND_OPERATOR, ('parent_right', '>', rec.parent_left), ('parent_left', '<=', rec.parent_left)]
if prefix:
return [(left, 'in', left_model.search(cr, uid, doms, context=context))]
return [(left, 'in', left_model.search(doms).ids)]
return doms
else:
def get_parent_ids(record, parent_field):
ids = set([record.id])
while record[parent_field]:
record = record[parent_field]
ids.add(record.id)
return ids
parent_name = parent or left_model._parent_name
parent_ids = set()
for node in left_model.browse(cr, uid, ids, context=context):
parent_ids |= get_parent_ids(node, parent or left_model._parent_name)
for record in left_model.browse(ids):
while record:
parent_ids.add(record.id)
record = record[parent_name]
return [(left, 'in', list(parent_ids))]
HIERARCHY_FUNCS = {'child_of': child_of_domain,
@@ -794,8 +795,8 @@ class expression(object):
model = leaf.model
field = model._fields.get(path[0])
column = model._columns.get(path[0])
comodel = model.pool.get(getattr(field, 'comodel_name', None))
column = getattr(field, 'column', None)
comodel = model.env.get(getattr(field, 'comodel_name', None))
# ----------------------------------------
# SIMPLE CASE
@@ -818,16 +819,20 @@ class expression(object):
# -> else: crash
# ----------------------------------------
elif not column and path[0] in model._inherit_fields:
elif not field:
raise ValueError("Invalid field %r in leaf %r" % (left, str(leaf)))
elif field.inherited:
# comments about inherits'd fields
# { 'field_name': ('parent_model', 'm2o_field_to_reach_parent',
# field_column_obj, origina_parent_model), ... }
next_model = model.pool[model._inherit_fields[path[0]][0]]
leaf.add_join_context(next_model, model._inherits[next_model._name], 'id', model._inherits[next_model._name])
parent_model = model.env[field.related_field.model_name]
parent_fname = model._inherits[parent_model._name]
leaf.add_join_context(parent_model, parent_fname, 'id', parent_fname)
push(leaf)
elif left == 'id' and operator in HIERARCHY_FUNCS:
ids2 = to_ids(right, model, context)
ids2 = to_ids(right, model)
dom = HIERARCHY_FUNCS[operator](left, ids2, model)
for dom_leaf in reversed(dom):
new_leaf = create_substitution_leaf(leaf, dom_leaf, model)
@@ -836,9 +841,6 @@ class expression(object):
elif not column and path[0] in MAGIC_COLUMNS:
push_result(leaf)
elif not field:
raise ValueError("Invalid field %r in leaf %r" % (left, str(leaf)))
# ----------------------------------------
# PATH SPOTTED
# -> many2one or one2many with _auto_join:
@@ -860,7 +862,7 @@ class expression(object):
elif len(path) > 1 and column and column._type == 'one2many' and column._auto_join:
# res_partner.id = res_partner__bank_ids.partner_id
leaf.add_join_context(comodel, 'id', column._fields_id, path[0])
domain = column._domain(model) if callable(column._domain) else column._domain
domain = field.domain(model) if callable(field.domain) else field.domain
push(create_substitution_leaf(leaf, (path[1], operator, right), comodel))
if domain:
domain = normalize_domain(domain)
@@ -872,14 +874,14 @@ class expression(object):
raise NotImplementedError('_auto_join attribute not supported on many2many column %s' % left)
elif len(path) > 1 and column and column._type == 'many2one':
right_ids = comodel.search(cr, uid, [(path[1], operator, right)], context=dict(context, active_test=False))
right_ids = comodel.with_context(active_test=False).search([('.'.join(path[1:]), operator, right)]).ids
leaf.leaf = (path[0], 'in', right_ids)
push(leaf)
# Making search easier when there is a left operand as column.o2m or column.m2m
elif len(path) > 1 and column and column._type in ['many2many', 'one2many']:
right_ids = comodel.search(cr, uid, [(path[1], operator, right)], context=context)
table_ids = model.search(cr, uid, [(path[0], 'in', right_ids)], context=dict(context, active_test=False))
right_ids = comodel.search([('.'.join(path[1:]), operator, right)]).ids
table_ids = model.with_context(active_test=False).search([(path[0], 'in', right_ids)]).ids
leaf.leaf = ('id', 'in', table_ids)
push(leaf)
@@ -895,12 +897,9 @@ class expression(object):
else:
# Let the field generate a domain.
if len(path) > 1:
right = comodel.search(
cr, uid, [(path[1], operator, right)],
context=context)
right = comodel.search([('.'.join(path[1:]), operator, right)]).ids
operator = 'in'
recs = model.browse(cr, uid, [], context=context)
domain = field.determine_domain(recs, operator, right)
domain = field.determine_domain(model, operator, right)
if not domain:
leaf.leaf = TRUE_LEAF
@@ -928,7 +927,7 @@ class expression(object):
# ignore it: generate a dummy leaf
fct_domain = []
else:
fct_domain = column.search(cr, uid, model, left, [leaf.leaf], context=context)
fct_domain = column.search(cr, uid, model._model, left, [leaf.leaf], context=context)
if not fct_domain:
leaf.leaf = TRUE_LEAF
@@ -947,7 +946,7 @@ class expression(object):
# Applying recursivity on field(one2many)
elif column._type == 'one2many' and operator in HIERARCHY_FUNCS:
ids2 = to_ids(right, comodel, context)
ids2 = to_ids(right, comodel)
if column._obj != model._name:
dom = HIERARCHY_FUNCS[operator](left, ids2, comodel, prefix=column._obj)
else:
@@ -961,7 +960,7 @@ class expression(object):
if right is not False:
if isinstance(right, basestring):
op = {'!=': '=', 'not like': 'like', 'not ilike': 'ilike'}.get(operator, operator)
ids2 = [x[0] for x in comodel.name_search(cr, uid, right, [], op, context=context, limit=None)]
ids2 = [x[0] for x in comodel.name_search(right, [], op, limit=None)]
if ids2:
operator = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in'
elif isinstance(right, collections.Iterable):
@@ -979,7 +978,7 @@ class expression(object):
if comodel._fields[column._fields_id].store:
ids1 = select_from_where(cr, column._fields_id, comodel._table, 'id', ids2, operator)
else:
recs = comodel.browse(cr, SUPERUSER_ID, ids2, {'prefetch_fields': False})
recs = comodel.browse(ids2).sudo().with_context(prefetch_fields=False)
ids1 = recs.mapped(column._fields_id).ids
if ids1:
call_null = False
@@ -1003,16 +1002,16 @@ class expression(object):
return ids
return select_from_where(cr, rel_id1, rel_table, rel_id2, ids, operator)
ids2 = to_ids(right, comodel, context)
ids2 = to_ids(right, comodel)
dom = HIERARCHY_FUNCS[operator]('id', ids2, comodel)
ids2 = comodel.search(cr, uid, dom, context=context)
ids2 = comodel.search(dom).ids
push(create_substitution_leaf(leaf, ('id', 'in', _rec_convert(ids2)), model))
else:
call_null_m2m = True
if right is not False:
if isinstance(right, basestring):
op = {'!=': '=', 'not like': 'like', 'not ilike': 'ilike'}.get(operator, operator)
res_ids = [x[0] for x in comodel.name_search(cr, uid, right, [], op, context=context, limit=None)]
res_ids = [x[0] for x in comodel.name_search(right, [], op, limit=None)]
if res_ids:
operator = 'not in' if operator in NEGATIVE_TERM_OPERATORS else 'in'
else:
@@ -1038,7 +1037,7 @@ class expression(object):
elif column._type == 'many2one':
if operator in HIERARCHY_FUNCS:
ids2 = to_ids(right, comodel, context)
ids2 = to_ids(right, comodel)
if column._obj != model._name:
dom = HIERARCHY_FUNCS[operator](left, ids2, comodel, prefix=column._obj)
else:
@@ -1046,11 +1045,7 @@ class expression(object):
for dom_leaf in reversed(dom):
push(create_substitution_leaf(leaf, dom_leaf, model))
else:
def _get_expression(comodel, cr, uid, left, right, operator, context=None):
if context is None:
context = {}
c = context.copy()
c['active_test'] = False
def _get_expression(comodel, left, right, operator):
#Special treatment to ill-formed domains
operator = (operator in ['<', '>', '<=', '>=']) and 'in' or operator
@@ -1061,14 +1056,14 @@ class expression(object):
operator = dict_op[operator]
elif isinstance(right, list) and operator in ['!=', '=']: # for domain (FIELD,'=',['value1','value2'])
operator = dict_op[operator]
res_ids = [x[0] for x in comodel.name_search(cr, uid, right, [], operator, limit=None, context=c)]
res_ids = [x[0] for x in comodel.with_context(active_test=False).name_search(right, [], operator, limit=None)]
if operator in NEGATIVE_TERM_OPERATORS:
res_ids.append(False) # TODO this should not be appended if False was in 'right'
return left, 'in', res_ids
# resolve string-based m2o criterion into IDs
if isinstance(right, basestring) or \
right and isinstance(right, (tuple, list)) and all(isinstance(item, basestring) for item in right):
push(create_substitution_leaf(leaf, _get_expression(comodel, cr, uid, left, right, operator, context=context), model))
push(create_substitution_leaf(leaf, _get_expression(comodel, left, right, operator), model))
else:
# right == [] or right == False and all other cases are handled by __leaf_to_sql()
push_result(leaf)
@@ -1140,7 +1135,7 @@ class expression(object):
params = (
model._name + ',' + left,
context.get('lang') or 'en_US',
model.env.lang or 'en_US',
'model',
right,
)
-4
View File
@@ -86,8 +86,6 @@ class _column(object):
'translate',
'select',
'manual',
'write',
'read',
'selectable',
'group_operator',
'groups', # CSV list of ext IDs of groups
@@ -120,8 +118,6 @@ class _column(object):
args['translate'] = translate
args['select'] = select
args['manual'] = manual
args['write'] = args.get('write', False)
args['read'] = args.get('read', False)
args['selectable'] = args.get('selectable', True)
args['group_operator'] = args.get('group_operator', None)
args['groups'] = args.get('groups', None)
+2 -2
View File
@@ -240,10 +240,10 @@ class Cursor(object):
self.sql_into_log[res_into.group(1)][1] += delay
return res
def split_for_in_conditions(self, ids):
def split_for_in_conditions(self, ids, size=None):
"""Split a list of identifiers into one or more smaller tuples
safe for IN conditions, after uniquifying them."""
return tools.misc.split_every(self.IN_MAX, ids)
return tools.misc.split_every(size or self.IN_MAX, ids)
def print_log(self):
global sql_counter
+8 -20
View File
@@ -883,19 +883,6 @@ def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init',
input = cStringIO.StringIO(csvcontent) #FIXME
reader = csv.reader(input, quotechar='"', delimiter=',')
fields = reader.next()
fname_partial = ""
if config.get('import_partial'):
fname_partial = module + '/'+ fname
if not os.path.isfile(config.get('import_partial')):
pickle.dump({}, file(config.get('import_partial'),'w+'))
else:
data = pickle.load(file(config.get('import_partial')))
if fname_partial in data:
if not data[fname_partial]:
return
else:
for i in range(data[fname_partial]):
reader.next()
if not (mode == 'init' or 'id' in fields):
_logger.error("Import specification does not contain 'id' and we are in init mode, Cannot continue.")
@@ -912,15 +899,16 @@ def convert_csv_import(cr, module, fname, csvcontent, idref=None, mode='init',
_logger.error("Cannot import the line: %s", line)
registry = openerp.registry(cr.dbname)
result, rows, warning_msg, dummy = registry[model].import_data(cr, uid, fields, datas,mode, module, noupdate, filename=fname_partial)
if result < 0:
context = {
'mode': mode,
'module': module,
'noupdate': noupdate,
}
result = registry[model].load(cr, uid, fields, datas, context=context)
if any(msg['type'] == 'error' for msg in result['messages']):
# Report failed import and abort module install
warning_msg = "\n".join(msg['message'] for msg in result['messages'])
raise Exception(_('Module loading %s failed: file %s could not be processed:\n %s') % (module, fname, warning_msg))
if config.get('import_partial'):
data = pickle.load(file(config.get('import_partial')))
data[fname_partial] = 0
pickle.dump(data, file(config.get('import_partial'),'wb'))
cr.commit()
def convert_xml_import(cr, module, xmlfile, idref=None, mode='init', noupdate=False, report=None):
doc = etree.parse(xmlfile)