[IMP] module loading: iterate on the module graph in deterministic order (by sorting...
[odoo/odoo.git] / openerp / osv / osv.py
index 222c08d..76a403b 100644 (file)
 #
 ##############################################################################
 
-#
-# OSV: Objects Services
-#
+#.apidoc title: Objects Services (OSV)
+
+import logging
+from psycopg2 import IntegrityError, errorcodes
 
 import orm
+import openerp
 import openerp.netsvc as netsvc
 import openerp.pooler as pooler
-import copy
-import logging
-from psycopg2 import IntegrityError, errorcodes
+import openerp.sql_db as sql_db
 from openerp.tools.func import wraps
 from openerp.tools.translate import translate
+from openerp.osv.orm import MetaModel, Model, TransientModel, AbstractModel
+import openerp.exceptions
 
-module_list = []
-module_class_list = {}
-
+# Deprecated.
 class except_osv(Exception):
-    def __init__(self, name, value, exc_type='warning'):
+    def __init__(self, name, value):
         self.name = name
-        self.exc_type = exc_type
         self.value = value
-        self.args = (exc_type, name)
+        self.args = (name, value)
 
+service = None
 
-class object_proxy(netsvc.Service):
+class object_proxy(object):
     def __init__(self):
         self.logger = logging.getLogger('web-services')
-        netsvc.Service.__init__(self, 'object_proxy', audience='')
-        self.exportMethod(self.exec_workflow)
-        self.exportMethod(self.execute)
+        global service
+        service = self
 
     def check(f):
         @wraps(f)
@@ -78,7 +77,7 @@ class object_proxy(netsvc.Service):
                 # We open a *new* cursor here, one reason is that failed SQL
                 # queries (as in IntegrityError) will invalidate the current one.
                 cr = False
-                
+
                 if hasattr(src, '__call__'):
                     # callable. We need to find the right parameters to call
                     # the  orm._sql_message(self, cr, uid, ids, context) function,
@@ -91,18 +90,18 @@ class object_proxy(netsvc.Service):
                                 ids = args[3]
                             else:
                                 ids = []
-                        cr = pooler.get_db_only(dbname).cursor()
+                        cr = sql_db.db_connect(dbname).cursor()
                         return src(obj, cr, uid, ids, context=(ctx or {}))
                     except Exception:
                         pass
                     finally:
                         if cr: cr.close()
-                   
+
                     return False # so that the original SQL error will
                                  # be returned, it is the best we have.
 
                 try:
-                    cr = pooler.get_db_only(dbname).cursor()
+                    cr = sql_db.db_connect(dbname).cursor()
                     res = translate(cr, name=False, source_type=ttype,
                                     lang=lang, source=src)
                     if res:
@@ -116,20 +115,18 @@ class object_proxy(netsvc.Service):
                 return tr(src, 'code')
 
             try:
-                if not pooler.get_pool(dbname)._ready:
+                if pooler.get_pool(dbname)._init:
                     raise except_osv('Database not ready', 'Currently, this database is not fully loaded and can not be used.')
                 return f(self, dbname, *args, **kwargs)
             except orm.except_orm, inst:
-                if inst.name == 'AccessError':
-                    self.logger.debug("AccessError", exc_info=True)
-                self.abortResponse(1, inst.name, 'warning', inst.value)
-            except except_osv, inst:
-                self.abortResponse(1, inst.name, inst.exc_type, inst.value)
+                raise except_osv(inst.name, inst.value)
+            except except_osv:
+                raise
             except IntegrityError, inst:
                 osv_pool = pooler.get_pool(dbname)
                 for key in osv_pool._sql_error.keys():
                     if key in inst[0]:
-                        self.abortResponse(1, _('Constraint Error'), 'warning',
+                        netsvc.abort_response(1, _('Constraint Error'), 'warning',
                                         tr(osv_pool._sql_error[key], 'sql_constraint') or inst[0])
                 if inst.pgcode in (errorcodes.NOT_NULL_VIOLATION, errorcodes.FOREIGN_KEY_VIOLATION, errorcodes.RESTRICT_VIOLATION):
                     msg = _('The operation cannot be completed, probably due to the following:\n- deletion: you may be trying to delete a record while other records still reference it\n- creation/update: a mandatory field is not correctly set')
@@ -150,9 +147,9 @@ class object_proxy(netsvc.Service):
                         msg += _('\n\n[object with reference: %s - %s]') % (model_name, model)
                     except Exception:
                         pass
-                    self.abortResponse(1, _('Integrity Error'), 'warning', msg)
+                    netsvc.abort_response(1, _('Integrity Error'), 'warning', msg)
                 else:
-                    self.abortResponse(1, _('Integrity Error'), 'warning', inst[0])
+                    netsvc.abort_response(1, _('Integrity Error'), 'warning', inst[0])
             except Exception:
                 self.logger.exception("Uncaught exception")
                 raise
@@ -201,157 +198,14 @@ class object_proxy(netsvc.Service):
             cr.close()
         return res
 
-object_proxy()
-
-class osv_pool(object):
-    def __init__(self):
-        self._ready = False
-        self.obj_pool = {}
-        self.module_object_list = {}
-        self.created = []
-        self._sql_error = {}
-        self._store_function = {}
-        self._init = True
-        self._init_parent = {}
-        self.logger = logging.getLogger("pool")
-
-    def init_set(self, cr, mode):
-        different = mode != self._init
-        if different:
-            if mode:
-                self._init_parent = {}
-            if not mode:
-                for o in self._init_parent:
-                    self.get(o)._parent_store_compute(cr)
-            self._init = mode
-
-        self._ready = True
-        return different
+# deprecated - for backward compatibility.
+osv = Model
+osv_memory = TransientModel
+osv_abstract = AbstractModel # ;-)
 
 
-    def obj_list(self):
-        return self.obj_pool.keys()
-
-    # adds a new object instance to the object pool.
-    # if it already existed, the instance is replaced
-    def add(self, name, obj_inst):
-        if name in self.obj_pool:
-            del self.obj_pool[name]
-        self.obj_pool[name] = obj_inst
-        module = obj_inst.__class__.__module__.split('.')[0]
-        self.module_object_list.setdefault(module, []).append(obj_inst)
-
-    # Return None if object does not exist
-    def get(self, name):
-        obj = self.obj_pool.get(name, None)
-        return obj
-
-    #TODO: pass a list of modules to load
-    def instanciate(self, module, cr):
-        res = []
-        class_list = module_class_list.get(module, [])
-        for klass in class_list:
-            res.append(klass.createInstance(self, module, cr))
-        return res
-
-class osv_base(object):
-    def __init__(self, pool, cr):
-        pool.add(self._name, self)
-        self.pool = pool
-        super(osv_base, self).__init__(cr)
-
-    def __new__(cls):
-        module = cls.__module__.split('.')[0]
-        if not hasattr(cls, '_module'):
-            cls._module = module
-        module_class_list.setdefault(cls._module, []).append(cls)
-        if module not in module_list:
-            module_list.append(cls._module)
-        return None
-
-class osv_memory(osv_base, orm.orm_memory):
-    #
-    # Goal: try to apply inheritancy at the instanciation level and
-    #       put objects in the pool var
-    #
-    def createInstance(cls, pool, module, cr):
-        parent_names = getattr(cls, '_inherit', None)
-        if parent_names:
-            if isinstance(parent_names, (str, unicode)):
-                name = cls._name or parent_names
-                parent_names = [parent_names]
-            else:
-                name = cls._name
-            if not name:
-                raise TypeError('_name is mandatory in case of multiple inheritance')
-
-            for parent_name in ((type(parent_names)==list) and parent_names or [parent_names]):
-                parent_class = pool.get(parent_name).__class__
-                assert pool.get(parent_name), "parent class %s does not exist in module %s !" % (parent_name, module)
-                nattr = {}
-                for s in ('_columns', '_defaults'):
-                    new = copy.copy(getattr(pool.get(parent_name), s))
-                    if hasattr(new, 'update'):
-                        new.update(cls.__dict__.get(s, {}))
-                    else:
-                        new.extend(cls.__dict__.get(s, []))
-                    nattr[s] = new
-                cls = type(name, (cls, parent_class), nattr)
-
-        obj = object.__new__(cls)
-        obj.__init__(pool, cr)
-        return obj
-    createInstance = classmethod(createInstance)
-
-class osv(osv_base, orm.orm):
-    #
-    # Goal: try to apply inheritancy at the instanciation level and
-    #       put objects in the pool var
-    #
-    def createInstance(cls, pool, module, cr):
-        parent_names = getattr(cls, '_inherit', None)
-        if parent_names:
-            if isinstance(parent_names, (str, unicode)):
-                name = cls._name or parent_names
-                parent_names = [parent_names]
-            else:
-                name = cls._name
-            if not name:
-                raise TypeError('_name is mandatory in case of multiple inheritance')
-
-            for parent_name in ((type(parent_names)==list) and parent_names or [parent_names]):
-                parent_class = pool.get(parent_name).__class__
-                assert pool.get(parent_name), "parent class %s does not exist in module %s !" % (parent_name, module)
-                nattr = {}
-                for s in ('_columns', '_defaults', '_inherits', '_constraints', '_sql_constraints'):
-                    new = copy.copy(getattr(pool.get(parent_name), s))
-                    if hasattr(new, 'update'):
-                        new.update(cls.__dict__.get(s, {}))
-                    else:
-                        if s=='_constraints':
-                            for c in cls.__dict__.get(s, []):
-                                exist = False
-                                for c2 in range(len(new)):
-                                     #For _constraints, we should check field and methods as well
-                                     if new[c2][2]==c[2] and (new[c2][0] == c[0] \
-                                            or getattr(new[c2][0],'__name__', True) == \
-                                                getattr(c[0],'__name__', False)):
-                                        # If new class defines a constraint with
-                                        # same function name, we let it override
-                                        # the old one.
-                                        new[c2] = c
-                                        exist = True
-                                        break
-                                if not exist:
-                                    new.append(c)
-                        else:
-                            new.extend(cls.__dict__.get(s, []))
-                    nattr[s] = new
-                cls = type(name, (cls, parent_class), nattr)
-        obj = object.__new__(cls)
-        obj.__init__(pool, cr)
-        return obj
-    createInstance = classmethod(createInstance)
+def start_object_proxy():
+    object_proxy()
 
 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: