Archive for May 2010

Using distant OpenERP objects pythonically

written by nicoe, on May 19, 2010 10:03:00 PM.

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.

Nokia 5800 et rhythmbox

written by nicoe, on May 19, 2010 8:57:00 AM.

J'ai enfin décidé d'utiliser les propriétés de lecteur MP3 de mon Nokia. Le déclic ce fut l'importation des 45 CDs achetés lors la (triste) liquidation de Caroline Musique. Il faut que je trouve du temps pour écouter tout ça ! Temps tout trouvé puisque je passe vingt cinq minutes dans le bus tous les matins.

libmtp est bien faite et détecte mon téléphone malheureusement soit elle, soit rhythmbox est incapable de transférer les fichiers musicaux correctement puisqu'ils ne respectent pas la hiérarchie Artiste/Album. Tant pis, je l'utilise alors en mass-storage et j'ajoute le fichier .is_audio_player suivant permettant à rhythmbox de correctement transcoder mes précieux flac en mp3 parfaitement compréhensibles par mon GSM.

audio_folders=Music/
folder_depth=2
output_formats=audio/mpeg

De retour

written by nicoe, on May 17, 2010 5:37:00 PM.

Après quelques mois de mort clinique, ce blog est reparti. Pour combien de temps, nous verrons.