À la découverte de l’informatique dans les nuages avec Seafile

Bonjour,

Quand j’étais petit, je me souviens que la télévision en noir et blanc ne diffusait que trois chaînes : TF1, Antenne 2 et FR3. Dans le temps, y’avait pas Linternet et c’était pas plus mal comme ça. On manquait de rien. On était heureux comme tout.

On partait jamais en vacances. On passait nos étés à battre le blé au fléau avant de le vanner mais on manquait de rien, on était vrai heureux. À Noël, quelle joie de découvrir dans mon sabot une orange que je partageais avec mes douze frères et soeurs. Le soir du réveillon, on écoutait Tino Rossi sur un vieux mange-disques mais pas trop longtemps pour pas user les piles. À minuit, on allait à la messe de minuit avec Jacquou le croquant, notre voisin qui avait été amputé des deux jambes après avoir sauté sur une mine en Indochine. C’était le bon temps.

Les téléphones n’étaient pas portatifs mais on manquait de rien, on était heureux comme tout. À la télé, tous les morveux regardaient Le Village dans les nuages. C’était une série avec des extrathérèses réfugiés dans le hameau du Glaude et du Bombé. C’était poilant! Qu’est-ce qu’on était heureux de manquer de rien!

Aujourd’hui, à cause du réchauffement climatique, le ciel est aussi bleu qu’un monochrome d’Yves Klein et il n’y a plus de village dans les nuages. Cela dit, l’esprit de ce lieu singulier n’a pas complètement disparu puisque de nos jours, il n’est pas rare de stocker ses données personnelles dans un nuage. On appelle ça l’informatique en nuage ou cloud computing en anglais. D’aucuns prétendent qu’il s’agit d’informatique dématérialisée mais c’est une illusion! Les données sont, de toute façon stockées quelques part, que ce soit sur un strato-cumulus, au fond d’une mine, dans le cul d’une vache ou bien dans un Raspberry pi!

Tiens justement, pour mes dernières vacances en France, j’ai eu la bonne idée d’emporter mon Raspberry pi. Il se trouve que j’ai également acheté le magazine Linux inside consacré à ce drôle de petit ordinateur. Au passage, je suis moyennement satisfait de mon acquisition. Je trouve que les tutoriaux sont parfois d’une précision toute relative (en termes de pédagogie). À 12,90€, je m’attendais quand-même à quelque chose de plus consistant. Notez qu’il est fort possible que ce soit aussi mon cerveau qui soit d’une précision toute relative.

rasp_guide

Bref, je suis tombé sur un tuto qui explique comment transformer son « Rasp » en nuage avec Owncloud. Je me suis lancé dans l’aventure et après moult déboires, j’ai réussi à créer mon propre nuage sur mon propre serveur. Cerise sur le gâteau, les données étaient stockées non pas sur la carte micro-SD du Raspberry mais déportées sur une clé USB de 31 GO. La grande classe!

Sauf que le nuage owncloud, je le trouvais bien lourd à l’usage. Le téléversement de mes documents prenaient des plombes, à tel point que je n’ai même pas osé essayer avec des images. J’avais grand peur de faire fondre mon rasp! Était-ce la faute d’Owncloud ou du Raspberry? Je ne saurai jamais le fin mot de l’histoire puisque tout a planté après quelques jours d’utilisation. Je me suis retrouvé devant une page blanche et d’une certaine manière, j’étais soulagé. Pour celles et ceux que ça intéresse quand-même, voici le tutoriel que j’ai suivi pour installer owncloud :

https://www.digitalocean.com/community/tutorials/how-to-install-and-configure-owncloud-on-ubuntu-16-04

Installation de Seafile

Je me suis donc mis en quête de solutions alternatives et j’ai jeté mon dévolu sur Seafile, un cloud certes un peu plus modeste en termes de capacités mais qui me comble de joie. Pour ce faire, j’ai utilisé ce tutoriel :

http://www.pihomeserver.fr/2014/09/24/raspberry-pi-home-server-hebergement-fichier-seafile/

Comme l’auteur l’explique à la fin, pour démarrer le serveur Seafile, il faut entrer cette commande :

seafile.sh start

Il faut également démarrer la partie hub qui permet les connexions :

seahub.sh start

N’ayant nullement envie d’entrer ces deux commandes à chaque connexion, je les ai paramétrées dans l’onglet Applications au démarrage d’Ubuntu Mate (le système d’exploitation de mon raspberry) afin qu’elles se lancent automatiquement à l’ouverture de session. Attention toutefois de ne pas lancer la commande Seahub en même temps que la commande Seafile! Ça ne fonctionnera pas. Il faut la lancer avec un léger temps de retard. Pour ma part, j’ai choisi soixante secondes.

Donc, pour résumer, ça nous donne ceci :

Système > Préférences > Personnel >Applications au démarrage

  • Démarrage de Seafile à l’ouverture de session :
/home/ordinosor/seafile-server-3.1.6/seafile.sh start
  • Démarrage de Seahub 60 secondes après l’ouverture de session :
sh -c "sleep 60; /home/ordinosor/seafile-server-3.1.6/seahub.sh start"

L’interface graphique de Seafile

Si tout s’est déroulé comme prévu, vous allez arriver sur une page qui vous invitera à vous connecter et à profiter pleinement des fonctionnalités de votre cumulo-nimbus. Le téléversement des documents est très rapide (grâce au glisser-déposer), le téléchargement aussi.

 

 

Ce diaporama nécessite JavaScript.

Petit bémol toutefois par rapport à owncloud, il n’y a pas d’extensions telles qu’un agenda ou un répertoire d’adresses téléphoniques. Je souhaiterais également déporter les données sur une clé USB de 30 GO pour avoir plus d’espace de stockage mais je n’ai toujours pas réussi à venir à bout de cette opération. Il faut dire aussi que je n’ai pas encore essayé.

En tout cas, je suis tout à fait satisfait de mon nouveau cumulo-nimbus!

seafile_2
C’est moi…

J’ai basculé ma messagerie sur Mail.Lilo.org

Étant un adepte convaincu de la distribution solidaire Emmabuntüs que j’ai installée sur Volgor mon fidèle ordinateur de bureau, je connaissais déjà le métamoteur de recherche Lilo. Du reste, je lui avais même consacré un article pour en dire tout le bien que j’en pensais. Je rappelle que grâce à lui, les recherches effectuées par les internautes sont comptabilisées en gouttes d’eau puis converties en argent avant d’être reversé à des projets sociaux et environnementaux. En ce qui me concerne, j’ai choisi de reverser mes gouttes d’eau au projet Emmabuntüs.

Or, les concepteurs de Lilo, Clément Le bras et Marc Haussaire, ont décidé d’aller plus loin dans leur projet en créant une messagerie écologique respectueuse des données privées de ses utilisateurs. Celle-ci s’appelle Mail.Lilo.org. Elle est encore en bêta-test mais je n’ai pas résisté à l’envie de regarder ce qu’elle avait sous le capot. Et le moins qu’on puisse dire, c’est que je n’ai pas été déçu.

lilo_2

C’est un article paru sur silicon.fr et référencé par le journal du hacker qui m’a permis de récupérer un code nécessaire à l’inscription. J’ai donc créé une adresse lilo.org dans le but avoué d’abandonner à plus où moins long terme mon adresse g….. Eh oui! J’avais une adresse de la messagerie Dont-On-Ne-Doit-Pas-Prononcer-Le-Nom! Mais je tiens à vous rassurer, j’en avais grand honte.

L’opération que j’ai baptisée du nom de code « Liloberté », a donc commencé par un recensement systématique des sites où je suis inscrit dans le but de basculer vers ma nouvelle adresse.

J’ai également paramétré ma messagerie Dont-On-Ne-Doit-Pas-Prononcer-Le-Nom afin que les mails que dorénavant je reçois, soient transférés dans ma nouvelle boite lilo.org avant d’être effacés automatiquement de ma future ancienne messagerie. Pour ce faire, il faut cliquer sur la roue dentée, sélectionner Paramètres puis Transfert et POP/IMAP et le tour est joué.

Pourquoi est-ce que Lilo m’a séduit? Parce qu’elle ne fourre pas son museau dans mes mails pour en renifler le contenu et le revendre à quelque annonceur qui viendra m’importuner sur mes terres digitales!

Bien que, politiquement parlant, je ne sois pas écolo pour un sou (je viens de la campagne), j’ai également été  séduit par l’aspect environnemental du projet. Le développement durable est un sujet qui me tient particulièrement à cœur (je viens de la campagne, je me lave au savon de Marseille… pas avec du gel douche Ushuaïa).

Pour mesurer l’impact, en terme de pollution, de ma nouvelle messagerie sur notre Mère-La-Terre, figurez-vous qu’il y a un graphique comparable à celui que l’on trouve sur les machines à laver et qui mesure le score CO2. Pour l’instant, ma boite mail ne contient que trois malheureux messages, donc mon score CO2 est excellent (ça correspond à la lettre A).

score_co2

Si mon score se dégrade, alors cela voudra dire qu’il sera temps pour moi de faire le ménage dans ma messagerie.

Je ne saurais trop vous conseiller d’adopter ce formidable outil qu’est Mail.Lilo.org et à en faire la publicité autour de vous. Comme le disait Lance Armstrong, le premier cycliste à avoir pédalé sur la Lune, c’est une goutte d’eau pour l’homme mais un grand océan pour l’humanité… ou un truc dans le genre.

La dame blanche de la forêt de Ragounite

Hier, figurez-vous que nous étions en vadrouille du côté de Jard-sur-Mer en Vendée et il nous est arrivé une drôle d’aventure.

À la recherche d’une plage où poser nos serviettes, nous nous égarâmes quelque peu et soudain, le moteur de notre voiture se mit à toussoter avant de caler aux abords de la plage de Ragounite.

IMG_2441.JPG

Ragounite…Quel nom étrange! Aussi loin que portait notre regard, il n’y avait pas âme qui vive. Pas d’enfants s’égayant sur la plage. Comment diable était-ce possible, en ce début de mois de Juillet?

IMG_2427

Tout semblait figé… L’océan était silencieux, la chaleur accablante.  Et cette voiture qui ne voulait plus démarrer! Ces voyants qui restaient désespérément éteints… Dans quelle mystérieuse dimension avions-nous chu? Nous nous résignâmes à abandonner notre véhicule devenue un four. Il faisait une chaleur abominable. Je pris mon sac à dos, deux bouteilles d’eau et nous nous enfoncâmes dans les entrailles de cette forêt qui nous tendait les branches.

IMG_2436

Nous marchâmes une bonne demi-heure sans croiser âme qui vive, au milieu de souches ressemblant à des monstres aliens. Les arbres aux branches tordues n’étaient que souffrance.

IMG_2426

Nous arrivâmes à un embranchement où un banc semblait nous attendre. Il était décoré de petites fleurs et portait cette mystérieuse inscription :

Tu n’es pas là et je pense à toi. J’ai tes yeux en face des miens.

IMG_2430

IMG_2431

Nous n’osâmes pas nous asseoir. Nous préférâmes continuer notre chemin tandis que petit à petit, l’angoisse nous gagnait à l’idée d’être prisonniers de cette forêt sinistre sans plus jamais pouvoir en réchapper.

IMG_2423.JPG

C’est alors que nous l’aperçûmes, aux abords de cette cabane faite de grosses branches que les tempêtes avaient arrachées. Toute de blanc vêtue, à l’exception de son t-shirt rose bonbon et de sa longue jupe noire, elle nous fixait de son regard hypnotique. Sa bouche n’était qu’un rictus informe, ses dents des chicots noircis. Elle avança lentement dans notre direction en nous tendant ses bras qui se résumaient à deux moignons couverts de pus. Elle semblait flotter à quelques centimètres du sol.

Ma raison vacilla. Je me retournai vers celle qui partage ma vie et m’écriai : « Tu fais ce que tu veux! Moi, j’me casse! » N’écoutant que mon courage, je pris mes jambes à mon cou et je détalai comme un petit lapin.

Mais ma fuite était vaine… La dame blanche qui flottait au-dessus du sol, tel un hydroglisseur, gagnait du terrain. Je l’entendais de plus en plus distinctement qui me hélait de sa voix d’outre-tombe :

« Beee-noîîît… »

« Beee-noîîît… »

« Beee-noîîît… »

« Beee-noîîît… »

………….

« Benoît »! Benoît!

« Hein! quoi? qui? »

« On y va, mon poussin? »

« Aaaahh! Pitié! Laissez-moi tranquille! Au secours! Au secours! »

« Non mais ça va pas la tête! Qu’est-ce qui te prends? C’est le soleil qui te tape sur le système? La prochaine fois, tu prendras un chapeau! »

« Elle est où la vieille? »

« Bon, allez! Ça suffit comme ça, on y va! Ça fait deux heures qu’on est sur cette plage, étalés sur nos serviettes. Moi, j’ai chaud! Le sable est brûlant et en plus tu ronfles. Tous les voisins nous regardent. Tu fais ce que tu veux! Moi je me casse… »

« Attends-moi, pupuce… »

 

Python: Variables et espaces de noms

Pour une lecture plus agréable (page plus large), je vous invite à cliquer sur ce lien et à lire ce chapitre dans la rubrique consacrée au langage Python.

Introduction

Dans le chapitre précédent, nous avons pu constater que grâce à la programmation orientée objet, deux développeurs, Briface et Jobriel, pouvaient coder un module chacun de leur côté et que ces deux modules pouvaient être « assemblés » in fine pour donner naissance au programme de notre choix.

Même si ces deux modules renfermaient un objet ou une variable dont le nom était identique, il n’y avait pas de risques que le programme se comporte de manière erratique puisque chaque objet évoluait dans son propre espace de noms. C’est la raison pour laquelle  une commande telle que self.random_choice.random_choice ne levait pas d’exception. 

La notion d’espace de noms dans le langage Python

La notion d’espace de noms est très importante dans le langage Python. Lorsque nous définissons une fonction avec des variables à l’intérieur, ces dernières ne peuvent vivre que dans l’espace de noms de cette fonction. Dès que celle-ci a exécuté sa dernière ligne d’instruction, les variables qui y séjournent deviennent hors de portée. Voici un exemple :

#!/usr/bin/env python3
# -*- coding: utf8 -*-

def first_names():
    lady_1 = "Gabiche"
    print(lady_1)

first_names() #appel de fonction

Résultat : Gabiche.

La fonction affiche bien la valeur contenue dans la variable définie localement.

Maintenant, nous allons modifier la dernière ligne du programme. Au lieu d’appeler la fonction, nous allons tenter de faire un print() de la variable lady_1.

#!/usr/bin/env python3
# -*- coding: utf8 -*-

def first_names():
    lady_1 = "Gabiche"
    print(lady_1)

print(lady_1)

Traceback (most recent call last):
File « /home/ordinosor/1_exemple.py », line 8, in
print(lady_1)
NameError: name ‘lady_1’ is not defined

Godverdomme! Keskispasse? Eh bien, nous avons tout simplement essayé d’afficher la valeur d’une variable qui est hors de portée puisqu’elle est définie à l’intérieur de la fonction.

À présent, nous allons essayer de faire le contraire. Nous allons définir une variable lady_2  dite globale c’est-à-dire à l’extérieur de toute fonction, et dans la fonction first_names, nous allons tenter de faire un print(lady_2).

#!/usr/bin/env python3
# -*- coding: utf8 -*-

lady_2 = "Amandale"

def first_names():
    print(lady_2)

first_names() #Appel de fonction

Résultat : Amandale.

Là, dans cet exemple, lady_2 n’est pas définie à l’intérieur de la fonction, et pourtant le programme ne plante pas! Warum?

En fait, Python va d’abord chercher dans l’espace local une variable portant le nom de lady_2. S’il ne la trouve pas, alors il va poursuivre sa recherche à l’extérieur de la fonction, c’est-à-dire dans l’espace global où il existe bien une variable définie avec le nom lady_2. Par conséquent, la fonction print() peut récupérer la valeur de cette variable dite globale.

Maintenant, définissons deux variables portant le même nom mais ne stockant pas la même valeur… Une variable globale lady_2 et une variable locale lady_2 dans la fonction. Reprenons le code précédent:

#!/usr/bin/env python3
# -*- coding: utf8 -*-

lady_2 = "Amandale"

def first_names():
    lady_2 = "Mandy-Bulle"
    print(lady_2)

first_names() #Appel de fonction

Résultat : Mandy-Bulle.

Python a d’abord effectué une recherche en local, dans l’espace de noms de la fonction. Il a réussi à trouver une variable nommé lady_2. Donc, la recherche s’est immédiatement interrompue et la fonction print() a récupéré la valeur contenue dans cette variable locale, à savoir Mandy-Bulle.

Le mot-clé global

Il n’est pas possible de modifier la valeur de la variable globale lady_2 à l’intérieur de la fonction… A moins de lui affecter au préalable le mot-clé global mais cette technique est parfaitement déconseillée car dans un gros programme, si quelqu’un modifie la valeur stockée dans la variable, il y a un gros risque que ce changement impacte sans le vouloir d’autres parties du programme. Gros risque de bugs en perspective!

#!/usr/bin/env python3
# -*- coding: utf8 -*-

lady_2 = "Amandale"

def first_names():
    global lady_2
    lady_2 = "Mandy-Bulle"

print(lady_2) #Variable globale

Résultat : Mandy-Bulle.

Amandale a disparu du programme…

Et avec la méthode append() ?

Créons une liste ladies_list et essayons voir…

#!/usr/bin/env python3
# -*- coding: utf8 -*-

ladies_list = ["Amandale", "Gabiche"] 

def first_names():
    ladies_list.append("Mandy-Bulle")

first_names() #Appel de fonction
print(ladies_list) #Variable globale

Résultat : [« Amandale », « Gabiche », « Mandy-Bulle »].

Nous avons réussi à modifier la liste malgré le fait que la méthode append() soit présente à l’intérieur de la fonction. Pourquoi donc? Parce que nous avons fait appel à une méthode qui appartient à l’objet ladies_list. En agissant ainsi, aucune barrière d’espace de noms ne peut nous empêcher de mener à bien notre modification.

Mais il est impossible de modifier la variable globale ladies_list en lui affectant une nouvelle valeur à l’intérieur de la fonction.

#!/usr/bin/env python3
# -*- coding: utf8 -*-

ladies_list = ["Amandale", "Gabiche"] 

def first_names():
    ladies_list = ["Mandy-Bulle", "Dominille"]
    print(ladies_list)

first_names() #Appel de fonction
print(ladies_list) #Variable globale

[« Mandy-Bulle », « Dominille »] : Résutat qui correspond au print() de la variable locale ladies_list dans la fonction first_names (à la ligne n° 10).

[« Amandale », « Gabiche »] : Résultat qui correspond au print() de la variable globale ladies_list (à la ligne n° 11). Nous n’avons pas réussi à modifier cette dernière.

Avec le slicing

#!/usr/bin/env python3
# -*- coding: utf8 -*-

ladies_list = ["Amandale", "Gabiche"] 

def first_names():
    ladies_list[1:1] = ["Mandy-Bulle"]

first_names() #Appel de fonction
print(ladies_list) #Variable globale

Résultat : [« Amandale », « Mandy-Bulle », « Gabiche »]

Avec la technique du slicing, le résultat est positif car en fait, sans le savoir, nous utilisons la méthode constructeur de la classe slice. Elle agit directement sur l’objet et là encore, aucune barrière d’espace de noms ne peut nous empêcher de mener à bien notre modification. C’est comme si nous avions écrit ce code (ligne n° 7) :

#!/usr/bin/env python3
# -*- coding: utf8 -*-

ladies_list = ["Amandale", "Gabiche"] 

def first_names():
    ladies_list[slice(1,1)] = ["Mandy-Bulle"]

first_names() #Appel de fonction
print(ladies_list) #Variable globale

Attributs d’instance et attributs de classe

Il existe également une hiérarchie entre les espaces de noms des instances et des classes.

  • Les instances et les classes peuvent utiliser les variables définies au niveau global mais elles ne peuvent pas les modifier.

Dans le code ci-dessous, nous avons trois types de variables :

  • Une variable globale
  • Un attribut de classe
  • Un attribut d’instance
#!/usr/bin/env python3
# -*- coding: utf8 -*-

man_1 = "Dentifritz_1" #Variable globale

class FirstName :
    """Test avec des prénoms"""

    man_1 = "Dentifritz_2" #Attribut de classe

    def first_name(self):
        """test des variables"""

        man_1 = "Sébanislas"
        self.man_1 = "Barnabulle"

#===== MAIN ===================================================================

if __name__ == '__main__':

    test = FirstName()
    test.first_name()
    print(man_1) #Variable globale
    print(FirstName.man_1) #Attribut(ou variable) de classe
    print(test.man_1) #Attribut (ou variable) d'instance

Ligne n° 23 : Dentifritz_1

Ligne n° 24 : Dentifritz_2

Ligne n° 25 : Barnabulle

Je vous invite à modifier ce code et à faire autant de tests que nécessaire pour bien comprendre le concept d’espaces de noms et la hiérarchie qui les gouverne.

#Python : classes et méthodes (partie 2) – mise en pratique

Pour une lecture plus agréable (page plus large), je vous invite à cliquer sur ce lien et à lire ce chapitre dans la rubrique consacrée au langage Python.

Nous allons confier à deux programmeurs en herbe, Briface et Jobriel, le soin de rédiger le code d’une petite application à caractère pédagogique. Elle consiste à faire apparaître des formes générées aléatoirement.

Jobriel va rédiger le code nécessaire à la création de l’environnement graphique, c’est-à-dire les widgets tandis que Briface, de son côté, va rédiger le module permettant de faire apparaître de manière aléatoire, des formes qui sont soit des triangles, soit des cercles, soit des carrés. La couleur de ces formes est également définie de manière aléatoire.

Au final, voici ce que nos deux gugusses doivent produire :

Le code de Jobriel

Commençons par le code de notre ami Jobriel :


#!/usr/bin/env python3
# -*- coding: utf8 -*-

from tkinter import*
import choice

class MainProg :
    """Création de l'environnement graphique de l'application"""

    def __init__(self, main_window, h = 300, w = 300, color = 'white'):
        """Méthode constructeur"""

        self.main_window = main_window
        self.h = h
        self.w = w
        self.color = color

    def widgets(self):
        """Création des widgets"""

        self.main_frame = Frame(self.main_window, height=self.h,\
                      width=self.w, bg=self.color)
        self.main_frame.pack()

        self.canevas = Canvas(self.main_frame, height=400, width=self.w,\
                   bg=self.color)
        self.canevas.pack(side=TOP)

        self.frame_1 = Frame(self.main_frame, height=100, width=self.w,\
                   bg=self.color)
        self.frame_1.pack(side=BOTTOM)

        self.random_choice = choice.RandomObjects(self.canevas)

        self.button = Button(self.frame_1, height=1, width=5, text='Afficher',\
                  relief='ridge', bd=3, bg='navy', fg='white',\
                  font=('Times', 14, 'bold'), padx=20,\
                  command = self.random_choice.random_choice)
        self.button.pack(padx=20, pady=10)

#===== MAIN ===================================================================

if __name__ == '__main__':

    main_window = Tk()
    main_window.title('Une forme au hasard')

    main_page = MainProg(main_window, 500, 500)
    main_page.widgets()

    main_window.mainloop()

ligne n° 4 : importation du module tkinter.
ligne n° 5 : importation du module choice qui va nous permettre de faire apparaître de manière aléatoire, différentes formes telles que des carrés, des ronds, des triangles. Les couleurs de ces formes sont également définies de manière aléatoire. Pour les deux formes d’importation, je vous renvoie au chapitre sur les modules. Personnellement, je préfère la forme d’importation ci-dessous car il n’y a pas de risques de conflits entre des variables portant le même nom. En outre, elle permet de raccourcir le nom du module. tkinter devient tk :

import tkinter as tk 

Pour de plus amples renseignements sur la bibliothèque tkinter, je vous invite à consulter cette documentation en français.

Ligne n° 43 : Nous trouvons une condition introduisant du code qui va s’exécuter uniquement si le programme est lancé de manière indépendante et non pas comme un module. Ici, c’est le cas. Par conséquent, cette partie du code s’exécute.

Ligne n° 45 : Création de l’objet main_window (fenêtre principale) par instanciation de la classe Tk() issue du module tkinter. Si j’avais écrit ceci à la ligne n° 4 : import tkinter as tk, alors la ligne n° 45 aurait été : main_window = tk.Tk().

Ligne n° 46 : application de la méthode title() sur l’objet main_window. Elle donne un titre à la fenêtre.

À ce stade, si on exécute le programme, voici ce qu’on obtient :

main_window

Ligne n° 48 : Création de l’objet main_page par instanciation de la classe MainProg(). Nous lui passons trois arguments qui sont main_window (la fenêtre mère), 500 (la hauteur de l’application) et 500 (la largeur). Nous choisissons de ne pas lui passer de paramètre de couleur. Ce sera donc la couleur par défaut qui va s’appliquer.
Ligne n° 49 : Application de la méthode widgets() sur l’objet main_page.

Ligne n° 51 : Application de la méthode mainloop() sur l’objet main_window ce qui a pour effet de déclencher le réceptionnaire d’événements et de permettre l’exécution du programme.

Ligne n° 7 : On remonte tout en haut! Définition d’une classe fondamentale baptisée MainProg
Ligne n° 10 : Méthode constructeur qui prend quatre paramètres:

  • self qui correspond à la référence de l’instance, c’est-à-dire l’objet main_page que nous avons instancié à la ligne n° 48. je rappelle qu’une méthode d’instance prend toujours au moins cet argument et que par convention, il est nommé self.
  • main_window qui correspond à la fenêtre principale et dont nous avons besoin pour instancier les widgets enfants.
  • h, w et color sont des paramètres qui possèdent une valeur par défaut. Si nous décidons de les ignorer, ce seront donc ces valeurs qui vont s’appliquer. C’est ce que nous avons fait avec color. Nous avons ignoré ce paramètre. Pour ce qui est des autres valeurs par défaut (h=300, w=300), nous avons choisi de les remplacer par 500 (voir ligne n° 48). Si nous décidons de ne pas respecter l’ordre de déclaration, il faut alors préciser le paramètre. Par exemple :

main_page = MainProg(main_window, color = ‘blue’, w=260, h=600)

Ligne n° 11 : Docstring

Lignes n° 13 à 16 : Création des attributs d’instance
Ligne n° 18 : Méthode widgets (création de tous les widgets de l’application)
Lignes n° 21 et 22 : Création de l’objet self.main_frame par instanciation de la classe Frame. Cette dernière créé un cadre que l’on peut remplir avec d’autres widgets. Nous pouvons lui passer plusieurs arguments. Notez bien la largeur (width) et la hauteur (height). Normalement, vous devez être capables de retrouver leurs valeurs. Notez également la barre oblique (antislash) qui permet d’écrire une instruction sur plusieurs lignes. La fondation Python préconise de ne pas dépasser 79 caractères par ligne, ce qui est assez strict. Dans la mesure du possible, il faut respecter cette convention.

Ligne n° 23 : Application de la méthode pack(). Cette dernière place le widget. Elle peut prendre des paramètres tels que TOP, BOTTOM, LEFT ou RIGHT qui poussent le widget dans la direction donnée.

À ce stade, si nous exécutons le programme, voici ce que nous obtenons. J’ai volontairement et provisoirement coloré en rouge, le fond du widget :

main_frame

Lignes n° 25 et 26 : Création de l’objet self.canevas par instanciation de la classe Canvas. C’est ce widget qui va nous permettre de placer les formes aléatoires grâce à différentes méthodes qui lui sont liées.
Ligne n° 27 : Méthode de placement pack(). Cette fois-ci, elle prend un paramètre (side=TOP) pour pousser le widget vers le haut.
Lignes n° 29 à 31: Nous créons un nouvel objet de type Frame que nous plaçons tout en bas de sa fenêtre parente (side=BOTTOM). Dans ce widget, nous placerons le bouton Afficher.

Ligne n° 33: Création de l’objet random_choice par instanciation de la classe RandomObjects du module importé choice. Nous lui passons un paramètre qui est self.canevas. Donc, cela nous donne:

self.random_choice = choice.RandomObjects(self.canevas)

Je rappelle que l’utilisation du point en Python signifie l’appartenance. Ainsi, la classe RandomObjects appartient au module choice.

Lignes n° 35 à 38: Création du bouton afficher par instanciation de la classe Button. Celle-ci prend plusieurs paramètres qui sont :

  • La hauteur
  • La largeur
  • Le texte à afficher
  • Le relief de la bordure
  • L’épaisseur de la bordure
  • La couleur de fond
  • La couleur du texte
  • La police et la fonte de caractères
  • L’espacement horizontal du texte à l’intérieur du widget
  • La commande que le bouton déclenche.

Pour ce dernier paramètre, nous appliquons la méthode random_choice issue du module importé choice, sur l’objet que nous avons créé (random_choice). Cela nous donne :

command=self.random_choice.random_choice

Alors là, vous allez me dire : « Mais Ordinosor! Tu bé, tu bé-bé, tu bégayes? »

Absolument pas! Il n’y a aucun risque de collision ou de confusion puisque ces deux noms identiques n’évoluent pas dans les mêmes espaces.

Notez bien que la commande déclenche une méthode lorsque nous cliquons sur le bouton. Il ne faut donc pas mettre les parenthèses () à la fin de la commande car cela aurait pour effet de shunter le bouton et d’activer la méthode dès le lancement du programme! Donc, il ne faut pas écrire :

command=self.random_choice.random_choice()

Ligne n° 39: La méthode pack() place le bouton dans sa fenêtre parente en réservant un espace vertical (pady=20) et horizontal (padx=20).

J’ai coloré provisoirement les différents widgets pour mieux les visualiser. Si nous exécutons le programme à ce stade, voici ce que nous obtenons:

  • En rouge, le widget self.main_frame
  • En blanc, le widget self.canevas
  • En jaune, le widget self.frame_1
  • En bleu, le widget self.button

button2

Merci pour ce travail, Jobriel! À présent, remettons tous les fonds des widgets en blanc Cliquons sur le bouton et voyons ce que notre ami Briface a codé…

Le code de Briface


#!/usr/bin/env python3
# -*- coding: utf8 -*-

from tkinter import*
import random

class RandomObjects :
    """Instancie aléatoirement les formes (triangles, cercles, carrés).
    Les couleurs de ces formes sont également définies de manière aléatoire"""

    def __init__(self, canevas):
        """Constructeur"""

        self.canevas = canevas

    def square(self):
        """Création du carré"""

        self.square_object = self.canevas.create_rectangle(200, 150, 300, 250,\
                             fill=self.random_color)

    def circle(self):
        """Création du cercle"""

        self.circle_object = self.canevas.create_oval(200, 150, 300, 250,\
                             fill=self.random_color)

    def triangle(self):
        """Création du triangle"""

        self.polygon = self.canevas.create_polygon(250, 150, 200, 250, 300,\
                       250,fill=self.random_color)

    def random_choice(self):
        """cf docstring class RandomObjects"""

        self.canevas.delete('all')
        self.random_color=random.choice(['green','red','yellow','blue','black'])
        random.choice([self.square, self.circle, self.triangle])()

Ligne n° 5 : importation du module random qui va nous permettre de faire des choix aléatoires.
Ligne n° 7: Création la classe RandomObjects.
Ligne n° 11: Méthode constructeur avec deux paramètres, la référence d’instance self et canevas.
Ligne n° 13: Déclaration d’une variable d’instance.
Ligne n° 16: Définition d’une méthode qui dessine un carré.
Ligne n° 19: Pour cela, nous utilisons la méthode create_rectangle qui prend quatre coordonnés en arguments ainsi qu’une couleur de remplissage.
Ligne n° 22: Définition d’une méthode qui dessine un cercle plein.
Ligne n° 25: Pour cela, nous utilisons la méthode create_oval qui prend quatre coordonnés en arguments ainsi qu’une couleur de remplissage.
Ligne n° 28: Définition d’une méthode qui dessine un triangle.
Ligne n° 31: Pour cela, nous utilisons la méthode create_polygon qui prend six coordonnés en arguments ainsi qu’une couleur de remplissage.

Pour de plus amples détails, je vous invite à consulter cette documentation en français.

Ligne n° 34: Définition de la méthode random_choice.
Ligne n° 37: Nous appliquons la méthode delete(‘all’) sur le widget self.canevas pour effacer une éventuelle forme avant que la suivante ne prenne sa place.
Ligne n° 38: Déclaration de la variable self.random_color. La valeur qui lui est affectée est une couleur choisie au hasard dans la liste passée en argument à la méthode random.choice.

Là encore, attention de ne pas confondre la méthode random_choice que nous avons nous-même définie et la méthode random.choice, c’est-à-dire la méthode choice du module importé random (ligne n° 5)!

Ligne n° 39: Cette fois-ci, random.choice choisit au hasard la méthode qui va matérialiser la forme. Pour que cette méthode exécute ses instructions, nous rajoutons tout à la fin, deux parenthèses. Sans ces deux parenthèses, rien ne se passerait:
random.choice([self.square, self.circle, self.triangle])()

Merci à toi , Briface, pour ce module qui exécute à la perfection la tâche qui lui a été impartie.

Ce diaporama nécessite JavaScript.

L’île de Schiermonnikoog (Pays-Bas)

Goedendag,

Aujourd’hui, je vous propose un article qui rompt avec le thème principal de ce blog puisque je vais vous présenter l’île de Schiermonnikoog. Cette dernière, qui appartient à la Frise, se situe au large de la province de Groningue, tout au Nord du Royaume des Pays-Bas. Continuer à lire … « L’île de Schiermonnikoog (Pays-Bas) »