[REF] model service: removed the unneeded object_service class.

bzr revid: vmt@openerp.com-20130130113646-pviw5d6gnohk7wrb
This commit is contained in:
Vo Minh Thu 2013-01-30 12:36:46 +01:00
parent 4144c0fc76
commit 19b0315f68
6 changed files with 178 additions and 189 deletions

View File

@ -94,7 +94,7 @@ def LocalService(name):
# Special case for addons support, will be removed in a few days when addons # Special case for addons support, will be removed in a few days when addons
# are updated to directly use openerp.osv.osv.service. # are updated to directly use openerp.osv.osv.service.
if name == 'object_proxy': if name == 'object_proxy':
return openerp.osv.osv.service return openerp.service.model
return Service._services[name] return Service._services[name]

View File

@ -21,22 +21,7 @@
#.apidoc title: Objects Services (OSV) #.apidoc title: Objects Services (OSV)
from functools import wraps from openerp.osv.orm import Model, TransientModel, AbstractModel
import logging
import threading
from psycopg2 import IntegrityError, errorcodes
import orm
import openerp
import openerp.netsvc as netsvc
import openerp.pooler as pooler
import openerp.sql_db as sql_db
from openerp.tools.translate import translate
from openerp.osv.orm import MetaModel, Model, TransientModel, AbstractModel
import openerp.exceptions
_logger = logging.getLogger(__name__)
# Deprecated. # Deprecated.
class except_osv(Exception): class except_osv(Exception):
@ -45,177 +30,9 @@ class except_osv(Exception):
self.value = value self.value = value
self.args = (name, value) self.args = (name, value)
service = None
class object_proxy(object):
def __init__(self):
global service
service = self
def check(f):
@wraps(f)
def wrapper(self, dbname, *args, **kwargs):
""" Wraps around OSV functions and normalises a few exceptions
"""
def tr(src, ttype):
# We try to do the same as the _(), but without the frame
# inspection, since we aready are wrapping an osv function
# trans_obj = self.get('ir.translation') cannot work yet :(
ctx = {}
if not kwargs:
if args and isinstance(args[-1], dict):
ctx = args[-1]
elif isinstance(kwargs, dict):
ctx = kwargs.get('context', {})
uid = 1
if args and isinstance(args[0], (long, int)):
uid = args[0]
lang = ctx and ctx.get('lang')
if not (lang or hasattr(src, '__call__')):
return src
# 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,
# or we skip..
# our signature is f(osv_pool, dbname [,uid, obj, method, args])
try:
if args and len(args) > 1:
obj = self.get(args[1])
if len(args) > 3 and isinstance(args[3], (long, int, list)):
ids = args[3]
else:
ids = []
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 = sql_db.db_connect(dbname).cursor()
res = translate(cr, name=False, source_type=ttype,
lang=lang, source=src)
if res:
return res
else:
return src
finally:
if cr: cr.close()
def _(src):
return tr(src, 'code')
try:
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:
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]:
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')
_logger.debug("IntegrityError", exc_info=True)
try:
errortxt = inst.pgerror.replace('«','"').replace('»','"')
if '"public".' in errortxt:
context = errortxt.split('"public".')[1]
model_name = table = context.split('"')[1]
else:
last_quote_end = errortxt.rfind('"')
last_quote_begin = errortxt.rfind('"', 0, last_quote_end)
model_name = table = errortxt[last_quote_begin+1:last_quote_end].strip()
model = table.replace("_",".")
model_obj = osv_pool.get(model)
if model_obj:
model_name = model_obj._description or model_obj._name
msg += _('\n\n[object with reference: %s - %s]') % (model_name, model)
except Exception:
pass
netsvc.abort_response(1, _('Integrity Error'), 'warning', msg)
else:
netsvc.abort_response(1, _('Integrity Error'), 'warning', inst[0])
except Exception:
_logger.exception("Uncaught exception")
raise
return wrapper
def execute_cr(self, cr, uid, obj, method, *args, **kw):
object = pooler.get_pool(cr.dbname).get(obj)
if not object:
raise except_osv('Object Error', 'Object %s doesn\'t exist' % str(obj))
return getattr(object, method)(cr, uid, *args, **kw)
def execute_kw(self, db, uid, obj, method, args, kw=None):
return self.execute(db, uid, obj, method, *args, **kw or {})
@check
def execute(self, db, uid, obj, method, *args, **kw):
threading.currentThread().dbname = db
cr = pooler.get_db(db).cursor()
try:
try:
if method.startswith('_'):
raise except_osv('Access Denied', 'Private methods (such as %s) cannot be called remotely.' % (method,))
res = self.execute_cr(cr, uid, obj, method, *args, **kw)
if res is None:
_logger.warning('The method %s of the object %s can not return `None` !', method, obj)
cr.commit()
except Exception:
cr.rollback()
raise
finally:
cr.close()
return res
def exec_workflow_cr(self, cr, uid, obj, signal, *args):
object = pooler.get_pool(cr.dbname).get(obj)
if not object:
raise except_osv('Object Error', 'Object %s doesn\'t exist' % str(obj))
res_id = args[0]
return object._workflow_signal(cr, uid, [res_id], signal)[res_id]
@check
def exec_workflow(self, db, uid, obj, signal, *args):
cr = pooler.get_db(db).cursor()
try:
try:
res = self.exec_workflow_cr(cr, uid, obj, signal, *args)
cr.commit()
except Exception:
cr.rollback()
raise
finally:
cr.close()
return res
# deprecated - for backward compatibility. # deprecated - for backward compatibility.
osv = Model osv = Model
osv_memory = TransientModel osv_memory = TransientModel
osv_abstract = AbstractModel # ;-) osv_abstract = AbstractModel # ;-)
def start_object_proxy():
object_proxy()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -75,8 +75,6 @@ def start_internal():
openerp.netsvc.init_logger() openerp.netsvc.init_logger()
openerp.modules.loading.open_openerp_namespace() openerp.modules.loading.open_openerp_namespace()
# Instantiate local services (this is a legacy design).
openerp.osv.osv.start_object_proxy()
# Export (for RPC) services. # Export (for RPC) services.
web_services.start_service() web_services.start_service()

172
openerp/service/model.py Normal file
View File

@ -0,0 +1,172 @@
# -*- coding: utf-8 -*-
from functools import wraps
import logging
from psycopg2 import IntegrityError, errorcodes
import threading
import openerp
from openerp.tools.translate import translate
from openerp.osv.orm import except_orm
from openerp.osv.osv import except_osv
_logger = logging.getLogger(__name__)
def check(f):
@wraps(f)
def wrapper(dbname, *args, **kwargs):
""" Wraps around OSV functions and normalises a few exceptions
"""
def tr(src, ttype):
# We try to do the same as the _(), but without the frame
# inspection, since we aready are wrapping an osv function
# trans_obj = self.get('ir.translation') cannot work yet :(
ctx = {}
if not kwargs:
if args and isinstance(args[-1], dict):
ctx = args[-1]
elif isinstance(kwargs, dict):
ctx = kwargs.get('context', {})
uid = 1
if args and isinstance(args[0], (long, int)):
uid = args[0]
lang = ctx and ctx.get('lang')
if not (lang or hasattr(src, '__call__')):
return src
# 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,
# or we skip..
# our signature is f(osv_pool, dbname [,uid, obj, method, args])
try:
if args and len(args) > 1:
# TODO self doesn't exist, but was already wrong before (it was not a registry but just the object_service.
obj = self.get(args[1])
if len(args) > 3 and isinstance(args[3], (long, int, list)):
ids = args[3]
else:
ids = []
cr = openerp.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 = openerp.sql_db.db_connect(dbname).cursor()
res = translate(cr, name=False, source_type=ttype,
lang=lang, source=src)
if res:
return res
else:
return src
finally:
if cr: cr.close()
def _(src):
return tr(src, 'code')
try:
if openerp.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(dbname, *args, **kwargs)
except except_orm, inst:
raise except_osv(inst.name, inst.value)
except except_osv:
raise
except IntegrityError, inst:
osv_pool = openerp.pooler.get_pool(dbname)
for key in osv_pool._sql_error.keys():
if key in inst[0]:
openerp.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')
_logger.debug("IntegrityError", exc_info=True)
try:
errortxt = inst.pgerror.replace('«','"').replace('»','"')
if '"public".' in errortxt:
context = errortxt.split('"public".')[1]
model_name = table = context.split('"')[1]
else:
last_quote_end = errortxt.rfind('"')
last_quote_begin = errortxt.rfind('"', 0, last_quote_end)
model_name = table = errortxt[last_quote_begin+1:last_quote_end].strip()
model = table.replace("_",".")
model_obj = osv_pool.get(model)
if model_obj:
model_name = model_obj._description or model_obj._name
msg += _('\n\n[object with reference: %s - %s]') % (model_name, model)
except Exception:
pass
openerp.netsvc.abort_response(1, _('Integrity Error'), 'warning', msg)
else:
openerp.netsvc.abort_response(1, _('Integrity Error'), 'warning', inst[0])
except Exception:
_logger.exception("Uncaught exception")
raise
return wrapper
def execute_cr(cr, uid, obj, method, *args, **kw):
object = openerp.pooler.get_pool(cr.dbname).get(obj)
if not object:
raise except_osv('Object Error', 'Object %s doesn\'t exist' % str(obj))
return getattr(object, method)(cr, uid, *args, **kw)
def execute_kw(db, uid, obj, method, args, kw=None):
return execute(db, uid, obj, method, *args, **kw or {})
@check
def execute(db, uid, obj, method, *args, **kw):
threading.currentThread().dbname = db
cr = openerp.pooler.get_db(db).cursor()
try:
try:
if method.startswith('_'):
raise except_osv('Access Denied', 'Private methods (such as %s) cannot be called remotely.' % (method,))
res = execute_cr(cr, uid, obj, method, *args, **kw)
if res is None:
_logger.warning('The method %s of the object %s can not return `None` !', method, obj)
cr.commit()
except Exception:
cr.rollback()
raise
finally:
cr.close()
return res
def exec_workflow_cr(cr, uid, obj, signal, *args):
object = openerp.pooler.get_pool(cr.dbname).get(obj)
if not object:
raise except_osv('Object Error', 'Object %s doesn\'t exist' % str(obj))
res_id = args[0]
return object._workflow_signal(cr, uid, [res_id], signal)[res_id]
@check
def exec_workflow(db, uid, obj, signal, *args):
cr = openerp.pooler.get_db(db).cursor()
try:
try:
res = exec_workflow_cr(cr, uid, obj, signal, *args)
cr.commit()
except Exception:
cr.rollback()
raise
finally:
cr.close()
return res
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -32,10 +32,12 @@ import threading
import time import time
import traceback import traceback
from cStringIO import StringIO from cStringIO import StringIO
from openerp.tools.translate import _ from openerp.tools.translate import _
import openerp.netsvc as netsvc import openerp.netsvc as netsvc
import openerp.pooler as pooler import openerp.pooler as pooler
import openerp.release as release import openerp.release as release
import openerp.service.model
import openerp.sql_db as sql_db import openerp.sql_db as sql_db
import openerp.tools as tools import openerp.tools as tools
import openerp.modules import openerp.modules
@ -608,9 +610,8 @@ class objects_proxy(netsvc.ExportService):
if method not in ['execute', 'execute_kw', 'exec_workflow']: if method not in ['execute', 'execute_kw', 'exec_workflow']:
raise NameError("Method not available %s" % method) raise NameError("Method not available %s" % method)
security.check(db,uid,passwd) security.check(db,uid,passwd)
assert openerp.osv.osv.service, "The object_proxy class must be started with start_object_proxy."
openerp.modules.registry.RegistryManager.check_registry_signaling(db) openerp.modules.registry.RegistryManager.check_registry_signaling(db)
fn = getattr(openerp.osv.osv.service, method) fn = getattr(openerp.service.model, method)
res = fn(db, uid, *params) res = fn(db, uid, *params)
openerp.modules.registry.RegistryManager.signal_caches_change(db) openerp.modules.registry.RegistryManager.signal_caches_change(db)
return res return res

View File

@ -22,6 +22,7 @@ import test_osv
import test_translate import test_translate
import test_uninstall import test_uninstall
import test_view_validation import test_view_validation
import test_xmlrpc # TODO Remove this before merge, or change oe run-tests to only run fast_suite + checks by default.
fast_suite = [ fast_suite = [
test_ir_sequence, test_ir_sequence,