Introduction au langage Python par l'exemple


précédentsommairesuivant

XIV. Exercice [IMPOTS] avec un service Web

Nous revenons à l'exercice [IMPOTS].

Image non disponible

XIV-A. Le serveur

Nous nous plaçons dans l'architecture client-serveur suivante :

Image non disponible

Côté serveur, nous allons utiliser de nouveau une architecture trois couches. La couche [DAO] sera implémentée par la classe ImpotsMySQL utilisée dans la version avec le Sgbd MySQL. La couche [metier] sera implémentée par la classe [ImpotsMetier] déjà étudiée. Il ne reste donc qu'à écrire le service Web. Celui-ci reçoit de ses clients un paramètre params sous la forme params= oui,2,200000 où le premier élément indique si le contribuable est marié ou non, le deuxième son nombre d'enfants, le troisième son salaire annuel.

Le service Web est le suivant (impots_web_01) :

impots_web_01
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
#!D:\Programs\ActivePython\Python2.7.2\python.exe

# -*- coding=Utf-8 -*-
# import du module des classes Impots*
from impots import *
import cgi,cgitb,re

# on autorise l'affichage d'informations de débogage
cgitb.enable()
sys.stderr=sys.stdout

# ------------------------------------------------ 
# le service Web des impôts
# ------------------------------------------------ 

# les données nécessaires au calcul de l'impôt ont été placées dans la table mysqL TABLE
# appartenant à la base BASE. La table a la structure suivante
# limites decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
# les paramètres des personnes imposables (statut marital, nombre d'enfants, salaire annuel)
# sont envoyés par le client sous la forme params=statut marital, nombre d'enfants, salaire annuel
# les résultats (statut marital, nombre d'enfants, salaire annuel, impôt à payer) sont renvoyés au client
# sous la forme <impot>valeur</impot>
# ou sous la forme <erreur>msg</erreur>, si les paramètres sont invalides

# le serveur renvoie au client du texte non formaté
print "Content-Type: text/plain\n"

# définition des constantes
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"


# on crée la couche [metier]
# Python ne semble pas avoir de support pour les sessions
# en PHP, on aurait utilisé une session pour mémoriser l'objet metier
# ici, on le construit systématiquement à partir des données de la base de données MySQL

# instanciation couche [metier]
try:
    metier=ImpotsMetier(ImpotsMySQL(HOTE,USER,PWD,BASE,TABLE))
except (IOError, ImpotsError) as infos:
    print ("<erreur>Une erreur s'est produite : {0}</erreur>".format(infos))
    sys.exit()

# on récupère la ligne envoyée par le client au serveur
params=cgi.FieldStorage().getlist('params')
# si pas de paramètre alors erreur
if not params:
  print "<erreur>Le parametre [params] est absent<erreur>"
  sys.exit()

# on exploite le paramètre params  
items=params[0].strip().lower().split(',')
# il ne doit y avoir que 3 champs
if len(items)!=3:
  print "<erreur>[%s] : nombre de parametres invalide</erreur>" % (params[0])
  sys.exit()
# le premier paramètre (statut marital) doit être oui/non
marie=items[0].strip()
if marie!="oui" and marie != "non":
  print "<erreur>[%s] : 1er parametre invalide</erreur>\n"% (params[0])
  sys.exit()
# le second paramètre (nbre d'enfants) doit être un nombre entier
match=re.match(r"^\s*(\d+)\s*$",items[1])
if not match:
  print "<erreur>[%s] : 2e parametre invalide</erreur>\n"% (params[0])
  sys.exit()
enfants=int(match.groups()[0])
# le troisième paramètre (salaire) doit être un nombre entier
match=re.match(r"^\s*(\d+)\s*$",items[2])
if not match:
  print "<erreur>[%s] : 3e parametre invalide</erreur>\n"% (params[0])
  sys.exit()
salaire=int(match.groups()[0])
# on calcule l'impôt
impot=metier.calculer(marie,enfants,salaire)
# on renvoie le résultat
print "<impot>%s</impot>\n" % (impot)
# fin

Notes :

  • ligne 5 : on importe les objets du fichier impots.py ;
  • ligne 9 : déboguer un script Cgi peut être problématique. Le module cgitb envoie, en cas d'erreur, la raison du plantage. Pour cela, il faut rediriger la sortie erreur standard (sys.stderr) vers la sortie standard (sys.stdout) (ligne 10) ;
  • ligne 26 : l'entête HTTP qui fixe la nature du document envoyé, ici un texte non formaté. Le service Web renvoie sa réponse sous forme d'une unique ligne de texte :
  • <erreur>message</erreur> s'il y a une erreur ;
  • <impot>valeur</impot>valeur est le montant de l'impôt.
  • ligne 43: instanciation des couches [DAO] et [metier] ;
  • lignes 44-46 : en cas d'erreur de l'instanciation, le script envoie sa réponse et se termine ;
  • lignes 49-53 : le paramètre 'params' est récupéré. S'il est absent, le script envoie sa réponse et se termine ;
  • ligne 56 : le paramètre 'oui,2,200000' est décomposé en 3 champs dans le tableau items ;
  • lignes 58-77 : la validité des 3 champs est vérifiée. S'il y a une erreur, le script envoie sa réponse et se termine ;
  • ligne 79 : l'impôt est calculé ;
  • ligne 81 : et envoyé au client.

Dans un navigateur Web, on obtient les résultats suivants :

Image non disponible

XIV-B. Un client programmé

Le programme (client_impots_web_01)
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
# -*- coding=utf-8 -*-

import httplib,urllib,re

# constantes
HOST="localhost"
URL="/cgi-bin/impots_web_01b.py"
data=("oui,2,200000","non,2,200000","oui,3,200000","non,3,200000","x,y,z,t","x,2,200000", "oui,x,200000","oui,2,x");

# connexion
connexion=httplib.HTTPConnection(HOST)
# suivi
#connexion.set_debuglevel(1)
# on boucle sur les données à envoyer au serveur
for params in data:
    # les paramètres doivent être encodés avant d'être envoyés au serveur
    parametres = urllib.urlencode({'params': params})
    # envoi de la requête
    connexion.request("POST",URL,parametres)
    # traitement de la réponse (ligne de texte)
    reponse=connexion.getresponse().read()
    lignes=reponse.split("\n")
    # la ligne de texte est de la forme
    # <impot>xxx</impot>
    # ou <erreur>xxx</erreur>
    impot=re.match(r"^<impot>(\S+)</impot>\s*$",lignes[0])
    if impot:
        print "params=%s, impot=%s" % (params,impot.groups()[0])
    else:
        erreur=re.match(r"^<erreur>(.+)</erreur>\s*$",lignes[0])
        if erreur:
            print "params=%s, erreur=%s" % (params,erreur.groups()[0])
        else:
            print lignes
# fermeture connexion
connexion.close()
Résultats
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
params=oui,2,200000, impot=22504.0
params=non,2,200000, impot=33388.0
params=oui,3,200000, impot=16400.0
params=non,3,200000, impot=22504.0
params=x,y,z,t, erreur=[x,y,z,t] : nombre de parametres invalide
params=x,2,200000, erreur=[x,2,200000] : 1er parametre invalide
params=oui,x,200000, erreur=[oui,x,200000] : 2e parametre invalide
params=oui,2,x, erreur=[oui,2,x] : 3e parametre invalide

précédentsommairesuivant

  

Licence Creative Commons
Le contenu de cet article est rédigé par Serge Tahé et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d’Utilisation Commerciale - Partage dans les Mêmes Conditions 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2013 Developpez.com.