From a95ae0dad9b4f701ffbb5e6590338f201ae56fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 20 Mar 2013 22:49:16 +0100 Subject: [PATCH] Remove _inherits review670002 --- CHANGELOG | 1 + doc/ref/models/models.rst | 11 - trytond/convert.py | 104 +------- trytond/ir/action.py | 342 ++++++++++----------------- trytond/ir/model.py | 20 +- trytond/model/fields/many2many.py | 15 +- trytond/model/fields/one2many.py | 10 +- trytond/model/model.py | 91 +------ trytond/model/modelsingleton.py | 3 +- trytond/model/modelsql.py | 260 ++------------------ trytond/model/modelstorage.py | 86 ++----- trytond/model/modelview.py | 33 +-- trytond/res/ir.xml | 53 +++++ trytond/test/__init__.py | 5 - trytond/test/model.py | 51 +--- trytond/tests/test_model_inherits.py | 139 ----------- trytond/tests/test_tryton.py | 2 - 17 files changed, 261 insertions(+), 965 deletions(-) delete mode 100644 trytond/tests/test_model_inherits.py diff --git a/CHANGELOG b/CHANGELOG index 7f070648f4..258d7bb793 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Remove _inherits * Add dynamic label * Add prefix, suffix on tree view * Replace _constraints with validate in ModelStorage diff --git a/doc/ref/models/models.rst b/doc/ref/models/models.rst index eb67101b2d..37cdb8d170 100644 --- a/doc/ref/models/models.rst +++ b/doc/ref/models/models.rst @@ -17,17 +17,6 @@ Class attributes are: It contains the a unique name to reference the model throughout the platform. -.. attribute:: Model._inherits - - It contains a dictionary with one or more :attr:`Model._name` as keys. For each - key a :class:`~trytond.model.fields.Many2One` field is defined as value. The - :class:`trytond.model.fields.Many2One` fields must be defined in the the current - model fields. A referenced model with ``_inherits`` is a generalization_ of the - current model which is *specialized*. In the specialized model it is possible to - interact with all attributes and methods of the general model. - - .. _generalization: http://en.wikipedia.org/wiki/Class_diagram#Generalization - .. attribute:: Model.__rpc__ It contains a dictionary with method name as key and an instance of diff --git a/trytond/convert.py b/trytond/convert.py index 3c4d3b4eeb..852a252571 100644 --- a/trytond/convert.py +++ b/trytond/convert.py @@ -340,7 +340,6 @@ class Fs2bdAccessor: self.fs2db[module] = {} module_data_ids = self.ModelData.search([ ('module', '=', module), - ('inherit', '=', None), ], order=[('db_id', 'ASC')]) record_ids = {} @@ -485,10 +484,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler): """ Model = record.__class__ # search the field type in the object or in a parent - if key in Model._fields: - field_type = Model._fields[key]._type - else: - field_type = Model._inherit_fields[key][2]._type + field_type = Model._fields[key]._type # handle the value regarding to the type if field_type == 'many2one': @@ -520,7 +516,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler): # problem when the corresponding recordds will be deleted: module_data = self.ModelData.search([ ('module', '=', self.module), - ('inherit', '=', None), ], order=[('id', 'DESC')]) return set(rec.fs_id for rec in module_data) @@ -558,8 +553,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler): db_id, db_model, mdata_id, old_values = [ self.fs2db.get(module, fs_id)[x] for x in ["db_id", "model", "id", "values"]] - inherit_db_ids = {} - inherit_mdata_ids = [] if not old_values: old_values = {} @@ -592,31 +585,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler): record = self.fs2db.get_browserecord( module, Model.__name__, record.id) - for table, field_name, field in \ - Model._inherit_fields.values(): - inherit_db_ids[table] = getattr(record, field_name).id - - for table in inherit_db_ids.keys(): - data = self.ModelData.search([ - ('fs_id', '=', fs_id), - ('module', '=', module), - ('model', '=', table), - ], limit=1) - if data: - self.ModelData.write(data, { - 'db_id': inherit_db_ids[table], - 'inherit': True, - }) - data, = data - else: - data, = self.ModelData.create([{ - 'fs_id': fs_id, - 'module': module, - 'model': table, - 'db_id': inherit_db_ids[table], - 'inherit': True, - }]) - inherit_mdata_ids.append((table, data.id)) data = self.ModelData.search([ ('fs_id', '=', fs_id), @@ -643,22 +611,13 @@ class TrytondXmlHandler(sax.handler.ContentHandler): # we cannot update a field if it was changed by a user... if key not in old_values: - if key in Model._fields: - expected_value = Model._defaults.get( - key, lambda *a: None)() - else: - Inherit = self.pool.get( - Model._inherit_fields[key][0]) - expected_value = Inherit._defaults.get( - key, lambda *a: None)() + expected_value = Model._defaults.get(key, + lambda *a: None)() else: expected_value = old_values[key] # Migration from 2.0: Reference field change value - if key in Model._fields: - field_type = Model._fields[key]._type - else: - field_type = Model._inherit_fields[key][2]._type + field_type = Model._fields[key]._type if field_type == 'reference': if (expected_value and expected_value.endswith(',0') and not db_field): @@ -688,19 +647,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler): self.fs2db.reset_browsercord( module, Model.__name__, [record.id]) - if not inherit_db_ids: - for table, field_name, field in \ - Model._inherit_fields.values(): - inherit_db_ids[table] = getattr(record, field_name).id - if not inherit_mdata_ids: - for table in inherit_db_ids.keys(): - data, = self.ModelData.search([ - ('fs_id', '=', fs_id), - ('module', '=', module), - ('model', '=', table), - ], limit=1) - inherit_mdata_ids.append((table, data.id)) - if to_update: # re-read it: this ensure that we store the real value # in the model_data table: @@ -725,16 +671,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler): 'values': str(values), 'date_update': datetime.datetime.now(), }) - for table, inherit_mdata_id in inherit_mdata_ids: - self.ModelData.write( - [self.ModelData(inherit_mdata_id)], { - 'fs_id': fs_id, - 'model': table, - 'module': module, - 'db_id': inherit_db_ids[table], - 'values': str(values), - 'date_update': datetime.datetime.now(), - }) # reset_browsercord to keep cache memory low self.fs2db.reset_browsercord(module, Model.__name__, [record.id]) @@ -742,11 +678,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler): # this record is new, create it in the db: with Transaction().set_context(module=module, language='en_US'): record, = Model.create([values]) - inherit_db_ids = {} - - for table, field_name, field in ( - Model._inherit_fields.values()): - inherit_db_ids[table] = getattr(record, field_name).id # re-read it: this ensure that we store the real value # in the model_data table: @@ -754,25 +685,14 @@ class TrytondXmlHandler(sax.handler.ContentHandler): for key in values: values[key] = self._clean_value(key, record) - to_create = [{ - 'fs_id': fs_id, - 'model': model, - 'module': module, - 'db_id': record.id, - 'values': str(values), - 'noupdate': self.noupdate, - }] - for table in inherit_db_ids.keys(): - to_create.append({ - 'fs_id': fs_id, - 'model': table, - 'module': module, - 'db_id': inherit_db_ids[table], - 'values': str(values), - 'inherit': True, - 'noupdate': self.noupdate, - }) - mdata = self.ModelData.create(to_create)[0] + mdata, = self.ModelData.create([{ + 'fs_id': fs_id, + 'model': model, + 'module': module, + 'db_id': record.id, + 'values': str(values), + 'noupdate': self.noupdate, + }]) # update fs2db: self.fs2db.set(module, fs_id, { diff --git a/trytond/ir/action.py b/trytond/ir/action.py index e14c88930d..0e213d9ac8 100644 --- a/trytond/ir/action.py +++ b/trytond/ir/action.py @@ -4,8 +4,9 @@ import base64 import os from operator import itemgetter from collections import defaultdict +from functools import partial -from ..model import ModelView, ModelSQL, fields +from ..model import ModelView, ModelStorage, ModelSQL, fields from ..tools import file_open, safe_eval from ..backend import TableHandler from ..pyson import PYSONEncoder, CONTEXT, PYSON @@ -82,7 +83,7 @@ class Action(ModelSQL, ModelView): @classmethod def get_action_values(cls, type_, action_ids): Action = Pool().get(type_) - columns = set(Action._fields.keys() + Action._inherit_fields.keys()) + columns = set(Action._fields.keys()) columns.add('icon.rec_name') to_remove = () if type_ == 'ir.action.report': @@ -230,10 +231,125 @@ class ActionKeyword(ModelSQL, ModelView): return keywords -class ActionReport(ModelSQL, ModelView): +class ActionMixin(ModelSQL): + + @classmethod + def __setup__(cls): + super(ActionMixin, cls).__setup__() + for name in dir(Action): + field = getattr(Action, name) + if (isinstance(field, fields.Field) + and not getattr(cls, name, None)): + setattr(cls, name, fields.Function(field, 'get_action', + setter='set_action', searcher='search_action')) + default_func = 'default_' + name + if getattr(Action, default_func, None): + setattr(cls, default_func, + partial(ActionMixin.default_action, name)) + + @staticmethod + def default_action(name): + pool = Pool() + Action = pool.get('ir.action') + return getattr(Action, 'default_' + name, None)() + + @classmethod + def get_action(cls, ids, names): + records = cls.browse(ids) + result = {} + for name in names: + result[name] = values = {} + for record in records: + value = getattr(record, 'action') + convert = lambda v: v + if value is not None: + value = getattr(value, name) + if isinstance(value, ModelStorage): + if cls._fields[name]._type == 'reference': + convert = str + else: + convert = int + elif isinstance(value, (list, tuple)): + convert = lambda v: [r.id for r in v] + values[record.id] = convert(value) + return result + + @classmethod + def set_action(cls, records, name, value): + pool = Pool() + Action = pool.get('ir.action') + Action.write([r.action for r in records], { + name: value, + }) + + @classmethod + def search_action(cls, name, clause): + return [('action.' + name,) + tuple(clause[1:])] + + @classmethod + def create(cls, vlist): + pool = Pool() + Action = pool.get('ir.action') + new_records = [] + for values in vlist: + later = {} + action_values = {} + values = values.copy() + for field in values: + if field in Action._fields: + action_values[field] = values[field] + if hasattr(getattr(cls, field), 'set'): + later[field] = values[field] + for field in later: + del values[field] + action_values['type'] = cls.default_type() + cursor = Transaction().cursor + if cursor.nextid(cls._table): + cursor.setnextid(cls._table, cursor.currid(Action._table)) + action, = Action.create([action_values]) + values['action'] = action.id + record, = super(ActionMixin, cls).create([values]) + cursor.execute('UPDATE "' + cls._table + '" SET id = %s ' + 'WHERE id = %s', (action.id, record.id)) + cursor.update_auto_increment(cls._table, action.id) + record = cls(action.id) + new_records.append(record) + cls.write([record], later) + return new_records + + @classmethod + def write(cls, records, values): + pool = Pool() + ActionKeyword = pool.get('ir.action.keyword') + super(ActionMixin, cls).write(records, values) + ActionKeyword._get_keyword_cache.clear() + + @classmethod + def delete(cls, records): + pool = Pool() + Action = pool.get('ir.action') + actions = [x.action for x in records] + super(ActionMixin, cls).delete(records) + Action.delete(actions) + + @classmethod + def copy(cls, records, default=None): + pool = Pool() + Action = pool.get('ir.action') + if default is None: + default = {} + default = default.copy() + new_records = [] + for record in records: + default['action'] = Action.copy([record.action])[0].id + new_records.extend(super(ActionMixin, cls).copy([record], + default=default)) + return new_records + + +class ActionReport(ActionMixin, ModelSQL, ModelView): "Action report" __name__ = 'ir.action.report' - _inherits = {'ir.action': 'action'} model = fields.Char('Model') report_name = fields.Char('Internal Name', required=True) report = fields.Char('Path') @@ -499,8 +615,6 @@ class ActionReport(ModelSQL, ModelView): @classmethod def copy(cls, reports, default=None): - Action = Pool().get('ir.action') - if default is None: default = {} default = default.copy() @@ -511,62 +625,23 @@ class ActionReport(ModelSQL, ModelView): if report.report: default['report_content'] = None default['report_name'] = report.report_name - default['action'] = Action.copy([report.action])[0].id new_reports.extend(super(ActionReport, cls).copy([report], default=default)) return new_reports - @classmethod - def create(cls, vlist): - new_vlist = [] - for vals in vlist: - later = {} - vals = vals.copy() - for field in vals: - if (field in cls._fields - and hasattr(cls._fields[field], 'set')): - later[field] = vals[field] - for field in later: - del vals[field] - cursor = Transaction().cursor - if cursor.nextid(cls._table): - cursor.setnextid(cls._table, cursor.currid('ir_action')) - report, = super(ActionReport, cls).create([vals]) - cursor.execute('SELECT action FROM "' + cls._table + '" ' - 'WHERE id = %s', (report.id,)) - new_id, = cursor.fetchone() - cursor.execute('UPDATE "' + cls._table + '" SET id = %s ' - 'WHERE id = %s', (new_id, report.id)) - cursor.update_auto_increment(cls._table, new_id) - report = cls(new_id) - new_vlist.append(report) - cls.write([report], later) - return new_vlist - @classmethod def write(cls, reports, vals): - pool = Pool() context = Transaction().context if 'module' in context: vals = vals.copy() vals['module'] = context['module'] super(ActionReport, cls).write(reports, vals) - pool.get('ir.action.keyword')._get_keyword_cache.clear() - - @classmethod - def delete(cls, reports): - Action = Pool().get('ir.action') - - actions = [x.action for x in reports] - super(ActionReport, cls).delete(reports) - Action.delete(actions) -class ActionActWindow(ModelSQL, ModelView): +class ActionActWindow(ActionMixin, ModelSQL, ModelView): "Action act window" __name__ = 'ir.action.act_window' - _inherits = {'ir.action': 'action'} domain = fields.Char('Domain Value') context = fields.Char('Context Value') res_model = fields.Char('Model') @@ -771,47 +846,6 @@ class ActionActWindow(ModelSQL, ModelView): or defaults.get(field, 'None'), CONTEXT)) return pysons - @classmethod - def create(cls, vlist): - new_vlist = [] - for vals in vlist: - later = {} - vals = vals.copy() - for field in vals: - if (field in cls._fields - and hasattr(cls._fields[field], 'set')): - later[field] = vals[field] - for field in later: - del vals[field] - cursor = Transaction().cursor - if cursor.nextid(cls._table): - cursor.setnextid(cls._table, cursor.currid('ir_action')) - act_window, = super(ActionActWindow, cls).create([vals]) - cursor.execute('SELECT action FROM "' + cls._table + '" ' - 'WHERE id = %s', (act_window.id,)) - new_id, = cursor.fetchone() - cursor.execute('UPDATE "' + cls._table + '" SET id = %s ' - 'WHERE id = %s', (new_id, act_window.id)) - cursor.update_auto_increment(cls._table, new_id) - act_window = cls(new_id) - new_vlist.append(act_window) - cls.write([act_window], later) - return new_vlist - - @classmethod - def write(cls, act_windows, values): - pool = Pool() - super(ActionActWindow, cls).write(act_windows, values) - pool.get('ir.action.keyword')._get_keyword_cache.clear() - - @classmethod - def delete(cls, act_windows): - Action = Pool().get('ir.action') - - actions = [x.action for x in act_windows] - super(ActionActWindow, cls).delete(act_windows) - Action.delete(actions) - @classmethod def get(cls, xml_id): 'Get values from XML id or id' @@ -824,19 +858,6 @@ class ActionActWindow(ModelSQL, ModelView): action_id = int(xml_id) return Action.get_action_values(cls.__name__, [action_id])[0] - @classmethod - def copy(cls, actions, default=None): - Action = Pool().get('ir.action') - if default is None: - default = {} - default = default.copy() - new_actions = [] - for act_window in actions: - default['action'] = Action.copy([act_window.action])[0].id - new_actions.extend(super(ActionActWindow, cls).copy([act_window], - default=default)) - return new_actions - class ActionActWindowView(ModelSQL, ModelView): "Action act window view" @@ -901,10 +922,9 @@ class ActionActWindowDomain(ModelSQL, ModelView): return True -class ActionWizard(ModelSQL, ModelView): +class ActionWizard(ActionMixin, ModelSQL, ModelView): "Action wizard" __name__ = 'ir.action.wizard' - _inherits = {'ir.action': 'action'} wiz_name = fields.Char('Wizard name', required=True) action = fields.Many2One('ir.action', 'Action', required=True, ondelete='CASCADE') @@ -916,68 +936,10 @@ class ActionWizard(ModelSQL, ModelView): def default_type(): return 'ir.action.wizard' - @classmethod - def create(cls, vlist): - new_vlist = [] - for vals in vlist: - later = {} - vals = vals.copy() - for field in vals: - if (field in cls._fields - and hasattr(cls._fields[field], 'set')): - later[field] = vals[field] - for field in later: - del vals[field] - cursor = Transaction().cursor - if cursor.nextid(cls._table): - cursor.setnextid(cls._table, cursor.currid('ir_action')) - wizard, = super(ActionWizard, cls).create([vals]) - cursor.execute('SELECT action FROM "' + cls._table + '" ' - 'WHERE id = %s', (wizard.id,)) - new_id, = cursor.fetchone() - cursor.execute('UPDATE "' + cls._table + '" SET id = %s ' - 'WHERE id = %s', (new_id, wizard.id)) - cursor.update_auto_increment(cls._table, new_id) - wizard = cls(new_id) - new_vlist.append(wizard) - cls.write([wizard], later) - return new_vlist - @classmethod - def write(cls, wizards, values): - pool = Pool() - super(ActionWizard, cls).write(wizards, values) - pool.get('ir.action.keyword')._get_keyword_cache.clear() - - @classmethod - def delete(cls, wizards): - pool = Pool() - Action = pool.get('ir.action') - - actions = [x.action for x in wizards] - - super(ActionWizard, cls).delete(wizards) - Action.delete(actions) - - @classmethod - def copy(cls, wizards, default=None): - Action = Pool().get('ir.action') - - if default is None: - default = {} - default = default.copy() - new_wizards = [] - for wizard in wizards: - default['action'] = Action.copy([wizard.action])[0].id - new_wizards.extend(super(ActionWizard, cls).copy([wizard], - default=default)) - return new_wizards - - -class ActionURL(ModelSQL, ModelView): +class ActionURL(ActionMixin, ModelSQL, ModelView): "Action URL" __name__ = 'ir.action.url' - _inherits = {'ir.action': 'action'} url = fields.Char('Action Url', required=True) action = fields.Many2One('ir.action', 'Action', required=True, ondelete='CASCADE') @@ -989,61 +951,3 @@ class ActionURL(ModelSQL, ModelView): @staticmethod def default_target(): return 'new' - - @classmethod - def create(cls, vlist): - new_vlist = [] - for vals in vlist: - later = {} - vals = vals.copy() - for field in vals: - if (field in cls._fields - and hasattr(cls._fields[field], 'set')): - later[field] = vals[field] - for field in later: - del vals[field] - cursor = Transaction().cursor - if cursor.nextid(cls._table): - cursor.setnextid(cls._table, cursor.currid('ir_action')) - url, = super(ActionURL, cls).create([vals]) - cursor.execute('SELECT action FROM "' + cls._table + '" ' - 'WHERE id = %s', (url.id,)) - new_id, = cursor.fetchone() - cls.write([url], {}) # simulate write to clear the cache - cursor.execute('UPDATE "' + cls._table + '" SET id = %s ' - 'WHERE id = %s', (new_id, url.id)) - cursor.update_auto_increment(cls._table, new_id) - url = cls(new_id) - new_vlist.append(url) - cls.write([url], later) - return new_vlist - - @classmethod - def write(cls, urls, values): - pool = Pool() - super(ActionURL, cls).write(urls, values) - pool.get('ir.action.keyword')._get_keyword_cache.clear() - - @classmethod - def delete(cls, urls): - pool = Pool() - Action = pool.get('ir.action') - - actions = [x.action for x in urls] - - super(ActionURL, cls).delete(urls) - Action.delete(actions) - - @classmethod - def copy(cls, urls, default=None): - Action = Pool().get('ir.action') - - if default is None: - default = {} - default = default.copy() - new_urls = [] - for url in urls: - default['action'] = Action.copy([url.action])[0].id - new_urls.extend(super(ActionURL, cls).copy([url], - default=default)) - return new_urls diff --git a/trytond/ir/model.py b/trytond/ir/model.py index 19b3afb4ad..6dda9235f5 100644 --- a/trytond/ir/model.py +++ b/trytond/ir/model.py @@ -666,7 +666,6 @@ class ModelData(ModelSQL, ModelView): date_update = fields.DateTime('Update Date') date_init = fields.DateTime('Init Date') values = fields.Text('Values') - inherit = fields.Boolean('Inherit') noupdate = fields.Boolean('No Update') _get_id_cache = Cache('ir_model_data.get_id', context=False) @@ -678,14 +677,24 @@ class ModelData(ModelSQL, ModelView): 'The triple (fs_id, module, model) must be unique!'), ] + @classmethod + def __register__(cls, module_name): + cursor = Transaction().cursor + + super(ModelData, cls).__register__(module_name) + + table = TableHandler(cursor, cls, module_name) + + # Migration from 2.6: remove inherit + if table.column_exist('inherit'): + cursor.execute('DELETE FROM "' + cls._table + '" ' + 'WHERE inherit = %s', (True,)) + table.drop_column('inherit', True) + @staticmethod def default_date_init(): return datetime.datetime.now() - @staticmethod - def default_inherit(): - return False - @staticmethod def default_noupdate(): return False @@ -708,7 +717,6 @@ class ModelData(ModelSQL, ModelView): data = cls.search([ ('module', '=', module), ('fs_id', '=', fs_id), - ('inherit', '=', False), ], limit=1) if not data: raise Exception("Reference to %s not found" diff --git a/trytond/model/fields/many2many.py b/trytond/model/fields/many2many.py index 5c92047c9c..954af80f22 100644 --- a/trytond/model/fields/many2many.py +++ b/trytond/model/fields/many2many.py @@ -75,10 +75,7 @@ class Many2Many(Field): order = self.order Relation = Pool().get(self.relation_name) - if self.origin in Relation._fields: - origin_field = Relation._fields[self.origin] - else: - origin_field = Relation._inherit_fields[self.origin][2] + origin_field = Relation._fields[self.origin] relations = [] for i in range(0, len(ids), Transaction().cursor.IN_MAX): @@ -116,10 +113,7 @@ class Many2Many(Field): return Relation = pool.get(self.relation_name) Target = self.get_target() - if self.origin in Relation._fields: - origin_field = Relation._fields[self.origin] - else: - origin_field = Relation._inherit_fields[self.origin][2] + origin_field = Relation._fields[self.origin] def search_clause(ids): if origin_field._type == 'reference': @@ -228,10 +222,7 @@ class Many2Many(Field): Relation = Pool().get(self.relation_name) if not self.target: return Relation - if self.target in Relation._fields: - return Relation._fields[self.target].get_target() - else: - return Relation._inherit_fields[self.target][2].get_target() + return Relation._fields[self.target].get_target() def __set__(self, inst, value): Target = self.get_target() diff --git a/trytond/model/fields/one2many.py b/trytond/model/fields/one2many.py index 0ec20f99fa..177001b786 100644 --- a/trytond/model/fields/one2many.py +++ b/trytond/model/fields/one2many.py @@ -79,10 +79,7 @@ class One2Many(Field): ''' pool = Pool() Relation = pool.get(self.model_name) - if self.field in Relation._fields: - field = Relation._fields[self.field] - else: - field = Relation._inherit_fields[self.field][2] + field = Relation._fields[self.field] res = {} for i in ids: res[i] = [] @@ -119,10 +116,7 @@ class One2Many(Field): if not values: return Target = self.get_target() - if self.field in Target._fields: - field = Target._fields[self.field] - else: - field = Target._inherit_fields[self.field][2] + field = Target._fields[self.field] def search_clause(ids): if field._type == 'reference': diff --git a/trytond/model/model.py b/trytond/model/model.py index 0b2663e9c2..453a8617c7 100644 --- a/trytond/model/model.py +++ b/trytond/model/model.py @@ -16,33 +16,11 @@ from trytond.rpc import RPC __all__ = ['Model'] -class ModelMeta(PoolMeta): - - def __getattr__(self, name): - pool = Pool() - for model_name, _ in self._inherits.iteritems(): - Model = pool.get(model_name) - if isinstance(getattr(Model, name, None), - collections.Callable): - meth = getattr(Model, name) - if not hasattr(meth, 'im_self') or meth.im_self: - # Return classmethod bounded to inherited class - return meth - else: - for cls in Model.__mro__: - if name in cls.__dict__: - # Return a method bounded to current class - return cls.__dict__[name].__get__(None, self) - raise AttributeError("'%s' Model has no attribute '%s'" - % (self.__name__, name)) - - class Model(WarningErrorMixin, URLMixin): """ Define a model in Tryton. """ - __metaclass__ = ModelMeta - _inherits = {} + __metaclass__ = PoolMeta _rec_name = 'name' id = fields.Integer('ID', readonly=True) @@ -76,48 +54,21 @@ class Model(WarningErrorMixin, URLMixin): if isinstance(getattr(cls, attr), fields.Field): cls._fields[attr] = getattr(cls, attr) - # Set _inherit_fields - cls._inherit_fields = {} - for model_name in cls._inherits: - Model = pool.get(model_name) - cls._inherit_fields.update(Model._inherit_fields) - for field_name in Model._fields.keys(): - cls._inherit_fields[field_name] = (model_name, - cls._inherits[model_name], - Model._fields[field_name]) - for field_name in Model._inherit_fields.keys(): - cls._inherit_fields[field_name] = (model_name, - cls._inherits[model_name], - Model._inherit_fields[field_name][2]) - # Update models that uses this one in _inherits - for _, Model in pool.iterobject(): - if cls.__name__ in Model._inherits: - Model.__post_setup__() - # Set _defaults cls._defaults = {} fields_names = cls._fields.keys() - fields_names += cls._inherit_fields.keys() for field_name in fields_names: default_method = getattr(cls, 'default_%s' % field_name, False) - if not default_method and field_name in cls._inherit_fields: - icls = pool.get(cls._inherit_fields[field_name][0]) - default_method = getattr(icls, 'default_%s' % field_name, - False) if isinstance(default_method, collections.Callable): cls._defaults[field_name] = default_method for k in cls._defaults: - assert (k in cls._fields) or (k in cls._inherit_fields), \ + assert k in cls._fields, \ 'Default function defined in %s but field %s does not exist!' \ % (cls.__name__, k,) # Update __rpc__ - for field_name in cls._fields.keys() + cls._inherit_fields.keys(): - if field_name in cls._fields: - field = cls._fields[field_name] - else: - field = cls._inherit_fields[field_name][2] + for field_name, field in cls._fields.iteritems(): if isinstance(field, (fields.Selection, fields.Reference)) \ and not isinstance(field.selection, (list, tuple)) \ and field.selection not in cls.__rpc__: @@ -364,10 +315,7 @@ class Model(WarningErrorMixin, URLMixin): for field_name in fields_names: if field_name in cls._defaults: value[field_name] = cls._defaults[field_name]() - if field_name in cls._fields: - field = cls._fields[field_name] - else: - field = cls._inherit_fields[field_name][2] + field = cls._fields[field_name] if (field._type == 'boolean' and not field_name in value): value[field_name] = False @@ -397,8 +345,6 @@ class Model(WarningErrorMixin, URLMixin): pool = Pool() res = value.copy() val = {} - for i in cls._inherits.keys(): - val.update(pool.get(i)._default_on_change(value)) for field in value.keys(): if field in cls._fields: if cls._fields[field].on_change: @@ -423,9 +369,6 @@ class Model(WarningErrorMixin, URLMixin): Translation = pool.get('ir.translation') FieldAccess = pool.get('ir.model.field.access') - for parent in cls._inherits: - res.update(pool.get(parent).fields_get(fields_names)) - #Add translation to cache language = Transaction().language trans_args = [] @@ -619,19 +562,6 @@ class Model(WarningErrorMixin, URLMixin): def __getattr__(self, name): if name == 'id': return self.__dict__['id'] - if (name not in self._fields - and name not in self._inherit_fields): - # Search for method on inherits parents - pool = Pool() - for model_name, _ in self._inherits.iteritems(): - iModel = pool.get(model_name) - if isinstance(getattr(iModel, name, None), - collections.Callable): - for cls in iModel.__mro__: - if name in cls.__dict__: - # Return a method bounded to current class - return cls.__dict__[name].__get__(self, - self.__class__) elif self._values and name in self._values: return self._values.get(name) raise AttributeError("'%s' Model has no attribute '%s': %s" @@ -641,11 +571,6 @@ class Model(WarningErrorMixin, URLMixin): if name == 'id': self.__dict__['id'] = value return - if (name not in self._fields - and name in self._inherit_fields): - field = self._inherit_fields[name][2] - field.__set__(self, value) - return super(Model, self).__setattr__(name, value) def __getitem__(self, name): @@ -654,8 +579,7 @@ class Model(WarningErrorMixin, URLMixin): return getattr(self, name) def __contains__(self, name): - return (name in self._fields - or name in self._inherit_fields) + return name in self._fields def __int__(self): return int(self.id) @@ -700,10 +624,7 @@ class Model(WarningErrorMixin, URLMixin): values = {} if self._values: for fname, value in self._values.iteritems(): - if fname in self._fields: - field = self._fields[fname] - else: - field = self._inherit_fields[fname][2] + field = self._fields[fname] if isinstance(field, fields.Reference): if value is not None: value = str(value) diff --git a/trytond/model/modelsingleton.py b/trytond/model/modelsingleton.py index 6da16ce95e..f680832c47 100644 --- a/trytond/model/modelsingleton.py +++ b/trytond/model/modelsingleton.py @@ -32,8 +32,7 @@ class ModelSingleton(ModelStorage): if not singleton: res = cls.default_get(fields_names, with_rec_name=False) if not fields_names: - fields_names = (set(cls._fields.keys() - + cls._inherit_fields.keys())) + fields_names = cls._fields.keys() for field_name in fields_names: if field_name not in res: res[field_name] = None diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py index 9f705d8523..921cada5c8 100644 --- a/trytond/model/modelsql.py +++ b/trytond/model/modelsql.py @@ -240,20 +240,11 @@ class ModelSQL(ModelStorage): # Get default values default = [] - avoid_table = [] - for (i, j) in cls._inherits.items(): - if j in values: - avoid_table.append(i) for i in cls._fields.keys(): if not i in values \ and i not in ('create_uid', 'create_date', 'write_uid', 'write_date'): default.append(i) - for i in cls._inherit_fields.keys(): - if ((not i in values) - and (not cls._inherit_fields[i][0] in avoid_table) - and i in cls._defaults): - default.append(i) if len(default): defaults = cls.default_get(default, with_rec_name=False) @@ -269,26 +260,6 @@ class ModelSQL(ModelStorage): (upd0, upd1, upd2) = ('', '', []) - # Create inherits - tocreate = {} - for i in cls._inherits: - if cls._inherits[i] not in values: - tocreate[i] = {} - - for i in values.keys(): - if i in cls._inherit_fields: - (inherits, _, _) = cls._inherit_fields[i] - if i in cls._fields: - continue - if inherits in tocreate: - tocreate[inherits][i] = values[i] - del values[i] - - for inherits in tocreate: - Inherits = pool.get(inherits) - inherits_record, = Inherits.create([tocreate[inherits]]) - values[cls._inherits[inherits]] = inherits_record.id - # Insert record for fname, value in values.iteritems(): field = cls._fields[fname] @@ -433,8 +404,7 @@ class ModelSQL(ModelStorage): cursor = Transaction().cursor if not fields_names: - fields_names = list(set(cls._fields.keys() - + cls._inherit_fields.keys())) + fields_names = cls._fields.keys() if not ids: return [] @@ -451,19 +421,15 @@ class ModelSQL(ModelStorage): field, field_related = field_name.split('.', 1) fields_related.setdefault(field, []) fields_related[field].append(field_related) - elif field_name in cls._fields: - field = cls._fields[field_name] else: - field = cls._inherit_fields[field_name][2] + field = cls._fields[field_name] if hasattr(field, 'datetime_field') and field.datetime_field: datetime_fields.append(field.datetime_field) - # all inherited fields + all non inherited fields - fields_pre = [x for x in - fields_names + fields_related.keys() + datetime_fields - if ((x in cls._fields - and not hasattr(cls._fields[x], 'set')) - or (x == '_timestamp'))] + cls._inherits.values() + fields_pre = [x + for x in fields_names + fields_related.keys() + datetime_fields + if (x in cls._fields and not hasattr(cls._fields[x], 'set')) + or (x == '_timestamp')] res = [] table_query = '' @@ -546,41 +512,9 @@ class ModelSQL(ModelStorage): for i in res: i[field] = res_trans.get(i['id'], False) or i[field] - for table in cls._inherits: - field = cls._inherits[table] - inherits_fields = list( - set(cls._inherit_fields.keys()).intersection( - set(fields_names + fields_related.keys() + datetime_fields) - ).difference(set(cls._fields.keys()))) - if not inherits_fields: - for record in res: - if field not in fields_names + fields_related.keys() + \ - datetime_fields: - del record[field] - continue - inherit_related_fields = [] - for inherit_field in inherits_fields: - if inherit_field in fields_related: - for field_related in fields_related[inherit_field]: - inherit_related_fields.append( - inherit_field + '.' + field_related) - res2 = pool.get(table).read([x[field] for x in res], - fields_names=inherits_fields + inherit_related_fields) - - res3 = {} - for i in res2: - res3[i['id']] = i - del i['id'] - - for record in res: - record.update(res3[record[field]]) - if field not in \ - fields_names + fields_related.keys() + datetime_fields: - del record[field] - ids = [x['id'] for x in res] - # all non inherited fields for which there is a get attribute + # all fields for which there is a get attribute fields_post = [x for x in fields_names + fields_related.keys() + datetime_fields if x in cls._fields and hasattr(cls._fields[x], 'get')] @@ -777,22 +711,17 @@ class ModelSQL(ModelStorage): upd0 = [] upd1 = [] upd_todo = [] - updend = [] direct = [] for field in values: - if field in cls._fields: - if not hasattr(cls._fields[field], 'set'): - if ((not getattr(cls._fields[field], 'translate', False)) - or (Transaction().language - == Config.get_language())): - upd0.append(('"' + field + '"', '%s')) - upd1.append(FIELDS[cls._fields[field]._type] - .sql_format(values[field])) - direct.append(field) - else: - upd_todo.append(field) + if not hasattr(cls._fields[field], 'set'): + if ((not getattr(cls._fields[field], 'translate', False)) + or (Transaction().language == Config.get_language())): + upd0.append(('"' + field + '"', '%s')) + upd1.append(FIELDS[cls._fields[field]._type] + .sql_format(values[field])) + direct.append(field) else: - updend.append(field) + upd_todo.append(field) upd0.append(('write_uid', '%s')) upd0.append(('write_date', '%s')) @@ -894,24 +823,6 @@ class ModelSQL(ModelStorage): 'FROM "' + cls._table + '" ' 'WHERE id = %s', (obj_id,)) - for iname in cls._inherits: - col = cls._inherits[iname] - iids = [] - for i in range(0, len(ids), cursor.IN_MAX): - sub_ids = ids[i:i + cursor.IN_MAX] - red_sql, red_ids = reduce_ids('id', sub_ids) - cursor.execute('SELECT DISTINCT "' + col + '" ' - 'FROM "' + cls._table + '" WHERE ' + red_sql, - red_ids) - iids.extend([x[0] for x in cursor.fetchall()]) - - values2 = {} - for val in updend: - if cls._inherit_fields[val][0] == iname: - values2[val] = values[val] - IModel = pool.get(iname) - IModel.write(IModel.browse(iids), values2) - cls._validate(records) # Check for Modified Preorder Tree Traversal @@ -1330,41 +1241,6 @@ class ModelSQL(ModelStorage): domain = domain[:] cursor = Transaction().cursor - def column_get(model, field_name): - field = model._fields.get(field_name) - if not field: - if not field_name in model._inherit_fields: - raise Exception('ValidateError', 'Field "%s" doesn\'t ' - 'exist on "%s"' % (field_name, model.__name__)) - parent_model = pool.get(model._inherit_fields[field_name][0]) - field = column_get(parent_model, field_name) - return field - - def get_model_for_field(model, field): - if field in model._fields: - return model - else: - parent_model = pool.get(model._inherit_fields[field][0]) - return get_model_for_field(parent_model, field) - - def get_inherits_join(model, field): - if field in model._fields: - return [] - itable = pool.get(model._inherit_fields[field][0]) - table_query = '' - table_arg = [] - if itable.table_query(): - table_query, table_args = model.table_query() - table_query = '(' + table_query + ') AS ' - table_join = ('LEFT JOIN ' + table_query + - '"' + itable._table + '" ON ' - '"%s".id = "%s"."%s"' - % (itable._table, model._table, - model._inherits[itable.__name__])) - inherits = [(table_join, table_arg)] - inherits.extend(get_inherits_join(itable, field)) - return inherits - for arg in domain: if arg[1] not in OPERATORS: raise Exception('ValidateError', 'Argument "%s" not supported' @@ -1373,21 +1249,13 @@ class ModelSQL(ModelStorage): joins = [] while i < len(domain): fargs = domain[i][0].split('.', 1) - if fargs[0] in cls._inherit_fields: - inherit_joins = get_inherits_join(cls, fargs[0]) - for (table_join, table_arg) in inherit_joins: - if table_join not in tables: - tables.append(table_join) - tables_args.extend(table_arg) - - field = column_get(cls, fargs[0]) - table = get_model_for_field(cls, fargs[0]) + field = getattr(cls, fargs[0]) + table = cls if len(fargs) > 1: if field._type == 'many2one': Target = pool.get(field.model_name) m2o_search = [(fargs[1], domain[i][1], domain[i][2])] - if ('active' in Target._fields - or 'active' in Target._inherit_fields): + if 'active' in Target._fields: m2o_search += [('active', 'in', (True, False))] if hasattr(field, 'search'): domain.extend([(fargs[0], 'in', @@ -1411,10 +1279,7 @@ class ModelSQL(ModelStorage): else: Relation = Target origin, target = field.field, 'id' - if origin in Relation._fields: - rev_field = Relation._fields[origin] - else: - rev_field = Relation._inherit_fields[origin][2] + rev_field = Relation._fields[origin] if rev_field._type == 'reference': sql_type = FIELDS[ cls.id._type].sql_type(cls.id)[0] @@ -1452,10 +1317,7 @@ class ModelSQL(ModelStorage): if Field.table_query(): table_query, table_args = Field.table_query() table_query = '(' + table_query + ') AS ' - if field.field in Field._fields: - rev_field = Field._fields[field.field] - else: - rev_field = Field._inherit_fields[field.field][2] + rev_field = Field._fields[field.field] if rev_field._type == 'reference': sql_type = FIELDS[cls.id._type].sql_type(cls.id)[0] select = ('CAST(SPLIT_PART("%s", \',\', 2) AS %s)' @@ -1546,11 +1408,7 @@ class ModelSQL(ModelStorage): if Relation.table_query(): table_query, table_args = Relation.table_query() table_query = '(' + table_query + ') AS ' - if field.origin in Relation._fields: - origin_field = Relation._fields[field.origin] - else: - origin_field = \ - Relation._inherit_fields[field.origin][2] + origin_field = Relation._fields[field.origin] if origin_field._type == 'reference': sql_type = FIELDS[cls.id._type].sql_type(cls.id)[0] select = ('CAST(SPLIT_PART("%s", \',\', 2) AS %s)' @@ -1650,8 +1508,7 @@ class ModelSQL(ModelStorage): if isinstance(domain[i][2], basestring): Field = pool.get(field.model_name) m2o_search = [('rec_name', domain[i][1], domain[i][2])] - if ('active' in Field._fields - or 'active' in Field._inherit_fields): + if 'active' in Field._fields: m2o_search += [('active', 'in', (True, False))] res_ids = map(int, Field.search(m2o_search, order=[])) domain[i] = (domain[i][0], 'in', res_ids, table) @@ -1722,10 +1579,10 @@ class ModelSQL(ModelStorage): qu1, qu2 = [], [] for arg in domain: - table = get_model_for_field(cls, arg[0]) - if table == cls and len(arg) > 3: + table = cls + if len(arg) > 3: table = arg[3] - column = column_get(table, arg[0]) + column = getattr(table, arg[0]) if arg[1] in ('inselect', 'notinselect'): clause = 'IN' if arg[1] == 'notinselect': @@ -1914,61 +1771,6 @@ class ModelSQL(ModelStorage): tables.insert(0, table_join) return order_by, tables, tables_args - obj2 = None - if obj._rec_name in obj._inherit_fields.keys(): - obj2 = pool.get( - obj._inherit_fields[obj._rec_name][0]) - field_name = obj._rec_name - - if obj._order_name in obj._inherit_fields.keys(): - obj2 = pool.get( - obj._inherit_fields[obj._order_name][0]) - field_name = obj._order_name - - if obj2 and field_name: - table_name2 = obj2._table - link_field2 = obj._inherits[obj2.__name__] - order_by, tables, tables_args = \ - obj2._order_calc(field_name, otype) - - table_join = ('LEFT JOIN "' + table_name + '" AS ' - '"' + table_name + '.' + link_field + '" ON ' - '"%s.%s".id = "%s"."%s"' - % (table_name, link_field, cls._table, link_field)) - for i in range(len(order_by)): - if table_name in order_by[i]: - order_by[i] = order_by[i].replace(table_name, - table_name + '.' + link_field) - for i in range(len(tables)): - if table_name in tables[i]: - args = tables_args.pop(tables[i], []) - tables[i] = tables[i].replace(table_name, - table_name + '.' + link_field) - tables_args[tables[i]] = args - if table_join not in tables: - tables.insert(0, table_join) - tables_args[table_join] = [] - - table_join2 = ('LEFT JOIN "' + table_name2 + '" AS ' - '"' + table_name2 + '.' + link_field2 + '" ON ' - '"%s.%s".id = "%s.%s"."%s"' - % (table_name2, link_field2, table_name, link_field, - link_field2)) - for i in range(len(order_by)): - if table_name2 in order_by[i]: - order_by[i] = order_by[i].replace(table_name2, - table_name2 + '.' + link_field2) - for i in range(1, len(tables)): - if table_name2 in tables[i]: - args = tables_args.pop(tables[i], []) - tables[i] = tables[i].replace(table_name2, - table_name2 + '.' + link_field2) - tables_args[tables[i]] = args - if table_join2 not in tables: - tables.insert(1, table_join2) - tables_args[table_join2] = [] - return order_by, tables, tables_args - if (field_name in cls._fields and getattr(cls._fields[field_name], 'translate', False)): translation_table = ('ir_translation_%s_%s' @@ -2049,18 +1851,6 @@ class ModelSQL(ModelStorage): % (table_name, field_name, otype)) return order_by, tables, tables_args - if field in cls._inherit_fields.keys(): - obj = pool.get(cls._inherit_fields[field][0]) - table_name = obj._table - link_field = cls._inherits[obj.__name__] - order_by, tables, tables_args = obj._order_calc(field, otype) - table_join = ('LEFT JOIN "' + table_name + '" ON ' - '"%s".id = "%s"."%s"' - % (table_name, cls._table, link_field)) - if table_join not in tables: - tables.insert(0, table_join) - return order_by, tables, tables_args - raise Exception('Error', 'Wrong field name (%s) for %s in order!' % (field, cls.__name__)) diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py index 61beeaae6b..ca5cf87684 100644 --- a/trytond/model/modelstorage.py +++ b/trytond/model/modelstorage.py @@ -15,7 +15,7 @@ except ImportError: import StringIO from decimal import Decimal -from itertools import islice, ifilter, ifilterfalse, chain, izip +from itertools import islice, ifilter, chain, izip from functools import reduce from trytond.model import Model @@ -304,10 +304,7 @@ class ModelStorage(Model): field_defs[field_name]['relation']) relation_field = field_defs[field_name]['relation_field'] if relation_field: - if relation_field in Relation._fields: - field = Relation._fields[relation_field] - else: - field = Relation._inherit_fields[relation_field][2] + field = Relation._fields[relation_field] if field._type == 'reference': value = str(new_record) else: @@ -368,8 +365,7 @@ class ModelStorage(Model): records = cls.search(domain, offset=offset, limit=limit, order=order) if not fields_names: - fields_names = list(set(cls._fields.keys() - + cls._inherit_fields.keys())) + fields_names = cls._fields.keys() if 'id' not in fields_names: fields_names.append('id') return cls.read(map(int, records), fields_names) @@ -380,10 +376,9 @@ class ModelStorage(Model): domain = reduce_domain(domain) # if the object has a field named 'active', filter out all inactive # records unless they were explicitely asked for - if not (('active' in cls._fields - or 'active' in cls._inherit_fields.keys()) - and (active_test - and Transaction().context.get('active_test', True))): + if not ('active' in cls._fields + and active_test + and Transaction().context.get('active_test', True)): return domain def process(domain): @@ -417,8 +412,7 @@ class ModelStorage(Model): It is used by the Function field rec_name. ''' rec_name = self._rec_name - if (rec_name not in self._fields - and rec_name not in self._inherit_fields): + if rec_name not in self._fields: rec_name = 'id' return unicode(getattr(self, rec_name)) @@ -428,8 +422,7 @@ class ModelStorage(Model): Return a list of arguments for search on rec_name. ''' rec_name = cls._rec_name - if (rec_name not in cls._fields - and rec_name not in cls._inherit_fields): + if rec_name not in cls._fields: return [] return [(rec_name,) + clause[1:]] @@ -470,13 +463,7 @@ class ModelStorage(Model): break field_name = fields_tree[i] eModel = pool.get(value.__name__) - if field_name in eModel._fields: - field = eModel._fields[field_name] - elif field_name in eModel._inherit_fields: - field = eModel._inherit_fields[field_name][2] - else: - raise Exception('Field %s not available on object "%s"' - % (field_name, eModel.__name__)) + field = eModel._fields[field_name] if field.states and 'invisible' in field.states: pyson_invisible = PYSONEncoder().encode( field.states['invisible']) @@ -833,13 +820,7 @@ class ModelStorage(Model): Function that checks if there is no recursion in the tree composed with parent as parent field name. ''' - if parent in cls._fields: - parent_type = cls._fields[parent]._type - elif parent in cls._inherit_fields: - parent_type = cls._inherit_fields[parent][2]._type - else: - raise Exception('Field %s not available on object "%s"' - % (parent, cls.__name__)) + parent_type = cls._fields[parent]._type if parent_type not in ('many2one', 'many2many'): raise Exception( @@ -1161,8 +1142,7 @@ class ModelStorage(Model): pool = Pool() vals = {} for field in defaults.keys(): - fld_def = (field in cls._fields) and cls._fields[field] \ - or cls._inherit_fields[field][2] + fld_def = cls._fields[field] if fld_def._type in ('many2one', 'one2one'): if isinstance(defaults[field], (list, tuple)): vals[field] = defaults[field][0] @@ -1223,13 +1203,10 @@ class ModelStorage(Model): self._local_cache.counter = counter # fetch the definition of the field - if name in self._fields: + try: field = self._fields[name] - elif name in self._inherit_fields: - field = self._inherit_fields[name][2] - else: - raise AttributeError("'%s' Model has no attribute '%s'" - % (self.__name__, name)) + except KeyError: + raise AttributeError('"%s" has no attribute "%s"' % (self, name)) try: return self._local_cache[self.id][name] @@ -1248,17 +1225,12 @@ class ModelStorage(Model): if field.loading == 'eager': FieldAccess = Pool().get('ir.model.field.access') fread_accesses = {} - for inherit_name in self._inherits: - Inherit = Pool().get(inherit_name) - fread_accesses.update(FieldAccess.check(inherit_name, - Inherit._fields.keys(), 'read', access=True)) fread_accesses.update(FieldAccess.check(self.__name__, self._fields.keys(), 'read', access=True)) to_remove = set(x for x, y in fread_accesses.iteritems() if not y and x != name) threshold = BROWSE_FIELD_TRESHOLD - inherit_threshold = threshold - len(self._fields) def not_cached(item): fname, field = item @@ -1274,17 +1246,6 @@ class ModelStorage(Model): fname, field = item return fname in self._fields - if inherit_threshold > 0: - ifields = ((fname, field) - for fname, (_, _, field) in - self._inherit_fields.iteritems()) - ifields = ifilterfalse(overrided, - ifilter(to_load, - ifilter(not_cached, ifields))) - ifields = islice(ifields, 0, inherit_threshold) - ffields.update(ifields) - threshold -= inherit_threshold - ifields = ifilter(to_load, ifilter(not_cached, self._fields.iteritems())) @@ -1294,11 +1255,7 @@ class ModelStorage(Model): # add datetime_field for field in ffields.values(): if hasattr(field, 'datetime_field') and field.datetime_field: - if field.datetime_field in self._fields: - datetime_field = self._fields[field.datetime_field] - else: - datetime_field = self._inherit_fields[ - field.datetime_field][2] + datetime_field = self._fields[field.datetime_field] ffields[field.datetime_field] = datetime_field def filter_(id_): @@ -1393,10 +1350,7 @@ class ModelStorage(Model): if not self._values: return values for fname, value in self._values.iteritems(): - if fname in self._fields: - field = self._fields[fname] - else: - field = self._inherit_fields[fname][2] + field = self._fields[fname] if field._type in ('many2one', 'one2one', 'reference'): if value: if value.id < 0 and field._type != 'reference': @@ -1453,14 +1407,10 @@ class EvalEnvironment(dict): def __getitem__(self, item): if item.startswith('_parent_'): field = item[8:] - if field in self._model._fields: - model_name = self._model._fields[field].model_name - else: - model_name = self._model._inherit_fields[field][2].model_name + model_name = self._model._fields[field].model_name ParentModel = Pool().get(model_name) return EvalEnvironment(getattr(self._record, field), ParentModel) - if (item in self._model._fields - or item in self._model._inherit_fields): + if item in self._model._fields: value = getattr(self._record, item) if isinstance(value, Model): return value.id diff --git a/trytond/model/modelview.py b/trytond/model/modelview.py index 322eedf8b6..eba53c4488 100644 --- a/trytond/model/modelview.py +++ b/trytond/model/modelview.py @@ -327,24 +327,6 @@ class ModelView(Model): if field_to_remove in field.depends: fields_to_remove.append(name) - # Find field inherited without read access - for inherit_name in cls._inherits: - Inherit = pool.get(inherit_name) - fread_accesses = FieldAccess.check(Inherit.__name__, - Inherit._fields.keys(), 'read', access=True) - fields_to_remove += list(x for x, y in fread_accesses.iteritems() - if not y and x not in cls._fields.keys()) - - # Find relation field without read access - for name, field in Inherit._fields.iteritems(): - if not check_relation(Inherit, field): - fields_to_remove.append(name) - - for name, field in Inherit._fields.iteritems(): - for field_to_remove in fields_to_remove: - if field_to_remove in field.depends: - fields_to_remove.append(name) - # Remove field without read access for field in fields_to_remove: for element in tree.xpath( @@ -372,26 +354,19 @@ class ModelView(Model): if field_children: fields_def.setdefault(field_children, {'name': field_children}) - model, field = None, None if field_children in cls._fields: - model = cls field = cls._fields[field_children] - elif field_children in cls._inherit_fields: - model_name, model, field = cls._inherit_fields[field_children] - if model and field and field.model_name == model.__name__: fields_def.setdefault(field.field, {'name': field.field}) for field_name in fields_def.keys(): if field_name in cls._fields: field = cls._fields[field_name] - elif field_name in cls._inherit_fields: - field = cls._inherit_fields[field_name][2] else: continue for depend in field.depends: fields_def.setdefault(depend, {'name': depend}) - if ('active' in cls._fields) or ('active' in cls._inherit_fields): + if 'active' in cls._fields: fields_def.setdefault('active', {'name': 'active'}) arch = etree.tostring(tree, encoding='utf-8', pretty_print=False) @@ -424,11 +399,7 @@ class ModelView(Model): if element.get(attr): fields_attrs.setdefault(element.get(attr), {}) try: - if element.get(attr) in cls._fields: - field = cls._fields[element.get(attr)] - else: - field = cls._inherit_fields[element.get( - attr)][2] + field = cls._fields[element.get(attr)] if hasattr(field, 'model_name'): relation = field.model_name else: diff --git a/trytond/res/ir.xml b/trytond/res/ir.xml index a071020197..dd99cc253a 100644 --- a/trytond/res/ir.xml +++ b/trytond/res/ir.xml @@ -459,6 +459,59 @@ this repository contains the full copyright notices and license terms. --> [('groups', '=', None)] + + + + + + + [('groups', 'in', [g.id for g in user.groups])] + + + + [('groups', '=', None)] + + + + + + + + + [('groups', 'in', [g.id for g in user.groups])] + + + + [('groups', '=', None)] + + + + + + + + + [('groups', 'in', [g.id for g in user.groups])] + + + + [('groups', '=', None)] + + + + + + + + + [('groups', 'in', [g.id for g in user.groups])] + + + + [('groups', '=', None)] + + + diff --git a/trytond/test/__init__.py b/trytond/test/__init__.py index 6528488867..8d200096c8 100644 --- a/trytond/test/__init__.py +++ b/trytond/test/__init__.py @@ -90,11 +90,6 @@ def register(): DictRequired, Singleton, URLObject, - ModelInherits, - ModelInheritsSubModel, - ModelInheritsSubSubModel, - ModelInheritsSubSubSubModel, - ModelInheritsOverriddenFieldModel, ModelSQLRequiredField, MPTT, ImportDataBoolean, diff --git a/trytond/test/model.py b/trytond/test/model.py index ff5a006cad..607f6ca9fb 100644 --- a/trytond/test/model.py +++ b/trytond/test/model.py @@ -3,9 +3,7 @@ from trytond.model import ModelSingleton, ModelSQL, fields __all__ = [ - 'Singleton', 'URLObject', 'ModelInherits', 'ModelInheritsSubModel', - 'ModelInheritsSubSubModel', 'ModelInheritsSubSubSubModel', - 'ModelInheritsOverriddenFieldModel', 'ModelSQLRequiredField' + 'Singleton', 'URLObject', 'ModelSQLRequiredField', ] @@ -25,53 +23,6 @@ class URLObject(ModelSQL): name = fields.Char('Name') -class ModelInherits(ModelSQL): - 'Model Inherits' - __name__ = 'test.model_inherits' - - name = fields.Char('Name') - - -class ModelInheritsSubModel(ModelSQL): - 'Model Inherits Sub-Model' - __name__ = 'test.submodel' - _inherits = {'test.model_inherits': 'parent_model'} - - subfield = fields.Char('SubField') - parent_model = fields.Many2One('test.model_inherits', 'Parent model', - required=True) - - -class ModelInheritsSubSubModel(ModelSQL): - 'Model Inherits Sub-Sub-Model' - __name__ = 'test.subsubmodel' - _inherits = {'test.submodel': 'parent_model'} - - subsubfield = fields.Char('SubField') - parent_model = fields.Many2One('test.submodel', 'Parent model', - required=True) - - -class ModelInheritsSubSubSubModel(ModelSQL): - 'Model Inherits Sub-Sub-Sub-Model' - __name__ = 'test.subsubsubmodel' - _inherits = {'test.subsubmodel': 'parent_model'} - - subsubsubfield = fields.Char('SubField') - parent_model = fields.Many2One('test.subsubmodel', 'Parent model', - required=True) - - -class ModelInheritsOverriddenFieldModel(ModelSQL): - 'Model Inherits Overridden Field Model' - __name__ = 'test.overriddeninheritedfieldmodel' - _inherits = {'test.subsubmodel': 'parent_model'} - - subfield = fields.Integer('Overridden field') - parent_model = fields.Many2One('test.subsubmodel', 'Parent model', - required=True) - - class ModelSQLRequiredField(ModelSQL): 'model with a required field' __name__ = 'test.modelsql' diff --git a/trytond/tests/test_model_inherits.py b/trytond/tests/test_model_inherits.py deleted file mode 100644 index 1f7282c3f8..0000000000 --- a/trytond/tests/test_model_inherits.py +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env python -# -*- 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 unittest -from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \ - install_module -from trytond.transaction import Transaction - - -class ModelInheritsTestCase(unittest.TestCase): - ''' - Test ModelInheritSearch - ''' - - def setUp(self): - install_module('test') - self.parent = POOL.get('test.model_inherits') - self.sub = POOL.get('test.submodel') - self.subsub = POOL.get('test.subsubmodel') - self.subsubsub = POOL.get('test.subsubsubmodel') - self.overridden = POOL.get('test.overriddeninheritedfieldmodel') - - def create_data(self): - parent_id, = self.parent.create([{'name': 'parent'}]) - sub_id, = self.sub.create([{ - 'name': 'sub', - 'subfield': 'level1', - }]) - subsub_id, = self.subsub.create([{ - 'name': 'subsub', - 'subfield': 'level2', - 'subsubfield': 'ssfcontent', - }]) - subsubsub_id, = self.subsubsub.create([{ - 'name': 'subsubsub', - 'subfield': 'level3', - 'subsubfield': 'ssfcontent2', - 'subsubsubfield': 'sssfcontent', - }]) - overridden_id, = self.overridden.create([{ - 'name': 'overridden', - 'subfield': 3, - }]) - return (parent_id, sub_id, subsub_id, subsubsub_id, overridden_id) - - def test0010selfsearch(self): - ''' - Test searching on own field - ''' - with Transaction().start(DB_NAME, USER, - context=CONTEXT) as transaction: - - (_parent_id, _sub_id, _subsub_id, subsubsub_id, overridden_id) = \ - self.create_data() - - ids = self.subsubsub.search([ - ('subsubsubfield', '=', 'sssfcontent'), - ]) - self.assertEqual(ids, [subsubsub_id]) - - transaction.cursor.rollback() - - def test0020parentsearch(self): - ''' - Test searching on parent field - ''' - with Transaction().start(DB_NAME, USER, - context=CONTEXT) as transaction: - - (_parent_id, _sub_id, _subsub_id, subsubsub_id, overridden_id) = \ - self.create_data() - - ids = self.subsubsub.search([('subsubfield', '=', 'ssfcontent2')]) - self.assertEqual(ids, [subsubsub_id]) - - ids = self.subsubsub.search([('subsubfield', '=', 'ssfcontent')]) - self.assertEqual(ids, []) - - transaction.cursor.rollback() - - def test0030granparentsearch(self): - ''' - Test searching on granparent field - ''' - with Transaction().start(DB_NAME, USER, - context=CONTEXT) as transaction: - - (_parent_id, _sub_id, _subsub_id, subsubsub_id, overridden_id) = \ - self.create_data() - - ids = self.subsubsub.search([('subfield', '=', 'level3')]) - self.assertEqual(ids, [subsubsub_id]) - - ids = self.subsubsub.search([('subfield', '=', 'level1')]) - self.assertEqual(ids, []) - - transaction.cursor.rollback() - - def test0040greatgranparentsearch(self): - ''' - Test searching on greatgranparent field - ''' - with Transaction().start(DB_NAME, USER, - context=CONTEXT) as transaction: - - (_parent_id, _sub_id, _subsub_id, subsubsub_id, overridden_id) = \ - self.create_data() - - ids = self.subsubsub.search([('name', '=', 'subsubsub')]) - self.assertEqual(ids, [subsubsub_id]) - - ids = self.subsubsub.search([('name', '=', 'parent')]) - self.assertEqual(ids, []) - - transaction.cursor.rollback() - - def test0050overriddenfieldsearch(self): - ''' - Test searching on greatgranparent field - ''' - with Transaction().start(DB_NAME, USER, - context=CONTEXT) as transaction: - - (_parent_id, _sub_id, _subsub_id, subsubsub_id, overridden_id) = \ - self.create_data() - - ids = self.overridden.search([('subfield', '=', 3)]) - self.assertEqual(ids, [overridden_id]) - - transaction.cursor.rollback() - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(ModelInheritsTestCase) - -if __name__ == '__main__': - suite = suite() - unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/trytond/tests/test_tryton.py b/trytond/tests/test_tryton.py index e01eb72fd0..71bf65b921 100644 --- a/trytond/tests/test_tryton.py +++ b/trytond/tests/test_tryton.py @@ -255,8 +255,6 @@ def all_suite(): suite_.addTests(test_mixins.suite()) import trytond.tests.test_wizard as test_wizard suite_.addTests(test_wizard.suite()) - import trytond.tests.test_model_inherits as test_inherits - suite_.addTests(test_inherits.suite()) import trytond.tests.test_modelsql as test_modelsql suite_.addTests(test_modelsql.suite()) import trytond.tests.test_cache as test_cache