From 0baab517f1a02c49d91d6ebca0be2b91784de794 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Thu, 5 Jan 2012 17:56:33 +0100 Subject: [PATCH] [imp] migrated to latest version of client bzr revid: nicolas.vanhoren@openerp.com-20120105165633-med9y3078abchs5q --- addons/web/common/http.py | 58 ++++++- addons/web/common/openerplib/main.py | 224 ++++----------------------- addons/web/common/session.py | 2 +- 3 files changed, 88 insertions(+), 196 deletions(-) diff --git a/addons/web/common/http.py b/addons/web/common/http.py index 098731183ba..0c239decb64 100644 --- a/addons/web/common/http.py +++ b/addons/web/common/http.py @@ -408,7 +408,7 @@ class Root(object): self.config = options if self.config.backend == 'local': - conn = openerplib.get_connector(protocol='local') + conn = LocalConnector() else: conn = openerplib.get_connector(hostname=self.config.server_host, port=self.config.server_port) @@ -522,4 +522,58 @@ class Root(object): return m return None -# +class LibException(Exception): + """ Base of all client lib exceptions """ + def __init__(self,code=None,message=None): + self.code = code + self.message = message + +class ApplicationError(LibException): + """ maps to code: 1, server side: Exception or openerp.exceptions.DeferredException""" + +class Warning(LibException): + """ maps to code: 2, server side: openerp.exceptions.Warning""" + +class AccessError(LibException): + """ maps to code: 3, server side: openerp.exceptions.AccessError""" + +class AccessDenied(LibException): + """ maps to code: 4, server side: openerp.exceptions.AccessDenied""" + + +class LocalConnector(openerplib.Connector): + """ + A type of connector that uses the XMLRPC protocol. + """ + PROTOCOL = 'local' + + def __init__(self): + pass + + def send(self, service_name, method, *args): + import openerp + import traceback + import xmlrpclib + try: + result = openerp.netsvc.dispatch_rpc(service_name, method, args) + except Exception,e: + # TODO change the except to raise LibException instead of their emulated xmlrpc fault + if isinstance(e, openerp.osv.osv.except_osv): + fault = xmlrpclib.Fault('warning -- ' + e.name + '\n\n' + e.value, '') + elif isinstance(e, openerp.exceptions.Warning): + fault = xmlrpclib.Fault('warning -- Warning\n\n' + str(e), '') + elif isinstance(e, openerp.exceptions.AccessError): + fault = xmlrpclib.Fault('warning -- AccessError\n\n' + str(e), '') + elif isinstance(e, openerp.exceptions.AccessDenied): + fault = xmlrpclib.Fault('AccessDenied', str(e)) + elif isinstance(e, openerp.exceptions.DeferredException): + info = e.traceback + formatted_info = "".join(traceback.format_exception(*info)) + fault = xmlrpclib.Fault(openerp.tools.ustr(e.message), formatted_info) + else: + info = sys.exc_info() + formatted_info = "".join(traceback.format_exception(*info)) + fault = xmlrpclib.Fault(openerp.tools.exception_to_unicode(e), formatted_info) + raise fault + return result + diff --git a/addons/web/common/openerplib/main.py b/addons/web/common/openerplib/main.py index 76bf7bad6ca..84484e49ae6 100644 --- a/addons/web/common/openerplib/main.py +++ b/addons/web/common/openerplib/main.py @@ -36,52 +36,13 @@ Code repository: https://code.launchpad.net/~niv-openerp/openerp-client-lib/trun """ import xmlrpclib -import logging -import socket -import sys - -try: - import cPickle as pickle -except ImportError: - import pickle - -try: - import cStringIO as StringIO -except ImportError: - import StringIO +import logging _logger = logging.getLogger(__name__) def _getChildLogger(logger, subname): return logging.getLogger(logger.name + "." + subname) -#---------------------------------------------------------- -# Exceptions -# TODO openerplib should raise those instead of xmlrpc faults: -#---------------------------------------------------------- - -class LibException(Exception): - """ Base of all client lib exceptions """ - def __init__(self,code=None,message=None): - self.code = code - self.message = message - -class ApplicationError(LibException): - """ maps to code: 1, server side: Exception or openerp.exceptions.DeferredException""" - -class Warning(LibException): - """ maps to code: 2, server side: openerp.exceptions.Warning""" - -class AccessError(LibException): - """ maps to code: 3, server side: openerp.exceptions.AccessError""" - -class AccessDenied(LibException): - """ maps to code: 4, server side: openerp.exceptions.AccessDenied""" - -#---------------------------------------------------------- -# Connectors -#---------------------------------------------------------- - class Connector(object): """ The base abstract class representing a connection to an OpenERP Server. @@ -126,7 +87,6 @@ class XmlRPCConnector(Connector): def send(self, service_name, method, *args): url = '%s/%s' % (self.url, service_name) service = xmlrpclib.ServerProxy(url) - # TODO should try except and wrap exception into LibException return getattr(service, method)(*args) class XmlRPCSConnector(XmlRPCConnector): @@ -141,145 +101,6 @@ class XmlRPCSConnector(XmlRPCConnector): super(XmlRPCSConnector, self).__init__(hostname, port) self.url = 'https://%s:%d/xmlrpc' % (self.hostname, self.port) -class NetRPC_Exception(Exception): - """ - Exception for NetRPC errors. - """ - def __init__(self, faultCode, faultString): - self.faultCode = faultCode - self.faultString = faultString - self.args = (faultCode, faultString) - -class NetRPC(object): - """ - Low level class for NetRPC protocol. - """ - def __init__(self, sock=None): - if sock is None: - self.sock = socket.socket( - socket.AF_INET, socket.SOCK_STREAM) - else: - self.sock = sock - self.sock.settimeout(120) - def connect(self, host, port=False): - if not port: - buf = host.split('//')[1] - host, port = buf.split(':') - self.sock.connect((host, int(port))) - - def disconnect(self): - self.sock.shutdown(socket.SHUT_RDWR) - self.sock.close() - - def mysend(self, msg, exception=False, traceback=None): - msg = pickle.dumps([msg,traceback]) - size = len(msg) - self.sock.send('%8d' % size) - self.sock.send(exception and "1" or "0") - totalsent = 0 - while totalsent < size: - sent = self.sock.send(msg[totalsent:]) - if sent == 0: - raise RuntimeError, "socket connection broken" - totalsent = totalsent + sent - - def myreceive(self): - buf='' - while len(buf) < 8: - chunk = self.sock.recv(8 - len(buf)) - if chunk == '': - raise RuntimeError, "socket connection broken" - buf += chunk - size = int(buf) - buf = self.sock.recv(1) - if buf != "0": - exception = buf - else: - exception = False - msg = '' - while len(msg) < size: - chunk = self.sock.recv(size-len(msg)) - if chunk == '': - raise RuntimeError, "socket connection broken" - msg = msg + chunk - msgio = StringIO.StringIO(msg) - unpickler = pickle.Unpickler(msgio) - unpickler.find_global = None - res = unpickler.load() - - if isinstance(res[0],Exception): - if exception: - raise NetRPC_Exception(str(res[0]), str(res[1])) - raise res[0] - else: - return res[0] - -class NetRPCConnector(Connector): - """ - A type of connector that uses the NetRPC protocol. - """ - - PROTOCOL = 'netrpc' - - __logger = _getChildLogger(_logger, 'connector.netrpc') - - def __init__(self, hostname, port=8070): - """ - Initialize by specifying the hostname and the port. - :param hostname: The hostname of the computer holding the instance of OpenERP. - :param port: The port used by the OpenERP instance for NetRPC (default to 8070). - """ - Connector.__init__(self, hostname, port) - - def send(self, service_name, method, *args): - socket = NetRPC() - socket.connect(self.hostname, self.port) - socket.mysend((service_name, method, )+args) - result = socket.myreceive() - socket.disconnect() - return result - -class LocalConnector(Connector): - """ - A type of connector that uses the XMLRPC protocol. - """ - PROTOCOL = 'local' - - __logger = _getChildLogger(_logger, 'connector.local') - - def __init__(self): - pass - - def send(self, service_name, method, *args): - import openerp - import traceback - try: - result = openerp.netsvc.dispatch_rpc(service_name, method, args) - except Exception,e: - # TODO change the except to raise LibException instead of their emulated xmlrpc fault - if isinstance(e, openerp.osv.osv.except_osv): - fault = xmlrpclib.Fault('warning -- ' + e.name + '\n\n' + e.value, '') - elif isinstance(e, openerp.exceptions.Warning): - fault = xmlrpclib.Fault('warning -- Warning\n\n' + str(e), '') - elif isinstance(e, openerp.exceptions.AccessError): - fault = xmlrpclib.Fault('warning -- AccessError\n\n' + str(e), '') - elif isinstance(e, openerp.exceptions.AccessDenied): - fault = xmlrpclib.Fault('AccessDenied', str(e)) - elif isinstance(e, openerp.exceptions.DeferredException): - info = e.traceback - formatted_info = "".join(traceback.format_exception(*info)) - fault = xmlrpclib.Fault(openerp.tools.ustr(e.message), formatted_info) - else: - info = sys.exc_info() - formatted_info = "".join(traceback.format_exception(*info)) - fault = xmlrpclib.Fault(openerp.tools.exception_to_unicode(e), formatted_info) - raise fault - return result - -#---------------------------------------------------------- -# Public api -#---------------------------------------------------------- - class Service(object): """ A class to execute RPC calls on a specific service of the remote server. @@ -319,7 +140,8 @@ class Connection(object): database=None, login=None, password=None, - user_id=None): + user_id=None, + auto_context=True): """ Initialize with login information. The login information is facultative to allow specifying it after the initialization of this object. @@ -330,10 +152,15 @@ class Connection(object): :param password: The password of the user. :param user_id: The user id is a number identifying the user. This is only useful if you already know it, in most cases you don't need to specify it. + :param auto_context: If true, automatically queries the context of the user and adds it to all + method calls on models. If a context is already specified, the contexts are merged with it (the + user context has the lowest priority). Default to True. """ self.connector = connector self.set_login_info(database, login, password, user_id) + self.user_context = None + self.auto_context = auto_context def set_login_info(self, database, login, password, user_id=None): """ @@ -369,6 +196,16 @@ class Connection(object): if not self.user_id: raise AuthenticationError("Authentication failure") self.__logger.debug("Authenticated with user id %s", self.user_id) + + def get_user_context(self): + """ + Query the default context of the user. + """ + if not self.user_context: + mod = self.get_model('res.users') + mod.override_auto_context = False + self.user_context = mod.context_get() + return self.user_context def get_model(self, model_name): """ @@ -407,6 +244,7 @@ class Model(object): """ self.connection = connection self.model_name = model_name + self.override_auto_context = None self.__logger = _getChildLogger(_getChildLogger(_logger, 'object'), model_name or "") def __getattr__(self, method): @@ -415,19 +253,23 @@ class Model(object): :param method: The method for the linked model (search, read, write, unlink, create, ...) """ - def proxy(*args): + def proxy(*args, **kw): """ :param args: A list of values for the method """ self.connection.check_login(False) self.__logger.debug(args) - result = self.connection.get_service('object').execute( + if (self.override_auto_context is not None and self.override_auto_context) or \ + (self.override_auto_context is None and self.connection.auto_context): + kw = dict(kw) + kw['context'] = dict(self.connection.get_user_context(), **kw.get('context', {})) + result = self.connection.get_service('object').execute_kw( self.connection.database, self.connection.user_id, self.connection.password, self.model_name, method, - *args) + args, kw) if method == "read": if isinstance(result, list) and len(result) > 0 and "id" in result[0]: index = {} @@ -457,24 +299,20 @@ class Model(object): def get_connector(hostname=None, protocol="xmlrpc", port="auto"): """ - A shortcut method to easily create a connector to a remote server using XMLRPC or NetRPC. + A shortcut method to easily create a connector to a remote server using XMLRPC. :param hostname: The hostname to the remote server. - :param protocol: The name of the protocol, must be "xmlrpc" or "netrpc". + :param protocol: The name of the protocol, must be "xmlrpc" or "xmlrpcs". :param port: The number of the port. Defaults to auto. """ if port == 'auto': - port = 8069 if protocol=="xmlrpc" else (8070 if protocol == "netrpc" else 8071) + port = 8069 if protocol=="xmlrpc" else 8071 if protocol == "xmlrpc": return XmlRPCConnector(hostname, port) elif protocol == "xmlrpcs": return XmlRPCSConnector(hostname, port) - elif protocol == "netrpc": - return NetRPCConnector(hostname, port) - elif protocol == "local": - return LocalConnector() else: - raise ValueError("You must choose xmlrpc(s), netrpc or local") + raise ValueError("You must choose xmlrpc or xmlrpcs") def get_connection(hostname=None, protocol="xmlrpc", port='auto', database=None, login=None, password=None, user_id=None): @@ -482,7 +320,7 @@ def get_connection(hostname=None, protocol="xmlrpc", port='auto', database=None, A shortcut method to easily create a connection to a remote OpenERP server. :param hostname: The hostname to the remote server. - :param protocol: The name of the protocol, must be "xmlrpc" or "netrpc". + :param protocol: The name of the protocol, must be "xmlrpc" or "xmlrpcs". :param port: The number of the port. Defaults to auto. :param connector: A valid Connector instance to send messages to the remote server. :param database: The name of the database to work on. diff --git a/addons/web/common/session.py b/addons/web/common/session.py index 905670404a9..4202ce45507 100644 --- a/addons/web/common/session.py +++ b/addons/web/common/session.py @@ -53,7 +53,7 @@ class OpenERPSession(object): def build_connection(self): conn = openerplib.Connection(self.config.connector, database=self._db, login=self._login, - user_id=self._uid, password=self._password) + user_id=self._uid, password=self._password, auto_context=False) return conn def proxy(self, service):