Vo Minh Thu (OpenERP) has proposed merging 
lp:~openerp-dev/openobject-server/trunk-register-simpler-vmt into 
lp:openobject-server.

Requested reviews:
  OpenERP Core Team (openerp)

For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-register-simpler-vmt/+merge/64687
-- 
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-register-simpler-vmt/+merge/64687
Your team OpenERP R&D Team is subscribed to branch 
lp:~openerp-dev/openobject-server/trunk-register-simpler-vmt.
=== modified file 'openerp/modules/module.py'
--- openerp/modules/module.py	2011-05-11 17:24:48 +0000
+++ openerp/modules/module.py	2011-06-15 13:31:30 +0000
@@ -274,22 +274,17 @@
 
     logger.notifyChannel('init', netsvc.LOG_INFO,
         'module %s: creating or updating database tables' % module_name)
-    # TODO _auto_init doesn't seem to return anything
-    # so this todo list would be useless.
     todo = []
     for obj in obj_list:
-        try:
-            # TODO the module in the context doesn't seem usefull:
-            # it is available (at least) in the class' _module attribute.
-            # (So module_name would be useless too.)
-            result = obj._auto_init(cr, {'module': module_name})
-        except Exception, e:
-            raise
+        result = obj._auto_init(cr, {'module': module_name})
         if result:
             todo += result
         if hasattr(obj, 'init'):
             obj.init(cr)
         cr.commit()
+    for obj in obj_list:
+        obj._auto_end(cr, {'module': module_name})
+        cr.commit()
     todo.sort()
     for t in todo:
         t[1](cr, *t[2])

=== modified file 'openerp/osv/orm.py'
--- openerp/osv/orm.py	2011-06-10 17:31:30 +0000
+++ openerp/osv/orm.py	2011-06-15 13:31:30 +0000
@@ -416,6 +416,32 @@
     return f_type
 
 
+class MetaModel(type):
+    """ Metaclass for the Model.
+
+    This class is used as the metaclass for the Model class to discover
+    the models defined in a module (i.e. without instanciating them).
+    If the automatic discovery is not needed, it is possible to set the
+    model's _register attribute to False.
+
+    """
+
+    module_to_models = {}
+
+    def __init__(self, name, bases, attrs):
+        if not self._register:
+            self._register = True
+            super(MetaModel, self).__init__(name, bases, attrs)
+            return
+
+        module_name = self.__module__.split('.')[0]
+        if not hasattr(self, '_module'):
+            self._module = module_name
+
+        # Remember which models to instanciate for this module.
+        self.module_to_models.setdefault(self._module, []).append(self)
+
+
 class orm_template(object):
     """ Base class for OpenERP models.
 
@@ -445,6 +471,11 @@
     _sequence = None
     _description = None
     _inherits = {}
+    # Mapping from inherits'd field name to triple (m, r, f)
+    # where m is the model from which it is inherits'd,
+    # r is the (local) field towards m,
+    # and f is the _column object itself.
+    _inherit_fields = {}
     _table = None
     _invalids = set()
     _log_create = False
@@ -469,9 +500,11 @@
         raise NotImplementedError(_('The read_group method is not implemented on this object !'))
 
     def _field_create(self, cr, context=None):
-        """
+        """ Create entries in ir_model_fields for all the model's fields.
 
-        Create/update entries in ir_model, ir_model_data, and ir_model_fields.
+        If necessary, also create an entry in ir_model, and if called from the
+        modules loading scheme (by receiving 'module' in the context), also
+        create entries in ir_model_data (for the model and the fields).
 
         - create an entry in ir_model (if there is not already one),
         - create an entry in ir_model_data (if there is not already one, and if
@@ -572,6 +605,9 @@
         raise_on_invalid_object_name(self._name)
         self._field_create(cr, context=context)
 
+    def _auto_end(self, cr, context=None):
+        pass
+
     #
     # Goal: try to apply inheritance at the instanciation level and
     #       put objects in the pool var
@@ -637,7 +673,7 @@
                     else:
                         new.extend(cls.__dict__.get(s, []))
                     nattr[s] = new
-                cls = type(name, (cls, parent_class), nattr)
+                cls = type(name, (cls, parent_class), dict(nattr, _register=False))
         obj = object.__new__(cls)
         obj.__init__(pool, cr)
         return obj
@@ -1222,6 +1258,8 @@
 
     def fields_get_keys(self, cr, user, context=None):
         res = self._columns.keys()
+        # TODO I believe this loop can be replace by
+        # res.extend(self._inherit_fields.key())
         for parent in self._inherits:
             res.extend(self.pool.get(parent).fields_get_keys(cr, user, context))
         return res
@@ -2070,7 +2108,6 @@
 class orm_memory(orm_template):
 
     _protected = ['read', 'write', 'create', 'default_get', 'perm_read', 'unlink', 'fields_get', 'fields_view_get', 'search', 'name_get', 'distinct_field_get', 'name_search', 'copy', 'import_data', 'search_count', 'exists']
-    _inherit_fields = {}
     _max_count = config.get('osv_memory_count_limit')
     _max_hours = config.get('osv_memory_age_limit')
     _check_time = 20
@@ -2559,149 +2596,74 @@
         - alter existing database columns to match _columns,
         - create database tables to match _columns,
         - add database indices to match _columns,
+        - save in self._foreign_keys a list a foreign keys to create (see
+          _auto_end).
 
         """
+        self._foreign_keys = []
         raise_on_invalid_object_name(self._name)
         if context is None:
             context = {}
         store_compute = False
-        create = False
         todo_end = []
+        update_custom_fields = context.get('update_custom_fields', False)
         self._field_create(cr, context=context)
+        create = not self._table_exist(cr)
+
         if getattr(self, '_auto', True):
-            cr.execute("SELECT relname FROM pg_class WHERE relkind IN ('r','v') AND relname=%s", (self._table,))
-            if not cr.rowcount:
-                cr.execute('CREATE TABLE "%s" (id SERIAL NOT NULL, PRIMARY KEY(id)) WITHOUT OIDS' % (self._table,))
-                cr.execute("COMMENT ON TABLE \"%s\" IS '%s'" % (self._table, self._description.replace("'", "''")))
-                create = True
-                self.__schema.debug("Table '%s': created", self._table)
+
+            if create:
+                self._create_table(cr)
 
             cr.commit()
             if self._parent_store:
-                cr.execute("""SELECT c.relname
-                    FROM pg_class c, pg_attribute a
-                    WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid
-                    """, (self._table, 'parent_left'))
-                if not cr.rowcount:
-                    cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_left" INTEGER' % (self._table,))
-                    cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_right" INTEGER' % (self._table,))
-                    if 'parent_left' not in self._columns:
-                        self.__logger.error('create a column parent_left on object %s: fields.integer(\'Left Parent\', select=1)',
-                                            self._table)
-                        self.__schema.debug("Table '%s': added column '%s' with definition=%s",
-                                            self._table, 'parent_left', 'INTEGER')
-                    elif not self._columns['parent_left'].select:
-                        self.__logger.error('parent_left column on object %s must be indexed! Add select=1 to the field definition)',
-                                            self._table)
-                    if 'parent_right' not in self._columns:
-                        self.__logger.error('create a column parent_right on object %s: fields.integer(\'Right Parent\', select=1)',
-                                            self._table)
-                        self.__schema.debug("Table '%s': added column '%s' with definition=%s",
-                                            self._table, 'parent_right', 'INTEGER')
-                    elif not self._columns['parent_right'].select:
-                        self.__logger.error('parent_right column on object %s must be indexed! Add select=1 to the field definition)',
-                                            self._table)
-                    if self._columns[self._parent_name].ondelete != 'cascade':
-                        self.__logger.error("The column %s on object %s must be set as ondelete='cascade'",
-                                            self._parent_name, self._name)
-
-                    cr.commit()
+                if not self._parent_columns_exist(cr):
+                    self._create_parent_columns(cr)
                     store_compute = True
 
+            # Create the create_uid, create_date, write_uid, write_date, columns if desired.
             if self._log_access:
-                logs = {
-                    'create_uid': 'INTEGER REFERENCES res_users ON DELETE SET NULL',
-                    'create_date': 'TIMESTAMP',
-                    'write_uid': 'INTEGER REFERENCES res_users ON DELETE SET NULL',
-                    'write_date': 'TIMESTAMP'
-                }
-                for k in logs:
-                    cr.execute("""
-                        SELECT c.relname
-                          FROM pg_class c, pg_attribute a
-                         WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid
-                        """, (self._table, k))
-                    if not cr.rowcount:
-                        cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, logs[k]))
-                        cr.commit()
-                        self.__schema.debug("Table '%s': added column '%s' with definition=%s",
-                                            self._table, k, logs[k])
+                self._add_log_columns(cr)
 
             self._check_removed_columns(cr, log=False)
 
             # iterate on the "object columns"
-            todo_update_store = []
-            update_custom_fields = context.get('update_custom_fields', False)
-
-            cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size " \
-               "FROM pg_class c,pg_attribute a,pg_type t " \
-               "WHERE c.relname=%s " \
-               "AND c.oid=a.attrelid " \
-               "AND a.atttypid=t.oid", (self._table,))
-            col_data = dict(map(lambda x: (x['attname'], x),cr.dictfetchall()))
-
-
-            for k in self._columns:
+            column_data = self._select_column_data(cr)
+
+            for k, f in self._columns.iteritems():
                 if k in ('id', 'write_uid', 'write_date', 'create_uid', 'create_date'):
                     continue
-                #Not Updating Custom fields
-                if k.startswith('x_') and not update_custom_fields:
+                # Don't update custom (also called manual) fields
+                if f.manual and not update_custom_fields:
                     continue
 
-                f = self._columns[k]
-
                 if isinstance(f, fields.one2many):
-                    cr.execute("SELECT relname FROM pg_class WHERE relkind='r' AND relname=%s", (f._obj,))
-
-                    if self.pool.get(f._obj):
-                        if f._fields_id not in self.pool.get(f._obj)._columns.keys():
-                            if not self.pool.get(f._obj)._inherits or (f._fields_id not in self.pool.get(f._obj)._inherit_fields.keys()):
-                                raise except_orm('Programming Error', ("There is no reference field '%s' found for '%s'") % (f._fields_id, f._obj,))
-
-                    if cr.fetchone():
-                        cr.execute("SELECT count(1) as c FROM pg_class c,pg_attribute a WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid", (f._obj, f._fields_id))
-                        res = cr.fetchone()[0]
-                        if not res:
-                            cr.execute('ALTER TABLE "%s" ADD FOREIGN KEY (%s) REFERENCES "%s" ON DELETE SET NULL' % (self._obj, f._fields_id, f._table))
-                            self.__schema.debug("Table '%s': added foreign key '%s' with definition=REFERENCES \"%s\" ON DELETE SET NULL",
-                                self._obj, f._fields_id, f._table)
+                    self._o2m_raise_on_missing_reference(cr, f)
+
                 elif isinstance(f, fields.many2many):
-                    cr.execute("SELECT relname FROM pg_class WHERE relkind IN ('r','v') AND relname=%s", (f._rel,))
-                    if not cr.dictfetchall():
-                        if not self.pool.get(f._obj):
-                            raise except_orm('Programming Error', ('There is no reference available for %s') % (f._obj,))
-                        ref = self.pool.get(f._obj)._table
-#                        ref = f._obj.replace('.', '_')
-                        cr.execute('CREATE TABLE "%s" ("%s" INTEGER NOT NULL REFERENCES "%s" ON DELETE CASCADE, "%s" INTEGER NOT NULL REFERENCES "%s" ON DELETE CASCADE, UNIQUE("%s","%s")) WITH OIDS' % (f._rel, f._id1, self._table, f._id2, ref, f._id1, f._id2))
-                        cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (f._rel, f._id1, f._rel, f._id1))
-                        cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (f._rel, f._id2, f._rel, f._id2))
-                        cr.execute("COMMENT ON TABLE \"%s\" IS 'RELATION BETWEEN %s AND %s'" % (f._rel, self._table, ref))
-                        cr.commit()
-                        self.__schema.debug("Create table '%s': relation between '%s' and '%s'",
-                                            f._rel, self._table, ref)
+                    self._m2m_raise_or_create_relation(cr, f)
+
                 else:
-                    res = col_data.get(k, [])
-                    res = res and [res] or []
+                    res = column_data.get(k)
+
+                    # The field is not found as-is in database, try if it
+                    # exists with an old name.
                     if not res and hasattr(f, 'oldname'):
-                        cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size " \
-                            "FROM pg_class c,pg_attribute a,pg_type t " \
-                            "WHERE c.relname=%s " \
-                            "AND a.attname=%s " \
-                            "AND c.oid=a.attrelid " \
-                            "AND a.atttypid=t.oid", (self._table, f.oldname))
-                        res_old = cr.dictfetchall()
-                        if res_old and len(res_old) == 1:
+                        res = column_data.get(f.oldname)
+                        if res:
                             cr.execute('ALTER TABLE "%s" RENAME "%s" TO "%s"' % (self._table, f.oldname, k))
-                            res = res_old
-                            res[0]['attname'] = k
+                            res['attname'] = k
+                            column_data[k] = res
                             self.__schema.debug("Table '%s': renamed column '%s' to '%s'",
                                                 self._table, f.oldname, k)
 
-                    if len(res) == 1:
-                        f_pg_def = res[0]
-                        f_pg_type = f_pg_def['typname']
-                        f_pg_size = f_pg_def['size']
-                        f_pg_notnull = f_pg_def['attnotnull']
+                    # The field already exists in database. Possibly
+                    # change its type, rename it, drop it or change its
+                    # constraints.
+                    if res:
+                        f_pg_type = res['typname']
+                        f_pg_size = res['size']
+                        f_pg_notnull = res['attnotnull']
                         if isinstance(f, fields.function) and not f.store and\
                                 not getattr(f, 'nodrop', False):
                             self.__logger.info('column %s (%s) in table %s removed: converted to a function !\n',
@@ -2839,13 +2801,13 @@
                                     if res2:
                                         if res2[0]['confdeltype'] != POSTGRES_CONFDELTYPES.get(f.ondelete.upper(), 'a'):
                                             cr.execute('ALTER TABLE "' + self._table + '" DROP CONSTRAINT "' + res2[0]['conname'] + '"')
-                                            cr.execute('ALTER TABLE "' + self._table + '" ADD FOREIGN KEY ("' + k + '") REFERENCES "' + ref + '" ON DELETE ' + f.ondelete)
+                                            self._foreign_keys.append((self._table, k, ref, f.ondelete))
                                             cr.commit()
                                             self.__schema.debug("Table '%s': column '%s': XXX",
                                                 self._table, k)
-                    elif len(res) > 1:
-                        netsvc.Logger().notifyChannel('orm', netsvc.LOG_ERROR, "Programming error, column %s->%s has multiple instances !" % (self._table, k))
-                    if not res:
+
+                    # The field doesn't exist in database. Create it if necessary.
+                    else:
                         if not isinstance(f, fields.function) or f.store:
                             # add the missing field
                             cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, get_pg_type(f)[1]))
@@ -2866,21 +2828,21 @@
                                 cr.commit()
                                 netsvc.Logger().notifyChannel('data', netsvc.LOG_DEBUG, "Table '%s': setting default value of new column %s" % (self._table, k))
 
+                            # remember the functions to call for the stored fields
                             if isinstance(f, fields.function):
                                 order = 10
-                                if f.store is not True:
+                                if f.store is not True: # i.e. if f.store is a dict
                                     order = f.store[f.store.keys()[0]][2]
-                                todo_update_store.append((order, f, k))
+                                todo_end.append((order, self._update_store, (f, k)))
 
                             # and add constraints if needed
                             if isinstance(f, fields.many2one):
                                 if not self.pool.get(f._obj):
                                     raise except_orm('Programming Error', ('There is no reference available for %s') % (f._obj,))
                                 ref = self.pool.get(f._obj)._table
-#                                ref = f._obj.replace('.', '_')
                                 # ir_actions is inherited so foreign key doesn't work on it
                                 if ref != 'ir_actions':
-                                    cr.execute('ALTER TABLE "%s" ADD FOREIGN KEY ("%s") REFERENCES "%s" ON DELETE %s' % (self._table, k, ref, f.ondelete))
+                                    self._foreign_keys.append((self._table, k, ref, f.ondelete))
                                     self.__schema.debug("Table '%s': added foreign key '%s' with definition=REFERENCES \"%s\" ON DELETE %s",
                                         self._table, k, ref, f.ondelete)
                             if f.select:
@@ -2898,8 +2860,6 @@
                                         "ALTER TABLE %s ALTER COLUMN %s SET NOT NULL"
                                     self.__logger.warn(msg, k, self._table, self._table, k)
                             cr.commit()
-            for order, f, k in todo_update_store:
-                todo_end.append((order, self._update_store, (f, k)))
 
         else:
             cr.execute("SELECT relname FROM pg_class WHERE relkind IN ('r','v') AND relname=%s", (self._table,))
@@ -2907,6 +2867,134 @@
 
         cr.commit()     # start a new transaction
 
+        self._add_sql_constraints(cr)
+
+        if create:
+            self._execute_sql(cr)
+
+        if store_compute:
+            self._parent_store_compute(cr)
+            cr.commit()
+
+        return todo_end
+
+
+    def _auto_end(self, cr, context=None):
+        """ Create the foreign keys recorded by _auto_init. """
+        for t, k, r, d in self._foreign_keys:
+            cr.execute('ALTER TABLE "%s" ADD FOREIGN KEY ("%s") REFERENCES "%s" ON DELETE %s' % (t, k, r, d))
+        cr.commit()
+        del self._foreign_keys
+
+
+    def _table_exist(self, cr):
+        cr.execute("SELECT relname FROM pg_class WHERE relkind IN ('r','v') AND relname=%s", (self._table,))
+        return cr.rowcount
+
+
+    def _create_table(self, cr):
+        cr.execute('CREATE TABLE "%s" (id SERIAL NOT NULL, PRIMARY KEY(id)) WITHOUT OIDS' % (self._table,))
+        cr.execute("COMMENT ON TABLE \"%s\" IS '%s'" % (self._table, self._description.replace("'", "''")))
+        self.__schema.debug("Table '%s': created", self._table)
+
+
+    def _parent_columns_exist(self, cr):
+        cr.execute("""SELECT c.relname
+            FROM pg_class c, pg_attribute a
+            WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid
+            """, (self._table, 'parent_left'))
+        return cr.rowcount
+
+
+    def _create_parent_columns(self, cr):
+        cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_left" INTEGER' % (self._table,))
+        cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_right" INTEGER' % (self._table,))
+        if 'parent_left' not in self._columns:
+            self.__logger.error('create a column parent_left on object %s: fields.integer(\'Left Parent\', select=1)',
+                                self._table)
+            self.__schema.debug("Table '%s': added column '%s' with definition=%s",
+                                self._table, 'parent_left', 'INTEGER')
+        elif not self._columns['parent_left'].select:
+            self.__logger.error('parent_left column on object %s must be indexed! Add select=1 to the field definition)',
+                                self._table)
+        if 'parent_right' not in self._columns:
+            self.__logger.error('create a column parent_right on object %s: fields.integer(\'Right Parent\', select=1)',
+                                self._table)
+            self.__schema.debug("Table '%s': added column '%s' with definition=%s",
+                                self._table, 'parent_right', 'INTEGER')
+        elif not self._columns['parent_right'].select:
+            self.__logger.error('parent_right column on object %s must be indexed! Add select=1 to the field definition)',
+                                self._table)
+        if self._columns[self._parent_name].ondelete != 'cascade':
+            self.__logger.error("The column %s on object %s must be set as ondelete='cascade'",
+                                self._parent_name, self._name)
+
+        cr.commit()
+
+
+    def _add_log_columns(self, cr):
+        logs = {
+            'create_uid': 'INTEGER REFERENCES res_users ON DELETE SET NULL',
+            'create_date': 'TIMESTAMP',
+            'write_uid': 'INTEGER REFERENCES res_users ON DELETE SET NULL',
+            'write_date': 'TIMESTAMP'
+        }
+        for k in logs:
+            cr.execute("""
+                SELECT c.relname
+                  FROM pg_class c, pg_attribute a
+                 WHERE c.relname=%s AND a.attname=%s AND c.oid=a.attrelid
+                """, (self._table, k))
+            if not cr.rowcount:
+                cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, logs[k]))
+                cr.commit()
+                self.__schema.debug("Table '%s': added column '%s' with definition=%s",
+                                    self._table, k, logs[k])
+
+
+    def _select_column_data(self, cr):
+        cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size " \
+           "FROM pg_class c,pg_attribute a,pg_type t " \
+           "WHERE c.relname=%s " \
+           "AND c.oid=a.attrelid " \
+           "AND a.atttypid=t.oid", (self._table,))
+        return dict(map(lambda x: (x['attname'], x),cr.dictfetchall()))
+
+
+    def _o2m_raise_on_missing_reference(self, cr, f):
+        # TODO this check should be a method on fields.one2many.
+        other = self.pool.get(f._obj)
+        if other:
+            # TODO the condition could use fields_get_keys().
+            if f._fields_id not in other._columns.keys():
+                if f._fields_id not in other._inherit_fields.keys():
+                    raise except_orm('Programming Error', ("There is no reference field '%s' found for '%s'") % (f._fields_id, f._obj,))
+
+
+    def _m2m_raise_or_create_relation(self, cr, f):
+        cr.execute("SELECT relname FROM pg_class WHERE relkind IN ('r','v') AND relname=%s", (f._rel,))
+        if not cr.dictfetchall():
+            if not self.pool.get(f._obj):
+                raise except_orm('Programming Error', ('There is no reference available for %s') % (f._obj,))
+            ref = self.pool.get(f._obj)._table
+            cr.execute('CREATE TABLE "%s" ("%s" INTEGER NOT NULL, "%s" INTEGER NOT NULL, UNIQUE("%s","%s")) WITH OIDS' % (f._rel, f._id1, f._id2, f._id1, f._id2))
+            self._foreign_keys.append((f._rel, f._id1, self._table, 'CASCADE'))
+            self._foreign_keys.append((f._rel, f._id2, ref, 'CASCADE'))
+            cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (f._rel, f._id1, f._rel, f._id1))
+            cr.execute('CREATE INDEX "%s_%s_index" ON "%s" ("%s")' % (f._rel, f._id2, f._rel, f._id2))
+            cr.execute("COMMENT ON TABLE \"%s\" IS 'RELATION BETWEEN %s AND %s'" % (f._rel, self._table, ref))
+            cr.commit()
+            self.__schema.debug("Create table '%s': relation between '%s' and '%s'",
+                                f._rel, self._table, ref)
+
+
+    def _add_sql_constraints(self, cr):
+        """
+
+        Modify this model's database table constraints so they match the one in
+        _sql_constraints.
+
+        """
         for (key, con, _) in self._sql_constraints:
             conname = '%s_%s' % (self._table, key)
 
@@ -2955,17 +3043,16 @@
                     self.__schema.warn(sql_action['msg_err'])
                     cr.rollback()
 
-        if create:
-            if hasattr(self, "_sql"):
-                for line in self._sql.split(';'):
-                    line2 = line.replace('\n', '').strip()
-                    if line2:
-                        cr.execute(line2)
-                        cr.commit()
-        if store_compute:
-            self._parent_store_compute(cr)
-            cr.commit()
-        return todo_end
+
+    def _execute_sql(self, cr):
+        """ Execute the SQL code from the _sql attribute (if any)."""
+        if hasattr(self, "_sql"):
+            for line in self._sql.split(';'):
+                line2 = line.replace('\n', '').strip()
+                if line2:
+                    cr.execute(line2)
+                    cr.commit()
+
 
     @classmethod
     def createInstance(cls, pool, cr):
@@ -3044,18 +3131,18 @@
                 }
 
                 if field['ttype'] == 'selection':
-                    self._columns[field['name']] = getattr(fields, field['ttype'])(eval(field['selection']), **attrs)
+                    self._columns[field['name']] = fields.selection(eval(field['selection']), **attrs)
                 elif field['ttype'] == 'reference':
-                    self._columns[field['name']] = getattr(fields, field['ttype'])(selection=eval(field['selection']), **attrs)
+                    self._columns[field['name']] = fields.reference(selection=eval(field['selection']), **attrs)
                 elif field['ttype'] == 'many2one':
-                    self._columns[field['name']] = getattr(fields, field['ttype'])(field['relation'], **attrs)
+                    self._columns[field['name']] = fields.many2one(field['relation'], **attrs)
                 elif field['ttype'] == 'one2many':
-                    self._columns[field['name']] = getattr(fields, field['ttype'])(field['relation'], field['relation_field'], **attrs)
+                    self._columns[field['name']] = fields.one2many(field['relation'], field['relation_field'], **attrs)
                 elif field['ttype'] == 'many2many':
                     _rel1 = field['relation'].replace('.', '_')
                     _rel2 = field['model'].replace('.', '_')
                     _rel_name = 'x_%s_%s_%s_rel' % (_rel1, _rel2, field['name'])
-                    self._columns[field['name']] = getattr(fields, field['ttype'])(field['relation'], _rel_name, 'id1', 'id2', **attrs)
+                    self._columns[field['name']] = fields.many2many(field['relation'], _rel_name, 'id1', 'id2', **attrs)
                 else:
                     self._columns[field['name']] = getattr(fields, field['ttype'])(**attrs)
         self._inherits_check()
@@ -3074,18 +3161,25 @@
     #
 
     def _inherits_reload_src(self):
+        """ Recompute the _inherit_fields mapping on each _inherits'd child model."""
         for obj in self.pool.obj_pool.values():
             if self._name in obj._inherits:
                 obj._inherits_reload()
 
     def _inherits_reload(self):
+        """ Recompute the _inherit_fields mapping.
+
+        This will also call itself on each inherits'd child model.
+
+        """
         res = {}
         for table in self._inherits:
-            res.update(self.pool.get(table)._inherit_fields)
-            for col in self.pool.get(table)._columns.keys():
-                res[col] = (table, self._inherits[table], self.pool.get(table)._columns[col])
-            for col in self.pool.get(table)._inherit_fields.keys():
-                res[col] = (table, self._inherits[table], self.pool.get(table)._inherit_fields[col][2])
+            other = self.pool.get(table)
+            res.update(other._inherit_fields)
+            for col in other._columns.keys():
+                res[col] = (table, self._inherits[table], other._columns[col])
+            for col in other._inherit_fields.keys():
+                res[col] = (table, self._inherits[table], other._inherit_fields[col][2])
         self._inherit_fields = res
         self._inherits_reload_src()
 

=== modified file 'openerp/osv/osv.py'
--- openerp/osv/osv.py	2011-06-01 09:49:08 +0000
+++ openerp/osv/osv.py	2011-06-15 13:31:30 +0000
@@ -35,6 +35,8 @@
 from openerp.tools.func import wraps
 from openerp.tools.translate import translate
 from openerp.osv.orm import module_class_list
+from openerp.osv.orm import MetaModel
+
 
 class except_osv(Exception):
     def __init__(self, name, value, exc_type='warning'):
@@ -245,17 +247,24 @@
         for klass in module_class_list.get(module, []):
             res.append(klass.createInstance(self, cr))
 
+        # Instanciate classes automatically discovered.
+        for cls in MetaModel.module_to_models.get(module, []):
+            if cls not in module_class_list.get(module, []):
+                res.append(cls.createInstance(self, cr))
+
         return res
 
 
 class osv_memory(orm.orm_memory):
     """ Deprecated class. """
-    pass
+    __metaclass__ = MetaModel
+    _register = False # Set to false if the model shouldn't be automatically discovered.
 
 
 class osv(orm.orm):
     """ Deprecated class. """
-    pass
+    __metaclass__ = MetaModel
+    _register = False # Set to false if the model shouldn't be automatically discovered.
 
 
 def start_object_proxy():

_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help   : https://help.launchpad.net/ListHelp

Reply via email to