Salut à tous, Je vais parler ici de ce que j'ai réussi à obtenir en testant le langage Python avec différents toolkits graphiques. Je sais que Guiguilinux a choisi le langage Ruby, mais il a fait son choix récemment, alors que j'ai commencé mes tests il y a plusieurs jours, au moment où l'on ne parlait encore que de Python :-). Vous pouvez déjà récupérer le programme, pour tester par vous-même, ainsi que voir des captures d'écran ici : http://winuxien.free.fr/python
Pour pouvoir tester, il faut installer : - Python (sans blague !? :-) ) - Snake.py (fourni avec newt) - PyGtk 2.x, et même 2.4 il me semble :-) Lancez « ./Nsetup » ou «python Nsetup » pour avoir une mini-aide. Le but de ce test est avant tout de voir comment utiliser des interfaces graphiques développées avec des toolkits différents, tout en ayant un traitement centralisé indépendant de l'interface graphique sélectionnée. Dans une moindre mesure, il représente une architecture possible pour Nsetup, mais comme le but n'était pas de coder Nsetup, il faudrait la revoir pour la rendre plus propre si elle est retenue. Pour le mode texte, j'ai voulu utiliser ncurses. Ncurses se décompose en quatre modules qui sont : curses, panel, menu et form. Bien que tous ces modules aient été adaptés sous Python (http://pyncurses.sourceforge.net/), ils ne sont pas tous incorporés dans les modules de base du langage (voir http://docs.python.org/modindex.html). En fait, seuls les modules curses et menu ont été ajoutés, et bien évidemment il manque celui qui nous intéresse le plus : form :-) Ne voulant pas bidouiller pour installer les modules manquants, j'ai cherché s'il y avait d'autres toolkits pour faire des interfaces en mode texte avec Python. J'en ai trouvé deux : - Snake (http://www.wanware.com/tsgdocs/snack.html) - Urwid (http://excess.org/urwid/) Je testé Snake mais par Urwid. Snake a été utilisé par RedHat pour faire leur premier programme d'installation de leur distribution. Il est basé sur la librairie Newt. Pour le mode graphique, j'ai utilisé Gtk+ en version 2.4, mais je ne sais pas si j'ai utilisé des fonctions spécifiques à cette version. En ce moment, je me documente pour faire une interface avec Qt. Je ne l'ai pas encore commencée, mais comme le BS de NSetup est relancé, je me suis dit que les résultats que j'ai obtenu peuvent déjà être intéressant. Donc j'en parle avant d'avoir fait tous les tests que je voulais :-) Du point de vue arborescence, mon Nsetup de test se décompose en plusieurs parties réparties dans les dossiers suivants : / |_ Commands |_ Common |_ Gui |_ gtk |_ snake À la racine se trouve le script principal Nsetup. Le répertoire Commands/ contient les commandes de Nsetup. Pour ce test, je n'en ai développé qu'une : adduser (ne vous inquiétez pas, elle ne modifie absolument rien sur votre système :-) ). Common/ contient ce qui est commun aux commandes et interfaces graphiques de Nsetup. Il contient un module Python nommé NsetupModule.py. Celui-ci définit une classe NsetupModuleInterface qui doit être héritée par toutes les commandes et interfaces de commandes de Nsetup. Elle contient des méthodes permettant à chaque commande de lancer l'interface graphique qui lui correspond sans avoir à se soucier du type toolkit choisi par l'utilisateur (snake ou gtk), de lancer d'autres commandes de Nsetup, d'accéder à la configuration de Nsetup (chemins d'accès aux commandes, aux Gui, etc). Enfin, Gui/ contient des sous-répertoires dont le nom correspond aux différents toolkits utilisés pour faire les interfaces graphiques des commandes. Par exemple, pour la commande adduser, il doit exister un module adduser_gui.py dans chaque sous-répertoires. Ici, Gui/gtk/adduser_gui.py contient l'interface en Gtk+ de la commande adduser, et Gui/snake/adduser_gui.py celle en Snake. Le bon module sera automatiquement chargé par le script Nsetup en fonction du type d'interface choisi par l'utilisateur, avec l'option -g de la commande Nsetup (snake par défaut). J'ai essayé de faire une interface un peu plus évoluée qu'un simple formulaire pour ma commande de test adduser. L'interface contient deux parties : celle du haut permet de saisir les nom, prénom, login et mot de passe du nouvel utilisateur, et de choisir son shell par défaut. Après avoir rempli le formulaire, le bouton [add] permet d'ajouter ce nouvel utilisateur dans la liste du bas (il n'est pas encore créé sur le système). Le bouton [cancel] permet de quitter Nsetup sans ajouter les utilisateurs. Le bouton [remove] permet de retirer un utilisateur de la liste. Enfin, le bouton [finish] permet de quitter Nsetup après avoir ajouté les utilisateurs sur le système. En fait, le programme se contente d'écrire la liste des utilisateurs déclarés dans un fichier nommé « result » :-). Il n'y a aucun tests pour vérifier si tous les champs sont remplis ou non, car je n'ai pas cherché à faire un truc poussé. Lorsque Nsetup est invoqué, il regarde si une interface graphique particulière a été sélectionné avec l'option -g. Si ce n'est pas le cas, il en utilise une par défaut (ici, snake). Il charge alors le module init.py qui se trouve dans le sous-répertoire correspondant à l'interface à utiliser. Ce module doit obligatoirement définir une classe « Gui » héritant de la classe NsetupModuleInterface, et comportant une méthode « launchGui ». Cette méthode doit contenir les instructions nécessaires pour initialiser le toolkit graphique, et créer la fenêtre principale de l'interface (par exemple, pour Gtk, cette méthode crèe une fenêtre de niveau TOPLEVEL, lui attribue un titre et connecte une méthode à l'événement « fermeture de la fenêtre »). Cette méthode prend aussi en paramètre le nom de la commande Nsetup à lancer : après avoir initialisé l'interface graphique, elle doit appeler sa méthode runCommand(), héritée de NsetupModuleInterface, en lui passant en paramètre le nom de la commande qu'elle a reçu, ainsi qu'une référence sur la fenêtre principale qu'elle vient de créer. La commande Nsetup ainsi appelée va utiliser cette fenêtre pour y dessiner son interface. En réalité, ne dessine pas « directement » leur interface, car elles n'ont aucune connaissance de l'interface graphique utilisée. Elles ne font que du traitement d'informations. Lorsqu'elle sont invoquées, elles appellent leur méthode getCommandGui(), héritée de NsetupModuleInterface, qui va charger de manière transparente le module contenant l'interface qui lui correspond pour le toolkit sélectionné. Par exemple, avec « -g gtk », getCommandGui() va charger le module Gui/gtk/adduser-gui.py. Chaque module *_gui.py doit définir une classe NsetupCommandGui avec obligatoirement la méthode showCommandGui(). C'est cette méthode qui est chargée de dessiner l'interface, de l'afficher et de passer dans la boucle de traitement des événements clavier et souris si nécessaire. Il peut ensuite y avoir une plusieurs méthodes spécifiques à la commande pour initialiser et récupérer des valeurs de l'interface. Par exemple, toutes les interfaces de la commande adduser doivent définir une commande getUsersList() qui retourne la liste des utilisateurs déclarés. Mes conclusions sur ce test : => Points forts Je ne sais pas si mes explications sont très claires ! :-) Il est certainement plus facile de comprendre en regardant directement le code. Ce qu'il est important de comprendre, c'est que le code des interfaces graphiques est clairement distinct de celui traitant les informations. Dans le cas de la commande Adduser, le code chargé d'écrire la liste des utilisateurs dans le fichier result figure à un seul et unique endroit. C'est toujours ce code qui est exécuté, quelle que soit l'interface graphique utilisée, Snake ou Gtk+. A ce niveau, je considère que l'objectif est atteint. Par contre, contrairement à ce que j'ai affirmé à Julien, il se peut que certaines interfaces nécessitent l'utilisation de threads, ce qui peut augmenter la complexité du code. Mais ce n'est pas « infaisable » :-) Je pense notamment aux interfaces utilisant des barres de progression se mettant à jour par rapport à un traitement dans une boucle. Peut-être que les toolkits offrent certaines « facilités » à ce niveau. C'est à vérifier. Comme vous pouvez le voir, chaque toolkit est utilisé indépendamment des autres en terme de capacité. Par exemple l'interface Gtk+ de adduser présente un texte d'aide qui se met à jour automatiquement dès que l'on sélectionne un champ texte du formulaire. Snake ne permet pas de faire cela (du moins je n'y suis pas arrivé). Il est donc possible d'exploiter au mieux chaque toolkit, ce qui ne serait pas possible si on utilisait une couche d'abstraction entre les toolkits et les commandes de Nsetup, car il faudrait là encore s'en tenir au PGCD. Il est parfaitement possible de livrer Nsetup avec une interface texte uniquement par défaut, et de fournir les interfaces réalisés avec d'autres toolkits sous forme d'extensions de Nsetup. Il suffit de placer ces extensions dans le répertoire Gui/ car les commandes en tant que telles, celles qui réalisent les traitements, seraient livrées avec Nsetup par défaut. => Points faibles J'ai rencontré qqs problèmes avec Python au niveau du chargement des modules, mais il est vrai que je n'ai pas poussé loin la réflexion sur la structure de Nsetup. Au début, j'ai créé les fichiers commands/adduser.py, Gui/snake/adduser.py et Gui/gtk/adduser.py. Bien que ces trois fichiers avaient le même nom, leur rôle se devinaient avec l'emplacement où ils se trouvaient. Mais lorsque le module commands/adduser.py étaient chargé, Python refusait de charger le module correspond à l'interface, car le tableau sys.modules (tableau géré par Python pour connaître la liste des modules chargés) comportant déjà une entrée pour adduser.py, il considère que le module demandé est déjà chargé, bien qu'étant dans un chemin/package différent (n'étant pas un expert en Python, le problème vient certainement de moi :-) ) => À revoir Si la structure que j'ai utilisée est retenue, il faudrait revoir le nommage des classes pour éviter des conflits potentiels. Voilà, des questions ? des remarques ? des incompréhensions ? N'hésitez-pas ;-) ++ Gontran
