Tutoriel CherryPy
Encore en traducation...
Qu'est-ce que CherryPy ?
CherryPy est un framework pour le développement Web, orienté objet et pythonic. Il fournit les fondations sur lesquelles il est possible d'écrire des applications Web évoluées et complexes, le tout avec une connaissance réduite des protocoles sous jacents. CherryPy permet aux développeurs d'écrire des applications Web de la même manière qu'ils écrivent des applications Python classiques. Il en résulte un code source plus réduit et un gain de temps.
CherryPy tente de ne pas influencer le développeur quant à la manière de résoudre un problème. Aussi les applications basées sur CherryPy sont souvent simples et fonctionnent sans devoir configurer le système de telle ou telle manière. Par ailleurs, le serveur HTTP fournit permet aux applications d'être déployées n'importe où Python est installé. En résumé, CherryPy est aussi pythonic que l'on peut.
Qu'est ce que n'est pas CherryPy ?
CherryPy est un framework Web simple et par conséquent, ne promet aux développeurs uniquement que de s'occuper de traiter une requête entrante et d'en restituer les composantes sous une forme structurée. En revanche, CherryPy n'est pas un langage de rendu tel que l'est PHP. En fait, CherryPy n'impose aucun langage de rendu mais sa souplesse lui permet de fonctionner avec n'importe lequel, comme par exemple Cheetah, CherryTemplate?, ZPT, XSLT, Kid, etc. Ceci étant, veuillez réaliser, que même si ces langages sont souvent utiles, CherryPy n'en necessite pas à proprement parler.
CherryPy inclus un server Web léger, suffisant pour gérer une charge moyenne. On estime que CherryPy peut traiter environ 500 requêtes/seconde sur une machine correctement configurée en ce sens (Janvier 2005); cette estimation peut se traduire par une sortie d'environ 15 Mb/s. Cependant, CherryPy n'est pas Apache. Si vos besoins sont de très simportant, alors nous vous invitons à faire tourner CherryPy derrière Apache ou à utiliser l'adaptateur WSGI avec un serveur comprenant WSGI.
Objectifs de ce tutoriel
Ce tutoriel couvre les étapes de base pour débuter avec l'approche que CherryPy propose pour développer des applications Web. Une fois ce tutoriel lu, le développeur comprendra comment s'architecture une application basée sur CherryPy et comment écrire ses propres applications. Pour suivre ce tutoriel, une connaissance du langage de programmation Python est supposée acquise. Il n'est pas demandé d'être un expert en programmation objet mais une notion basique est souhaitée.
Prérequis
Ce tutoriel suppose que vous possédiez :
- Une connaissance de Python
- Des notions de programmation orientée objet
- Des notions d'HTML
Apprendre Python
Il existe plusieurs tutoriels sur le langage de programmation Python, tel que Dive Into Python de Mark Pilgrim, ainsi que bien entendu le site officiel du langage Python lui même.
Votre première application
Le classique 'Hello World' prend moins de 10 lignes de code :
from cherrypy import cpg class HelloWorld: def index(self): return "Hello world!" index.exposed = True cpg.root = HelloWorld() cpg.server.start()
Bien entendu, nous supposons que CherryPy est correctement installé sur votre machine. Puis copiez le code ci-dessus et sauvegardez le dans un fichier hello.py et entrez la ligne de commande suivante :
python hello.py
En utilisant votre navigateur favori, pointez à l'adresse suivante http://localhost:8080 et vous verrez appraître le
.
Comment cela fonctionne-t-il ?
- La ligne from cherrypy import cpg importe l'objet cpg du module CherryPy. C'est le seul objet requis par CherryPy pour fonctionner. D'une certaine façon, cpg est la glue entre le serveur web et votre application.
- Nous créons une classe HelloWorld?. Une instance de cette classe est l'objet qui sera publié par CherryPy. Cette classe contient une seule méthode, index(), qui sera appelée lorsque l'URL racine du site sera (par exemple: http://localhost/). Cette méthode retourne le contenu de la page, qui dans notre cas présent n'est qu'une chaine de caractères "Hellow World!".
- La ligne index.exposed = True, est une étape indispensable pour indiquer à CherryPy que cette méthode sera exposée. Seules les méthodes exposées peuvent être appelées lors d'une requête. Cette caractéristique nous permet de définir dans une classe les méthodes participant effectivement à la structure du site telle qu'elle est perçue par le client.
- La ligne cpg.root = HelloWorld() publie une instance de la classe HelloWorld? à la racine du site.
- La ligne cpg.server.start() démarre le serveur web intégré de CherryPy. Pour l'arrêter, envoyez lui un signal via par exemple la commande kill ou Ctrl-C. Il est possible aussi de définir une méthode pour arrêter le serveur depuis l'application elle-même, mais cela sortirait des bornes de ce tutoriel.
Quand l'application est exécutée, le serveur de CherryPy est démarré avec la configuration par défaut. Le serveur écoute sur localhost sur le port 8080. Vous pouvez changer simplement ces paramètres via un fichier ou dictionnaire de configuration (cf plus bas).
Lorsque le serveur reçoit une requête (pour l'URL http://localhost:8080/ par exemple), il cherche la meilleure méthode pour traiter la requête, en commençant à partir de cpg.root (dans notre exemple, nous avons une instance de la classe HelloWorld?). Dans ce cas particulier, la racine du site est automatiquement mis en correspondance avec la méthode index() de la classe. Puisque la classe HelloWorld? définie et expose une méthode index(), CherryPy peut appeler cpg.root.index(). Le résultat de cet appel est retourné vers le navigateur. Tout le travail de traitement HTTP est réalisé en interne par CherryPy, le développeur ne doit fournir que le contenu à renvoyer.
Concepts
Publication
Tout objet attaché à cpg.root est dit publié. Cela signifie que l'objet est accessible grâce à la routine interne de CherryPy de conversion d'une URL vers un objet Python.
Exemples d'objets publiés :
cpg.root.user cpg.root.group.add
Ceci dit, cela ne signifie pas que cet objet est encore accessible depuis l'extérieur, pour cela il faut que l'objet soit exposé.
Exposer des objets
CherryPy met en correspondance une URL (et sa requête générée par le client) et l'objet dans l'arbre des objets publiés par l'application. Une méthode qui peut être appelée de cette manière est dite exposable.
Pour exposer une métode, vous devez définir l'attribut exposed de la manière suivante :
def index(self): ... index.exposed = True
Si vous utilisez Python 2.4, vous pouvez utilisez un décorateur définie par CherryPy comme ceci :
@cpg.expose def index(self): ...
Pourquoi cette distinction ?
A première vue, on peut se demander de l'utilité de définir deux notions si semblables. En effet par définition, tout objet exposé est aussi publié.
La nécessité de différencier les deux réside dans la possibilité en interne de rediriger une requête vers un autre objet publié, même si ce dernier n'est pas exposé explicitement. C'est une caractéristique avancé de CherryPy en dehors de ce tutoriel.
La nécessité vient aussi du fait qu'en général vous publierez une instance de classe (une fonction, ou n'importe quel callable python pouvant aussi l'être). Or, dans une classe, vous pouvez souhaiter ne pas rendre accessible certaines méthodes de traitement internes à la classe.
Trouvez le bon objet
Du point de vue l'utilisateur, une application n'est rien de plus qu'un site web construit de pages statiques. L'utilisateur navigue via une URL vers une page web. Un server web classique ne s'occupe que chercher un fichier statique sur le système de fichiers. D'un autre côté, un serveur d'application web peut à la fois servir des fichiers statiques, mais peut aussi convertir une requête dans un objet compréhensible par l'application elle même. Le résultat du traitement réalisé sur cet objet par l'application est retourné vers le client. Ce processus est à la base d'une application web dynamique, puisque les pages visibles par l'utilisateur sont issues d'un traitement par le serveur d'application.
La clé de base pour construire votre application web, est la compréhension de la mise en correspondance (mapping) entre l'URL (et sa requête) et l'objet manipulé en interne par l'application. CherryPy utilise un algorithme plutot simple pour cela. La racine du site est l'objet désigné par cpg.root. Quand CherryPy reçoit une requête, il la divise suivant son chemin d'accès, puis recherche dans l'arbre d'objets celui qui correspond à la requête. Par exemple :
cpg.root.onepage = OnePage() cpg.root.otherpage = OtherPage()
L'URL http://localhost/onepage pointera vers le premier objet appelé 'onepage' et l'URL http://localhost/otherpage pointera vers le second objet. La recherche est entièrement réalisée en interne par CherryPy qui se charge d'appelée les 'callable' python correspondant. D'autre part :
cpg.root.some = Page() cpg.root.some.page = Page()
Ici, l'URL http://localhost/some/page correspond à l'objet cpg.root.some.page. Si cet objet est exposé (ou si sa méthode index l'est), il sera utilisé pour l'URL.
La méthode index
La méhode index() possède un caractère spécial dans CherryPy. Un peu à la manière d'un fichier index.html, il s'agit de la méthode par défaut appelée au sein d'un objet si aucune méthode n'est passée dans l'URL. Par exemple :
from cherrypy import cpg class Page(): def index(self): return "index Page" index.exposed = True def test(self): return "test Page" test.exposed = True class Root(): def index(self): return "index Root" index.exposed = True cpg.root = Root() cpg.root.page = Page() cpg.server.start()
Dans l'exemple ci-dessus, bous aurons :
http://localhost:8080/ retournant 'index Root' http://localhost:8080/page/test retournant 'test Root' http://localhost:8080/page retournant 'index Page'
La méthode index() n'est appelée uniquement que lorsqu'il y a une correspondance complète de l'URL. Cela signifie que si CherryPy ne peut pas trouver une correspondance pour une partie de l'URL alors index() ne sera pas appelée.
Ainsi, l'exemple ci-après ne marchera pas :
http://localhost:8080/chemin/page
Appeler des fonctions Python
CherryPy peut aussi appeler des fonctions Python en dehors des classes, le mécanisme est le même que pour une instance de classe et ses méthodes :
def foo(): return 'Foo!' foo.exposed = True cpg.root.foo = foo
Si jamais CherryPy rencontre deux possibilités pour une requête, la métjode index() est prioritaire.
CherryPy vous permet d'appeler n'importe quel objet dit "callable", donc aussi tous les objets qui redéfinissent class.
Traiter les données venant d'un formulaire HTML
CherryPy vous permet de le faire de deux manières :
- En utilisant des paramètres nommés. Ceux-ci doivent avoir le même nom que dans le formulaire HTML.
- En utilisant un dictionnaire du type **kwargs
Exemples :
<form action="doLogin" method="post">
<p>Username</p>
<input type="text" name="username" value="" size="15" maxlength="40"/>
<p>Password</p>
<input type="password" name="password" value="" size="10" maxlength="40"/>
<p><input type="submit" value="Login"/></p>
<p><input type="reset" value="Clear"/></p>
</form>
Vous pouvez traiter de deux manières différentes avec CherryPy.
class Root: def doLogin(self, username=None, password=None): # check the username & password ... doLogin.exposed = True cpg.root = Root()
Ou bien :
class Root: def doLogin(self, **kwargs): # check the kwargs['username'] & kwargs['password'] ... doLogin.exposed = True cpg.root = Root()
CherryPy support les méthodes GET et POST. Mais ceci est totalement transparent pour le développeur. Cependant, vous pouvez retrouver la méthode effectivement utilisé grâce à l'objet cpg.request?.
Correspondances incomplètes et la méthode default()
Une correspondance partielle peut apparaître quand l'URL contient des éléments qui n'appartiennent pas à l'arbre des objets publiés. Les deux causes possibles de ce genre de situation sont :
- L'utilisateur a entré une mauvaise URL
- Des arguments de l'URL ne sont pas gérés par la méthode finale
Lorsqu'une correspondance partielle a lieu, CherryPy appelle la méthode default(). Cette méthode n'est appelée uniquement que lorsqu'une correspondance partielle intervient. Cette méthode est donc utile pour deux cas principallement :
- Gestion des erreurs par le développeur simplifiée
- Support des URLs avec des arguments par position
Le second cas permet par exemple de gérer des applications comme un blog et d'avoir une URL du type :
http://www.mondomaine.org/annee/mois/jour/entree
Cette URL peut ainsi être gérée comme suit par CherryPy :
class Blog: def default(self, annee, mois, jour): ... default.exposed = True ... cpg.root.blog = Blog()
CherryPy fera la correspondance de la manière suivante :
cpg.root.blog.default(annee, mois, jour)
Dans ce dernier exemple, CherryPy rencontre une correspondance partielle et doit donc appeler la méthode default() (le développeur doit bien entendu la définir aussi...) avec le reste de l'URL comme paramètres de la requête.
Si jamais, une requête partielle n'est pas prise en charge par l'application, alors une erreur est levée et retournée au client. Cette erreur peut être changée en redéfinissant la fonction _cpOnError?.

