Files
ENI-PythonAdvanced_05/README.md
2025-12-16 14:18:21 +01:00

257 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TP : Galerie d'images (flask)
## Informations générales
**Cours** : Python Avancé > Web > Flask \
**Objectifs pédagogiques** :
- Python avancé : framework Flask pour le développement web
- Outils modernes (poetry, PyCharm)
- Bonnes pratiques de l'entreprise
---
## Prérequis
### Installation et configuration de lenvironnement
Installer les dépendances avec `poetry install` depuis un terminal PyCharm.
### Connaissances préalables
- Connaissances de base en programmation
---
## Énoncé
### Contexte
L'objectif de ce TP Bonus est de développer une application web simple mais robuste avec le micro-framework Flask.
Vous êtes invité à lire les premières sections de la [documentation officielle de Flask](https://flask.palletsprojects.com/en/stable/quickstart/) pour vous familiariser avec les concepts de base, avant de commencer le TP.
Cette application web affichera une galerie d'images à partir de fichiers stockés localement sur le serveur.
Les images étant fournies par le serveur avec différentes largeurs, cela permettra au client d'optimiser la performance réseau en fonction de la taille de l'image réelle à afficher côté client (navigateur).
Pour vous concentrer sur la logique métier et le fonctionnement de Flask, une partie significative du code vous est déjà fournie :
* Les **templates HTML** (`layout.html`, `gallery.html`, `404.html`) qui gèrent l'affichage.
* Les **fichiers statiques** (CSS Bootstrap) pour le design, ainsi que les images statiques.
* Un module utilitaire `utils.py` contenant une fonction `build_image_structure` qui analyse et structure les données du répertoire contenant les images.
* Une suite de **tests automatisés** (`test_app.py`) qui vous permettra de valider votre travail au fur et à mesure.
Votre mission est de compléter le fichier `src/app/views.py` pour faire le lien entre les requêtes des utilisateurs, les données des images et les templates HTML.
### Objectifs pédagogiques
À la fin de ce TP, vous saurez :
* Créer et organiser des routes (vues) dans une application Flask à l'aide de Blueprints.
* Faire le rendu de templates HTML en leur transmettant des données dynamiques (`render_template`).
* Gérer les erreurs de manière élégante (`try...except`) pour rendre une application plus robuste.
* Créer un premier endpoint d'API simple qui retourne des données au format JSON.
* Utiliser une suite de tests (Pytest) pour guider et valider votre développement (approche TDD-lite).
* Lancer et déboguer une application Flask localement.
### Mise en place
Le projet utilise `poetry` pour la gestion des dépendances.
La structure du projet est la suivante :
```
.
├── poetry.lock
├── pyproject.toml
├── src
│ └── app
│ ├── __init__.py # Point d'entrée de l'application
│ ├── static/ # Fichiers CSS, et images
│ ├── templates/ # Fichiers HTML (templates Jinja2)
│ ├── utils.py # Fonctions utilitaires (fourni)
│ └── views.py # Le fichier à compléter !
└── tests
└── test_views.py # Tests pour valider votre code (fourni)
```
### Travail à réaliser
Ouvrez le fichier `src/app/views.py`. Il est actuellement presque vide. Vous allez le compléter étape par étape.
#### Étape 1 : afficher la galerie d'images
Votre premier objectif est de créer la vue principale qui affiche la galerie.
**Tâche :** Créez une fonction `index()` qui répond à la route `/` (la racine du site).
**Logique à implémenter dans la fonction `index()` :**
1. Construisez le chemin vers le dossier contenant les images. Ce dossier se trouve dans `static/images`. Utilisez `current_app.static_folder` de Flask et la bibliothèque `pathlib` pour un code propre et portable.
2. Appelez la fonction `build_image_structure()` (importée depuis `.utils`) en lui passant le chemin du dossier des images.
3. **Rendez votre code robuste !** Encadrez l'appel à cette fonction dans un bloc `try...except`. En cas d'erreur (par exemple, si le dossier n'existe pas ou si un autre problème survient), vous devez éviter que l'application ne plante.
* En cas de succès, vous passez les données des images au template.
* Si aucune image n'est trouvée par la fonction, prévoyez un message d'erreur à afficher.
* En cas d'exception, logguez l'erreur et préparez un message d'erreur générique pour l'utilisateur.
4. Faites le rendu du template `gallery.html` en utilisant `render_template()`. Vous devez lui passer deux variables :
* `structured_images`: Le dictionnaire d'images retourné par `build_image_structure`.
* `error_message`: Un message d'erreur (ou `None` si tout va bien).
**Diagramme de flux (Étape 1) :**
```mermaid
graph TD
subgraph Client[Navigateur]
A[Utilisateur]
end
subgraph Serveur[Serveur Flask]
B["Route /"]
C["views.py: index()"]
D["utils.py: build_image_structure()"]
E["templates/gallery.html"]
F[Réponse HTML]
end
subgraph SystemeFichiers[Disque Serveur]
G["static/images"]
end
A -- "1. Requête GET /" --> B
B -- "2. Déclenche" --> C
C -- "3. Construit chemin et appelle" --> D
D -- "4. Lit le dossier" --> G
G -- "5. Retourne la structure" --> D
D -- "6. Retourne dict_images" --> C
C -- "7. Injecte données dans" --> E
E -- "8. Génère" --> F
F -- "9. Envoie" --> A
```
**Logique de gestion d'erreur (commune aux étapes 1 et 4) :**
```mermaid
graph TD
A[Début de la vue] --> B{try}
B -- "Succès" --> C["Appel: build_image_structure()"]
C --> D{Images trouvées?}
D -- "Oui" --> E[Préparer réponse 200 OK - HTML ou JSON]
D -- "Non" --> F[Préparer réponse - HTML avec erreur ou JSON 404]
B -- "Échec" --> G[except Exception as e]
G --> H[Logguer l'erreur e]
H --> I[Préparer réponse - HTML avec erreur ou JSON 500]
E --> Z[Fin]
F --> Z[Fin]
I --> Z[Fin]
```
#### Étape 2 : valider avec les tests
Avant même de regarder le résultat dans votre navigateur, vérifiez que votre code est correct en lançant la suite de tests.
```bash
poetry run pytest -p no:warnings
```
Analysez le résultat. Certains tests qui échouaient au début devraient maintenant passer. L'objectif est de faire passer tous les tests relatifs à la galerie.
#### Étape 3 : lancer le serveur et constater le résultat
Une fois les tests au vert, lancez le serveur de développement Flask.
1. Assurez-vous d'être dans le bon dossier :
```bash
cd src
```
2. Lancez le serveur en mode "debug" (ce mode recharge automatiquement le serveur à chaque modification de votre code) :
```bash
flask run --debug
```
3. Ouvrez votre navigateur à l'adresse [http://127.0.0.1:5000](http://127.0.0.1:5000) et admirez votre galerie !
#### Étape 4 : créer un endpoint d'API JSON
Votre second objectif est de fournir les mêmes données via une API, au format JSON.
**Tâche :** Créez une fonction `api_images()` qui répond à la route `/api/images`.
**Logique à implémenter :**
1. La logique de récupération des données est la même que pour la vue `index()` : chemin du dossier, appel à `build_image_structure()`, gestion des exceptions.
2. La différence réside dans la réponse :
* En cas de succès, retournez directement le dictionnaire `structured_images`. Flask le convertira automatiquement en une réponse JSON avec un code de statut `200 OK`.
* Si aucune image n'est trouvée, retournez un dictionnaire d'erreur (ex: `{'error': "Aucune image n'a été trouvée"}`) et le code de statut `404 Not Found`.
* En cas d'exception serveur, retournez un dictionnaire d'erreur (ex: `{'error': "Erreur interne du serveur"}`) et le code de statut `500 Internal Server Error`.
**Diagramme de flux (Étape 4) :**
```mermaid
graph TD
subgraph Client[Client API ex: Postman, script]
A[Utilisateur/Service]
end
subgraph Serveur[Serveur Flask]
B[Route /api/images]
C["views.py: api_images()"]
D["utils.py: build_image_structure()"]
E[Réponse JSON]
end
subgraph SystemeFichiers[Disque Serveur]
G["static/images"]
end
A -- "1. Requête GET /api/images" --> B
B -- "2. Déclenche" --> C
C -- "3. Construit chemin et appelle" --> D
D -- "4. Lit le dossier" --> G
G -- "5. Retourne la structure" --> D
D -- "6. Retourne dict_images" --> C
C -- "7. Formate en JSON" --> E
E -- "8. Envoie" --> A
```
#### Étape 5 : ajouter un ou plusieurs tests pour l'API
Pour aller plus loin, ouvrez le fichier `tests/test_app.py` et ajoutez un ou plusieurs nouveaux tests pour votre API.
**Idée de test :**
Créez une fonction `test_api_images_success()` qui :
1. Fait un `GET` sur `/api/images`.
2. Vérifie que le code de statut est bien `200`.
3. Vérifie que le `content_type` de la réponse est bien `application/json`.
4. Vérifie que la réponse JSON contient des clés attendues (par exemple, le nom d'une des images).
Relancez les tests pour vous assurer que l'ancien et le nouveau code fonctionnent parfaitement.
### Bonnes pratiques
* La page d'accueil (`/`) s'affiche correctement avec les images. Les images téléchargées par le navigateur sont cohérentes avec la taille réelles des images à afficher.
* La page gère correctement l'absence du dossier d'images sans planter, en affichant un message d'erreur.
* L'endpoint `/api/images` retourne une structure JSON valide en cas de succès.
* L'endpoint `/api/images` retourne les codes d'erreur HTTP et les messages appropriés (404, 500).
* L'ensemble des tests fournis (et les vôtre) passent avec succès.
* Le code dans `views.py` est clair, commenté et suit les bonnes pratiques Python.