TP done async/sync

This commit is contained in:
Johan
2025-12-15 16:05:03 +01:00
parent f042f8e3e2
commit cac4fd62bb
3 changed files with 54 additions and 59 deletions

3
.idea/misc.xml generated
View File

@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Poetry (m01_tp01_asyncio)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Poetry (m01_tp01_asyncio)" project-jdk-type="Python SDK" />
</project>

View File

@@ -74,21 +74,23 @@ async def download_and_save(
url (str): l'URL de l'image à télécharger.
output_dir (Path): le répertoire où sauvegarder l'image.
"""
# TODO : votre code ici. Similaire à la version synchrone, mais avec `async`/`await`.
# 1. Utilisez un bloc `try...except` pour gérer les erreurs (ClientError, asyncio.TimeoutError, IOError).
#
# 2. Dans le bloc `try` :
# a. Extrayez le nom du fichier et construisez le chemin de sauvegarde (comme avant).
# b. Logguez le début du téléchargement.
# c. Utilisez `async with session.get(url) as response:` pour effectuer la requête.
# d. Vérifiez le statut de la réponse avec `response.raise_for_status()`.
# e. Lisez le contenu de la réponse de manière asynchrone : `data = await response.read()`.
# f. Utilisez `async with aiofiles.open(path, "wb") as f:` pour ouvrir le fichier
# sans bloquer la boucle événementielle.
# g. Écrivez les données dans le fichier : `await f.write(data)`.
# h. Logguez la confirmation de la sauvegarde.
#
# 3. Dans les blocs `except`, logguez les erreurs spécifiques.
filename = None
try:
filename = url.split("/")[-1]
output_path = output_dir / filename
logging.debug(f"Début du téléchargement -> {url}")
async with session.get(url, timeout=30) as response:
response.raise_for_status()
content = await response.read()
logging.debug(f"Sauvegarde de {filename} sur {output_path}")
async with aiofiles.open(output_path, "wb") as f:
await f.write(content)
logging.info(f"Image {filename} sauvegardée !")
except ClientError as e:
logging.error(f"Erreur {url}: {e}")
except IOError as e:
file_ref = f"le fichier {filename}" if filename else "un fichier"
logging.error(f"Erreur d'écriture pour {file_ref}: {e}")
async def main() -> None:
@@ -103,19 +105,16 @@ async def main() -> None:
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
logging.info(f"Le répertoire de sortie est : {OUTPUT_DIR}")
# TODO : votre code ici. C'est ici que la magie de l'asynchronisme opère.
# 1. Créez une session client avec `async with aiohttp.ClientSession() as session:`.
#
# 2. À l'intérieur du `async with`, créez une liste de "tâches". Chaque tâche
# est un appel à votre coroutine `download_and_save`.
# Astuce : une compréhension de liste est parfaite pour ça.
# Exemple : `tasks = [download_and_save(session, url, OUTPUT_DIR) for url in IMG_URLS]`
#
# 3. Utilisez `asyncio.gather()` pour lancer toutes les tâches en parallèle et
# attendre qu'elles se terminent toutes.
# La syntaxe est : `await asyncio.gather(*tasks)`
# (L'étoile `*` dépaquette la liste de tâches en arguments pour `gather`).
start_time = time.perf_counter()
async with aiohttp.ClientSession() as session:
tasks = [download_and_save(session, url, OUTPUT_DIR) for url in IMG_URLS]
await asyncio.gather(*tasks)
end_time = time.perf_counter()
duration = end_time - start_time
logging.info("-" * 40)
logging.info("Tous les téléchargements sont terminés !")
logging.info(f"Temps total d'exécution : {duration:.2f} secondes !")
logging.info("-" * 40)
if __name__ == "__main__":

View File

@@ -64,25 +64,20 @@ def download_and_save(session: requests.Session, url: str, output_dir: Path) ->
url (str): L'URL de l'image à télécharger.
output_dir (Path): Le répertoire où sauvegarder l'image.
"""
# TODO : votre code ici. Suivez ces étapes :
# 1. Utilisez un bloc `try...except` pour gérer les erreurs potentielles
# (RequestException, IOError).
#
# 2. Dans le bloc `try` :
# a. Extrayez le nom du fichier à partir de l'URL.
# Astuce : `url.split("/")[-1]` est une méthode simple.
# b. Construisez le chemin de sauvegarde complet en utilisant `pathlib`.
# Exemple : `output_dir / nom_du_fichier`
# c. Logguez le début du téléchargement.
# d. Effectuez une requête GET avec `session.get(url)`. Pensez à ajouter un timeout.
# e. Vérifiez que la requête a réussi avec `response.raise_for_status()`.
# f. Ouvrez le fichier de destination en mode écriture binaire ('wb')
# en utilisant un `with open(...)`.
# g. Écrivez le contenu de la réponse (`response.content`) dans le fichier.
# h. Logguez la confirmation de la sauvegarde.
#
# 3. Dans les blocs `except`, logguez l'erreur de manière descriptive
# (ex: `logging.error(...)`).
filename = None
try:
filename = url.split("/")[-1]
output_path = output_dir / filename
response = session.get(url, timeout=30)
response.raise_for_status()
with open(output_path, "wb") as f:
f.write(response.content)
logging.info(f"Image {filename} sauvegardée !")
except RequestException as e:
logging.error(f"Erreur {url}: {e}")
except IOError as e:
file_ref = f"le fichier {filename}" if filename else "un fichier"
logging.error(f"Erreur d'écriture pour {file_ref}: {e}")
def main() -> None:
@@ -100,20 +95,18 @@ def main() -> None:
# `exist_ok=True` évite une erreur si le répertoire existe déjà.
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
logging.info(f"Le répertoire de sortie est : {OUTPUT_DIR}")
start_time = time.perf_counter()
# TODO : votre code ici. Suivez ces étapes :
# 1. Utilisez un gestionnaire de contexte `with requests.Session() as session:`
# pour créer une session qui sera utilisée pour toutes les requêtes.
# Ceci optimise les connexions réseau.
#
# 2. À l'intérieur du `with`, faites une boucle `for` sur la liste `IMG_URLS`.
#
# 3. Dans la boucle, appelez la fonction `download_and_save()` pour chaque URL,
# en lui passant la session, l'URL et le répertoire de sortie.
with requests.Session() as session:
for url in IMG_URLS:
logging.info(f"Téléchargement de {url}...")
download_and_save(session, url, OUTPUT_DIR)
end_time = time.perf_counter()
duration = end_time - start_time
logging.info("-" * 40)
logging.info("Téléchargement terminé !")
logging.info(f"Temps total d'exécution : {duration:.2f} secondes !")
logging.info("-" * 40)
if __name__ == "__main__":
main()