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.

epiphany utilise webkit

written by nicoe, on Sep 25, 2009 8:15:00 PM.

Avec la sortie de la nouvelle version du bureau GNOME arrive la fonctionnalité que j'attendais vraiment : le passage à WebKit d'epiphany.

WebKit c'est un moteur de rendu Web. WebKit c'est aussi un troll (mourrant) sur l'implication d'Apple dans le logiciel libre car ce moteur est basé sur KHTML et la collaboration entre l'équipe de KDE et celle de la Pomme n'a pas toujours été parfaite.

Mais WebKit c'est surtout une bibliothèque ultra-rapide, j'ai l'impression de revivre et que le net va 5× plus vite depuis que je l'utilise.

Tirage de la CL ...

written by nicoe, on Aug 28, 2009 9:12:00 PM.

Et le voila, cet hymne qu'on attendait depuis si longtemps. Il va retentir dans le stade à l'affiche de FIFA 2010. Le tirage avait lieu hier, et on est maintenant fixé sur les adversaires du Standard :

Toutes les équipes jouent en rouge et blanc, ce sera l'occasion de voir nos joueurs avec le maillot brun. C'est pas plus mal. Et l'un dans l'autre, le tirage est relativement abordable. Ça pourrait le faire.

Demain rendez-vous à Sclessin pour choper des places pour les trois matches.

EDIT: C'est fait j'ai mes places ! 20 minutes de file, seulement 5 personnes devant moi, le rêve du à une communication très approximative du Standard.

Nouvel appartement

written by nicoe, on Aug 25, 2009 12:58:00 PM.

Mon appartement est complètement sous eaux pour l'instant. En conséquence, et il en était grand temps, je suis à la recherche d'un nouvel appartement.

Immoweb, me voilà ! Mes critères : de préférence un jardin, un balcon est le minimum minimorum, pas trop loin du centre ville. J'en ai repéré quelques uns, on va voir ce qu'on va voir.

Un peu marre là

written by nicoe, on Aug 20, 2009 11:10:00 PM.

Résumons nous: le Pukkelpop a comme a son habitude une affiche du tonnerre (Faith No More, Them Crooked Vultures, Squarepusher, Dinosaur Jr, Kraftwerk, et j'en passe).

Et pour illuster cela, lesoir en ligne nous propose un slideshow avec des photos de Ghinzu (qui est passé de 13:50 à 14:30).

Je commence à en avoir marre là. Faire la promotion des groupes locaux, c'est bien, ça peut même faire éclore des vocations. Mais avec Ghinzu on frise l'overdose, n'en jettez plus ! Ils n'ont plus besoin de l'aide des médias pour cartonner (du moins chez nous) et laissons faire : on verra bien si le soufflé prendra.

Déboguer du python

written by nicoe, on Aug 14, 2009 8:18:00 AM.

Il est amusant de constater que Guido utilise print pour déboguer son code (via Matt Harrison).

Je pense que c'est ainsi que fonctionnent 90% des gens qui travaillent en python : pas de Visual Studio Integrated FX 3000 Pouet Pouet, dans des cas extrèmes pdb vient à notre secours. L'essentiel du temps de déboguage est passé à tester (avec py.test pourquoi pas) ou dans une console ipython. Ça nous suffit et cette config explique très bien pourquoi vim et emacs sont les éditeurs les plus répandus dans la communauté.

De banshee à rhythmbox

written by nicoe, on Aug 9, 2009 8:06:00 AM.

À cause de quelques problèmes de performances, j'ai finallement décidé de me passer de banshee. Et comme on peut le voir avec la commande debtags suivante, le choix n'est pas immense :

kinder:~% debtags search 'works-with-format::oggvorbis &&
                          uitoolkit::gtk && use::playing &&
                          ! (implemented-in::c-sharp || implemented-in::python)'
alsaplayer-gtk - PCM player designed for ALSA (GTK version)
ardour - digital audio workstation (graphical gtk2 interface)
audacious - small and fast audio player which supports lots of formats
gecko-mediaplayer - Media plug-in for Gecko browsers
geekast - GNOME interface to peercast
geekast-binary - GNOME interface to peercast - binaries
gnome-mplayer - A simple GUI for MPlayer
mplayer - movie player for Unix-like systems
quark - music player daemon controlled from the gnome panel or cli
rhythmbox - music player and organizer for GNOME
somaplayer - player audio for the soma suite
somaplayer-doc - documentation for somaplayer
totem-gstreamer - A simple media player for the GNOME desktop based on GStreamer
totem-xine - A simple media player for the GNOME desktop based on xine

Je suis donc de retour après quelques années de MPD, Quodlibet et autre Banshee sous Rhythmbox. Évidemment entre temps, j'ai attribué des notes à pas mal de morceaux et je ne veux pas perdre ces informations. C'est pourquoi j'ai concocté le petit script suivant :

# -*- encoding: utf8 -*-
import os
import sys
import sqlite3
import urllib
from lxml import etree

RMB_FILE = os.path.expanduser('~/.local/share/rhythmbox/rhythmdb.xml')
XPATH_EXPR = "//entry[@type='song']/location[contains(., '%s')]"
xml_tree = etree.parse(RMB_FILE)

conn = sqlite3.connect(sys.argv[1])
cursor = conn.cursor()
cursor.execute('select uri, rating from coretracks')

for uri, rating in cursor:
    if rating == 0:
        continue

    try:
        quoted_uri = urllib.quote(uri.encode('utf8', 'ignore'),
                                  safe="/()+&,!=")
        loc_node = xml_tree.xpath(XPATH_EXPR % quoted_uri)[0]
        entry = loc_node.getparent()
        if not entry.find('rating'):
            score = etree.Element('rating')
            score.text = '%s' % rating
            entry.append(score)
    except IndexError:
        print >> sys.stderr, '%s (score: %s) not added' % (uri, rating)
        continue

print etree.tostring(xml_tree)

Il sortira sur stdin, le nouveau fichier XML utilisable avec rhythmbox et prend en argument le fichier banshee.

Migration à zine

written by nicoe, on Aug 8, 2009 6:39:00 PM.

Avec les changements dont je parlais précédemment, je vais revoir le contenu de mon (je suppose que maintenant je peux utiliser la première personne) site Web.

Première étape: j'ai décidé de migrer le moteur de blog à zine. Celui-ci est écrit en python, m'apparaît très simple à utiliser et la migration s'est déroulée sans trop de soucis puisqu'il supporte l'importation de feed atom. La procédure d'installation est détaillée dans ce sujet du forum de mon hébergeur (l'excellent webfaction).

Techniquement zine est une application WSGI baséé sur werkzeug, ce qui devrait garantir une certaine flexibilité. D'ailleurs un ensemble de plugins existent déjà et j'utilise par exemple celui permettant d'écrire en restructured text.

Quelques manipulations maladroites de Gimp et un peu de chipotages avec la feuille de style, voici le résultat.