Programmation Python/Applications web
Vous avez certainement déjà appris par ailleurs un grand nombre de choses concernant la rédaction de pages web. Vous savez que ces pages sont des documents au format HTML, que l'on peut consulter "via" un réseau (intranet ou internet) à l'aide d'un logiciel appelé browser web ou "navigateur" (ex : ', , ', "", ...).
Les pages HTML sont installées dans les répertoires publics d'un autre ordinateur où fonctionne en permanence un logiciel appelé "serveur Web" ("Apache", ', ', ...). Lorsqu'une connexion a été établie entre cet ordinateur et le vôtre, votre logiciel navigateur peut dialoguer avec le logiciel serveur (par l'intermédiaire de toute une série de dispositifs matériels et logiciels dont nous ne traiterons pas ici : lignes téléphoniques, routeurs, caches, protocoles de communication ...).
Le "protocole " qui gère la transmission des pages web autorise l'échange de données dans les deux sens. Mais dans la grande majorité des cas, le transfert d'informations n'a pratiquement lieu que dans un seul, à savoir du serveur vers le navigateur : des textes, des images, des fichiers divers lui sont expédiés en grand nombre (ce sont les pages consultées) ; en revanche, le navigateur n'envoie guère au serveur que de toutes petites quantités d'information : essentiellement les adresses URL des pages que l'internaute désire consulter.
Pages web interactives.
Vous savez cependant qu'il existe des sites web où vous êtes invité à fournir vous-même des quantités d'information plus importantes : vos références personnelles pour l'inscription à un club ou la réservation d'une chambre d'hôtel, votre numéro de carte de crédit pour la commande d'un article sur un site de commerce électronique, votre avis ou vos suggestions, etc.
Dans un cas comme ceux-là, vous vous doutez bien que l'information transmise doit être prise en charge, du côté du serveur, par un programme spécifique. Il faut donc que les pages web destinées à accueillir cette information soient dotées d'un mécanisme assurant son transfert vers le logiciel destiné à le traiter. Il faudra également que ce logiciel puisse lui-même transmettre en retour une information au serveur, afin que celui-ci puisse présenter le résultat de l'opération à l'internaute, sous la forme d'une nouvelle page web.
Le but du présent chapitre est de vous expliquer comment vous pouvez vous servir de vos compétences de programmeur Python pour ajouter une telle interactivité à un site web, en y intégrant de véritables applications.
Remarque importante : Ce que nous allons expliquer dans les paragraphes qui suivent sera directement fonctionnel sur l'intranet de votre établissement scolaire ou de votre entreprise (à la condition toutefois que l'administrateur de cet intranet ait configuré son serveur de manière appropriée). En ce qui concerne l'internet, par contre, les choses sont un peu plus compliquées. Il va de soi que l'installation de logiciels sur un ordinateur serveur relié à l'internet ne peut se faire qu'avec l'accord de son propriétaire. Si un fournisseur d'accès à l'internet a mis a votre disposition un certain espace où vous êtes autorisé à installer des pages web « statiques » (c'est-à-dire de simples documents à consulter), cela ne signifie pas pour autant que vous pourrez y faire fonctionner des scripts Python. Pour que cela puisse marcher, vous devrez demander une autorisation et un certain nombre de renseignements à votre fournisseur d'accès. Il faudra en particulier lui demander si vous pouvez activer des scripts CGI écrits en Python à partir de vos pages, et dans quel(s) répertoire(s) vous pouvez les installer.
Un serveur web en pur Python !
Dans les pages précédentes, nous vous avons expliqué quelques rudiments de programmation CGI afin que vous puissiez mieux comprendre comment fonctionne une application web. Mais si vous voulez véritablement développer une telle application (par exemple un site web personnel doté d'une certaine interactivité), vous constaterez rapidement que l'interface CGI est un outil trop sommaire. Son utilisation telle quelle dans des scripts se révèle fort lourde, et il est donc préférable de faire appel à des outils plus élaborés.
L'intérêt pour le développement web est devenu très important, et il existe donc une forte demande pour des interfaces et des environnements de programmation bien adaptés à cette tâche. Or, même s'il ne peut pas prétendre à l'universalité de langages tels que C/C++, Python est déjà largement utilisé un peu partout dans le monde pour écrire des programmes très ambitieux, y compris dans le domaine des serveurs d'applications web. La robustesse et la facilité de mise en œuvre du langage ont séduit de nombreux développeurs de talent, qui ont réalisé des outils de développement web de très haut niveau. Plusieurs de ces applications peuvent vous intéresser si vous souhaitez réaliser vous-même des sites web interactifs de différents types.
Les produits existants sont pour la plupart des logiciels libres. Ils permettent de couvrir une large gamme de besoins, depuis le petit site personnel de quelques pages, jusqu'au gros site commercial collaboratif, capable de répondre à des milliers de requêtes journalières, et dont les différents secteurs sont gérés sans interférence par des personnes de compétences variées (infographistes, programmeurs, spécialistes de bases de données, etc.).
Le plus célèbre de ces produits est le logiciel "Zope", déjà adopté par de grands organismes privés et publics pour le développement d'intranets et d'extranets collaboratifs. Il s'agit en fait d'un système serveur d'applications, très performant, sécurisé, presque entièrement écrit en Python, et que l'on peut administrer à distance à l'aide d'une simple interface web. Il ne nous est pas possible de décrire l'utilisation de Zope dans ces pages : le sujet est trop vaste, et un livre entier n'y suffirait pas. Sachez cependant que ce produit est parfaitement capable de gérer de très gros sites d'entreprise en offrant d'énormes avantages par rapport à des solutions classiques telles que "PHP" ou "Java".
D'autres outils moins ambitieux mais tout aussi intéressants sont disponibles. Tout comme Zope, la plupart d'entre eux peuvent être téléchargés librement depuis l'internet. Le fait qu'ils soient écrits en Python assure en outre leur portabilité : vous pourrez donc les employer aussi bien sous Windows que sous Linux ou MacOs. Chacun d'eux peut être utilisé en conjonction avec un serveur web « classique » tel que Apache ou Xitami (c'est préférable si le site à réaliser est destiné à supporter une charge de connexions très importante), mais certains d'entre eux intègrent en outre leur propre serveur web, ce qui leur permet de fonctionner également de manière tout à fait autonome. Cette possibilité se révèle particulièrement intéressante au cours de la mise au point d'un site, car elle facilite la recherche des erreurs.
Cette totale autonomie alliée à la grande facilité de leur mise en œuvre fait de ces produits de fort bonnes solutions pour la réalisation de sites web d'intranet spécialisés, notamment dans des petites et moyennes entreprises, des administrations, ou dans des écoles. Si vous souhaitez développer une application Python qui soit accessible par l'intermédiaire d'un simple navigateur web, via un intranet d'entreprise (ou même via l'internet, si la charge prévisible n'est pas trop importante), ces applications sont faites pour vous.
Il en existe une grande variété : "Poor man's Zope", "Spyce", "Karrigell", "Webware", "Cherrypy", "Quixote", "Twisted", etc. Choisissez en fonction de vos besoins : vous n'aurez que l'embarras du choix.
Dans les lignes qui suivent, nous allons décrire une petite application web fonctionnant à l'aide de "Karrigell". Vous pouvez trouver ce système à l'adresse : "http://karrigell.sourceforge.net". Il s'agit d'une solution de développement web simple, bien documentée en anglais et en français (son auteur, Pierre Quentel, est en effet originaire de Bretagne, tout comme le mot "karrigell", d'ailleurs, lequel signifie « charrette »). 
Installation de Karrigell.
L'installation de Karrigell est un jeu d'enfant : il vous suffit d'extraire dans un répertoire quelconque le fichier archive que vous aurez téléchargé depuis l'internet. L'opération de désarchivage crée automatiquement un sous-répertoire nommé "Karrigell-numéro de version". C'est ce répertoire que nous considérerons comme répertoire racine dans les lignes qui suivent.
Si vous ne comptez pas utiliser le serveur de bases de données Gadfly qui vous est fourni en complément de Karrigell lui-même, c'est tout ! Sinon, entrez dans le sous-répertoire gadfly-1.0.0 et lancez la commande : codice_1 (Sous Linux, il faut être root). Vous devez effectuer cette opération si vous souhaitez visualiser la totalité de la démonstration intégrée. 
Démarrage du serveur :.
Il s'agit donc bel et bien de mettre en route un "serveur" web, auquel vous pourrez accéder ensuite à l'aide d'un navigateur quelconque, localement ou par l'intermédiaire d'un réseau. Avant de le faire démarrer, il est cependant conseillé de jeter un petit coup d’œil dans son fichier de configuration, lequel se nomme "Karrigell.ini" et se trouve dans le répertoire-racine.
Par défaut, Karrigell attend les requêtes "http" sur le port n° 80. Et c'est bien ce numéro de port que la plupart des logiciels navigateurs utilisent eux-mêmes par défaut. Cependant, si vous installez Karrigell sur une machine Linux dont vous n'êtes pas l'administrateur, vous n'avez pas le droit d'utiliser les numéros de port inférieurs à 1024 (pour des raisons de sécurité). Si vous êtes dans ce cas, vous devez donc modifier le fichier de configuration afin que Karrigell utilise un numéro de port plus élevé. En général, vous choisirez d'enlever simplement le caractère codice_2 au début de la ligne 39, ce qui activera l'utilisation du n° de port 8080. Plus tard, vous souhaiterez peut-être encore modifier le fichier de configuration afin de modifier l'emplacement du répertoire racine pour votre site web (par défaut, c'est le répertoire du serveur lui-même).
Une fois le fichier de configuration modifié, entrez dans le répertoire racine du serveur, si vous n'y êtes pas déjà, et lancez simplement la commande :
 python Karrigell.py
C'est tout. Votre serveur Karrigell se met en route, et vous pouvez en vérifier le fonctionnement tout de suite à l'aide de votre navigateur web préféré. Si vous lancez celui-ci sur la même machine que le serveur, vous le dirigerez vers une adresse telle que : "http://localhost:8080/index.html", « localhost » étant le terme consacré pour désigner la machine locale, « 8080 » le numéro de port choisi dans le fichier de configuration, et « index.html » le nom du fichier qui contient la page d'accueil du site. Par contre, si vous voulez accéder à cette même page d'accueil depuis une autre machine, vous devrez (dans le navigateur de celle-ci) indiquer le nom ou l'adresse IP du serveur, en lieu et place de "localhost".
Avec l'adresse indiquée au paragraphe précédent, vous atteindrez la page d'accueil d'un site de démonstration de Karrigell, qui est déjà pré-installé dans le répertoire racine. Vous y retrouverez la documentation de base, ainsi que toute une série d'exemples.
Dans ce qui précède, il est sous-entendu que vous avez lancé le serveur depuis une console texte, ou depuis une fenêtre de terminal. Dans un cas comme dans l'autre, les messages de contrôle émis par le serveur apparaîtront dans cette console ou cette fenêtre. C'est là que vous pourrez rechercher des messages d'erreur éventuels. C'est là aussi que vous devrez intervenir si vous voulez arrêter le serveur (avec la combinaison de touches CTRL-C). 
Ébauche de site web.
Essayons à présent de réaliser notre propre ébauche de site web. À la différence d'un serveur web classique, Karrigell peut gérer non seulement des pages HTML statiques (fichiers ".htm", ".html", ".gif", ".jpg", ".css") mais également :
Laissons de côté les scripts hybrides, dont vous pourrez étudier vous-même la syntaxe (par ailleurs très simple) si vous vous lancez dans une réalisation d'une certaine importance (ils pourront vous faciliter la vie). Dans le contexte limité de ces pages, nous nous contenterons de quelques expériences de base avec des scripts Python ordinaires.
Comme tous les autres éléments du site (fichiers ".html", ".gif", ".jpeg", etc.), ces scripts Python devront être placés dans le répertoire racine. Vous pouvez tout de suite effectuer un test élémentaire en rédigeant un petit script d'une seule ligne, tel que :
print "Bienvenue sur mon site web !"
Sauvegardez ce script sous le nom "hello.py" dans le répertoire racine, puis entrez l'adresse : "http://localhost/hello.py" (ou même : "http://localhost/hello" - l'extension ".py" peut être omise) dans votre navigateur. Vous devriez y voir apparaître le message. Cela signifie donc que dans l'environnement Karrigell, la sortie de l'instruction print est redirigée vers la fenêtre du navigateur client, plutôt que la console (ou la fenêtre de terminal) du serveur.
Étant donné que l'affichage a lieu dans une fenêtre de navigateur web, vous pouvez utiliser toutes les ressources de la syntaxe HTML afin d'obtenir un formatage déterminé. Vous pouvez par exemple afficher un petit tableau de 2 lignes et 3 colonnes, avec les instructions suivantes :
print """
<TABLE BORDER="1" CELLPADDING="5">
<TR> <TD> Rouge </TD> <TD> Vert </TD> <TD> Bleu </TD> </TR>
<TR> <TD> 15 % </TD> <TD> 62 % </TD> <TD> 23 % </TD> </TR>
</TABLE>
Rappelons que la balise codice_3 définit un tableau. Son option codice_4 spécifie la largeur des bordures de séparation, et codice_5 l'écart à réserver autour du contenu des cellules. Les Balises codice_6 et codice_7 ("Table Row" et "Table Data") définissent les lignes et les cellules du tableau.
Vous pouvez bien entendu utiliser également toutes les ressources de Python, comme dans l'exemple ci-dessous où nous construisons une table des sinus, cosinus et tangentes des angles compris entre 0° et 90°, à l'aide d'une boucle classique.
from math import sin, cos, tan, pi
print """<TABLE BORDER="1" CELLPADDING="5">
<TR><TD>Angle</TD><TD>Sinus</TD><TD>Cosinus</TD><TD>Tangente</TD></TR>"""
for angle in range(0,62,10): 
 # conversion des degrés en radians :
 aRad = angle * pi / 180
 # construction d'une ligne de tableau, en exploitant le formatage des
 # chaînes de caractères pour fignoler l'affichage :
 print "<TR><TD>%s</TD><TD>%8.7f</TD><TD>%8.7f</TD><TD>%8.7g</TD></TR>"\
 % (angle, sin(aRad), cos(aRad), tan(aRad))
print "</TABLE>"
Ligne 7 : Nous nous servons de la fonction codice_8 pour définir la gamme d'angles à couvrir (de zéro à 60 degrés par pas de 10).
Ligne 9 : Les fonctions trigonométriques de Python nécessitent que les angles soient exprimés en radians. Il faut donc effectuer une conversion.
Ligne 12 : Chaque ligne du tableau comporte quatre valeurs, lesquelles sont mises en forme à l'aide du système de formatage des chaînes de caractères : le marqueur de conversion codice_9 force un affichage à 8 chiffres, dont 7 après la « virgule » décimale. Le marqueur codice_10 fait à peu près la même chose, mais passe à la notation scientifique lorsque c'est nécessaire.
À ce stade, vous vous demandez peut-être où se situe la différence entre ce que nous venons d'expérimenter ici et un script CGI classique.
L'intérêt de travailler dans un environnement plus spécifique tel que Karrigell apparaît cependant très vite si vous faites des erreurs. En programmation CGI classique, les messages d'erreur émis par l'interpréteur Python ne s'affichent pas dans la fenêtre du navigateur. Ils sont enregistrés dans un fichier journal du serveur (Apache, par exemple), ce qui ne facilite pas leur consultation.
Avec un outil comme Karrigell, par contre, vous disposez d'une signalisation très efficace, ainsi que d'un outil de débogage complet. Faites l'expérience d'introduire une petite erreur dans le script ci-dessus, et relancez votre navigateur sur la page modifiée. Par exemple, en supprimant le double point à la fin de la ligne 7, nous avons obtenu nous-mêmes l'affichage suivant :
En cliquant sur le bouton « Debug », on obtient encore une foule d'informations complémentaires (affichage du script complet, variables d'environnement, etc.).
Prise en charge des sessions.
Lorsque l'on élabore un site web interactif, on souhaite fréquemment que la personne visitant le site puisse s'identifier et fournir un certain nombre de renseignements tout au long de sa visite dans différentes pages (l'exemple type étant le remplissage d'un « caddy » au cours de la consultation d'un site commercial), toutes ces informations étant conservées quelque part jusqu'à la fin de sa visite. Et il faut bien entendu réaliser cela indépendamment pour chaque client connecté.
Il serait possible de transmettre les informations de page en page à l'aide de champs de formulaires cachés, mais ce serait compliqué et très contraignant. Il est préférable que le système serveur soit doté d'un mécanisme spécifique, qui attribue à chaque client une "session" particulière. Karrigell réalise cet objectif par l'intermédiaire de "cookies". Lorsqu'un nouveau visiteur du site s'identifie, le serveur génère un "cookie" appelé "sessionId" et l'envoie au navigateur web, qui l'enregistre. Ce cookie contient un « identifiant de session » unique, auquel correspond un objet-session sur le serveur. Lorsque le visiteur parcourt les autres pages du site, son navigateur renvoie à chaque fois le contenu du cookie au serveur, et celui-ci peut donc retrouver l'objet-session correspondant, à l'aide de son identifiant. L'objet-session reste donc disponible tout au long de la visite de l'internaute : il s'agit d'un objet Python ordinaire, dans lequel on mémorise un nombre quelconque d'informations sous forme d'attributs.
Au niveau de la programmation, voici comment cela se passe :
Pour chaque page dans laquelle vous voulez consulter ou modifier une information de session, vous commencez par créer un objet de la classe codice_11 : 
objet_session = Session()
Si vous êtes au début de la session, Karrigell génère un identifiant unique, le place dans un cookie et envoie celui-ci au navigateur web. Vous pouvez alors ajouter un nombre quelconque d'attributs à l'objet-session :
objet_session.nom = "Jean Dupont"
Dans les autres pages, vous procédez de la même manière, mais l'objet produit dans ce cas par la classe codice_11 n'est pas nouveau : c'est l'objet créé en début de session, retrouvé en interne par le serveur grâce à son identifiant relu dans le cookie. Vous pouvez accéder aux valeurs de ses attributs, et aussi en ajouter de nouveaux :
obj_sess = Session() # récupérer l'objet indiqué par le cookie
nom = obj_sess.nom # retrouver la valeur d'un attribut existant
obj_sess.article = 49137 # ajouter un nouvel attribut
Les objets-sessions prennent aussi en charge une méthode codice_13, qui a pour effet d'effacer l'information de session. Vous n'êtes cependant pas obligé de clore explicitement les sessions : Karrigell s'assure de toute façon qu'il n'y ait jamais plus de 1000 sessions simultanées : il efface les plus anciennes quand on arrive à la 1000ème.
Sauvegardez les trois petits scripts ci-dessous dans le répertoire-racine. Le premier génère un formulaire HTML similaire à ceux qui ont été décrits plus haut. Nommez-le "sessionTest1.py" :
print """
<H3>Veuillez vous identifier, SVP :</H3>
<FORM ACTION = "sessionTest2.py">
Votre nom : <INPUT NAME = "nomClient"> <BR> 
Votre prénom : <INPUT NAME = "prenomClient"> <BR>
Votre sexe (m/f) : <INPUT NAME = "sexeClient" SIZE ="1"> <BR>
<INPUT TYPE = "submit" VALUE = "OK">
</FORM>"""
Le suivant sera nommé "sessionTest2.py". C'est le script mentionné dans la balise d'ouverture du formulaire ci-dessus à la ligne 6, et qui sera invoqué lorsque l'utilisateur actionnera le bouton mis en place à la ligne 10. Ce script recevra les valeurs entrées par l'utilisateur dans les différents champs du formulaire, par l'intermédiaire d'un dictionnaire de requête situé dans la variable d'environnement codice_14 de Karrigell :
obSess = Session()
obSess.nom = QUERY["nomClient"]
obSess.prenom = QUERY["prenomClient"]
obSess.sexe = QUERY["sexeClient"]
if obSess.sexe.upper() == "M":
 vedette ="Monsieur"
else:
 vedette ="Madame"
print "<H3> Bienvenue, %s %s </H3>" % (vedette, obSess.nom)
print "<HR>"
print """
<a href = "sessionTest3.py"> Suite...</a>"""
La première ligne de ce script crée l'objet-session, génère pour lui un identifiant unique, et expédie celui-ci au navigateur sous la forme d'un cookie.
Dans les lignes 3, 4, 5, on récupère les valeurs entrées dans les champs du formulaire précédent, en utilisant leurs noms comme clés d'accès au dictionnaire de requêtes.
La ligne 14 définit un lien http pointant vers le troisième script, nommé "sessionTest3.py" :
suiviSess = Session() # retrouver l'objet-session
suiviSess.article = 12345 # lui ajouter des attributs
suiviSess.prix = 43.67
print """
<H3> Page suivante </H3> <HR>
Suivi de la commande du client : <BR> %s %s <BR>
Article n° %s, Prix : %s <HR>
""" % (suiviSess.prenom, suiviSess.nom,
 suiviSess.article, suiviSess.prix)
Dirigez votre navigateur web vers l'adresse : http://localhost:8080/sessionTest1. Entrez des valeurs de votre choix dans les champs du formulaire, et cliquez sur le bouton OK :
Comme attendu, les informations entrées dans le formulaire sont transmises à la deuxième page. À présent, si vous cliquez sur le lien : « Suite... » dans celle-ci, vous dirigez encore une fois votre navigateur vers une nouvelle page, mais celle-ci n'aura fait l'objet d'aucune transmission de données (puisqu'on n'y accède pas par l'intermédiaire d'un formulaire). Dans le script "sessionTest3.py" qui génère cette page, vous ne pouvez donc pas utiliser la variable codice_14 pour retrouver les informations entrées par le visiteur.
C'est ici qu'intervient le mécanisme des objets-sessions. Lors du lancement de ce troisième script, le cookie mémorisé par le navigateur est relu par le serveur, ce qui lui permet de régénérer l'objet-session créé dans le script précédent.
Analysez les trois premières lignes du script "sessionTest3.py" : l'objet codice_16 instancié à partit de la classe codice_11 est l'objet-session régénéré. Il contient les informations sauvegardées à la page précédente, et on peut lui en ajouter d'autres dans des attributs supplémentaires.
Vous aurez compris que vous pouvez désormais récupérer toutes ces informations de la même manière dans n'importe quelle autre page, car elles persisteront jusqu'à ce que l'utilisateur termine sa visite du site, à moins que vous ne fermiez vous-même cette session par programme, à l'aide de la méthode codice_13 évoquée plus haut.
Autres développements.
Nous terminons ici cette brève étude de Karrigell, car il nous semble vous avoir expliqué l'essentiel de ce qu'il vous faut connaître pour démarrer. Si vous désirez en savoir davantage, il vous suffira de consulter la documentation et les exemples fournis avec le produit. Comme nous l'avons déjà signalé plus haut, l'installation de Karrigell inclut l'installation du système de bases de données Gadfly. Vous pouvez donc très rapidement et très aisément réaliser un site interactif permettant la consultation à distance d'un ensemble de données quelconques, en admettant bien entendu que la charge de requêtes de votre site reste modérée, et que la taille de la base de données elle-même ne devienne pas gigantesque. N'espérez pas gérer à l'aide de Karrigell un site commercial susceptible de traiter plusieurs millions de requêtes journalières !
Si vous ambitionnez de réaliser ce genre de choses, il vous faudra étudier d'autres offres logicielles, comme par exemple "CherryPy" ou "Zope" associés à "Apache" pour le système serveur, et "SQLite", "MySQL" ou "PostgreSQL" pour le gestionnaire de bases de données.