Tous les articles par icnisnboissy

Programmation du traitement d’image avec python

Dans la section précédente, vous avez utilisé un logiciel de traitement d’image (Photofiltre) qui contient différents algorithmes permettant de modifier automatiquement des images. Dans un appareil photo ou un smartphone, il y a aussi de tels types d’algorithmes. Ici, vous allez programmer vous-mêmes en Python différents algorithmes permettant de modifier des images.

INDISPENSABLE : Pour travailler avec Python, il faut créer un répertoire (par exemple travail) dans lequel vous enregistrerez à la fois vos fichiers Python (format .py) et vos images (format .png)

A la fin de la section, vous zipperez (= clic droit > compresser) ce répertoire contenant l’intégralité des fichiers .py et .png pour nous le rendre avec votre compte-rendu.

A faire vous-même 0 : Configurer le logiciel Thonny dans lequel on va programmer en Python

Ouvrez le logiciel Thonny (faire une recherche avec la loupe)

Une boite de dialogue apparaît avec le message suivant : « Can’t find backend ‘LocalCPython’. Please select another backend from options »

  • ouvrir le menu Outils > Options > Onglet Interpéteur
  • choisir l’option par défaut : « Le même interpréteur qui exécute Thonny »

Ensuite, il est nécessaire d’importer la librairie PILLOW (Python Imaging Library) qui fournit les outils nécessaires pour les manipulations d’images :

  • de nouveau, ouvrir le Menu Outil > Gérer les paquets…
  • écrire « Pillow » dans la barre de recherche et cliquer sur rechercher
  • Cliquer sur le lien « pillow » dans la liste obtenue

A faire vous-même 1 : Créer une image avec Python

Voici un script qui génère deux images en couleurs RVB (=RGB en anglais) de dimension 100 x 100.

Tapez-le dans l’éditeur de script de Thonny (fenêtre du haut) et enregistrez-le sous le nom afvm1.py dans votre dossier de travail créé précédemment.

Exécutez le script (icône « lecture »)

from PIL import Image
im=Image.new("RGB", (100, 100)) 
im2= Image.new("RGB", (100, 100), (255,255,255))
im.save("afvm1_1.png")
im2.save("afvm1_2.png") 
  • Vérifiez que vous avez 2 images créées dans le dossier de travail (sinon demander de l’aide)
  • Lancez le logiciel Photofiltre et ouvrez les 2 images créées
  • Expliquez la couleur de l’image afvm1_1.png

Pour modifier la couleur de l’image, il suffit de modifier la couleur de chaque pixel.

On va utiliser la commande putpixel((x,y), (a, b, c)) qui permet de colorer le pixel de coordonnées (x, y) avec la couleur RVB (a, b, c) où a, b et c sont les valeurs de luminance de chaque canal, comprises entre 0 et 255.

Remarque : x est le n° de colonne et y est le n° de ligne. Le 1er pixel en haut à gauche a pour coordonnées (0,0)

A faire vous-même 2 : mettre de la couleur

Dans l’éditeur Thonny, modifiez le script précédent en ajoutant la boucle « for » suivante.

Attention  !

  • respectez l’indentation qui délimite les blocs de code (Elle se fait avec la touche de tabulation « tab »)
  • n’oubliez pas les « deux-points » : à la fin de la ligne for
from PIL import Image
im=Image.new("RGB", (100, 100))
for x in range (100):
    for y in range(100):
        im.putpixel((x,y),(0,255,0))
im.save("afvm2.png")
  • Expliquez ce que produit la boucle ajoutée sur l’image.
  • Remplacez la boucle par celle donnée ci-dessous et expliquez le résultat.
for x in range (50):
    for y in range (50,100):
        im.putpixel((x,y),(0,255,0))  

A faire vous-même 3 : coder des drapeaux

Le script suivant permet de produire le drapeau français sous forme d’une image de dimension 120×100 pixels. Une première boucle « for » permet de parcourir les lignes de l’image. Les boucles for imbriquées (attention aux indentations) parcourent les colonnes dans un rectangle donné et y affectent une couleur.

from PIL import Image
col=120
lgn=100
im=Image.new("RGB", (col,lgn))
#il y a 3 bandes verticales, on définit la variable bande :
bande=col//3
for y in range (100):
    for x in range (bande):
        im.putpixel((x,y),(0,0,255))
    for x in range (bande, (2*bande)):
        im.putpixel((x,y),(255,255,255))
    for x in range ((2*bande), col):
        im.putpixel((x,y),(255,0,0))
im.save("france.png")

Après avoir compris le script précédent, vous allez le modifier pour produire d’autres drapeaux. Pensez à enregistrer votre script modifié sous un autre nom et à modifier également le nom de l’image enregistrée par python pour ne pas écraser l’image précédente.

Enregistrez vos différentes versions de script jusqu’à ce que cela fonctionne. Vous joindrez vos scripts python afvm3-irlande et afm3-colombie à votre compte-rendu.

  • Modifiez les arguments de la commande putpixel() pour reproduire le drapeau irlandais. (pour avoir le code RGV des couleurs, vous pouvez les sélectionner sur une image avec Pixie ou avec la pipette de Photofiltre)
  • Pour ceux qui aiment les défis : plus difficile : modifiez les arguments de la commande putpixel() pour reproduire le drapeau colombien

A faire vous-même 4 : apporter des nuances

Avec quelques petites astuces, on peut aussi produire des dégradés assez facilement. Voici un script qui permet d’obtenir deux dégradés de bleu différents.

from PIL import Image
largeur = 255
hauteur = 255
im=Image.new('RGB', (largeur, hauteur))
for x in range(largeur):
    for y in range(hauteur):
        im.putpixel((x, y), (0, 0, y))
im2=Image.new('RGB', (largeur, hauteur))
for x in range(largeur):
    for y in range(hauteur):
        im2.putpixel((x, y), (0, 0, x))
im.save("camaieubleu1.png")
im2.save("camaieubleu2.png")   
  • Expliquez la ligne 7 du script précédent.
  • Expliquez la différence entre les 2 images.
  • Modifiez le script pour produire le dégradé suivant et enregistrer l’image sous le nom degrade.png

Dans un logiciel de traitement d’image comme Photofiltre, ou celui qui est présent dans l’appareil photo, il est possible de faire des corrections automatiques comme passer l’image en négatif.

Le principe de l’algorithme est de donner pour chaque pixel la couleur inverse : cette couleur est calculée selon le principe suivant :

A faire vous-même 5 : l’image en négatif

  • Enregistrez une image de votre choix dans votre répertoire de travail (pensez à choisir une image dont la licence vous permet sa modification)

Voici une partie du script permettant de créer le même effet négatif.

La commande pix = img.getpixel((x,y)) permet d’affecter dans une variable pix  les valeurs des canaux RVB extraites du pixel de coordonnées (x,y).

On peut exprimer ces valeurs sous forme d’un 3-tuple (c’est-à-dire une collection de 3 valeurs, ici correspondant aux 3 canaux RVG) :      p = (pix[0], pix[1], pix[2]) que l’on peut affecter à une variable (ici p) pour l’utiliser ensuite.

Remarque : les indices entre [ ] permettent d’accéder aux différents éléments du tuple. Pour accéder à un élément d’indice   i  d’un tuple t , on écrit      t[i]

  • On veut transformer chaque pixel de l’image (variable pix) en son négatif (variable pixneg). Trouvez comment calculer pixneg à partir de pix.

L’extrait de script ci-dessous permet d’ouvrir l’image que vous avez enregistrée, puis de créer une nouvelle image qui sera son négatif. Il manque dans le script suivant 3 lignes (respectez les indentations !) qui permettent de passer l’image en négatif.

  • À vous de les écrire et de tester le résultat. Vous joindrez vos images et votre script à votre compte-rendu.
from PIL import Image
  
img = Image.open(MonImage)
col,lgn = img.size
imgF = Image.new(img.mode,img.size)
print("Patientez pendant l'exécution du script …")
  
for x in range(col):
    for y in range(lgn):
...
...
... 
print("… C'est fait !, voir le résultat avec Photofiltre")
imgF.save("image_negatif.png")   

Parmi les retouches d’images très utilisées pour incruster un logo, un copyright ou une signature dans une image, il y a la fusion de deux images. Il s’agit de transformer plus ou moins légèrement la couleur des pixels de manière à ce que l’incrustation ne puisse pas être enlevée facilement.

L’opération mathématique à appliquer pour modifier l’encodage des pixels est la suivante :

                (R1, V1, B1)           est le 3-tuple de l’image 1,         

                (R2, V2, V2)          est le 3-tuple de l’image 2

                a             est le coefficient de dominance d’une image sur l’autre, dont la valeur est comprise entre 0 et 1.

A faire vous-même 6 : fusion d’images

  • Utilisez les informations ci-dessus pour compléter le script suivant de façon à obtenir une fusion des drapeaux de la France et de la Colombie.

Astuce : les valeurs (R,V,B) d’un pixel sont obligatoirement des entiers à utilisez     int()

La ligne 2 indique qu’il faudra entrer la valeur de a dans le shell (fenêtre de droite). Vous pourrez essayer différentes valeurs de a et comparer les images produites. Dans ce cas, pensez à modifier le nom du fichier enregistré (ligne 17) sous peine d’écraser le fichier précédent.

(Vous pouvez bien sûr utiliser des images de votre choix dans ce script, mais les 2 images doivent avoir les mêmes dimensions)

from PIL import Image
a=float(input("Entrez la valeur de a : "))
  
im1 = Image.open('france.png')
im2 = Image.open('colombie.png')
  
largeur,hauteur = im1.size
  
im = Image.new('RGB', (largeur, hauteur))
    for x in range(largeur):
        for y in range(hauteur):
            pix1 = im1.getpixel((x,y))
            pix2 = im2.getpixel((x,y))
            fusion = .......................... 
            im.putpixel((x,y),fusion)
  
im.save('fusion.jpg') 

Codage de l’image et capteur photo

Commençons par un bref historique de la photo sur cette vidéo:

La photo : de l’argentique au numérique

Revenons un petit peu en arrière à l’époque du Noir et Blanc:

Bien entendu, le codage en noir et blanc ne donne pas des images de bonne qualité !

On appelle profondeur de couleur le nombre de bits utilisés pour coder la couleur d’un pixel. Pour une image en noir et blanc, la profondeur est de 2 bits. Cela ne suffit pas pour donner une image correcte d’un ensemble complexe : en fait, la photographie en « noir et banc », n’est pas codée en noir et banc, mais en nuances de gris.

Ces 2 images correspondent à une même prise de vue, mais l’une est en noir et blanc (image en noir et blanc) et l’autre en nuances de gris (= image monochrome)

Souris en Noir et Blanc
La même souris, en nuances de gris

Un capteur photographique (dans un appareil photo ou un smartphone) contient des photosites : il s’agit de composants électroniques qui convertissent l’énergie lumineuse en tension électrique. Les tensions électriques seront converties en valeurs numériques par l’ordinateur afin de reconstituer les pixels.

 

A faire vous-même 1: codage en niveau de gris

Dans les travaux précédents, vous avez utilisé des images en noir et blanc : chaque pixel était encodé sur 1 bit. Pour avoir des nuances de gris, il est nécessaire d’avoir un encodage plus complexe utilisant davantage de bits pour un pixel. Par exemple, chaque bit pouvant prendre 2 valeurs, avec 2 bits, on peut obtenir 4 nuances.

En général, pour une image monochrome, la profondeur de couleur est de 8 bits : combien de nuances de gris sont possibles ?

Une photographie en couleur rendra encore mieux la réalité. Dans l’œil humain, la rétine contient des cellules sensibles au changement de luminosité (les bâtonnets) et des cellules sensibles à des radiations particulières de la lumière : les cônes.  Il existe 3 types de cônes : ceux qui sont sensibles aux radiations bleues, ceux qui sont sensibles au vert et ceux qui captent plutôt les rouges.  Grâce à ces 3 types de cônes, on peut voir toutes les couleurs par synthèse additive.

Ces 3 couleurs de lumière sont dites primaires.

Pour obtenir une photographie en couleurs, il y a devant le capteur photographique des filtres colorés comme la matrice Bayer RVB (Rouge, Vert, Bleu). On utilise donc un codage en Rouge/Vert/bleu.

La matrice Bayer est composée de 50 % de filtres verts (car l’œil humain est capable de distinguer de très nombreuses nuances de verts), 25 % de filtres rouges et autant de bleus.  

Il existe différents types de filtres (voir https://geometrian.com/programming/reference/subpixelzoo/index.php) qui permettent tous de capter pour chaque pixel, la luminance en rouge, vert et bleu.

Un pixel sera donc composé des informations en luminance des photosites par synthèse additive des couleurs primaires R, V, B

Expliquez en quoi consiste la synthèse additive (si besoin, faites une recherche)

On codera donc un pixel à l’aide d’un triplet de valeurs (par exemple 247, 56, 98). La première valeur donnant l’intensité du canal rouge, la deuxième valeur donnant l’intensité du canal vert et la troisième valeur donnant l’intensité du canal bleu (RVB ou RGB en anglais).

Expliquez pourquoi, pour chaque canal de chaque pixel, l’intensité lumineuse est comprise entre 0 et 255.

Si chaque canal est codé avec 8 bits, quelle est la profondeur de couleur ?

Combien de couleurs différentes sont-elles possibles avec une telle profondeur ?

A faire vous-même 2

Lancez le logiciel photofiltre puis ouvrez l’image souris.jpeg

Avec l’outil pipette (copie d’écran), prélevez différentes couleurs et donnez les codes correspondants en RVB.

A faire vous-même 3

Menu Réglage > négatif

Que deviennent les différentes couleurs ?

Donnez les codes RVB correspondants.

A faire vous-même 4

 A l’aide de l’outil Pixies à lancer ici, relevez le code RVB de la couleur sélectionnée en avant plan.

https://icn-isn-boissy.yj.fr/wp/wp-content/uploads/2020/02/pixie.zip

Calculez la couleur qu’on obtiendrait avec le réglage négatif réalisé dans le « à faire vous-même 3 ». Quel nom pourrait-on lui donner ?

Codage des pixels de l’image en noir et blanc

Le codage le plus simple de l’image est celui en noir et blanc. Dans ce type de codage, la couleur est encodée sur un bit (=binary digit) qui peut prendre 2 valeurs (vrai ou faux, 0 ou 1, blanc ou noir, ouvert ou fermé… etc.)

Pour une image matricielle en noir et blanc, telle que votre image initiale1.png, chaque pixel est encodé par 1 bit noir ou blanc. Le format le plus élémentaire d’image en noir et blanc est le format .pbm (Portable Bit Map).

Vous disposez du fichier carré8×8.pbm qui correspond à un carré blanc de 8 X 8 pixels. Vous allez manipuler l’image avec le logiciel EditHexa ou éditeur en ligne HexEd.it.

Télécharger l’image zippé ci dessous, pensez à la dézipper et à l’enregistrer dans votre dossier.

Vous allez créer une image en manipulant son encodage. Pour chaque étape, votre compte-rendu comportera la copie d’écran de l’encodage et l’image obtenue.

A faire vous-même 1 : le codage d’un carré blanc

Lancez le logiciel EditHexa (ou HexEd.it en ligne) et ouvrez le fichier carré8×8.pbm

Dans la fenêtre centrale, la partie encadrée contient l’encodage en octets et à droite, il y a la traduction sous forme de texte selon la norme ASCII (à un code sur 7 ou 8 bits, correspond un caractère ou une commande)

Copie d’écran de EditHexa (pour HexEd.it, c’est le même principe)

A partir de ce fichier,

Quel est le nombre d’octets qui encodent l’entête de l’image ? (astuce : cliquer sur différents octets dans la fenêtre centrale et vérifier à droite, à quelle « partie » du fichier cela correspond)

Déterminez le nombre d’octets qui encodent l’image elle-même. Quelle valeur ont-ils ?

 

Vous avez vu précédemment qu’un octet de l’image (ou du texte de l’entête) correspond à un « nombre » à 2 éléments.

Exemples : le G de GIMP correspond à 47, l’espace entre les deux 8, c’est 20 ou le point correspond à 0A.

  • Le système décimal utilise 10 symboles (de 0 à 9) : c’est notre système habituel de numération.
  • Le système binaire utilise 2 symboles (0 et 1) : utilisé car en électronique, le courant passe ou pas.
  • Le système hexadécimal utilise 16 symboles (0 à 9 et A à F) : cela permet d’écrire des nombres plus longs avec moins de symboles à avantage pour le stockage en informatique. C’est l’idéal pour les images !

Pour faire le travail suivant, il va falloir convertir un octet écrit avec 8 bits dans le système binaire (donc une série de huit 0 ou 1) en sa correspondance dans le système hexadécimal.

Prenons l’exemple de 2 octets 0000 0000 et 0011 1101. (remarque, on on écrit le nombre binaire en 2 paquets de 4 )

Pour convertir ces octets dans le système hexadécimal, on utilise le tableau de conversion ci-dessous pour chaque paquet de 4.

  • 0000 0000 du système binaire devient 00 dans le système hexadécimal.
  • 0011 1101 du système binaire devient 3D dans le système hexadécimal.
Hexadécimal Binaire
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
A 1010
B 1011
C 1100
D 1101
E 1110
F 1111

A faire vous-même 2 : le codage d’un carré noir et d’un damier

Modifiez les bits des octets de l’image de manière à former un carré noir. (si besoin, revoir ce qui a été fait sur le codage d’un pixel dans la section précédente)

  • Avec l’outil en ligne HexEd.it, modifiez les valeurs des octets de l’image.
  • Avec EditHexa : Utilisez menu Outils avancés > manipuler les bits ou modifiez directement les valeurs dans la fenêtre centrale.

Enregistrez votre image sous le nom carrénoir.pbm

Vérifiez votre manipulation en ouvrant le fichier avec Photofiltre ou Gimp (Par défaut, les fichiers du format .pbm sont masqués : cliquez sur le menu déroulant « images les plus courantes » puis sélectionnez « toutes les images »)

Pour obtenir un carré 8×8 à rayure, il faut par exemple que la première ligne soit noire. Ce sera donc une suite de huit bits à 1, c’est-à-dire un octet dont tous les bits valent 1 qu’on peut écrire 1111 1111 ou alors FF.
La deuxième ligne doit être blanche, donc c’est l’octet 0000 0000 ou 00 dans le système hexadécimal.
Et ainsi de suite…

Procédez de la même façon pour obtenir un damier que vous appellerez damier.pbm
astuce : au brouillon, réalisez un tableau de 8×8, coloriez les cases noires du damier que vous voulez obtenir.

A faire vous-même 3 : le codage de l’initiale

Avec Photofiltre ou Gimp, ouvrez l’image initiale2.png créée à la séance précédente. Affichez la grille de repérage avec un pas de 2 pixels.

Avec EditHexa ou HexEd.it, modifiez l’encodage de l’image carré8×8.pbm de manière à reproduire le motif de votre initiale2.png    Vous obtenez alors votre image (vérifiez avec Photofiltre) sur 8 X 8 pixels.

caractéristiques d’une image numérique

Avant tout, créer un répertoire « thème Photo » dans votre zone personnelle SNT.

Ajouter dans ce répertoire, un nouveau dossier appelé « travail » dans lequel vous enregistrerez toutes les étapes intermédiaires de vos travaux sur les images.

Pour ce thème et les suivants, vous devez progresser sur la mise en forme de votre CR. La mise en forme sera prise en compte dans l’évaluation. Pistes de progrès à respecter:

  • Rédaction sans fautes d’orthographe
  • Utiliser l’option Justifier le texte dans LibreOffice pour utiliser toute la largeur de la page (disponible avec marge gauche, droite ou centrer)
  • Utiliser l’option Rogner les images afin de ne montrer que l’essentiel de la copie d’écran que vous faites
  • Après Rogner penser à agrandir les images pour plus de lisibilité et éventuellement centrer les images
  • Utiliser les options classiques de mise en forme du texte: police de caractères, titre , gras , italique , couleur , taille , souligné pour mettre en évidence les différents corps de votre texte

Une image numérique est un tableau (=matrice) de pixels. Un pixel (Picture Element) est un carré élémentaire de l’image.

A faire vous-même 1

Ouvrez le logiciel Photofiltre puis ouvrez l’image carreblanc.png (Fichier>Ouvrir) ci-dessous.

  • Utilisez le scroll ou l’outil zoom pour grossir l’image au maximum.
  • Utilisez le plus petit outil pinceau (taille 1 pixel) pour dessiner en noir l’initiale de votre prénom

Enregistrer votre image sous le nom de fichier initiale1.png.

Une image est caractérisée par différents paramètres (revoir la vidéo si besoin) : la définition, la résolution, la taille.

A faire vous-même 2

Quelles sont les caractéristiques de l’image ? Fichier>Propriétés de l’image

  • quelle est sa définition ?
  • combien de pixels contient l’image initiale1.png ?
  • quelle est la taille réelle de l’image ?
  • quelle est sa résolution ?
  • vérifiez par le calcul la résolution indiquée.

pour vous aider allez voir ici.

vidéo à regarder tout sur la résolution.

rappels : la résolution s’exprime en français en ppp (= pixel par pouce) ou en anglais en dpi (=dot per inch)

                               1 pouce (1 inch en anglais) = 2,54 cm

Si on fait varier le nombre de pixels, on modifie certains paramètres de l’image :

A faire vous-même 3

Menu Affichage > afficher la grille de repérage

Menu Outils > Préférences > palette d’outils et grille

  • Modifiez les paramètres de grille tels que figurés sur l’image :

Vous obtenez un quadrillage par pixels en rouge sur votre image.

  • Vérifiez la définition de votre image et faites une copie d’écran à joindre au compte-rendu.
  • Chaque pixel est codé avec 1 bit qui peut prendre 2 valeurs : noir ou blanc. Comme un octet = 8 bits, quel est le poids théorique de cette image ?
  • Quel serait le poids de l’image si c’était juste un carré blanc ?

A faire vous-même 4

  • Modifiez à nouveau les paramètres de grille de façon à quadriller avec des carrés de 2×2 pixels.
  • Coloriez entièrement en noir chaque carré contenant au moins 1 pixel noir.
  • Enregistrez la nouvelle image sous le nom initiale2.png . Faites une copie d’écran à joindre au compte-rendu.

Si on considère que chaque carré de la nouvelle grille représente un pixel :

  • combien de pixels contient la nouvelle version de l’image ?
  • quelle est sa définition ?
  • la taille de l’image a-t-elle changé ?
  • quelle est alors sa résolution ?
  • quel est le poids de cette nouvelle version ?

A faire vous-même 5

application

  1. J’ai une photo dont la définition est de 3000 × 4000, la résolution est de 72 dpi. Quelle est la taille d’impression ?
  2. Je souhaite pouvoir l’imprimer en format 10 × 13.5 cm, donc réduire les dimensions tout en gardant le même nombre de pixels. Comment puis-je faire ? L’image sera-t-elle de bonne qualité ? Quelle est maintenant la nouvelle résolution ?

Codage – Exercices

Exercice 1

Ecrire une fonction decimal_vers_binaire() qui prend comme argument un nombre entier décimal saisi par l’utilisateur et qui renvoi le nombre binaire correspondant sur 1 octet (8bits).

La fonction devra coder le nombre décimal en binaire et rajoutera le nombre de 0 voulu pour faire un octet.

Exemples :

Exercice 2

Modifier la fonction précédente pour coder le nombre entier sur 16 bits.

Exemples :

Exercice 3

Ecrire une fonction plus_un() qui ajoute 1 à un nombre binaire de 8 bits saisi par l’utilisateur passé en argument.

Exemples :

Pour vous aiguiller :
1- Recopier l’octet saisi par l’utilisateur dans une liste.
2- Comparer chaque bit, rang par rang. Si le bit de rang 0 est égal à 1, le changer à 0 et marquer la retenue à Vraie. Si le bit de rang 0 est égal à 0, le changer à 1 et garder les autres intacts.
3- Si la retenue est Vraie tester les bit de rang suivant, les uns après les autres tant que la retenue est Vraie.
4- Recopie du résultat dans un string que l’on affichera en appelant la fonction plus_un()

Exercice 4

Ecrire un programme qui permet de convertir les nombres entiers en binaire signé en complément à 2 (en 8 bits) .
1- Adapter la fonction decimal_vers_binaire () de l’exercice 1 afin de convertir le nombre binaire en décimal (sur 7 bits).
2- Créer une fonction inversion() qui prend en argument le nombre binaire convertit précédemment et renvoi le résultat d’une inversion bit à bit.
3- Utiliser la fonction plus_un() de l’exercice 3 avec comme argument le nombre binaire renvoyé par la fonction inversion() et renvoi le résultat de l’addition de ce dernier avec 1.
Enfin, imprimer à l’écran le résultat et vérifier la justesse de ce dernier.

Exemples :

Exercice 5

NoteBook de correction

Linux : les commandes de base en ligne de commande

À la « préhistoire » des systèmes d’exploitation, ces derniers étaient dépourvus d’interface graphique (système de fenêtres « pilotables » à la souris), toutes les interactions « système d’exploitation – utilisateur » se faisaient par l’intermédiaire de « lignes de commandes » (suites de caractères, souvent ésotériques, saisies par l’utilisateur). Aujourd’hui, même si les interfaces graphiques modernes permettent d’effectuer la plupart des opérations, il est important de connaitre quelques-unes de ces lignes de commandes.

Nous allons utiliser une clé Freeduc-JBART, cette clé est basée sur Debian-Live , ce qui nous permettra de travailler sous Linux .

Pour saisir des lignes de commandes, nous allons utiliser une console (aussi appelé terminal même si ce n’est pas exactement la même chose).

À faire vous-même 1

Après avoir démarrer sur votre clé Freeduc-JBART

Ouvrez une console, vous devriez avoir quelque chose qui ressemble à cela :

console

console système GNU/Linux

Nous avons ci-dessus la console de l’utilisateur « david » qui utilise un ordinateur qui se nomme « PC-Bureau » (« david@PC-Bureau »).


Principalement nous allons, grâce à la ligne de commande, travailler sur les fichiers et les répertoires. Dans les systèmes de type « UNIX » (par exemple GNU/Linux ou macOS), nous avons un système de fichier en arborescence :

console

système de fichiers

Dans le schéma ci-dessus on trouve des répertoires (noms entourés d’un rectangle, exemple : « home ») et des fichiers (uniquement des noms « grub.cfg »). À noter : les extensions des noms de fichiers, par exemple le « cfg » de « grub.cfg », ne sont pas obligatoires dans les systèmes de type « UNIX », par exemple, « bash » est bien un nom de fichier et il n’a pas d’extension.

On parle d’arborescence, car ce système de fichier ressemble à un arbre à l’envers.

Comme vous pouvez le constater, la base de l’arbre s’appelle la racine de l’arborescence et se représente par un « / »

Chemin absolu ou chemin relatif ?

Pour indiquer la position d’un fichier (ou d’un répertoire) dans l’arborescence, il existe 2 méthodes : indiquer un chemin absolu ou indiquer un chemin relatif. Le chemin absolu doit indiquer « le chemin » depuis la racine. Par exemple le chemin absolu du fichier fiche.ods sera : /home/elsa/documents/fiche.ods

Remarquez que nous démarrons bien de la racine / (attention les symboles de séparation sont aussi des /)

Il est possible d’indiquer le chemin non pas depuis la racine, mais depuis un répertoire quelconque, nous parlerons alors de chemin relatif :

Le chemin relatif permettant d’accéder au fichier « photo_1.jpg » depuis le répertoire « max » est : « images/photo_vac/photo_1.jpg »

Remarquez l’absence du / au début du chemin (c’est cela qui nous permettra de distinguer un chemin relatif et un chemin absolu).

Imaginons maintenant que nous désirions indiquer le chemin relatif pour accéder au fichier « gdbd_3.jpg » depuis le répertoire « photos_vac ».

Comment faire ?

Il faut « remonter » d’un « niveau » dans l’arborescence pour se retrouver dans le répertoire « images » et ainsi pouvoir repartir vers la bonne « branche ». Pour ce faire il faut utiliser 2 points : ..

« ../ski/gdbd_3.jpg »

Il est tout à fait possible de remonter de plusieurs « crans » : « ../../ » depuis le répertoire « photos_vac » permet de « remonter » dans le répertoire « max »

À faire vous-même 2

En vous basant sur l’arborescence ci-dessus, déterminez le chemin absolu permettant d’accéder au fichier :

  • « cat »
  • « rapport.odt »

Toujours en vous basant sur l’arborescence ci-dessus, déterminez le chemin relatif permettant d’accéder au fichier :

  • « rapport.odt » depuis le répertoire « elsa »
  • « fiche.ods » depuis le répertoire « boulot »

Comme déjà évoqué plus haut, les systèmes de type « UNIX » sont des systèmes « multi-utilisateurs » : chaque utilisateur possède son propre compte. Chaque utilisateur possède un répertoire à son nom, ces répertoires personnels se situent traditionnellement dans le répertoire « home ». Dans l’arborescence ci-dessus, nous avons 2 utilisateurs : « max » et « elsa ». Par défaut, quand un utilisateur ouvre une console, il se trouve dans son répertoire personnel. Dans l’image de la console ci-dessus, nous avons un « david@PC-Bureau ~ $ » (au passage, on appelle cela « l’invite de commande »), le « ~ » (caractère « tilde ») signifie que l’on se trouve actuellement dans le répertoire personnel de l’utilisateur courant, autrement dit dans le répertoire de chemin absolu « /home/david » (puisque l’utilisateur courant est « david »). Le répertoire « où l’on se trouve actuellement » est appelé « répertoire courant ». L’invite de commande vous indique à tout moment le répertoire courant : « david@PC-Bureau ~/Documents $ » vous indique que vous êtes dans le répertoire « Documents » qui se trouve dans le répertoire « david » qui se trouve dans le répertoire « home » (chemin absolu : « /home/david/Documents »)

Attention : les systèmes de type « UNIX » sont « sensibles à la casse » (il faut différencier les caractères majuscules et les caractères minuscules) : le répertoire « Documents » et le répertoire « documents » sont 2 répertoires différents.

La commande cd

Signification : list

La commande « cd » permet de changer le répertoire courant. Il suffit d’indiquer le chemin (relatif ou absolu) qui permet d’atteindre le nouveau répertoire :

Par exemple (en utilisant l’arborescence ci-dessus) :

  • si le répertoire courant est le répertoire « elsa » et que vous « voulez vous rendre » dans le répertoire « documents », il faudra saisir la commande : « cd documents » (relatif) ou « cd /home/elsa/documents » (absolu)
  • si le répertoire courant est le répertoire « photos_vac » et que vous « voulez vous rendre » dans le répertoire « ski », il faudra saisir la commande : « cd ../ski » (relatif) ou « cd /home/max/images/ski » (absolu)
  • si le répertoire courant est le répertoire « boulot » et que vous « voulez vous rendre » dans le répertoire « documents », il faudra saisir la commande : « cd .. » (relatif) ou « cd /home/elsa/documents » (absolu)

À faire vous-même 3

Toujours en utilisant l’arborescence ci-dessus, quelle est la commande à saisir si le répertoire courant est le répertoire « home » et que vous « voulez vous rendre » dans le répertoire « boulot » (vous utiliserez d’abord un chemin absolu puis un chemin relatif)

La commande ls

Signification : list

La commande « ls » permet de lister le contenu du répertoire courant.

console

Dans l’exemple ci-dessus, depuis le répertoire personnel de l’utilisateur « david », nous passons dans le répertoire « nsi » à l’aide d’un « cd nsi », puis nous affichons le contenu de ce répertoire « nsi » à l’aide de la commande « ls ». Nous trouvons dans le répertoire « nsi » : 2 fichiers (« fiche1.odt » et « photo.jpg ») et un répertoire (« test »).

À faire vous-même 4

Après avoir ouvert une console, utilisez la commande ls depuis votre répertoire personnel.


La commande « mkdir »

Signification : make directory

La commande « mkdir » permet de créer un répertoire dans le répertoire courant. La commande est de la forme « mkdir nom_du_répertoire »

console

Remarque : il est préférable de ne pas utiliser de caractères accentués dans les noms de répertoire (ou de fichier). Il en est de même pour les espaces (à remplacer par des caractères tirets bas « _ »)

La commande man

Signification : manual

Affiche les pages du manuel système.
Chaque argument donné à man est généralement le nom d’un programme, d’un utilitaire, d’une fonction ou d’un fichier spécial. Exemples d’utilisation :

  • man man
    affiche les informations pour l’utilisation de man
  • man mkdir
    affiche les informations pour l’utilisation de mkdir

‘q’ pour quitter.

À faire vous-même 5

Après avoir ouvert une console, utilisez la commande « mkdir » afin de créer un répertoire « test_nsi » dans votre répertoire personnel.

La commande « rm »

Signification : remove

La commande « rm » permet de supprimer un fichier ou un répertoire. La commande est de la forme « rm nom_du_répertoire_ou_nom_du_fichier »

console

La plupart des commandes UNIX peuvent être utilisées avec une ou des options. Par exemple, pour supprimer un répertoire non vide, il est nécessaire d’utiliser la commande « rm » avec l’option « -r » : « rm -r nom_du_répertoire »

Attention si vous utilisez la commande « rm * » cela supprime tous les fichiers présent dans le répertoire courant.

A noter que pour afficher le répertoire courant il existe une fonction « pwd », même s’il est spécifié sur le terminal en bleu…

console

La commande « touch »

La commande « touch » permet de créer un fichier vide. La commande est de la forme « touch nom_du_fichier_à_créer »

console

La commande « cp »

Signification : copy

La commande « cp » permet de copier un fichier. La commande est de la forme « cp /répertoire_source/nom_fichier_à_copier /répertoire_destination/nom_fichier »

console

À noter : le nom du fichier « destination » n’est pas obligatoirement le même que le nom du fichier « source » (on peut avoir « cp fic.txt info/fiche.txt »)

La commande « mv »

Signification : move

la commande « mv » permet de déplacer ou renommer des fichiers et des répertoires Options les plus fréquentes :

  • -f : Écrase les fichiers de destination sans confirmation
  • -i : Demande confirmation avant d’écraser
  • -u : N’écrase pas le fichier de destination si celui-ci est plus récent

Exemples d’utilisation :

  • mv monFichier unRep/
    Déplace monFichier dans le répertoire unRep
  • mv unRep/monFichier .
    Déplace le fichier monFichier du répertoire unRep là où on se trouve
  • mv unRep monRep
    Renomme unRep en monRep

À faire vous-même 6

Placez-vous dans le répertoire « test_nsi » créé au « À faire vous-même 5 ». Créez un fichier « test.txt » avec du texte à l’intérieur.

Saisir la commande « cat test.txt » que se passe t’il?

Créez un répertoire « doc ». Copiez le fichier « test.txt » dans le répertoire « doc ». Effacez le répertoire doc (et son contenu).

Gestion des utilisateurs et des groupes

Les systèmes de type « UNIX » sont des systèmes multi-utilisateurs, plusieurs utilisateurs peuvent donc partager un même ordinateur, chaque utilisateur possédant un environnement de travail qui lui est propre.

Chaque utilisateur possède certains droits lui permettant d’effectuer certaines opérations et pas d’autres. Le système d’exploitation permet de gérer ces droits très finement. Un utilisateur un peu particulier est autorisé à modifier tous les droits : ce « super utilisateur » est appelé « administrateur » ou « root ». L’administrateur pourra donc attribuer ou retirer des droits aux autres utilisateurs. Au lieu de gérer les utilisateurs un par un, il est possible de créer des groupes d’utilisateurs. L’administrateur attribue des droits à un groupe au lieu d’attribuer des droits particuliers à chaque utilisateur.

Comme nous venons de le voir, chaque utilisateur possède des droits qui lui ont été octroyés par le « super utilisateur ». Nous nous intéresserons ici uniquement aux droits liés aux fichiers, mais vous devez savoir qu’il existe d’autres droits liés aux autres éléments du système d’exploitation ((imprimante, installation de logiciels…).

Les fichiers et les répertoires possèdent 3 types de droits :

  • les droits en lecture (symbolisés par la lettre r) : est-il possible de lire le contenu de ce fichier
  • les droits en écriture (symbolisés par la lettre w) : est-il possible de modifier le contenu de ce fichier
  • les droits en exécution (symbolisés par la lettre x) : est-il possible d’exécuter le contenu de ce fichier (quand le fichier du code exécutable)

Il existe 3 types d’utilisateurs pour un fichier ou un répertoire :

  • le propriétaire du fichier (par défaut c’est la personne qui a créé le fichier), il est symbolisé par la lettre u
  • un fichier est associé à un groupe, tous les utilisateurs appartenant à ce groupe possèdent des droits particuliers sur ce fichier. Le groupe est symbolisé par la lettre g
  • tous les autres utilisateurs (ceux qui ne sont pas le propriétaire du fichier et qui n’appartiennent pas au groupe associé au fichier). Ces utilisateurs sont symbolisés la lettre « o »

Il est possible d’utiliser la commande « ls » avec l’option « -l » afin d’avoir des informations supplémentaires.

console

Prenons la première ligne :


-rw-r--r-- 1 david david 0 avril 13 19:58 fic.txt
 

Lisons cette ligne de gauche à droite :

  • le premier symbole « – » signifie que l’on a affaire à un fichier, dans le cas d’un répertoire, nous aurions un « d » (voir la 2e ligne)
  • les 3 symboles suivants « rw-« donnent les droits du propriétaire du fichier : lecture autorisée (r), écriture autorisée (w), exécution interdite (- à la place de x)
  • les 3 symboles suivants « r–« donnent les droits du groupe lié au fichier : lecture autorisée (r), écriture interdite (- à la place de w), exécution interdite (- à la place de x)
  • les 3 symboles suivants « r–« donnent les droits des autres utilisateurs : lecture autorisée (r), écriture interdite (- à la place de w), exécution interdite (- à la place de x)
  • le caractère suivant « 1 » donne le nombre de liens (nous n’étudierons pas cette notion ici)
  • le premier « david » représente le nom du propriétaire du fichier
  • le second « david » représente le nom du groupe lié au fichier
  • le « 0 » représente la taille du fichier en octet (ici notre fichier est vide)
  • « avril 13 19:58 » donne la date et l’heure de la dernière modification du fichier
  • « fic.txt » est le nom du fichier

Prenons la deuxième ligne :


drwxr-xr-x 2 david david 4096 avril 13 20:05 info
	  

Lisons cette ligne de gauche à droite :

  • le premier symbole « d » signifie que l’on a un répertoire
  • les 3 symboles suivants « rwx »donnent les droits du propriétaire du répertoire : lecture du contenu du répertoire autorisée (r), modification du contenu du répertoire autorisée (w), il est possible de parcourir le répertoire (voir le contenu du répertoire) (x)
  • les 3 symboles suivants « r-x »donnent les droits du groupe lié au répertoire : modification du contenu du répertoire interdite (- à la place de w)
  • les 3 symboles suivants « r-x »donnent les droits des autres utilisateurs : modification du contenu du répertoire interdite (- à la place de w)
  • le caractère suivant « 2 » donne le nombre de liens (nous n’étudierons pas cette notion ici)
  • le premier « david » représente le nom du propriétaire du répertoire
  • le second « david » représente le nom du groupe lié au répertoire
  • le « 4096 » représente la taille du répertoire en octets
  • « avril 13 20:05 » donne la date et l’heure de la dernière modification du contenu du répertoire
  • « info » est le nom du répertoire

À faire vous-même 7

Analysez la 3e ligne du résultat de la commande « ls -l » ci-dessus


Il est important de ne pas perdre de vu que l’utilisateur « root » a la possibilité de modifier les droits de tous les utilisateurs.

Le propriétaire d’un fichier peut modifier les permissions d’un fichier ou d’un répertoire à l’aide de la commande « chmod ». Pour utiliser cette commande, il est nécessaire de connaitre certains symboles :

  • les symboles liés aux utilisateurs : « u » correspond au propriétaire, « g » correspond au groupe lié au fichier (ou au répertoire), « o » correspond aux autres utilisateurs et « a » correspond à « tout le monde » (permet de modifier « u », « g » et « o » en même temps)
  • les symboles liés à l’ajout ou la suppression des permissions : « + » on ajoute une permission, « – » on supprime une permission, « = » les permissions sont réinitialisées (permissions par défaut)
  • les symboles liés aux permissions : « r » : lecture, « w » : écriture, « x » : exécution.

La commande « chmod » à cette forme :


chmod [u g o a] [+ - =] [r w x] nom_du_fichier
		 

par exemple


chmod o+w toto.txt
		

attribuera la permission « écriture » pour le fichier « toto.txt » « aux autres utilisateurs »

Il est possible de combiner les symboles :


chmod g-wx toto.txt
	 

La commande « chmod » ci-dessus permet de supprimer la permission « écriture » et la permission « exécution » pour le fichier « toto.txt » « au groupe lié au fichier »

Une fois de plus, « root » a tous les droits sur l’ensemble des fichiers et des répertoires, il peut donc utiliser la commande « chmod » sur tous les répertoires et tous les fichiers.

À faire vous-même 8

Analysez attentivement l’enchainement de commandes suivantes :

console

À faire vous-même 9

Créez un répertoire « test_nsi2 » dans votre répertoire personnel. Placez-vous dans le répertoire « test_nsi2 ». Créez un fichier « titi.txt », vérifiez les permissions associées à ce fichier. Modifiez les permissions associées au fichier « titi.txt » afin que les « autres utilisateurs » aient la permission « écriture »


Retrouver toutes les commandes ici : documentation Ubuntu console de commande

Extraction de données d’un fichier csv et tri simple sur une liste

Présentation


On se propose dans cette activité de traiter des données issues d’un fichier csv récupéré sur le site Strava afin de les filtrer dans un nouveau fichier.
Le fichier de données de départ se nomme « liste_origine.csv ».


Il faudra écrire 5 fonctions :
• « import_lignes » avec en argument le fichier de données de départ et qui renvoie une liste des lignes contenues dans le fichier.
• « Separe_lignes » avec en argument la liste précédente et qui renvoie la liste avec les lignes séparées.
• « creation_liste » qui créera la liste voulue en enlevant les champs inutiles.
• « classement_annee » permettra de ne garder que les lignes de l’année courante.
• « nouveau_fichier » qui écrira les lignes de l’année dans un nouveau fichier créé pour l’occasion.


Activité 1 : Présentation et découverte du format csv

Strava est un site qui est utilisé pour enregistrer des activités sportives. Les membres du site peuvent partager leurs activités préalablement enregistrées via GPS. En cyclisme et en course à pied, il existe des segments de route chronométrés où les athlètes peuvent se concurrencer. Nous travaillerons sur un fichier contenant les performances d’une montée du Mont-Ventoux, réalisée en cyclisme.
Les données sont alors disponibles et téléchargeables dans un fichier au format csv. Un fichier csv est un fichier texte, représentant des données tabulaires sous forme de valeurs séparées par des virgules, tabulations ou points-virgules. Les lignes sont séparées par un retour à la ligne matérialisé par un « \n ».


Dans notre cas, ouvrir le fichier « liste_origine.csv » avec un éditeur de texte, et indiquer quel est le séparateur utilisé :
Séparateur : ?
Quels champs (étiquettes des colonnes) contient-il ?
?
Nous souhaitons traiter ce fichier, en ne gardant uniquement que les performances de l’année en cours et en séparant le nom du prénom car dans le champ « nom » il y a les 2, mais également en supprimant les champs qui ne nous intéressent pas (« Vitesse », « HR », « Puissance », « Vit. Ascens. » et « Temps »)
Pour cela, il faudra dans un premier temps récupérer les lignes contenues dans le fichier de départ et les placer dans une liste exploitable.

Activité 2 : Récupération des lignes du fichier de départ

Écrire une fonction « import_lignes » qui prend en argument un nom de fichier (on testera avec le nôtre « liste_origine.csv ») et qui renvoie la liste des lignes du fichier, c’est-à-dire une liste de chaînes de caractères, où chaque élément de la liste correspond à une ligne du fichier. Il faudra bien penser à fermer le fichier avant de faire le return ! Tester votre fonction en affichant le résultat de la liste créée.

un peu d’aide fiche

et toujours fiche mémo


Activité 3 : Séparation des lignes

Écrire une fonction « separe_lignes » qui prend en argument une chaine de caractère et qui renvoie une liste contenant les chaînes de caractères correspondants aux champs de notre fichier.

(par exemple: separe_lignes(’28;David POLVERONI;21/09/2012;17,7km/h;166bpm;300W;1368,0;01:05:56;3956\n’) renvoie une liste =[’28’, ‘David POLVERONI’, ’21/09/2012′, ‘17,7km/h’, ‘166bpm’, ‘300W’, ‘1368,0’, ’01:05:56′, ‘3956’] Elle sera obtenue en séparant la ligne le long des points-virgules. Pour cela, aidez-vous de la propriété « chaine_caractere.strip » qui permet d’enlever un éventuel \n (retour à la ligne) et/ou des espaces à la fin de la chaine de caractère, ainsi que de la propriété  » chaine_caractere .split(« ; ») » qui sépare la ligne à chaque fois qu’un point-virgule est rencontré…

aide sur les méthodes s’appliquant au string w3schools


Activité 4 : Création d’un dictionnaire dico_coureur

Écrire une fonction « creation_dico » qui prend en argument une ligne (chaîne de caractères) et qui renvoie un dictionnaire correspondant au cycliste de la ligne, en omettant les champs non retenus (« Vitesse », « HR », « Puissance », « Vit. Ascens. » et « Temps »)…
Exemple de résultat : creation_dico(‘2;Romain Bardet;17/06/2019;19,9km/h;-;-;1\xa0539,7;00:58:35;3515\n’) doit renvoyer : {‘classement’: ‘2’, ‘nomcomplet’: ‘Romain Bardet’, ‘date’: ’17/06/2019′, ‘temps_s’: ‘3515’} , si vous voulez séparer la clé nomcomplet en deux clé prenom et nom.

Activité 5 : Création d’une liste de dictionnaire

Écrire une fonction « liste_perf » qui prend en argument un nom de fichier et qui renvoie une liste de dictionnaire des performances correspondant aux lignes du fichier ( en omettant la première ligne).

Exemple de résultat: liste_perf (‘liste_origine.csv’) doit renvoyer : une liste de dictionnaire:

[{‘classement’: ‘1’, ‘nomcomplet’: ‘Laurens ten Dam’, ‘date’: ’14/07/2013′, ‘temps_s’: ‘3497’}, {‘classement’: ‘2’, ‘nomcomplet’: ‘Romain Bardet’, ‘date’: ’17/06/2019′, ‘temps_s’: ‘3515’}, {‘classement’: ‘3’, ‘nomcomplet’: ‘Rein Taaramae’, ‘date’: ’17/06/2019′, ‘temps_s’: ‘3583’}, {‘classement’: ‘4’, ‘nomcomplet’: ‘El Fares Julien’, ‘date’: ’17/06/2019′, ‘temps_s’: ‘3607’},…… , {‘classement’: ’28’, ‘nomcomplet’: ‘David POLVERONI’, ‘date’: ’21/09/2012′, ‘temps_s’: ‘3956’}]


Activité 6 : Création d’une liste de dictionnaire

Écrire une fonction « classement_annee » qui prend en argument la liste de dictionnaire précédemment créée et qui renvoie une nouvelle liste contenant uniquement les performances de l’année 2019. Pour cela, vous devrez vous aider de la liste créer lors de l’activité précédente , pour rechercher l’année dans la date vous devrez utiliser la propriété .split(‘/’), vue précédemment !
Exemple de résultat : classement_annee([{‘classement’: ‘1’, ‘prenom’: ‘Laurens’, ‘nom’: ‘ten’, ‘date’: ’14/07/2013′, ‘temps_s’: 3497}, {‘classement’: ‘2’, ‘prenom’: ‘Romain’, ‘nom’: ‘Bardet’, ‘date’: ’17/06/2019′, ‘temps_s’: 3515}])

doit renvoyer : [{‘classement’: ‘2’, ‘prenom’: ‘Romain’, ‘nom’: ‘Bardet’, ‘date’: ’17/06/2019′, ‘temps_s’: 3515]

Si vous voulez vous pouvez ajouter l’année de tri en argument, et trié ainsi en fonction de l’année donnée en argument.


Pour aller plus loin : Écriture dans un nouveau fichier

On souhaite enfin réécrire tous ces résultats dans un nouveau fichier « classement_2019.csv ». Pour cela, écrire une fonction « nouveau_fichier » qui prend en argument la liste précédente et qui va l’écrire ligne à ligne dans le fichier « classement_2019.csv » en insérant des points-virgules entre les champs. La première ligne du fichier devra être :  » ‘classement;prenom;nom;date;temps_s;’+’\n’ « 

Exercice 3 : Dictionnaire

Stock de fruits

Dans cet exercice, nous allons gérer un stock de fruits qui sera représenté par un dictionnaire, dont les clés seront les noms de fruits (au singulier), et les valeurs seront le nombre de fruits correspondant dans le stock. Par exemple, si le stock contient 2 pommes et 6 bananes, il sera représenté par le dictionnaire suivant: {‘pomme’ : 2, ‘banane’ : 6}. Pour simplifier l’écriture des exemples, on supposera que ce dictionnaire sera stocké dans une variable appelée stock.

Dans tout l’exercice, le(s) dictionnaire(s) passé(s) en argument ne doi(ven)t pas être modifié(s).

Vous n’êtes pas obligés de traiter les questions dans l’ordre.

  1. Ecrire une fonction ajoute1 qui prend en argument un stock (dictionnaire) et un nom de fruit, et qui renvoie le nouveau stock, dans lequel un fruit du type donné a été ajouté.
    Test:
    • ajoute1(stock , 'pomme') renvoie {'pomme' : 3, 'banane' : 6}
    • ajoute1(stock , 'poire') renvoie {'pomme' : 2, 'banane' : 6, 'poire' : 1}
  2. Ecrire une fonction enleve1 qui prend en argument un stock (dictionnaire) et un nom de fruit, et qui renvoie le nouveau stock, où un fruit du type donné a été enlevé (s’il y avait un stock suffisant). Si le stock de ce fruit tombe à zéro, il faut enlever la clé du dictionnaire. Si le stock n’était pas suffisant, le programme affichera « Erreur: quantité insuffisante de (*nom du fruit*) » et renverra le stock initial non modifié.
    Test:
    • enleve1(stock , 'pomme') renvoie {'pomme' : 1, 'banane' : 6}
    • enleve1(stock , 'poire') affiche « Erreur: Quantité insuffisante de poire » et renvoie {‘pomme’ : 2, ‘banane’ : 6}
  3. Ecrire une fonction ajoute qui prend en argument un stock (dictionnaire), un nom de fruit et une quantité q, et qui renvoie le nouveau stock, dans lequel on a ajouté une quantité q du type de fruit précisé.
    Test:
    • ajoute(stock , 'pomme', 5) renvoie {‘pomme’ : 7, ‘banane’ : 6}
    • ajoute(stock , 'poire', 4) renvoie {‘pomme’ : 2, ‘banane’ : 6, ‘poire’ : 4}
  4. Ecrire une fonction enleve qui prend en argument un stock (dictionnaire), un nom de fruit et une quantité q, et qui renvoie le nouveau stock où l’on a enlevé la quantité q du type de fruit précisé. De même que pour la fonction enleve1, si le stock de ce fruit tombe à zéro, il faut enlever la clé du dictionnaire. Si le stock n’était pas suffisant, le programme affichera « Erreur: quantité insuffisante de (*nom du fruit*) » et renverra le stock initial non modifié.
    Test:
    • enleve(stock , 'pomme', 2) renvoie {'banane' : 6}
    • enleve(stock , 'banane', 10) affiche « Erreur: Quantité insuffisante de banane » et renvoie {‘pomme’ : 2, ‘banane’ : 6}
  5. Ecrire une fonction apres_livraison qui prend en argument un stock (dictionnaire) ainsi que le contenu de la livraison (représenté aussi par un dictionnaire) et qui renvoie le nouveau stock après la livraison.
    Test:
    • apres_livraison(stock , {'peche' : 4, 'pomme' : 5}) renvoie {‘pomme’ : 7, ‘banane’ : 6, ‘peche’ : 4}
  6. Ecrire une fonction commande qui prend en argument le stock actuel (dictionnaire) ainsi que le stock minimum voulu (dictionnaire aussi) et qui renvoie le dictionnaire correspondant à la commande qu’il faut faire pour obtenir le stock voulu. Si le fruit apparaît déjà en quantité suffisante dans le stock actuel (supérieure ou égal au stock voulu), il ne doit pas apparaître dans la commande.
    Test:
    • En supposant que stock_voulu={'pomme': 15, 'orange': 20}, alors commande(stock , stock_voulu) renvoie {‘pomme’ : 13, ‘orange’ : 20}.
    • En supposant que stock_voulu={'pomme': 10, 'banane': 4}, alors commande(stock , stock_voulu) renvoie {‘pomme’ : 8}.
  7. Ecrire une fonction total qui prend en argument le stock et qui renvoie le nombre total de fruits présents dans le stock (tous types confondus)
    Test:
    • total(stock) renvoie 8.
  8. Ecrire une fonction quantite qui prend en argument le stock ainsi qu’une liste de noms de fruits fruits_a_compter, et qui renvoie la quantité de fruits présents dans le stock dont le nom est dans la liste fruits_a_compter.
    Test:
    • En supposant que stock_bis={'pomme': 15, 'peche': 4, 'citron': 3, 'orange': 20}, alors quantite(stock_bis , ['pomme', 'citron', 'poire']) renvoie 18.
  9. Ecrire une fonction quantite_agrumes qui prend en argument le stock et qui renvoie la quantité d’agrumes présents dans le stock. Seront considérés comme noms d’agrumes: orange, citron, mandarine, clémentine (sans accent dans le code) et pamplemousse.
    Test:
    • En supposant que stock_bis={'pomme': 15, 'peche': 4, 'citron': 3, 'orange': 20}, alors quantite_agrumes(stock_bis) renvoie 23.