Using distant OpenERP objects pythonically
At work we have a project to realize a pygtk POS interface for OpenERP. It is getting closer and closer everyday and after much hagglings to create the right UI, I had to connect it to the underlying server. Using the so called netrpc protocol out of the box is not really the most pythonic you can get.
So I came up with those classes that made me fells just like home when I needed to work with the OpenERP objects.
class MetaOEObject(type):
def __init__(cls, name, bases, dict):
super(MetaOEObject, cls).__init__(name, bases, dict)
cls.proxy = Config.client.create_proxy(Config.database,
dict['dotted_name'])
cls.fields = cls.proxy.fields_get()
OEObject.proxies[dict['dotted_name']] = cls
class OEObject(object):
proxies = {}
def __init__(self, id=None):
self.id = id
if id is not None:
self.value = self.proxy.read(id)
@classmethod
def select(cls, condition):
ids = cls.proxy.search(condition)
return [cls(id) for id in ids]
def __getattr__(self, name):
if name not in self.fields:
raise AttributeError
elif self.fields[name]['type'] == 'many2one':
oeobj = OEObject.proxies[self.fields[name]['relation']]
if self.value[name]:
return oeobj(self.value[name][0])
else:
return None
elif self.fields[name]['type'] == 'one2many':
oeobj = OEObject.proxies[self.fields[name]['relation']]
return [oeobj(id) for ids in self.value[name]]
elif self.fields[name]['type'] == 'binary':
if not self.value[name]:
return None
filename = os.tempnam()
fd = open(filename, 'w')
fd.write(base64.b64decode(self.value[name]))
fd.flush()
return filename
return self.value[name]
def __str__(self):
print self.dotted_name, self.id
return '<%s (%d)>' % (self.dotted_name, self.id)
class Category(OEObject):
__metaclass__ = MetaOEObject
dotted_name = 'product.category'
class Product(OEObject):
__metaclass__ = MetaOEObject
dotted_name = 'product.product'
Those kind of classes makes use of metaclasses so that proxy and fields are class-attributes which seems nicer to me. It allows me write pieces of code like this
for category in Category.select([('parent_id', '=', None)]):
page = self.create_category_page(category, notebook)
for product in Product.select([('categ_id', '=', category.id)]):
page.add_product(product)
Which populates a GtkIconView into a notebook used to display products sorted by categories.