I. Introduction▲
Pyreverse est un outil en ligne de commande qui permet de scanner le code Python d'un projet afin de générer, de façon entièrement automatique, un diagramme UML.
Cet outil, développé par la société Logilab, est depuis septembre 2008 intégré à Pylint. Une simple installation via pip vous permettra alors d'en disposer pleinement.
Dans cet article, tous les codes sont exécutés en Python 3 exclusivement.
II. Possibilités offertes▲
Pyreverse permet de générer des diagrammes UML avec les caractéristiques suivantes :
- attributs de classes, avec si possible leur type ;
- méthodes de classe ;
- liens d'héritage entre classes ;
- liens d'association entre classes ;
- représentations des exceptions.
Côté fichier de sortie, Pyreverse ne propose nativement que deux formats : le dot et le vcg.
Même si le fichier généré ne correspond pas à 100 % à vos attentes, il vous permettra tout de même de vous simplifier un minimum le travail.
III. Ajoutons des formats de sortie▲
Comme vu précédemment, par défaut, seuls deux formats de sortie sont possibles : dot et vcg.
Cela limitant, basiquement, beaucoup les possibilités, il est possible d'augmenter la quantité des formats de sortie : l'installation de GraphViz.
Graphviz ne doit pas être installé depuis pip, mais depuis l'installeur dédié à votre OS, que vous pourrez trouver sur le site officiel de l'outil.
Une fois installé, il vous faudra modifier votre variable d'environnement PATH sous Windows, afin d'y ajouter le chemin vers le dossier « GraphvizX.YZ\bin ».
Pyreverse vous propose alors les formats suivants en sus :
canon |
cmap |
cmap_np |
dia |
dot |
eps |
fig |
gd |
gd2 |
gif |
hpgl |
imap |
imap_np |
ismap |
jpe |
jpeg |
jpg |
mif |
mp |
pcl |
|
pic |
plain |
plain-ext |
png |
ps |
ps2 |
svg |
svgz |
tk |
vml |
vmlz |
vrml |
vtx |
wbmp |
xdot |
xlib |
Les formats proposés deviennent tout de suite plus appréciables, je pense notamment aux formats images (png, jpg), au pdf, ou encore le format dia pour faire de l'édition facilement.
Vous l'aurez compris, dans les faits, Pyreverse sera quasiment toujours utilisé avec Graphviz.
Pour l'ensemble des manipulations qui suivront, nous considérerons que vous avez correctement installé et paramétré Pyreverse et Graphviz.
IV. Les options▲
Pyreverse dispose d'un certain nombre d'options. Voici un récapitulatif des principales :
Option courte |
Option verbeuse |
Description |
-a <level> |
--show-ancestors=<level> |
Permet de stipuler combien de niveaux d'héritage afficher. |
-A |
--all-ancestors |
Permet d'afficher tout l'arbre d'héritage. |
-b |
--show-builtin |
Permet d'afficher les classes des objets builtin dans le diagramme. |
-f <mode> |
--filter-mode=<mode> |
Permet de filtrer ce qu'il faut faire apparaître dans le diagramme. Quatre filtres sont possibles :
Par défaut, le filtre est à PUB_ONLY. |
-k |
--only-classnames |
Génère un diagramme exclusivement avec les noms des classes. |
-m [yn] |
--module-names=[yn] |
Permet d'inclure ou non ([yn] à y pour oui (yes) ou à n pour non (no)) le nom des modules dans la représentation des classes. Pas de valeur par défaut. |
-o <format> |
--output=<format> |
Permet de stipuler le format de sortie. Le format doit être l'un de ceux stipulés précédemment. Par défaut, il s'agit du format dot. |
-p <project name> |
--project=<project name> |
Permet de stipuler le nom du projet pour la génération du nom du fichier de sortie. |
-s <level> |
--show-associated=<level> |
Permet d'afficher les liaisons liées aux imports (création d'objets) sur le nombre de niveaux stipulés. |
-S |
--all-associated |
Permet d'afficher toutes les liaisons liées aux imports. |
V. Mise en œuvre▲
Pour mettre en œuvre cet outil, nous allons nous appuyer sur un exemple déjà utilisé dans le tutoriel sur l'héritage. Nous aurons quatre classes :
- Voiture
- Citroen
- CB
- CitroenDs
La dernière héritera des deux premières et possédera des attributs privés et protégés. On y surchargera également la fonction spéciale « __del__ ». Enfin, nous considérerons que le propriétaire ajoute une CB dans sa voiture.
La commande est à exécuter dans le dossier où se trouve le code que l'on désire analyser.
Nous aurons donc la structure suivante :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
class
Voiture
(
):
def
__init__
(
self):
self.nombre_roues =
4
self.nombre_fauteuils =
1
self.moteur =
False
self.volant =
True
def
start_moteur
(
self):
self.moteur =
True
return
self.moteur
def
stop_moteur
(
self):
self.moteur =
False
return
self.moteur
def
statut_moteur
(
self):
return
self.moteur
if
__name__
==
"__main__"
:
ma_voiture_basique =
Voiture
(
)
print
(
ma_voiture_basique.statut_moteur
(
))
ma_voiture_basique.start_moteur
(
)
print
(
ma_voiture_basique.statut_moteur
(
))
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
class
Citroen
(
):
def
__init__
(
self):
self.type_suspension =
"Hydractives"
self.logo =
"Chevrons"
self.marque =
"Citroen"
if
__name__
==
"__main__"
:
ma_citroen =
Citroen
(
)
print
(
ma_citroen.type_suspension)
print
(
ma_citroen.logo)
2.
3.
4.
5.
6.
7.
8.
class
CB
(
):
def
__init__
(
self):
self.marque =
"Citizen-Band"
if
__name__
==
"__main__"
:
ma_cb =
CB
(
)
print
(
ma_cb.marque)
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.
from
voiture import
Voiture
from
citroen import
Citroen
from
cb import
CB
class
CitroenDs
(
Voiture, Citroen):
def
__init__
(
self):
Voiture.__init__
(
self)
Citroen.__init__
(
self)
self.modele =
"DS moderne (>2000)"
self._option_payante_ds_01 =
False
self._option_payante_ds_02 =
False
self._option_payante_ds_03 =
False
self.__option_calculateur_ds_01 =
False
self.__option_calculateur_ds_02 =
False
self.__option_calculateur_ds_03 =
False
self.start_options
(
)
self.cb =
CB
(
)
def
__del__
(
self):
print
(
"Suppression de la voiture"
)
def
start_options
(
self):
if
_option_payante_ds_01:
print
(
"GPS activé"
)
if
_option_payante_ds_02:
print
(
"Anti dépassement lignes blanches activé"
)
if
_option_payante_ds_03:
print
(
"Freinage urgence activé"
)
if
__option_calculateur_ds_01:
print
(
"Puissance moteur: 120 cv"
)
elif
__option_calculateur_ds_02:
print
(
"Puissance moteur: 150 cv"
)
elif
__option_calculateur_ds_03:
print
(
"Puissance moteur: 180 cv"
)
if
__name__
==
"__main__"
:
ma_ds =
CitroenDs
(
)
print
(
ma_ds.marque)
print
(
ma_ds.modele)
print
(
ma_ds.type_suspension)
print
(
ma_ds.statut_moteur
(
))
ma_ds.start_moteur
(
)
print
(
ma_ds.statut_moteur
(
))
Afin de mieux appréhender le fonctionnement des principales options, je vous propose d'y aller progressivement.
V-A. Utilisation basique▲
Tout d'abord, aucune option précisée :
Pyreverse -
o png citroen_DS.py
Nous récupérons un fichier nommé « classes_No_Name.png ». Ce diagramme représente la classe présente dans le module, avec ses attributs et méthodes.
Le « No_Name » du nom du fichier vient du fait que nous n'avons stipulé aucun nom de classe lors de l'appel de Pyreverse, chose que nous corrigerons à partir de maintenant.
V-B. Stipuler le nom du fichier généré▲
Pyreverse -
o png -
p demo_DVP citroen_DS.py
Le fichier généré porte désormais le nom de « classes_demo_DVP.png ».
V-C. Afficher les noms des modules▲
Remarquons tout de même que si les classes figurent bien, nous ne savons dans quel module elles se trouvent. Cela peut être mis à jour via l'option « -my » :
Pyreverse -
o png -
p demo_DVP -
my citroen_DS.py
Le diagramme généré est désormais plus clair.
Le nom du module y figure désormais, rendant plus aisée la localisation du code.
V-D. Afficher l'héritage▲
V-D-1. Afficher tous les héritages▲
Voyons maintenant l'option « -A » :
Pyreverse -
o png -
p demo_DVP -
A -
my citroen_DS.py
Le nouveau diagramme montre clairement les divers héritages de notre classe CitroenDs.
V-D-2. Stipuler le niveau d'héritage à afficher▲
Si vous le désirez, vous pouvez stipuler expressément combien de niveaux d'héritage afficher, afin de vous concentrer sur une classe précise par exemple, ou encore alléger le diagramme.
Notre exemple ne contenant qu'un seul niveau, je vous propose de demander à n'avoir aucun héritage affiché en stipulant comme nombre de niveaux « 0 ».
Pyreverse -
o png -
p demo_DVP -
a0 -
my citroen_DS.py
V-E. Afficher les imports et les objets▲
Quand vous générez le diagramme d'une classe, il peut être pratique de connaître les liaisons avec les divers imports.
V-E-1. Afficher toutes les liaisons▲
Pour cela, nous allons utiliser l'option « -S ».
Pyreverse -
o png -
p demo_DVP -
A -
my -
S citroen_DS.py
Dans ce diagramme, nous voyons clairement, que l'objet « cb » de notre classe CitroenDs dérive de la classe « cb.CB ». Au passage, remarquez en vert le nom de l'objet ; et que la classe dont provient « cb » figurant sur le diagramme, n'est plus stipulé au niveau de la classe « CitroenDs ».
V-E-2. Afficher n niveaux de liaison▲
Nous allons utiliser ici l'option « -s ». Cette option fonctionne exactement comme l'option « -a ». Pour obtenir le diagramme précédent, il suffit de saisir la ligne de commande suivante.
Pyreverse -
o png -
p demo_DVP -
A -
my -
s1 citroen_DS.py
V-E-3. Afficher les objets builtins▲
S'il est possible d'afficher les imports et objets de notre code, on peut également vouloir faire apparaître ceux fournis par défaut avec Python, ce qu'on appelle les builtins. Pour cela, il faut utiliser l'option « -b ». Et en Python, tout étant objet, votre diagramme va rapidement prendre un peu d'espace.
Pyreverse -
o png -
p demo_DVP -
A -
my -
S -
b citroen_DS.py
V-F. Filtrer les informations▲
Vous disposez de la possibilité de filtrer les méthodes et attributs affichés sur le diagramme, via l'option « -f ». Quatre possibilités vous sont offertes, vous permettant de coller au plus près de vos besoins.
V-F-1. Filtre PUB_ONLY▲
Il s'agit de l'option « -f PUB_ONLY ».
Pyreverse -
o png -
p demo_DVP -
A -
my -
f PUB_ONLY citroen_DS.py
Vous ne voyez aucune différence avec la commande sans l'option « -f ». Normal, il s'agit de l'option par défaut.
V-F-2. Filtre SPECIAL▲
Le filtre « -f SPECIAL » filtre les méthodes spéciales (__init__, __del__…). En revanche, aucun filtrage n'est effectué sur les attributs.
Pyreverse -
o png -
p demo_DVP -
A -
my -
f SPECIAL citroen_DS.py
V-F-3. Filtre OTHER▲
L'option « -f OTHER », est l'inverse du filtre SPECIAL. Il vous permet de ne pas afficher les attributs protégés et privés, mais d'afficher tout de même, toutes les méthodes, quelles qu'elles soient.
Pyreverse -
o png -
p demo_DVP -
A -
my -
f OTHER citroen_DS.py
V-F-4. Filtre ALL▲
Si vous désirez tout afficher sans distinction, ni filtrage précis, il vous suffit d'utiliser « -f ALL ».
Pyreverse -
o png -
p demo_DVP -
A -
my -
f ALL citroen_DS.py
V-G. Épurer le diagramme▲
Vient enfin la dernière option, « -k ». Cette dernière vous permet d'épurer l'affichage en le limitant simplement aux modules, classes et objets. Comprenez que nous ne ferons alors figurer ni attributs, ni méthodes.
Pyreverse -
o png -
p demo_DVP -
A -
my -
S -
b -
k citroen_DS.py
VI. Conclusion▲
Comme nous venons de le voir, l'outil Pyreverse est très simple d'emploi.
Couplé avec Graphviz, il vous permettra de générer simplement des diagrammes UML, éditables ou non selon le format utilisé, qui vous seront fort utiles.
J'espère que cet article vous a plu et que la découverte de cet outil vous permettra de vous simplifier la vie pour vos futurs développements.
VII. Remerciements▲
Merci aux personnes suivantes pour leur aide :