[imp] migrated to latest version of client

bzr revid: nicolas.vanhoren@openerp.com-20120105165633-med9y3078abchs5q
This commit is contained in:
niv-openerp 2012-01-05 17:56:33 +01:00
parent 9b998a6551
commit 0baab517f1
3 changed files with 88 additions and 196 deletions

View File

@ -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

View File

@ -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.

View File

@ -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):