From a35e4dbf680666893dbba9f9aefffcc39ffdaafc Mon Sep 17 00:00:00 2001 From: Zikzakmedia Date: Mon, 11 Jul 2011 11:06:51 +0200 Subject: [PATCH 01/12] [IMP] New features OOOP: - Order by - Offset and Limit - Pyro - Order Filter - convert DateTime instance to datetime.datetime object - Some create models, id field is duplicated and broken sql. Create method don't need id = we remove if exists - Unlink. Need list value. Check if value is a list or change to list More info commits see old project: https://code.launchpad.net/~zikzak/zoook/ooop --- AUTHORS | 1 + README.md | 10 +++++ examples/basic.py | 4 +- ooop.py | 98 ++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 94 insertions(+), 19 deletions(-) diff --git a/AUTHORS b/AUTHORS index c8b2a90..c0c1d66 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,2 +1,3 @@ Pedro A. Gracia Fajardo Gamaliel Toro +Raimon Esteve Cusiné diff --git a/README.md b/README.md index cad03d6..ea579f1 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,16 @@ Connecting to server >>> o = OOOP(dbname='demo') +Pyro Protocol +-------------------- +1. Install PyRO library (openerp-server and web client). +http://www.xs4all.nl/~irmen/pyro3/ +2. Install PyRO Module OpenERP from Nan (thanks this contribution!) +https://launchpad.net/openobject-client-kde +

+  >>> o = OOOP(user='admin',pwd='admin',dbname='zikzakmedia',uri='localhost',port=8071,protocol='pyro')
+
+ Retrieving all from model ------------------------- diff --git a/examples/basic.py b/examples/basic.py index b0c16b2..5dfd4b7 100644 --- a/examples/basic.py +++ b/examples/basic.py @@ -1,6 +1,8 @@ from ooop import OOOP o = OOOP(dbname="testv6") +#Pyro Demo +#o = OOOP(user='admin',pwd='admin',dbname='zikzakmedia',uri='localhost',port=8071,protocol='pyro') partners = o.ResPartner.all() for partner in partners: - print "id: %d, name: %s" % ( partner._ref, partner.name ) \ No newline at end of file + print "id: %d, name: %s" % ( partner._ref, partner.name ) diff --git a/ooop.py b/ooop.py index c99a206..be0735d 100644 --- a/ooop.py +++ b/ooop.py @@ -32,6 +32,12 @@ except: pydot = False +# check if pyro is installed +try: + import Pyro.core +except: + pyro = False + __author__ = "Pedro Gracia " __license__ = "GPLv3+" __version__ = "0.2.3" @@ -111,13 +117,14 @@ def execute(self, *args, **kargs): class OOOP: """ Main class to manage xml-rpc comunitacion with openerp-server """ def __init__(self, user='admin', pwd='admin', dbname='openerp', - uri='http://localhost', port=8069, debug=False, + uri='http://localhost', port=8069, protocol='xmlrpc', debug=False, exe=False, active=True, **kwargs): self.user = user # default: 'admin' self.pwd = pwd # default: 'admin' self.dbname = dbname # default: 'openerp' self.uri = uri self.port = port + self.protocol = protocol # default: 'xmlrpc' self.debug = debug self.exe = exe self.active = active @@ -127,13 +134,17 @@ def __init__(self, user='admin', pwd='admin', dbname='openerp', self.uid = None self.models = {} self.fields = {} + self.proxy = False #has to be uid, cr, parent (the openerp model to get the pool) if len(kwargs) == 3: self.uid = kwargs['uid'] self.objectsock = objectsock_mock(kwargs['parent'], kwargs['cr']) else: - self.connect() + if protocol == 'pyro': + self.connect_pyro() + else: + self.connect() self.load_models() @@ -147,46 +158,85 @@ def login(self, dbname, user, pwd): self.commonsock = xmlrpclib.ServerProxy('%s:%i/xmlrpc/common' % (self.uri, self.port)) return self.commonsock.login(dbname, user, pwd) + def connect_pyro(self): + """login and sockets to pyro services: common, object and report""" + url = 'PYROLOC://%s:%s/rpc' % (self.uri,self.port) + self.proxy = Pyro.core.getProxyForURI(url) + self.uid = self.proxy.dispatch( 'common', 'login', self.dbname, self.user, self.pwd) + self.reportsock = False + def execute(self, model, *args): if self.debug: print "DEBUG [execute]:", model, args - return self.objectsock.execute(self.dbname, self.uid, self.pwd, model, *args) + if self.protocol == 'pyro': + result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, *args) + else: + result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, *args) + return result def create(self, model, data): """ create a new register """ if self.debug: print "DEBUG [create]:", model, data - return self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'create', data) + if 'id' in data: + del data['id'] + if self.protocol == 'pyro': + result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'create', data) + else: + result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'create', data) + return result def unlink(self, model, ids): """ remove register """ if self.debug: print "DEBUG [unlink]:", model, ids - return self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'unlink', ids) + if not type(ids) == 'list': + ids = [ids] + if self.protocol == 'pyro': + result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'unlink', ids) + else: + result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'unlink', ids) + return result def write(self, model, ids, value): """ update register """ if self.debug: print "DEBUG [write]:", model, ids, value - return self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'write', ids, value) + if self.protocol == 'pyro': + result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'write', ids, value) + else: + result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'write', ids, value) + return result def read(self, model, ids, fields=[]): """ update register """ if self.debug: print "DEBUG [read]:", model, ids, fields - return self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'read', ids, fields) + if self.protocol == 'pyro': + result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'read', ids, fields) + else: + result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'read', ids, fields) + return result def read_all(self, model, fields=[]): """ update register """ if self.debug: print "DEBUG [read_all]:", model, fields - return self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'read', self.all(model), fields) + if self.protocol == 'pyro': + result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'read', self.all(model), fields) + else: + result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'read', self.all(model), fields) + return result - def search(self, model, query): + def search(self, model, query, offset=0, limit=999, order=''): """ return ids that match with 'query' """ if self.debug: - print "DEBUG [search]:", model, query - return self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'search', query) + print "DEBUG [search]:", model, query, offset, limit, order + if self.protocol == 'pyro': + result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'search', query, offset, limit, order) + else: + result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'search', query, offset, limit, order) + return result # TODO: verify if remove this def custom_execute(self, model, ids, remote_method, data): @@ -451,15 +501,27 @@ def all(self, fields=[], offset=0, limit=999999, as_list=False): def filter(self, fields=[], as_list=False, **kargs): q = [] # query dict + offset = 0 + limit = 999 + order = '' for key, value in kargs.items(): - if not '__' in key: - op = '=' - else: + if key == 'offset': + if int(value): + offset = value + elif key == 'limit': + if int(value): + limit = value + elif key == 'order': + order = value + elif '__' in key: i = key.find('__') op = OPERATORS[key[i+2:]] key = key[:i] - q.append(('%s' % key, op, value)) - ids = self._ooop.search(self._model, q) + q.append(('%s' % key, op, value)) + else: + op = '=' + q.append(('%s' % key, op, value)) + ids = self._ooop.search(self._model, q, offset, limit, order) if as_list: return self.read(ids, fields) return List(self, ids) @@ -520,8 +582,8 @@ def __init__(self, manager, ref=None, model=None, copy=False, data=None, fields= # convert DateTime instance to datetime.datetime object for i in default_values: if self.fields[i]['ttype'] == 'datetime': - t = default_values[i].timetuple() - default_values[i] = datetime(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec) + t = default_values[i].timetuple() + default_values[i] = datetime(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec) # active by default ? if self._ooop.active: default_values['active'] = True From a96d9ba80d19bc3a600729120cb975a581f71ab9 Mon Sep 17 00:00:00 2001 From: Zikzakmedia Date: Sat, 17 Dec 2011 08:22:56 +0100 Subject: [PATCH 02/12] [FIX] README crash browser navigators --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index ea579f1..c60e4f4 100644 --- a/README.md +++ b/README.md @@ -195,9 +195,4 @@ but if you want to get deep in the tables just need: o.ResPartner.export(deep=1) - The deep param its relative to the model param, deep means how far you want to get with the relations. - - - - From b1204824499b4ab05ec7afeb1ee3695888b059e6 Mon Sep 17 00:00:00 2001 From: resteve Date: Wed, 11 Jan 2012 17:53:18 +0100 Subject: [PATCH 03/12] [FIX] If type datetime, we get str, not datetime. Convert str to datetime --- ooop.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) mode change 100644 => 100755 ooop.py diff --git a/ooop.py b/ooop.py old mode 100644 new mode 100755 index be0735d..f28b934 --- a/ooop.py +++ b/ooop.py @@ -582,8 +582,11 @@ def __init__(self, manager, ref=None, model=None, copy=False, data=None, fields= # convert DateTime instance to datetime.datetime object for i in default_values: if self.fields[i]['ttype'] == 'datetime': - t = default_values[i].timetuple() - default_values[i] = datetime(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec) + if isinstance(default_values[i], str): + t = datetime.strptime(default_values[i], "%Y-%m-%d %H:%M:%S").timetuple() + else: + t = default_values[i].timetuple() + default_values[i] = datetime(t.tm_year, t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec) # active by default ? if self._ooop.active: default_values['active'] = True From 58d4f2e3d14df2e619ae310ef07ca5631d830c85 Mon Sep 17 00:00:00 2001 From: resteve Date: Wed, 11 Jan 2012 18:00:23 +0100 Subject: [PATCH 04/12] [FIX] Error on default data form M2O when come with false --- ooop.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ooop.py b/ooop.py index f28b934..21fc50c 100755 --- a/ooop.py +++ b/ooop.py @@ -604,7 +604,7 @@ def init_values(self, *args, **kargs): else: self.__dict__[name] = List(Manager(relation, self._ooop), data=self, model=relation) elif ttype == 'many2one': - if name in keys: + if name in keys and kargs[name]: # manager, ref=None, model=None, copy=False instance = Data(Manager(relation, self._ooop), kargs[name], relation) self.INSTANCES['%s:%s' % (relation, kargs[name])] = instance From 3ad498342be4c3f5a23369e5263ed2f3ff6a9c06 Mon Sep 17 00:00:00 2001 From: resteve Date: Thu, 12 Jan 2012 15:50:25 +0100 Subject: [PATCH 05/12] [FIX] m2o name in object --- ooop.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ooop.py b/ooop.py index 21fc50c..a47d8f3 100755 --- a/ooop.py +++ b/ooop.py @@ -739,7 +739,7 @@ def save(self): for i in self.__dict__[name]: self.INSTANCES['%s:%s' % (relation, i._ref)] = i elif ttype == 'many2one': - if self.__dict__[name]: + if self.__dict__[name] and 'name' in dir(self.__dict__[name]): data[name] = self.__dict__[name]._ref # update __name and INSTANCES (cache) self.__dict__['__%s' % name] = [self.__dict__[name]._ref, self.__dict__[name].name] From f6cd98c39a82c5bb148f70f5afa32f994cd0c027 Mon Sep 17 00:00:00 2001 From: resteve Date: Thu, 19 Jan 2012 16:55:17 +0100 Subject: [PATCH 06/12] [IMP] Create and write context lang (translated fields) --- ooop.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/ooop.py b/ooop.py index a47d8f3..b92d9ac 100755 --- a/ooop.py +++ b/ooop.py @@ -118,7 +118,7 @@ class OOOP: """ Main class to manage xml-rpc comunitacion with openerp-server """ def __init__(self, user='admin', pwd='admin', dbname='openerp', uri='http://localhost', port=8069, protocol='xmlrpc', debug=False, - exe=False, active=True, **kwargs): + exe=False, active=True, lang='en_US', **kwargs): self.user = user # default: 'admin' self.pwd = pwd # default: 'admin' self.dbname = dbname # default: 'openerp' @@ -135,6 +135,7 @@ def __init__(self, user='admin', pwd='admin', dbname='openerp', self.models = {} self.fields = {} self.proxy = False + self.lang = lang #has to be uid, cr, parent (the openerp model to get the pool) if len(kwargs) == 3: @@ -176,22 +177,23 @@ def execute(self, model, *args): def create(self, model, data): """ create a new register """ + context = {'lang':self.lang} if self.debug: print "DEBUG [create]:", model, data if 'id' in data: - del data['id'] + del data['id'] if self.protocol == 'pyro': - result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'create', data) + result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'create', data, context) else: - result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'create', data) + result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'create', data, context) return result def unlink(self, model, ids): """ remove register """ if self.debug: print "DEBUG [unlink]:", model, ids - if not type(ids) == 'list': - ids = [ids] + if not type(ids) == 'list': + ids = [ids] if self.protocol == 'pyro': result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'unlink', ids) else: @@ -200,12 +202,13 @@ def unlink(self, model, ids): def write(self, model, ids, value): """ update register """ + context = {'lang':self.lang} if self.debug: print "DEBUG [write]:", model, ids, value if self.protocol == 'pyro': - result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'write', ids, value) + result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'write', ids, value, context) else: - result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'write', ids, value) + result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'write', ids, value, context) return result def read(self, model, ids, fields=[]): From 9ce38bcbed8f7309bf74ac68c1416a21205e4081 Mon Sep 17 00:00:00 2001 From: resteve Date: Fri, 20 Jan 2012 15:15:33 +0100 Subject: [PATCH 07/12] [FIX] Write method check ids if list or not --- ooop.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ooop.py b/ooop.py index b92d9ac..6a5c9f3 100755 --- a/ooop.py +++ b/ooop.py @@ -205,6 +205,8 @@ def write(self, model, ids, value): context = {'lang':self.lang} if self.debug: print "DEBUG [write]:", model, ids, value + if not type(ids) == 'list': + ids = [ids] if self.protocol == 'pyro': result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'write', ids, value, context) else: From 009e56261558b8e3e81b67caa9d5d5212274f1d0 Mon Sep 17 00:00:00 2001 From: resteve Date: Thu, 8 Mar 2012 18:47:57 +0100 Subject: [PATCH 08/12] [FIX] many2one if not save in dicc --- ooop.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ooop.py b/ooop.py index 6a5c9f3..785fdc9 100755 --- a/ooop.py +++ b/ooop.py @@ -737,7 +737,7 @@ def save(self): elif ttype in ('boolean', 'float', 'integer') or self.__dict__[name]: data[name] = self.__dict__[name] elif ttype in ('one2many', 'many2many'): - if len(self.__dict__[name]) > 0: + if len(self.__dict__[name]) > 0 and hasattr(i,'save'): data[name] = [(6, 0, [i.save() for i in self.__dict__[name]])] # update __name and INSTANCES (cache) self.__dict__['__%s' % name] = [i._ref for i in self.__dict__[name]] # REVIEW: two loops? From f05d64430b01eb22aafc4061c6191648277b24ed Mon Sep 17 00:00:00 2001 From: resteve Date: Fri, 9 Mar 2012 09:46:46 +0100 Subject: [PATCH 09/12] [IMP] Revert last commit --- ooop.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ooop.py b/ooop.py index 785fdc9..6a5c9f3 100755 --- a/ooop.py +++ b/ooop.py @@ -737,7 +737,7 @@ def save(self): elif ttype in ('boolean', 'float', 'integer') or self.__dict__[name]: data[name] = self.__dict__[name] elif ttype in ('one2many', 'many2many'): - if len(self.__dict__[name]) > 0 and hasattr(i,'save'): + if len(self.__dict__[name]) > 0: data[name] = [(6, 0, [i.save() for i in self.__dict__[name]])] # update __name and INSTANCES (cache) self.__dict__['__%s' % name] = [i._ref for i in self.__dict__[name]] # REVIEW: two loops? From f7459b544a4dbf906a8dd145a39b809b27b92a6b Mon Sep 17 00:00:00 2001 From: resteve Date: Fri, 4 May 2012 15:43:12 +0200 Subject: [PATCH 10/12] [FIX] write/unlink if ids is int, change to list --- ooop.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ooop.py b/ooop.py index 6a5c9f3..8f510e0 100755 --- a/ooop.py +++ b/ooop.py @@ -192,7 +192,7 @@ def unlink(self, model, ids): """ remove register """ if self.debug: print "DEBUG [unlink]:", model, ids - if not type(ids) == 'list': + if isinstance(ids, int): ids = [ids] if self.protocol == 'pyro': result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'unlink', ids) @@ -205,7 +205,7 @@ def write(self, model, ids, value): context = {'lang':self.lang} if self.debug: print "DEBUG [write]:", model, ids, value - if not type(ids) == 'list': + if isinstance(ids, int): ids = [ids] if self.protocol == 'pyro': result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'write', ids, value, context) From f853cfdb122a22e991b4ecd2fa3eb9a1522bc034 Mon Sep 17 00:00:00 2001 From: Mariano Ruiz Date: Thu, 30 Aug 2012 11:44:37 -0300 Subject: [PATCH 11/12] Fix lang context was not passed in read/search operations --- ooop.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/ooop.py b/ooop.py index 8f510e0..5ad8f0b 100755 --- a/ooop.py +++ b/ooop.py @@ -215,32 +215,35 @@ def write(self, model, ids, value): def read(self, model, ids, fields=[]): """ update register """ + context = {'lang':self.lang} if self.debug: print "DEBUG [read]:", model, ids, fields if self.protocol == 'pyro': - result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'read', ids, fields) + result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'read', ids, fields, context) else: - result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'read', ids, fields) + result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'read', ids, fields, context) return result def read_all(self, model, fields=[]): """ update register """ + context = {'lang':self.lang} if self.debug: print "DEBUG [read_all]:", model, fields if self.protocol == 'pyro': - result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'read', self.all(model), fields) + result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'read', self.all(model), fields, context) else: - result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'read', self.all(model), fields) + result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'read', self.all(model), fields, context) return result def search(self, model, query, offset=0, limit=999, order=''): """ return ids that match with 'query' """ + context = {'lang':self.lang} if self.debug: print "DEBUG [search]:", model, query, offset, limit, order if self.protocol == 'pyro': - result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'search', query, offset, limit, order) + result = self.proxy.dispatch( 'object', 'execute', self.dbname, self.uid, self.pwd, model, 'search', query, offset, limit, order, context) else: - result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'search', query, offset, limit, order) + result = self.objectsock.execute(self.dbname, self.uid, self.pwd, model, 'search', query, offset, limit, order, context) return result # TODO: verify if remove this From 4831377ca8d7e96aacdd78761b299f4e8282bbe6 Mon Sep 17 00:00:00 2001 From: Mariano Ruiz Date: Tue, 3 Dec 2013 14:54:26 -0300 Subject: [PATCH 12/12] Performance improvements (20% - 80% faster) --- ooop.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ooop.py b/ooop.py index 5ad8f0b..b73cb1b 100755 --- a/ooop.py +++ b/ooop.py @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- ######################################################################## # # OOOP, OpenObject On Python @@ -40,7 +40,7 @@ __author__ = "Pedro Gracia " __license__ = "GPLv3+" -__version__ = "0.2.3" +__version__ = "0.2.4" OOOPMODELS = 'ir.model' @@ -269,7 +269,7 @@ def insert_items(self, model, data): print 'Warning: %s already in %s model: %s' % (item, model) def load_models(self): - models = self.read_all(OOOPMODELS) + models = self.read_all(OOOPMODELS, fields=['model']) for model in models: self.models[model['model']] = model self.__dict__[self.normalize_model_name(model['model'])] = Manager(model['model'], self)