Informatique

How to load UTF8 data with python minidom ?

Wednesday, 22 August 2012
|
Écrit par
Grégory Soutadé

For the dynastie project, I need to load data encoded in UTF-8 with Python minidom XML parser. But when I wrote node.toxml('utf-8') to display the XML tree, I get this error :

UnicodeDecodeError at /generate/1

'ascii' codec can't decode byte 0xc2 in position 187: ordinal not in range(128)

In facts Python thinks that all data in XML tree are in ASCII and try to encode it into UTF-8 (or anything else you supplied). The solution is to use your own writer that will convert all non utf-8 strings in unicode string which can be then re-encoded in every format (like utf-8). This doesn't appears in Python 3 because, in Python 3, all strings are already in unicode. Add the following class to your code :

class UnicodeWriter(codecs.StreamWriter): encode = codecs.utf_8_encode def __init__(self): self.value = u'' def write(self, object): if not type(object) == unicode: self.value = self.value + unicode(object, 'utf-8') else: self.value = self.value + object return self.value def reset(self): self.value = u'' def getvalue(self): return self.value

And our node.toxml('utf-8') becomes :

writer = UnicodeWriter() node.writexml(writer) writer.getvalue().encode('utf-8')

Proxy a subdomain with nginx

Thursday, 09 August 2012
|
Écrit par
Grégory Soutadé

A lot of things has been written about nginx and Apache : proxy_pass, proxy_redirect, subdomains... I just want to publish my configuration that is in test but works. This is a response to my requirements : I want nginx to serve the subdomain blog.soutade.fr but transfer all other requests to an Apache server (soutade.fr, www.soutade.fr, indefero.soutade.fr ...).

 

First step is to install nginx. Nginx current version is 0.7.23 (thanks to debian stable). Then edit /etc/nginx/sites-available/default :

server { listen 80 default; ## listen for ipv4 server_name soutade.fr *.soutade.fr; access_log /var/log/nginx/soutade.fr.access.log; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header Host $host; resolver localhost; proxy_pass http://$host:8000; } } server { listen 80; ## listen for ipv4 server_name blog.soutade.fr; access_log /var/log/nginx/soutade.fr.access.log; location / { root /var/www/blog; index index.html; } location = /favicon.ico { access_log off; log_not_found off; } location ~ /\. { deny all; access_log off; log_not_found off; } }

The first block tells nginx to redirect all request from soutade.fr and *.soutade.fr to a local Apache server listening on port 8000. The second block creates a special rule for blog.soutade.fr : files will be served by nginx server and no redirection will be applied. We also disable favicon.ico error log and deny serving \.* files. There is a tip in the first block : we need to set up a local DNS server ("resolver localhost" directive). If this option is not set, it will try to do another DNS request to resolve $host address. So we'll simply install bind9 and configure it. Edit /etc/bind/named.conf.local

zone "soutade.fr" { type master; file "/etc/bind/db.soutade.fr"; };

Finally edit /etc/bind/db.soutade.fr with :

$TTL 604800 @ IN SOA soutade.fr. root.soutade.fr. ( 07082012 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire 604800 ) ; Negative Cache TTL ; @ IN NS localhost. @ IN A 127.0.0.1 * IN CNAME soutade.fr. @ IN AAAA ::1

And restart bind : sudo service bind9 restart. root.soutade.fr. is the mail address of the administrator. Now everything might be ok.

Migration chez Gandi

Tuesday, 03 July 2012
|
Écrit par
Grégory Soutadé

Alors que mon certificat SSL expire dans deux mois, OVH m'envoie un mail m'indiquant qu'ils abandonnent la certification SSL. Je trouve dommage de ne plus proposer de certification SSL quand on veut être un acteur majeur de l'Internet... Bref je n'ai pas envie d'avoir deux contrats dans deux sociétés différentes (pour mon certificat et mon nom de domaine), j'ai donc pris la décision (contestable) de tout migrer chez Gandi. À la base je voulais m'enregistrer chez Gandi car ils ont une bonne renommée, mais j'ai finalement choisi OVH. La migration s'est faite en huit jours une fois que j'ai eu désactivé la protection du domaine et récupéré la clé secrète chez OVH.

Après quelques jours d'utilisation, je me rend compte qu'OVH est supérieur techniquement à Gandi dans les outils qu'ils proposent, ils sont beaucoup plus simples et intuitifs (même si le support est loin d'être terrible). Bon, une fois configuré, on ne touche plus à rien, mais quand même... Et surtout un GROS manque chez Gandi est qu'ils ne gèrent pas nativement une ip dynamique (DynDNS). Évidemment je m'en suis rendu compte après migration...

La solution proposé sur les forums est de faire pointer un enregistrement IP (A) vers un DynDNS ... ce n'est pas acceptable. Heureusement, après quelques recherches, je découvre que Gandi met a disposition une API XML permettant de manipuler son compte ! Après m'être battu inutilement avec la version OT&E (qui ne permet de rien faire), j'ai finalement réussit à obtenir l'équivalent d'un DynDNS avec un petit script python que l'on mettra en cron :

#!/usr/bin/env python import xmlrpclib import urllib2 import re import sys # # Update Gandi DNS with dynamic IP # # This doesn't work with OT&E platform !! # DEBUG = False zone_to_edit = 'Soutade' apikey = 'Your private API key' api = xmlrpclib.ServerProxy('https://rpc.gandi.net/xmlrpc/') def debug(str): if DEBUG: print str # Get current IP current_ip = '' try: dyndns_url = 'http://checkip.dyndns.com/' f = urllib2.urlopen(dyndns_url) data = f.read() f.close() pattern = re.compile('[^:]*(\d+\.\d+\.\d+\.\d+)') result = pattern.search(data, 0) if result == None: print "No IP found" sys.exit(1) else: current_ip = result.group(0).strip() except urllib2.HTTPError: print "Connexion error" sys.exit(1) debug('Your current IP is \'' + current_ip + '\'') # Update Gandi DNS zones = api.domain.zone.list(apikey, {'name' : zone_to_edit}) if len(zones) == 0: print 'Zone \'' + zone_to_edit + '\' not found' sys.exit(1) zone = zones[0] debug('Zone to be edited') debug(zone) records = api.domain.zone.record.list(apikey, zone['id'], zone['version']) edited = False for record in records: if record['type'] == 'A' and current_ip != record['value']: debug('Edit record') debug(record) record['value'] = current_ip edited = True # Delete all id keys del record['id'] if edited: debug('Edit result') debug(records) if zone['version'] == 1: zone['version'] = 2 else: zone['version'] = 1 debug('New version is ' + str(zone['version'])) api.domain.zone.record.set(apikey, zone['id'], zone['version'], records) api.domain.zone.version.set(apikey, zone['id'], zone['version']) debug('New zone values') debug(api.domain.zone.record.list(apikey, zone['id'], zone['version']))

Le script ne se veut pas générique, mais il fonctionne ! Il faut l'adapter en changeant la clé d'API et le nom de la zone à éditer. Il faut aussi créer deux versions (1 et 2) de la zone à modifier avec au moins un champs A et attacher le nom de domaine à cette zone. On pourra activer les traces en changeant la valeur de DEBUG. Pour info, mes paramètres DNS sont (mode expert) :

@ 1080 IN A 86.193.241.253 * 1080 IN CNAME soutade.fr. @ 1080 IN MX 10 soutade.fr.

La première ligne fait pointer soutade.fr (nom de domaine attaché = @) à une IP que l'on mettra à jour dynamiquement. La seconde ligne fait pointer n'importe quel sous domaine de soutade.fr (blog.soutade.fr par exemple) vers soutade.fr qui point lui même vers une IP. La troisième ligne permet d'indiquer que le serveur mail se trouve également sur l'IP pointée par soutade.fr.

La bonne nouvelle est que j'ai droit à un certificat SSL gratuit pendant un an et le renouvellement de mon nom de domaine pour un an également, le tout pour 15€ ! Je reviendrai peut être chez OVH pour Internet... un jour...

Version 0.3 de KissCount

Friday, 22 June 2012
|
Écrit par
Grégory Soutadé

Comme pour la version précédente il a fallu attendre presque un an pour voir sortir la mouture 0.3 de KissCount. L'objet de ce retard est double : D'une part j'ai, depuis un an, beaucoup moins de temps de libre et, d'autre part, la création d'une version pour Windows a fortement retardé l'évolution du projet. Qu'est ce qu'on retrouve dans cette nouvelle version ? La principale modification est le passage à Qt4. Ça a été plus long que compliqué et une fois que j'ai réussi à reproduire un tableau correct, j'ai pu dérouler ! Le passage depuis wxWidgets est relativement "simple" car ils font tous les deux partis d'un monde objet avec des concepts proches en ce qui concerne l'approche graphique.

Nouvelles fonctionnalités

Aucun designer n'a rejoint l'équipe, mais grâce au trio Qt + icônes oxygen + libkdchart (bibliothèque graphique de KMyMoney), l'application commence vraiment à ressembler à quelque chose. Il faut noter aussi la mise en place de l'auto complétion, fonctionnalité attendue depuis la première version de KissCount. Une autre fonctionnalité intéressante est la gestion simple des sauvegardes. Enfin il y a une option pour "cacher" un compte, ainsi il n'apparaîtra plus dans le panneau principal. C'est un bon moyen pour garder un compte plutôt que de le supprimer (et donc de perdre son historique) ou pour ne pas afficher les comptes dont on se sert peu.

L'import des fichiers OFX n'est pas disponible pour la version Windows.


Attention : la nouvelle version de la base de données n'est pas compatible avec les versions 0.1 et 0.2, la migration étant impossible du fait de la suppression de certaines colonnes d'index.


Pour l'avenir

La version précédente était (selon moi) très aboutie en ce qui concerne le coeur de l'application. Maintenant il ne reste que l'enrobage à fignoler. Il ne manque plus de fonctionnalité majeure, mais on pourrait penser à :

  • Meilleure interface graphique (toujours)
  • Traductions
  • Empaquetage
  • Plugin
  • Imports/Exports plus larges
  • Impression


Au gré des besoins et de la popularité, il sortira peut être un jour une version 0.4.

D'autres captures d'écran sont disponibles dans la documentation française et anglaise. Le code source est disponible ici et la page de téléchargements se trouve .