Baccalauréat général — Session 2026

Numérique et Sciences Informatiques
Épreuve de l'enseignement de spécialité — Partie pratique

Classe Terminale — Voie générale Sujet Bibliothèque Durée : 1 heure

Cette situation d'évaluation comporte ce document ainsi que des fichiers de codes et de données présents sur l'ordinateur à la disposition du candidat. Le candidat doit restituer ce document avant de sortir de la salle d'examen. Le candidat doit agir en autonomie et faire preuve d'initiative tout au long de l'épreuve.

En cas de difficulté, le candidat peut solliciter l'examinateur afin de lui permettre de continuer la tâche. Des moments privilégiés pour solliciter l'examinateur sont indiqués dans le document sous la forme d'appels professeur. L'examinateur peut intervenir à tout moment, s'il le juge utile.

Cadre

Une bibliothèque municipale utilise une base de données pour gérer ses collections, ses adhérents et les emprunts de livres. La bibliothécaire souhaite améliorer son service en automatisant les rappels de retour par SMS.

Objectif

La durée maximale d'emprunt d'un livre est de 14 jours. Passé ce délai, les adhérents n'ayant pas rendu leur livre reçoivent des rappels par SMS. La bibliothécaire dispose d'une plateforme d'envoi de SMS, mais il est nécessaire de préparer les données et les messages à envoyer.

Pour cela, on devra extraire depuis la base de données la liste des emprunts en retard (livres non rendus, empruntés depuis plus de 14 jours), puis contacter chaque adhérent par SMS sur son téléphone portable.

Description de la base de données

Le logiciel mis en œuvre par la bibliothèque utilise 3 tables pour enregistrer les livres, les adhérents et les emprunts.

emprunt
id : int
id_livre : int
id_adherent : int
date_emprunt : str (AAAAMMJJ)
date_retour : str (AAAAMMJJ)
livre
id : int
titre : str
auteur : str
genre : str
adherent
id : int
nom : str
prenom : str
telephone : str
clef primaire clef étrangère

Note : le champ date_retour est NULL tant que le livre n'a pas été rendu.

Extraits de la base de données

Table adherent
idnomprenomtelephone
1MartinAlice06 12 34 56 78
2DupontBernard07.89.01.23.45
3LeroyClaire(0)6.55.44.33.22
Table livre
idtitreauteurgenre
1DuneFrank Herbertscience-fiction
21984George Orwellscience-fiction
6Sherlock HolmesA.C. Doylepolicier
Table emprunt
idid_livreid_adherentdate_empruntdate_retour
11120251110NULL
22120251026NULL
5522025092720251004

Rappels techniques

Le système de gestion de base de données utilisé est SQLite, accessible via le module sqlite3 de la bibliothèque standard Python.

Connexion et exécution de requêtes :

DB_PATH = "biblio.sqlite"
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()

resultats = cursor.execute(
    "SELECT id, titre FROM livre ORDER BY titre LIMIT 5"
)
# resultats est itérable, chaque élément est un tuple
for r in resultats:
    print("id:", r[0], ", titre:", r[1])

Passage de paramètre dans une requête SQL :

resultat = cursor.execute(
    """SELECT titre FROM livre
    WHERE genre = ? ORDER BY titre""",
    ("policier",)
)

Les clauses SQL à utiliser sont : SELECT, FROM, JOIN, ON, WHERE, IS NULL, ORDER BY

Rappel sur les dates : les dates sont stockées au format AAAAMMJJ (ex. : 20251101 pour le 1er novembre 2025). Ce format permet de comparer des dates directement avec les opérateurs <, >, = dans SQL et en Python.

Numéros de téléphone

La plateforme d'envoi de SMS requiert un numéro de téléphone au format 06XXXXXXXX ou 07XXXXXXXX — 10 chiffres au total, sans espace, ni point, ni autre caractère. Malheureusement, les téléphones ont été enregistrés sans distinction entre mobiles et fixes, et avec des formats variés : "(0)6 12 34 56 78", "07.89.01.23.45", "0623145896 dupuis"

Rappel : on peut utiliser la méthode isdigit() de la classe str pour déterminer si un caractère est un chiffre.

>>> '3'.isdigit()
True
>>> 'A'.isdigit()
False
Question 1 — Nettoyage des numéros de téléphone

Écrire une fonction Python normalisation_tel qui prend un numéro de téléphone tel de type str en argument et renvoie le numéro nettoyé en ne conservant que les chiffres. Exemples :

normalisation_tel("(0)6.55.44.33.22")  # renvoie "0655443322"
normalisation_tel("07.89.01.23.45")    # renvoie "0789012345"
normalisation_tel("0623145896 dupuis") # renvoie "0623145896"

Une fonction test_normalisation_tel est fournie dans le fichier biblio.py.

✋ Appel professeur — présentez votre réponse ou signalez une difficulté

Validation des numéros de téléphone

La fonction validation_tel(tel) prend comme argument un numéro de téléphone normalisé et renvoie un booléen selon que ce numéro est un numéro de téléphone portable français valide ou non (commence par 06 ou 07, exactement 10 chiffres).

Question 2 — Tests de la fonction validation_tel

Écrire un jeu de tests permettant de vérifier le bon fonctionnement de la fonction validation_tel fournie. Le jeu de tests devra couvrir au minimum les cas suivants :

  • un numéro portable valide commençant par 06
  • un numéro portable valide commençant par 07
  • un numéro fixe (ne commence pas par 06 ou 07)
  • un numéro trop court ou trop long
✋ Appel professeur — présentez votre réponse ou signalez une difficulté

Détermination de la liste des emprunts en retard

Pour pouvoir envoyer les rappels, la bibliothécaire doit d'abord identifier les adhérents concernés à partir de la base de données.

On commencera par extraire tous les emprunts en retard via la fonction emprunts_en_retard(date), puis on déterminera pour chaque adhérent son emprunt le plus récent (le livre qu'il a pris en dernier, qui est donc celui dont le retour est le plus urgent).

Interrogation de la base de données

La fonction emprunts_en_retard(date) doit récupérer tous les emprunts de livres non rendus dont la date d'emprunt est strictement antérieure à la date date (format AAAAMMJJ).

On souhaite récupérer les champs suivants :

Le résultat sera trié par id_adherent puis par date_emprunt croissants.

Question 3 — Fonction emprunts_en_retard(date)

En vous inspirant de la fonction adherents_livres_empruntes_apres(date) déjà fournie dans biblio.py, écrire la fonction emprunts_en_retard(date).

Des tests sont fournis dans la fonction test_emprunts_en_retard — votre fonction doit les passer.

✋ Appel professeur — présentez votre réponse ou signalez une difficulté

Détermination de l'emprunt le plus récent par adhérent

Un adhérent peut avoir plusieurs livres en retard simultanément. Pour lui envoyer un seul SMS, on souhaite identifier son emprunt le plus récent (la date d'emprunt la plus grande), qui correspond au livre pris en dernier.

La fonction emprunt_le_plus_recent(emprunts) prend en paramètre une liste d'emprunts sous la forme :

(id_emprunt, titre_livre, tel_adherent, date_emprunt)

Elle doit renvoyer un dictionnaire dont la clef est le numéro de téléphone de l'adhérent, et la valeur associée est le tuple correspondant à son emprunt le plus récent.

Exemple : pour Alice Martin, qui a deux emprunts en retard :

(60, "Fahrenheit 451", "06 12 34 56 78", "20250928"),
(2,  "1984",           "06 12 34 56 78", "20251026"),

Son emprunt le plus récent est 1984 (emprunté le 20251026), donc le dictionnaire doit contenir :

{
  "06 12 34 56 78": (2, "1984", "06 12 34 56 78", "20251026"),
  ...
}

Cependant, la fonction fournie dans biblio.py contient un bug : les tests de test_emprunt_le_plus_recent échouent.

Question 4 — Identification et correction du bug

a) Expliquer le problème rencontré dans la fonction emprunt_le_plus_recent : quel est le bug, et pourquoi produit-il un résultat incorrect ?

b) Corriger la fonction pour qu'elle passe les tests avec succès.

✋ Appel professeur — présentez votre réponse ou signalez une difficulté

Description du dossier

Le dossier fourni au candidat sur l'ordinateur comporte les éléments suivants :

Environnement de travail

Pour faire fonctionner le code fourni, la bibliothèque sqlite3 doit être disponible (elle fait partie de la bibliothèque standard Python — aucune installation supplémentaire n'est nécessaire).

Éditeur conseillé : Thonny ou tout éditeur Python disponible sur le poste.

Lycée Antoine Watteau — Valenciennes — NSI Terminale — Épreuve pratique — DarkSATHI Li