07 — Générateur de mots de passe
Niveau requis : 4 (fonctions, paramètres) / Difficulté : 2/5 / Durée estimée : 1–2 h
Objectif
Le programme génère des mots de passe aléatoires sur mesure : l'utilisateur choisit la longueur et les familles de caractères (minuscules, majuscules, chiffres, symboles), et obtient un ou plusieurs mots de passe.
Longueur (8-64) : 16
Majuscules ? (o/n) : o
Chiffres ? (o/n) : o
Symboles ? (o/n) : n
Combien de mots de passe ? 3
kR8mtwQ2nXbfP4ae
J7cVpz9qLsWm3dHu
x2NfB6ykUcT8rGwa
Le vrai sujet du projet n'est pas le hasard : c'est la conception de fonctions — qui décide quoi, qui reçoit quoi, qui retourne quoi.
Notions utilisées
- Fonctions : paramètres, valeurs par défaut,
return— niveau 4 - Séparation logique / entrées-sorties : la génération ne fait aucun
input()/print()— niveau 4 - Module
random:random.choice()— vu au niveau 2, approfondi ici - Constantes de
string:string.ascii_lowercase,ascii_uppercase,digits,punctuation— niveau 4 (découverte de la stdlib) - Boucles
foret construction de chaîne — niveaux 2–3
Cahier des charges
- Fichier
password_generator.py. - Fonction cœur :
generate_password(length, use_upper=True, use_digits=True, use_symbols=False)qui retourne une chaîne. Elle ne lit rien au clavier, n'affiche rien. - Les minuscules sont toujours incluses ; les trois autres familles sont optionnelles via les paramètres.
- Longueur acceptée : 8 à 64. Hors bornes → l'utilisateur est redemandé (dans la partie interface, PAS dans
generate_password). - Garantie de composition : si une famille est activée, le mot de passe contient AU MOINS un caractère de cette famille. (C'est le point difficile du projet — voir étape 5.)
- Le programme peut générer N mots de passe d'un coup.
- Honnêteté technique, à mettre en commentaire en haut du fichier :
randomn'est pas cryptographiquement sûr ; pour de vrais secrets, Python fournit le modulesecrets(extension 3).
Étapes de construction
- Sans fonction ni options : construis un pool
string.ascii_lowercaseet génère une chaîne de 12 caractères avec une boucle etrandom.choice().print()du résultat. Lance plusieurs fois : ça change. - Emballe ce code dans
generate_password(length)et appelle-la depuis le bas du fichier avec plusieurs longueurs. Vérifielen()des résultats. - Ajoute les paramètres
use_upper,use_digits,use_symbols(défauts raisonnables) : le pool se construit par concaténation conditionnelle. Teste chaque combinaison en appelant la fonction directement — pas encore de menu, c'est plus rapide à tester ainsi. - Écris l'interface : questions
input(), conversion des réponseso/nen booléens, validation de la longueur en boucle, puis appel de la fonction et affichage. Le programme complet tourne. - Implémente la garantie de composition : tire d'abord UN caractère de chaque famille active, complète avec le pool général, puis mélange (
random.shuffle()travaille sur une liste — passe parlist(password)puis"".join(...)). Vérifie en générant des mots de passe courts (8) avec tout activé : chaque famille est représentée. - Ajoute « Combien de mots de passe ? » et la boucle d'affichage. Relis la fonction : toujours aucun
input()/print()dedans ? Fini.
Extensions possibles
- Mode « phrase de passe » : 4-5 mots tirés d'une liste de mots français, séparés par des tirets (
correct-cheval-pile-orange). - Estimer et afficher la force : taille du pool ** longueur, traduite en « faible / correct / fort ».
- Remplacer
randompar le modulesecrets(secrets.choice()) et comprendre pourquoi c'est la bonne pratique pour des secrets réels. - Option
--length 20en ligne de commande viasys.argv(avant-goût du niveau 10, oùargparsefera ça proprement).
Erreurs fréquentes sur ce projet
- Mettre
input()DANSgenerate_password(): la fonction devient intestable et inréutilisable. Si tu dois répondre à des questions pour la tester, c'est raté — recommence la séparation. - Oublier le
return: la fonction afficheNone. Symptôme classique :print(generate_password(12))→Nonecar la fonction fait son propreprintet ne retourne rien. - Pool vide impossible ici (minuscules toujours incluses) — mais si tu rends les minuscules optionnelles (variante),
random.choice("")lèveIndexError: Cannot choose from an empty sequence. Il faut un garde-fou. - Garantie de composition faite en re-générant en boucle « jusqu'à ce que ça passe » : ça marche, mais c'est non borné et inélégant. La méthode « un de chaque + complément + shuffle » est déterministe en une passe.
random.shuffle()retourneNone(il mélange EN PLACE) :password = random.shuffle(chars)te laisse avecNone. Piège de mutabilité classique, déjà vu au niveau 3.
Critères de réussite
-
generate_password(12)appelée depuis le REPL retourne une chaîne de 12 caractères, sans rien afficher ni demander. - Chaque combinaison d'options produit un pool correct (vérifié sur au moins 3 combinaisons).
- Avec toutes les familles actives et longueur 8, chaque famille est toujours représentée (testé 10 fois).
- Une longueur invalide est redemandée sans traceback.
- Le commentaire d'honnêteté sur
randomvssecretsest présent.
Commit conseillé
git add projects/mini-projects/07-generateur-mots-de-passe/
git commit -m "project: add password generator"
Puis entrée de journal + git push.