Archive

Archive for the ‘Python’ Category

HMAC Paybox en Python

3 décembre 2012 3 commentaires

Paybox est une solution de paiement électronique que nous avons utilisé plusieurs fois.

Pour se connecter avec le service Paybox (en version 5.08), il est nécessaire de produire une empreinte HMAC des données du serveur que le client va envoyer vers le serveur Paybox pour payer. L’objectif est d’empêcher toute falsification car elle serait détectée grâce à l’empreinte qui ne correspondrait plus.

La documentation fournit une implémentation d’exemple en PHP :

<?php
 $key = 
 "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF";
 $msg = "FORMULAIRE";
 $binkey = pack("H*", $key);
 $hmac = strtoupper(hash_hmac('sha512', $msg, $binkey));
 ?>

Voici l’équivalent en Python :

import binascii
import hashlib
import hmac


PRIVATE_KEY = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"
msg = "FORMULAIRE"
binary_key = binascii.unhexlify(PRIVATE_KEY)
hmac = hmac.new(binary_key, msg, hashlib.sha512).hexdigest().upper()

Les deux codes fournissent le même résultat pour des couples (clé privée, message) identiques. Charge à vous de mettre les bonnes valeurs. 😉

Catégories :Python Étiquettes :

Volume d’une pizza: un cas généralisable ?

9 août 2012 1 commentaire

Peut-être connaissez-vous le dessin montrant que le calcul du volume d’une pizza est équivalent à son nom (http://jaytest.posterous.com/solve-for-pizza) ?

pi.z.z.a = π.z².a
(avec z étant le rayon et a la hauteur)

Si cela fonctionne avec le mot pizza, peut-être cela fonctionne-t-il avec d’autres mots? Voilà la question que vous ne vous êtes jamais posé et dont cet article va s’empresser de répondre.

Contraintes

Il faut que le mot comporte :

  • le terme « pi » ;
  • strictement deux fois une autre lettre que p ou i et qu’elles soient consécutives ;
  • une cinquième lettre, différente de p, de i et de la lettre en double.

Par exemple, les mots suivants ne sont pas valides : « abcpi » (pas de lettre en double), « pizzas » (trop long), « pizaz » (non consécutifs), « pizzz » et « zpizz » (lettre triple).

Outils

Il faut une liste de mots du dictionnaire, par exemple /usr/share/dict/french et un peu de code pour faire le traitement.

Le script python écrit pour la circonstance :

#! /usr/bin/env python
# -*- encoding: utf-8 -*-

import codecs
import re

def main():
   print(filtrer_mots(mots_avec_pi()))
   
def mots_avec_pi():
    with codecs.open("/usr/share/dict/french", "r", "utf-8") as f:
        return [mot[:-1] for mot in f.readlines() if "pi" in mot]


def filtrer_mots(mots):
    return [mot 
            for mot 
            in mots 
            if a_la_bonne_longueur(mot) and a_seulement_deux_caracteres_consecutifs(mot)]

def a_la_bonne_longueur(mot):
    return len(mot) == len("pi" + "rr" + "h")

def a_seulement_deux_caracteres_consecutifs(mot):
    doublons = re.compile(r".*(.).*\1")
    try:
        group = doublons.match(mot).group(1)
    except AttributeError:
        return False
    else:
        return not est_dans_pi(mot, group) and \
                est_consecutif(mot, group) and \
                a_deux_occurences(mot, group)

def est_dans_pi(mot, caractere):
    return caractere in "pi"

def est_consecutif(mot, caractere):
    return caractere * 2 in mot

def a_deux_occurences(mot, character):
    return mot.count(character) == 2


if __name__ == "__main__":
    main()

Conclusion

On obtient quatre résultats : « pilla », « pille », « pillé », « pizza ». À part pizza, pas facile de faire une représentation graphique. 😦

L’équation reste valide même si les deux lettres représentant le rayon ne se suivent pas. Si on supprime cette contrainte, la liste est plus longue mais pas vraiment meilleure. Elle inclut de nouveaux termes : « épicé », « épiée », « épiés », « épilé », « expie », « piégé », « piété » et « tapit ».

Il existe donc des mots avec les mêmes caractéristiques sans qu’on puisse les utiliser pour faire le même trait d’humour. C’est vraiment pas drôle !

Catégories :Python Étiquettes :

Ajouter la détection des bases de données zodb par file

ZODB est la base de données utilisée par Zope (LE serveur d’application Python). file est un outil en ligne de commande Unix, quasiment aussi vieux qu’Unix lui-même : il existe depuis novembre 1973. Depuis, il a été amélioré et de nombreux formats de fichier ont été ajoutés. Malheureusement, les bases de données Zodb ne sont pasn’étaient pas encore prises en charge :

$ file db.fs 
db.fs: data

On sait uniquement que l’on est en présence d’un fichier binaire, ce qui est un peu vague… C’est tout de même assez ballot parce que c’est ce que nous utilisons au travail. Comment avoir une détection correcte ?

Nouvelle définition d’un type de fichier

file se base sur le début du fichier (les nombres magiques) pour en déduire son type et non sur l’extension du fichier. Il faut donc ajouter la définition suivante dans un fichier :
0 string FS21 Zope Database FileStorage (data)

L’insertion de cette ligne dans le fichier /etc/magic, permet d’obtenir automagiquement le résultat suivant pour l’ensemble des utilisateurs du système :

$ file db.fs
db.fs: Zope Database FileStorage (data)

Succinctement, le format attendu pour les définitions est :

  • l’emplacement dans le fichier, en octets (ici 0 parce que c’est tout au début du fichier) ;
  • le type de données attendu (ici string mais cela pourrait aussi être byte, long, etc.) ;
  • la valeur attendue (ici FS21) ;
  • et la description à afficher si la valeur correspond (ici Zope Database FileStorage (data)).

Le format de Zodb est très simple, donc la définition ajoutée est à son image mais magic permet aussi de tester plusieurs valeurs, à plusieurs emplacements. Pour plus de détails, lisez la page de manuel de magic(5).

Le terme « data » est ajouté à la description pour signaler le type de fichier d’un point de vue assez général. Les deux autres possibilités étant soit « text », soit « exécutable ». Il est important que l’un de ces mots-clef soit présent dans la description, quelque soit l’endroit à l’intérieur de la description. La page de manuel de file(1) insiste sur le fait de respecter cette convention en cas d’ajout de définitions.

Déploiement vers le reste du monde

Plutôt que de garder cette définition, pourquoi ne pas la diffuser pour que d’autres puissent en profiter ? Le plus logique est de contacter les développeurs de ZODB pour savoir s’il y aurait des détails qui n’auraient pas été pris en compte par ignorance.

(Note : la liste de diffusion ZODB-dev nécessite une inscription pour pouvoir envoyer des messages. Si ce n’est pas le cas, le robot de la liste ignore silencieusement le message posté. Inscrivez-vous avant tout envoi.)
Après proposition sur la liste de diffusion de ZODB-dev, Jim Fulton a proposé une meilleure description et suggéré d’ajouter les fichiers de cache pour ZEO.

Grâce à lui, la version finale suivante est obtenue :

# Database file for Zope (done by FileStorage)
0       string  FS21    Zope Object Database File Storage (data)

# Cache file for the database of Zope (done by ClientStorage)
0       string  ZEC3    Zope Object Database Client Cache File (data)

C’est cette version qui a été envoyé et accepté par Christos Zoulas, mainteneur de file. Si vous voulez bénéficier tout de suite de la détection de ces deux types de fichiers, il suffit de copier les lignes précédentes dans /etc/magic. Sinon, cela sera réalisé automatiquement lorsque la prochaine version de file sera publiée et intégrée sur votre système.

Catégories :Python

Poésie en Python (3)

Cet article termine la série de poésie en Python. L’objectif est de corriger les défauts signalés dans le second article pour enfin livrer une version finale de la poésie. Le premier article présentait les contraintes d’écriture et les poèmes créés.

Le jury a validé globalement le poème mais reproche les lignes de code trop visibles qui gâche l’esthétique globale du poème. Heureusement, ces défauts ne sont pas insurmontables comme nous allons le voir. Il est donc possible de partir du poème déjà écrit, d’ajouter quelques patchs pour obtenir un résultat satisfaisant. Comme le dit très approximativement l’adage : « Sur le métier remet au moins deux fois ton ouvrage ».

Critiques et correctifs

Voici la liste des lignes de code posant problèmes :

  • #! /usr/bin/env python
  • # -*- coding: utf-8 -*-
  • import os
  • "".join([v[0] for v in

Il est possible de les prendre successivement pour les résoudre un à un :

Le shebang #! /usr/bin/env python

Cette ligne est simplement à enlever. Cette ligne servant à informer l’interprète de commande du programme à utiliser, il ne sera plus possible de lancer le script directement mais cela restera faisable en passant le script en paramètre à python :
$ ./suicide.py => pas bien
$ python suicide.py => bien

La déclaration d’encodage # -*- coding: utf-8 -*-

Cette ligne permet à l’interpréteur de ne pas avoir de soucis avec les problèmes d’encodage des accents et autres caractères spéciaux (comprendre non-ASCII). Plusieurs solutions se dégagent :

  • déclarer les chaînes comme de l’unicode (u"ma chaine"). Le défaut étant que le rendu n’est pas très élégant, ce qu’on essaie actuellement de corriger…
  • supprimer les accents : « éloignes » devient « eloignes ». Solution qui fonctionne mais qui prête le flanc à de nouvelles critiques. 😦
  • enlever les mots accentués : s’ils sont remplacés par des mots sans accents, le problème est résolu de lui-même. Je trouve ce contournement très amusant mais lourd à mettre en place (beaucoup de passages à réécrire).
  • passer à python 3 : Unicode, et donc les accents, est géré nativement.

Ce n’est pas parce que la poésie est une matière poussiéreuse, qu’on ne peut pas faire du code tourné vers l’avenir ! Nous choisirons donc Python 3 qui est trivial à mettre en place puisqu’il suffit d’installer une nouvelle version du compilateur (paquet python3 sous Debian et distributions assimilées). Lancer le script devient donc :
$ python3 suicide_final.py

L’import de la bibliothèque import os

Il est impossible de se passer de l’import pour appeler la fonction de suppression. En revanche, il est possible de l’inclure dans la chaîne à exécuter :
import os;os.remove(__file__) fonctionnera ; le point-virgule servant de séparateur entre les deux instructions.

Insérer l’import ajoute 10 caractères à la ligne donc 10 vers supplémentaire à ajouter au début du poème. Malheureusement, cela ne fait pas des quatrains donc il faut rajouter 2 vers inutiles pour garder la structure principale du poème. Par contre, il ne faut pas que les premiers caractères de ces deux vers soient pris en compte. La méthode la plus évidente et de mettre un espace comme premier caractère, comme pour le vers qui sépare import de os. L’autre solution, qui sera préférée ici est de ne pas mettre de virgule à la fin de la ligne, python concaténant les lignes pour en faire une seule chaîne. Cette solution a été choisie uniquement pour son avantage graphique (pas de décalage en début de vers).

La concaténation du premier caractère de chaque vers "".join([v[0] for v in

Cette ligne était simplement entre les stophes du programme et la dernière strophe introduisant l’exécution. Il est facile de la déplacer en début de fichier : au lieu d’utiliser une variable temporaire, il suffit de mettre l’ensemble du poème comme paramètre du in.

Résultat final

Et voilà le résultat final !

ute = "".join([v[0] for v in (
    "imperceptiblement tu te détaches de",
    "mes bras et t'éloignes encore et encore,",
    "puis à l'horizon mes yeux te perdent.",
    "ostracisé par ton coeur et par ton corps.",

    "restent de jolis souvenirs passés",
    "toujours si vivants dans ma mémoire,",
    " nos jeux complices au soleil couchant cet été",
    "ou ces promenades sur les bords de la Loire.",

    "souvent j'y repense en souriant",
    ";d'un sourire d'autant plus douloureux"
    "que ma tristesse restera longtemps :"
    "tu m'as quitté et m'as rendu malheureux.",

    "où souhaiterais-tu que nous allions",
    "si jamais nous avions encore un avenir?",
    ".je ne veux pas que nous nous reperdions;",
    "reconstruisons ensemble de nouveaux souvenirs.",

    "en me rappellant de toi,",
    "mes yeux se remplissent de larmes.",
    "oubliés les causes, les pourquois",
    "voulais-tu que je subisse un tel blâme?",

    "ennamourés tous les deux",
    "(juste nous, le reste du monde",
    "_disparu_ à nos yeux)",
    "_mes espoirs_ s'effondrent.",

    "furtivement, tu t'éclipses.",
    "insensible lorsque tu me quittes à",
    "la douleur dans mes synapses",
    "et je sais bien que je ne te reverrai pas.",

    "_ma vie_ devenue bien trop grande",
    "_sans toi_ (juste remplie de pleurs",
    ") n'est plus rien que des cendres."
    )])

"Ma décision est prise: une fin "
"Rapide plutôt qu'une longue chute."
"J'aurai assez de courage pour que je m";exec(ute)

Et vous, le langage que vous utilisez au quotidien est-il assez expressif pour écrire des poèmes ?

Catégories :Python

Poésie en Python (2)

30 juin 2011 1 commentaire

Après avoir livré la poésie en Python (cf. épisode précédent) au jury, celui-ci rend sa décision. Pour apprécier le poème et les pertinentes remarques du jury, il est nécessaire de comprendre le fonctionnement du programme :

The art of poem programming

À la lecture, le texte raconte l’histoire d’un amoureux déçu qui décide de se suicider. Pour voir l’effet du poème, il suffit de le copier-coller dans un fichier (suicide.py dans l’exemple suivant) et d’exécuter le programme :

stephane@foehn:/tmp/poeme$ ls
suicide.py
stephane@foehn:/tmp/poeme$ chmod u+x suicide.py 
stephane@foehn:/tmp/poeme$ ./suicide.py 
stephane@foehn:/tmp/poeme$ ls
stephane@foehn:/tmp/poeme$

Le programme s’est supprimé tout seul ! Le code fait ce que le programme raconte, ce qui était la nouvelle contrainte à respecter.

Comment ce petit miracle s’est réalisé ?

Le programme se compose de trois parties :

  • la définition de _
  • la définition de ute
  • la production de l’effet

La définition de _ :
C’est un n-uplet de chaines de caractères (les vers du poème). Chaque vers est séparé par une virgule, ce qui explique les virgules à chaque fin de ligne alors qu’elles n’ont pas de sens poétique. Le choix du nom de la variable est motivé par sa discrétion, aux antipodes de l’expressivité, pour masquer le code au maximum.

La définition de ute :
Elle est faite en une seule ligne grâce à l’utilisation de deux bouts de code pythoniques. C’est véritablement le coeur du programme :
[v[0] for v in _] est une comprehension list : elle prend un objet itérable, ici _, et pour chaque élément, nommé ici v pour « vers  », prend son premier élément (donc le premier caractère du vers). Ce morceau de code retourne donc

['o', 's', '.', 'r', 'e', 'm', 'o', 'v', 'e', '(', '_', '_', 'f', 'i', 'l', 'e', '_', '_', ')']

Prendre la première lettre de chaque vers pour composer un message en rapport avec le poème est une figure de style (un acrostiche). Ici, le message est le texte du programme, sorte de trait d’union entre le poème et le code.

separateur.join(iterable) est le code typique de concaténation de chaîne de caractères : il ajoute separateur entre chaque élément de l’objet iterable. Dans le poème, on ajoute une chaîne vide entre chaque élément, lui-même constitué uniquement d’une lettre. (En python, il faut éviter d’utiliser l’opérateur + pour concaténer, en particulier dans une boucle pour des raisons de performance.)

ute est donc une chaîne valant os.remove(__file__).

La production de l’effet : jusque ici, on a simplement une chaine qui va falloir rendre active. C’est réalisé à la toute fin du poème, lorsque le narrateur dit qu’il va se suicider. exec(ute) permet de faire le lien entre la personne qui se suicide (donc s’exécute) et le programme qui fait de même. Dans beaucoup de langage, l’évaluation dynamique du code se fait avec la fonction eval(). Cette fonction est aussi disponible en Python mais n’est pas très adapté à cette poésie. On obtient donc le résultat grâce à exec().

__file__ est une variable spéciale remplie automatiquement par l’interpréteur. C’est une chaîne de caractère valant le chemin vers le fichier. L’utilisateur peut donc choisir le nom qu’il veut, le programme fonctionnera.

Le fonctionnement même du programme impose la première lettre (ce qui explique que certains vers commencent par les caractères soulignés, plus ou moins maquillés par d’autres caractères soulignés sur la même ligne, simulant la volonté de donner de l’emphase sur certains termes).

Verdict du jury

Après analyse de l’impartial jury, celui-ci rendit son verdict. L’effort était apprécié mais le résultat ne pouvait être considéré comme une véritable réussite. En effet, pour le jury :

on n’atteignait pas encore les sommets de la poésie parce qu’il y a du texte parasite, genre ça :

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import os

C’est vrai, je confesse avoir naïvement espéré que le jury ferme les yeux sur ces détails. Que nenni, le jury, inflexible, à l’oeil de faucon et d’une main de fer dans un gant de titane blindé, ne pouvait être abusé. Oui, le jury est dur mais juste. Mais dur surtout.

Un léger abattement se fit sentir un court instant. Mais allé-je me laisser abattre par la douloureuse sentence du jury (impartial, je le rappelle) ?

Non ! C’est ce que nous verrons dans le troisième et dernier épisode, nommé « Le retour du Python qui contre-attaque » (ou « Poésie en Python (3) », j’hésite encore).

(à suivre…)

Catégories :Python
Concevoir un site comme celui-ci avec WordPress.com
Commencer