post

Python fr:Résolution de Problèmes

Nous avons étudié diverses parties du langage Python et nous allons maintenant voir comment ces parties s’assemblent ensemble, en concevant et en écrivant un programme qui fait quelque chose d’utile. L’idée est d’apprendre à écrire un script Python.

Contents

Le Problème

Le problème est “je veux un programme qui fasse une sauvegarde de tous mes fichiers importants “.

Bien que cela soit un problème simple, il n’y a pas assez d’information pour nous permettre de travailler à une solution. Nous avons besoin d’un peu plus d’ analyse. Par exemple, comment choisir quels fichiers vont être backupés? Comment les stocker? les stocker?

Après une analyse du problème, nous concevons notre programme. Nous écrivons une liste de choses que notre programme doit faire. Dans ce cas, j’ai créé la liste suivante sur la manière dont Je veux qu’il fonctionne. Si vous concevez ce programme, vous fairez sans doute une analyse différente, car chaque personne a sa manière de faire.

  1. Les fichiers et répertoires à backuper seront dans une liste.
  2. Le backup doit être stocké dans un répertoire principal de backup.
  3. Les fichiers seront sauvés dans un fichier zip.
  4. Le nom de l’archive zip est la date et l’heure courante.
  5. Nous utilisons la commande standard zip disponible par défaut dans toute distribution standard Linux/Unix. les utilisateurs Windows peuvent installer zip à partir de page du projet GnuWin32 et ajouter C:Program FilesGnuWin32bin à votre variable d’environnement PATH, comme ce que nous avons fait pour reconnaître la commande Python. Notez que vous pouvez utiliser n’importe quelle commande d’archivage dans la mesure où une interface en ligne de commande est disponible, afin de pouvoir passer des paramètres à notre script.

La Solution

Comme la conception de notre programme est maintenant suffisamment stable, nous pouvons écrire le code qui est une implémentation de notre solution.

#!/usr/bin/python
# Nom de fichier: backup_ver1.py

import os
import time

# 1. Les fichiers et répertoires à sauvegarder sont indiqués dans une liste.
source = ['"C:\My Documents"', 'C:\Code']
# Notez qu'il faut utiliser des double quotes à l'intérieur de la chaîne pour les noms comportant des espaces.

# 2. La sauvegarde est stockée dans un répertoire principal
target_dir = 'E:\Backup' # A adapter chez vous

# 3. Les fichiers sauvegardés sont mis dans une archive zip.
# 4. Le nom de l'archive zip contient la date et l'heure courante
target = target_dir + os.sep + time.strftime('%Y%m%d%H%M%S') + '.zip'

# 5. La commande zip sert à créer l'archive
zip_command = "zip -qr {0} {1}".format(target, ' '.join(source))

# Lancement de la sauvegarde
if os.system(zip_command) == 0:
    print('Sauvegarde réussie à', target)
else:
    print('La sauvegarde a ÉCHOUÉ')

Résultat:

   $ python backup_ver1.py
   Sauvegarde réussie à E:Backup20080702185040.zip

Maintenant, nous sommes dans la phase de test, où nous testons notre programme. S’il ne se comporte pas comme prévu, nous allons le deboguer c’est-à-dire enlever les bugs (erreurs) dans le programme.
Si le programme ci-dessus ne fonctionne pas chez vous, mettez un print(zip_command) juste avant l’appel à os.system et lancez le programme. Maintenant copiez et collez la commande zip affichée dans le prompt shell et voyez si cela se passe correctement. Si la commande échoue, vérifiez la documentation de la commande zip, pour voir ce qui pourrait être inexact. Si la commande fonctionne, alors vérifiez si le programme Python correspond exactement au programme écrit.

Comment cela fonctionne:

Vous noterez comment nous avons converti notre design en code en l’écrivant pas à pas.

Nous utilisons les modules os et time en commençant par les importer. Puis, nous indiquons les fichiers et répertoires à sauvegarder dans la liste source. Le répertoire de destination est l’endroit où nous stockons tous les fichiers sauvegardés, et ceci est indiqué dans la variable target_dir. Le nom de l’archive zip que nous allons créer est la date et l’heure courante, que nous générons avec la fonction time.strftime(). L’archive aura une extension .zip et sera stockée dans le répertoire target_dir .

Notez l’utilisation de la variable os.sep – cela donne le nom du séparateur de répertoire en fonction du système d’exploitation, c’est-à-dire que cela sera '/' avec Linux et Unix, '\' avec Windows et ':' avec Mac OS. Le fait d’utiliser directement os.sep au lieu de ces caractères rend notre programme portable et il fonctionnera sous ces trois systèmes d’exploitation.

La fonction time.strftime() prend des arguments comme ceux utilisés dans le programme ci-dessus. La spécification %Y sera remplacée par l’année dans le siècle. La spécification %m sera remplacée par le mois en tant que nombre compris entre 01 et 12 et ainsi de suite. La liste complète de ces spécifications peut être trouvée dans le Python Référence Manuel.

Nous créons le nom du fichier zip cible en utilisant l’opérateur d’addition qui concatène les chaînes de caractère, c’est-à-dire qu’il assemble les deux chaînes ensemble et en renvoie une nouvelle. Ensuite, nous créons une chaîne zip_command qui contient la commande que nous allons exécuter. Vous pouvez vérifier si votre commande fonctionne en la lançant dans le shell (terminal Linux ou prompt DOS).

La commande zip est utilisée avec quelques options et paramètres. L’option -q est utilisée pour indiquer que la commande zip doit travailler quietly (discrètement). L’option -r indique que la commande zip doit travailler de manière récursive pour les répertoires, c’est-à-dire inclure tous les sous-répertoires et les fichiers. Les deux options sont combinées et indiquées dans un raccourci -qr. Les options sont suivies par le nom de l’archive zip à créer, la liste des fichiers et répertoires à sauvegarder. Nous convertissons la liste source en une chaîne avec la méthode join que nous avons déjà vue.

Ensuite, nous exécutons (run) la commande en utilisant la fonction os.system qui lance la commande comme si elle était lancée à partir du système c’est-à-dire dans le shell – il retourne 0 si la commande s’est exécutée avec succès, sinon il renvoie un numéro d’erreur.

En fonction du résultat de la commande, nous affichons le message approprié indiquant que le backup a échoué ou réussi.

Ca y est, nous avons créé un script pour faire une sauvegarde de nos fichiers importants!

Note pour les utilisateurs Windows
Au lieu des double backslash, vous pouvez utiliser des raw strings. Par exemple, utilisez 'C:\Documents' ou r'C:Documents'. Cependant, n’utilisez pas 'C:Documents' car vous vous retrouveriez avec un caractère d’échappement inconnu D.

Maintenant que nous avons un script de sauvegarde qui fonctionne, nous pouvons l’utiliser quand nous voulons une sauvegarde de nos fichiers. Les utilisateurs Linux/Unix sont incités à utiliser la méthode exécutable comme vu précédemment, afin de pouvoir lancer le script n’importe où et n’importe quand. Cela est appelé la phase d’ opération ou la phase de déploiement du logiciel.

Le programme ci-dessus fonctionne correctement, mais (en général) la première version d’un programme ne fonctionne pas comme prévu. Par exemple, il peut y avoir des problèmes si vous n’avez pas réfléchi correctement à votre programme ou si vous avez fait une faute de frappe en rentrant le code, etc. Dans ce cas, il vous faudrait revenir à la phase du design ou à déboguer votre programme.

Deuxième Version

La première version de notre script fonctionne. Cependant, nous pouvons faire quelques améliorations, afin qu’il soit meilleur pour une utilisation journalière. Ceci est appelé la phase de maintenance du logiciel.

Une amélioration que je trouvais utile était un meilleur nommage des fichiers – utiliser la date en tant que nom de fichier dans un répertoire à l’intérieur du répertoire de backup principal. Le premier avantage est que vos backups sont stockés d’une façon hiérarchique et donc plus faciles à gérer. Le deuxième avantage est que les noms de fichiers sont plus courts. Le troisième avantage est que des répertoires séparés vous aideront à vérifier si vous avez fait des sauvegardes pour chaque jour, vu que le répertoire sera créé seulement si ce jour a été sauvé.

#!/usr/bin/python
# Nom de fichier: backup_ver2.py

import os
import time

# 1. Les fichiers et répertoires à sauver sont indiqués dans une liste.
source = ['"C:\My Documents"', 'C:\Code']
# Notez qu'il faut utiliser des double quotes à l'intérieur la chaîne pour les noms de fichiers avec des espaces.

# 2. la sauvegarde est rangée dans un répertoire à part.

target_dir = 'C:\Backup' # A adapter 

# 3. Les fichiers sont placés dans une archive zip.
# 4. Le jour courant est le nom du sous-répertoire dans le répertoire principal
today = target_dir + os.sep + time.strftime('%Y%m%d')
# L'heure courante est le nom de l'archive zip
now = time.strftime('%H%M%S')

# Créer le sous-répertoire s'il n'existe pas
if not os.path.exists(today):
    os.mkdir(today) # crée le répertoire
    print('Création réussie du répertoire', today)

# Le nom du fichier zip
target = today + os.sep + now + '.zip'

# 5. Nous utilisons la commande zip pour créer une archive
zip_command = "zip -qr {0} {1}".format(target, ' '.join(source))

# lancement de la sauvegarde
if os.system(zip_command) == 0:
    print('Sauvegarde réussie vers', target)
else:
    print('Echec de la sauvegarde')

Résultat:

   $ python backup_ver2.py
   Création réussie du répertoire E:Backup20080702
   Sauvegarde réussie vers E:Backup20080702202311.zip

   $ python backup_ver2.py
   Sauvegarde réussie vers E:Backup20080702202325.zip

Comment cela fonctionne:

L’essentiel du programme reste le même. Les changements sont que nous vérifions si un répertoire avec le jour courant dans le répertoire principal des sauvegardes existe, en utilisant la fonction os.path.exists . S’il n’existe pas, nous le créons avec la fonction os.mkdir .

Troisième Version

La deuxième version fonctionne bien quand je veux de nombreux backups, mais dans ce cas, j’ai du mal à trouver la raison des backups! Par exemple, si j’ai fait des modifications importantes dans un programme ou une présentation, alors je veux associer ces changements avec le nom de l’archive zip. Cela peut être facilement obtenu en ajoutant un commentaire de l’utilisateur au nom de l’archive zip.

Note
Ce programme ne fonctionne pas, mais ne vous inquiétez pas, continuez, il y a une leçon à en tirer.
#!/usr/bin/python
# Nom de fichier: backup_ver3.py

import os
import time

# 1. Les fichiers et répertoires à sauver sont indiqués dans une liste.
source = ['"C:\My Documents"', 'C:\Code']
# Notez qu'il faut utiliser des double quotes à l'intérieur la chaîne pour les noms de fichiers avec des espaces.

# 2. la sauvegarde est rangée dans un répertoire à part.
target_dir = 'C:\Backup' # A adapter

# 3. Les fichiers sont placés dans une archive zip.
# 4. Le jour courant est le nom du sous-répertoire dans le répertoire principaltoday = target_dir + os.sep + time.strftime('%Y%m%d')
today = target_dir + os.sep + time.strftime('%Y%m%d')
# L'heure courante est le nom de l'archive zip
now = time.strftime('%H%M%S')

# Un commentaire de l'utilisateur est ajouté au nom du fichier zip
comment = input('Entrez un commentaire --> ')
if len(comment) == 0: # vérifie si un commentaire a été saisi
    target = today + os.sep + now + '.zip'
else:
    target = today + os.sep + now + '_' +
        comment.replace(' ', '_') + '.zip'

# Créer le sous-répertoire s'il n'existe pas déjà.
if not os.path.exists(today):
    os.mkdir(today) # création du répertoire
    print('Répertoire créé avec succès', today)

# 5. Nous utilisons la commande zip pour créer une archive
zip_command = "zip -qr {0} {1}".format(target, ' '.join(source))

# lancement de la sauvegarde
if os.system(zip_command) == 0:
    print('Sauvegarde réussie vers', target)
else:
    print('Echec de la sauvegarde')

Résultat:

   $ python backup_ver3.py
     File "backup_ver3.py", line 25
       target = today + os.sep + now + '_' +
                                           ^
   SyntaxError: invalid syntax

Comment cela (ne) fonctionne (pas):

Ce programme ne fonctionne pas! Python dit qu’il y a une erreur de syntaxe, ce qui signifie que le script ne respecte pas les règles que Python s’attend à trouver. Quand nous regardons l’erreur indiquée par Python, il nous indique l’endroit où a été trouvée l’erreur. Donc nous commençons le debugging de notre programme à partir de cette ligne.

En regardant attentivement, nous voyons que la seule ligne logique a été coupée en deux lignes physiques, mais nous n’avons pas indiqué que les deux lignes physiques vont ensemble. Fondamentalement, Python a trouvé l’opérateur d’addition (+) sans aucune opérande dans cette ligne logique et en conséquence ne sait pas comment continuer. Souvenez-vous que nous indiquons que la ligne logique continue sur la prochaine ligne physique en utilisant un backslash à la fin de la ligne physique. Donc, nous faisons cette correction à notre programme. Cette correction du programme quand nous trouvons des erreurs est appelée bug fixing.

Quatrième Version

#!/usr/bin/python
# Nom de fichier: backup_ver3.py

import os
import time

# 1. Les fichiers et répertoires à sauver sont indiqués dans une liste.
source = ['"C:\My Documents"', 'C:\Code']
# Notez qu'il faut utiliser des double quotes à l'intérieur la chaîne pour les noms de fichiers avec des espaces.

# 2. la sauvegarde est rangée dans un répertoire à part.
target_dir = 'C:\Backup' # A adapter

# 3. Les fichiers sont placés dans une archive zip.
# 4. Le jour courant est le nom du sous-répertoire dans le répertoire principaltoday = target_dir + os.sep + time.strftime('%Y%m%d')
today = target_dir + os.sep + time.strftime('%Y%m%d')
# L'heure courante est le nom de l'archive zip
now = time.strftime('%H%M%S')

# Un commentaire de l'utilisateur est ajouté au nom du fichier zip
comment = input('Entrez un commentaire --> ')
if len(comment) == 0: # vérifie si un commentaire a été saisi
    target = today + os.sep + now + '.zip'
else:
    target = today + os.sep + now + '_' + 
        comment.replace(' ', '_') + '.zip'

# Créer le sous-répertoire s'il n'existe pas déjà.
if not os.path.exists(today):
    os.mkdir(today) # création du répertoire
    print('Répertoire créé avec succès', today)

# 5. Nous utilisons la commande zip pour créer une archive
zip_command = "zip -qr {0} {1}".format(target, ' '.join(source))

# lancement de la sauvegarde
if os.system(zip_command) == 0:
    print('Sauvegarde réussie vers', target)
else:
    print('Echec de la sauvegarde')

Résultat:

   $ python backup_ver4.py
   Entrez un commentaire --> ajout de nouveaux exemples
   Sauvegarde réussie vers C:Backup20091005101312_ajout_de_nouveaux_exemples.zip

Comment cela fonctionne:

Maintenant le programme fonctionne! Regardons les améliorations que nous avons ajoutées dans la version 3. Nous saisissons les commentaires de l’utilisateur avec la fonction input et nous vérifions si quelque chose a été saisi en trouvant la longueur de l’entrée avec la fonction len . Si l’utilisateur a juste tapé enter sans rien saisir (c’était peut-être un backup quelconque ou sans modification), alors nous faisons comme avant.

Cependant, si un commentaire a été saisi, alors il est ajouté au nom de l’archive zip juste avant l’extension .zip . Notez que nous remplaçons les espaces dans le commentaire par des underscores – parce qu’il est plus facile de gérer des noms de fichiers sans des espaces.

Encore Des Améliorations

La quatrième version conviendra pour la plupart des utilisateurs, mais on peut toujours améliorer. Par exemple, vous pouvez inclure un niveau de verbosité pour le programme, et quand vous indiquerez une option -v votre programme sera plus bavard.

Une autre amélioration possible serait de permettre de passer au script en ligne de commande des fichiers et répertoires en plus. Nous pouvons récupérer ces noms à partir de la liste sys.argv et nous pouvons les ajouter à notre liste source en utilisant la méthode extend fournie par la classe list .

Le raffinement le plus important serait de ne pas utiliser os.system pour créer les archives mais d’utiliser plutôt les modules zipfile ou tarfile . Ils font partie de la librairie standard et sont disponibles sans dépendances externes sur votre ordinateur.

Cependant, j’ai utilisé la création de backup avec os.system dans les exemples précédents uniquement pour des raisons pédagogiques, afin que l’exemple puisse être compris par tout lemonde, mais être également utile.

Pouvez-vous essayer d’écrire la cinquième version qui utilise le module zipfile mau lieu de l’appel à os.system?

Le Cycle De Développement

Nous avons parcouru les différentes phases de l’écriture d’un logiciel. Ces phases peuvent être résumées comme suit:

  1. Quoi (Analyse)
  2. Comment (Design)
  3. Le faire (Implémentation)
  4. Test (Test et mise au point)
  5. Utilisation (Opération ou Déploiement)
  6. Maintenance (Perfectionnement)

Une manière recommandée d’écrire un programme est la procédure que nous avons suivie en créant le script backup: faire l’analyse et le design. Commencer à implémenter avec une version simple. Tester et mettre au point. L’utiliser pour s’assurer qu’il fonctionne comme prévu. Maintenant, ajouter les fonctionnalités que vous voulez et continuer le cycle Créer – Tester – Utiliser autant de fois que nécessaire. Souvenez-vous, Software is grown, not built.

Récapitulatif

Nous avons vu comment créer notre programme/script Python et les différentes étapes dans l’écriture d’un tel programme. Vous trouverez utile de créer vos programmes comme nous l’avons fait dans ce chapitre, ainsi vous serez plus à l’aise avec Python comme dans la résolution de problèmes.

Ensuite, nous allons parler de programmation orientée objet.