Comment rendre les variables du code persistentes à travers le temps et les pannes de courants en passant par les crashs d'application ?
Cette problèmatique fut mise en avant lors du développement d'ECS, un framework e-commerce écrit en Python, au sein d'Emencia, société de services en logiciels libres.
Les modules Python pickle et cPickle servent à cela, mais leurs mise en place de manière générique peuvent etre coûteuse et de plus comment centraliser des centaines d'objets à un moment T donné ?
ECS grâce au projet SQLAchemy, supporte tous types de bases données et fournis en plus un tas de fonctions pour manipuler des tables en base de donnée à partir d'un modèle de code. C'est donc à partir de la que fut developpé le modèle de persistence.
Le modèle de persistence écrit pour ECS, fournit donc les outils pour effectuer la sauvegarde de tout objet instancié au sein de Python. Il contient en plus une implémentation rapide par métaclasse pour accélérer l'intégration au sein du code.
Voici un exemple d'implémentation de classe persistente, prenons l'exemple d'un chat :
[cc lang="python"]
from persistency import PersistentClass
class Cat(object):
__metaclass__ = PersistentClass
age = None
name = None
def __init__(self, name='', age=-1):
self.age = age
self.name = name
if self.age == -1:
self.load()
else:
self.save()
def database(cls):
return 'sqlite:///:memory:'
Cat._sqluri_callback = database
[/cc]
Nous allons donc créer un chat du nom de Felix agé de 8 ans.
[cc lang="python"]
felix = Cat('Felix', 8)
# Roooh il est beau ce chat !
[/cc]
Malheureusement Felix meurt lors d'une messe noire 
[cc lang="python"]
del felix
# Oh non c'est terrible !
[/cc]
Heureusement comme tout le monde le sait, les chats ont neuf vies et Felix n'est pas mort !
Hourra pour Felix !!!
[cc lang="python"]
felix_is_not_dead = Cat('Felix')
felix_is_not_dead.age
[/cc]
Ce qui affichera au final 8.
La métaclasse permet de sauvegarder tout les attributs d'objet, excluant ceux commencant par un '_' comme pour les attributs privés. La sauvegarde des attributs de l'objet se fais au format JSON, ce qui permet la visualisation de chaques objets sauvegardés à partir d'un autre language.
Dans les métaclasses, on peut aussi ajouter des attributs et des méthodes qui vont s'ajouter à l'état et à l'interface des classes instanciées. Ce seront donc des attributs et des méthodes de classe. Dans notre cas, nous allons ajouter les méthodes save, load, delete.
[cc lang="python"]
class PersistentClass(type):
def __new__(clsbase, name, bases, dic):
"""Turns the given class into a persistent one.
By adding a wrapped SQL mapper
"""
if '_sqluri_callback' not in dic:
dic['_sqluri_callback'] = getBaseForPersistence
def _get_persistence(cls):
"""Return the persistence"""
return Persistence(sqluri_callback=cls._sqluri_callback,
wrapper=GenericWrapper,
table=cls.__class__.__name__.lower())
dic['_get_persistence'] = _get_persistence
def save(cls):
"""Saves into the DB"""
persistence = cls._get_persistence()
cls_wrapped = GenericWrapper(cls)
persistence.delete(cls_wrapped.id)
persistence.save(cls_wrapped)
dic['save'] = save
def delete(cls):
"""Deletes into the DB"""
cls._get_persistence().delete(GenericWrapper(cls).id)
dic['delete'] = delete
def load(cls):
"""Loads from the DB."""
wrapper = cls._get_persistence().load(cls.name)
if wrapper is not None:
wrapper._load(cls)
dic['load'] = load
return type(name, bases, dic)
[/cc]
SVN du projet : http://svn.emencia.net/public
Discussion
5 réponses à "Persistence"
Pour les transactions et les sous-objets stoqués persistent dans la transaction vous faites comment ?
Par Alex | lundi 04 juin 2007 11:04Il suffit de rendre ces mêmes objets persistent, en implémentant le mécanisme de sauvegarde aux endroits necessaires dans les méthode de cet objet.
Par Fantomas | lundi 04 juin 2007 11:21Tu aurai un exemple stp ?
Par Alex | lundi 04 juin 2007 14:52Pose moi un use case.
Par Fantomas | lundi 04 juin 2007 17:46Julien on voit que tu es a font dans tes codes! Je dirais meme plus tu vis ton code !! (lol)

Par Maxime | mardi 05 juin 2007 19:51Merci pour cette petite démo Python un jour peut etre je pourrais faire ce genre de chose ...
Remarque avec un prof comme j'ai y'a pas de raisons ...
Je ne te remercierai jamais asser Julien(joublierai pas)