Pour reprendre un script Python que personne n'a écrit dans l'équipe, ne
commencez pas par le lire de haut en bas. Lisez sa docstring pour le rôle,
descendez au bloc if __name__ == "__main__" qui est son point
d'entrée, notez ses options et ses variables d'environnement,
lancez-le sans risque, regardez ce qu'il affiche et son code de sortie,
puis trouvez la fonction qui décide. Ce n'est qu'ensuite qu'on le modifie,
d'un caractère si possible, et qu'on relance pour vérifier. Cette leçon
conclut le module de découverte de Python : elle utilise ce que vous avez appris (variables,
conditions, boucles, fonctions, fichiers, exceptions) sur un petit script
d'exploitation, puis le lab vous confie certcheck.py.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Dire ce que fait un script avant d'en lire le détail.
- Repérer son point d'entrée, ses options et ses variables d'environnement.
- Voir quel programme externe il lance et ce qu'il affiche.
- Lire son code de sortie et le sens qu'il porte.
- Trouver la fonction qui décide, puis la modifier et vérifier.
Prérequis
Section intitulée « Prérequis »- Être à l'aise dans un terminal Linux : lancer une commande, lire sa sortie.
- Avoir suivi les leçons Python du module de découverte : premier programme, variables et types, conditions et boucles, fonctions, fichiers et exceptions.
- Savoir ce qu'est une variable d'environnement : Variables d'environnement Linux.
Aucune autre notion de Python n'est supposée : la leçon montre comment lire un script, pas comment en écrire un de zéro.
Par où commencer quand on hérite d'un script ?
Section intitulée « Par où commencer quand on hérite d'un script ? »Un script hérité arrive avec une phrase du type « il tourne chaque nuit, ne le touchez pas ». Lire du code ressemble à une enquête : on pose des questions précises, et on cherche la réponse dans le code ou dans son exécution. Cinq questions, dans cet ordre, suffisent pour un script : que fait-il, par où démarre-t-il, de quoi dépend-il, que produit-il, où décide-t-il ? Tant que vous n'avez pas répondu, ne modifiez rien : une correction faite sur une mauvaise compréhension ajoute un défaut de plus.
Pour la démonstration, voici archivelog.py, un script d'une trentaine de
lignes qui compresse les vieux journaux d'un dossier. Le lab applique la même
démarche à certcheck.py. Pour suivre les essais, enregistrez-le dans un
fichier archivelog.py. Lisez-le en entier une fois, sans chercher à tout
comprendre : les sections suivantes le décortiquent.
#!/usr/bin/env python3"""archivelog : compresse les journaux .log d'un dossier.
Usage : python3 archivelog.py --dossier /var/log/appli --age 7"""import argparseimport osimport subprocessimport sysimport time
def trop_vieux(age_en_jours, seuil): """Vrai si le fichier a plus de `seuil` jours.""" return age_en_jours > seuil
def main(): parser = argparse.ArgumentParser(description="Compresse les vieux journaux.") parser.add_argument("--dossier", default=os.environ.get("ARCHIVELOG_DOSSIER", "journaux")) parser.add_argument("--age", type=int, default=7, help="âge minimal, en jours") args = parser.parse_args()
compresses = 0 for nom in sorted(os.listdir(args.dossier)): if not nom.endswith(".log"): continue chemin = os.path.join(args.dossier, nom) age = int((time.time() - os.path.getmtime(chemin)) / 86400) if trop_vieux(age, args.age): subprocess.run(["gzip", chemin], check=True) print(f"compressé : {nom}") compresses += 1 return 0 if compresses else 3
if __name__ == "__main__": sys.exit(main())Que fait ce script, et par où démarre-t-il ?
Section intitulée « Que fait ce script, et par où démarre-t-il ? »Le rôle d'un script se lit d'abord dans sa docstring, la chaîne entre triples guillemets placée tout en haut : ici, « compresse les journaux .log d'un dossier », avec un exemple d'appel. Une docstring peut être périmée, donc on la traite comme une déclaration d'intention, à confirmer par la lecture et par l'exécution.
Le point d'entrée est l'endroit où l'exécution commence quand on lance le
fichier. En Python, on le cherche tout en bas : le bloc
if __name__ == "__main__": ne s'exécute que lorsque le fichier est lancé
directement, et non lorsqu'un autre fichier l'importe. Ici, il appelle
main() et passe son résultat à sys.exit, ce qui fait de ce nombre le
code de sortie du script. Lisez ensuite main() de haut en bas : c'est elle
qui appelle les autres fonctions, et c'est donc elle la table des matières.
Quelles options, variables et programmes externes ?
Section intitulée « Quelles options, variables et programmes externes ? »Un script se règle de l'extérieur, et ces réglages sont les entrées à noter
en premier. Trois endroits à repérer dans main() : argparse déclare les
options de la ligne de commande, os.environ.get(...) lit une
variable d'environnement (une paire nom-valeur que le shell transmet au
programme), et subprocess.run(...) lance un programme externe, ici
gzip. Python n'a pas à tout faire : il pilote des outils du système.
Le plus simple pour lister les options est de demander l'aide au script
lui-même, car argparse la génère à partir de ses déclarations :
python3 archivelog.py --helpLa sortie liste --dossier, --age et l'option -h. Une valeur par défaut
cachée dans le code se lit dans l'argument default= : ici, le dossier vaut la
variable ARCHIVELOG_DOSSIER si elle existe, sinon journaux. Pour ne rien
oublier, un grep relève tous les indices d'un coup, mais il propose des
candidats : il ne prouve jamais qu'il n'y a rien d'autre.
grep -nE "argparse|os\.environ|subprocess|open\(" archivelog.pyComment lancer un script inconnu sans risque ?
Section intitulée « Comment lancer un script inconnu sans risque ? »Exécuter est la meilleure façon de vérifier ce que vous avez cru lire, à
condition de ne pas toucher au réel. Trois précautions couvrent la plupart
des cas : travailler sur une copie jetable des fichiers, pointer le script
vers des données d'essai plutôt que vers la production, et s'assurer que le
script ne fait que lire quand c'est possible. Ici, archivelog.py
compresse des fichiers : l'essai se fait dans un dossier créé pour l'occasion.
mkdir essai && printf 'a\n' > essai/vieux.log && printf 'b\n' > essai/neuf.logtouch -d '10 days ago' essai/vieux.logARCHIVELOG_DOSSIER=essai python3 archivelog.pyecho "code : $?"ls essaiLa sortie affiche compressé : vieux.log, puis code : 0, puis la liste
neuf.log et vieux.log.gz. La syntaxe VARIABLE=valeur commande fixe la
variable pour cette seule exécution. Comparez le résultat à ce que vous
aviez lu : si un fichier imprévu apparaît ou disparaît, la lecture était
fausse et il faut la corriger.
Que dit le code de sortie ?
Section intitulée « Que dit le code de sortie ? »Le code de sortie est le nombre qu'un programme rend à celui qui l'a lancé.
0 veut dire « tout s'est bien passé », tout autre nombre signale quelque
chose, et echo $? affiche celui de la dernière commande. C'est le seul
élément que lisent cron (le planificateur de tâches de Linux) ou un
pipeline : il décide s'il doit prévenir quelqu'un. Dans le script, c'est la
valeur que rend main(), ici return 0 if compresses else 3.
Relancez le script une seconde fois dans le même dossier : plus rien n'est à
compresser, la sortie est vide et echo "code : $?" affiche cette fois
code : 3. Le script distingue donc « j'ai travaillé » de « il n'y avait rien
à faire », ce qu'aucun texte affiché ne dirait aussi nettement. Lire ce que
produit un script, c'est lire les deux : ce qu'il imprime et le code qu'il
rend. Les messages d'erreur, eux, passent par un flux séparé, la sortie
d'erreur (stderr).
Où le script décide-t-il ?
Section intitulée « Où le script décide-t-il ? »Dans la plupart des scripts d'exploitation, une seule fonction porte la
règle métier : celle qui répond à la question « faut-il agir ? ». Elle est
courte, prend des valeurs en entrée et rend un verdict. Ici, c'est
trop_vieux(age_en_jours, seuil). Pour la trouver, partez de main() et
cherchez, à l'intérieur de la boucle, la condition if qui commande l'action :
la fonction qu'elle appelle est la bonne.
C'est aussi là que se cachent les cas limites, c'est-à-dire les valeurs
exactement à la frontière. Avec age_en_jours > seuil, un fichier de
exactement 7 jours n'est pas compressé avec --age 7 ; avec
age_en_jours >= seuil, il l'est. Les deux écritures sont correctes, mais
elles ne disent pas la même chose, et une documentation qui parle d'« au moins
7 jours » ne s'accorde qu'avec la seconde. Les défauts d'un script hérité se
rangent presque toujours dans trois familles : un cas limite mal tranché,
une erreur avalée par un except qui continue sans rien dire, ou un
secret écrit en clair dans le code. Chacun laisse un signe qu'une lecture
attentive retrouve, mais un défaut n'est avéré qu'une fois reproduit.
Comment modifier un script sans le casser ?
Section intitulée « Comment modifier un script sans le casser ? »On ne modifie qu'après avoir compris, et on modifie le moins possible : un caractère de condition, un cas ajouté. La méthode tient en quatre gestes. Observez d'abord le comportement actuel avec une commande précise, changez une seule chose, relancez exactement la même commande, puis comparez les deux résultats. Si le résultat n'est pas celui que vous attendiez, annulez et relisez : ne corrigez pas par essais successifs.
Voici le cycle sur un cas limite. Le dossier d'essai doit contenir
vieux.log non encore compressé : l'essai précédent l'a compressé, donc
recréez-le d'abord, puis touch -d '7 days ago' essai/vieux.log, qui le
rend vieux de 7 jours révolus (le script compte des jours entiers : int(...) ignore les heures
restantes). On lance ensuite avec --age 7.
Avant la modification, age_en_jours > seuil ne le compresse pas, car 7 n'est
pas supérieur à 7. On change > en >= dans trop_vieux, on relance la même
commande, et le fichier est cette fois compressé. La différence entre les deux
sorties prouve que votre modification fait ce que vous croyez. Pour garder
une trace de ce que vous changez et pouvoir l'annuler, Git est l'outil de
référence : la formation l'introduit avec le travail collaboratif, et la
formation Git montre aussi comment retrouver, dans
l'historique, qui a changé une ligne et pourquoi.
Mettre en pratique
Section intitulée « Mettre en pratique »Le lab vous confie certcheck.py, un script d'environ quatre-vingts lignes
qu'un collègue a écrit puis quitté, et qui contrôle chaque nuit l'expiration
des certificats TLS du parc. Vous le lisez d'abord sans le modifier : son rôle,
l'option qui règle le seuil, la variable qui remplace la date du jour, le
programme qu'il lance, la fonction qui décide, puis ce qu'il affiche et son
code de sortie à une date fixée. Vous le modifiez ensuite : le seuil devient
inclusif, et un certificat déjà expiré s'affiche expired. La validation porte
sur vos réponses dans reponses.yaml, que le contrôle recalcule, et sur le
comportement du script modifié, rejoué sur des cas tirés au hasard.
À retenir
Section intitulée « À retenir »- Lire un script est une enquête : rôle, point d'entrée, entrées, sorties, fonction qui décide, dans cet ordre, avant toute modification.
- La docstring donne le rôle annoncé, et le bloc
if __name__ == "__main__"donne le point d'entrée, qui appellemain(). - Les options viennent d'
argparse(et de--help), les variables d'environnement d'os.environ, les programmes externes desubprocess. - On lance un script inconnu sur des données d'essai, en notant ce qu'il
affiche et son code de sortie (
echo $?). - La fonction qui décide est celle que la boucle appelle pour savoir s'il
faut agir : c'est là que se jouent les cas limites, comme
>contre>=. - Une modification se fait petite, se vérifie en relançant la même commande et en comparant les deux résultats.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Score par domaine
Un domaine regroupe plusieurs guides et reçoit plusieurs questions : son score est plus fiable qu'un score par thème, qui porte souvent sur une seule question.
Bilan
Points forts
Aucun sujet réussi à 80 % sur au moins deux questions pour l’instant.
Points faibles
Aucun sujet sous le seuil de réussite.
À faire ensuite
Des indices pour retenter votre chance ?
Continuer le cours : Structurer un projet Python en outil en ligne de commande
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications