seo-dev-env 0.1.0__tar.gz → 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. {seo_dev_env-0.1.0/seo_dev_env.egg-info → seo_dev_env-0.1.1}/PKG-INFO +1 -1
  2. seo_dev_env-0.1.1/seo/__init__.py +3 -0
  3. seo_dev_env-0.1.1/seo/cli.py +165 -0
  4. seo_dev_env-0.1.1/seo/commandes.py +93 -0
  5. seo_dev_env-0.1.1/seo/generators.py +335 -0
  6. seo_dev_env-0.1.1/seo/templates/debutant/app.py +16 -0
  7. seo_dev_env-0.1.1/seo/templates/debutant/index.html +46 -0
  8. seo_dev_env-0.1.1/seo/templates/debutant/style.css +110 -0
  9. seo_dev_env-0.1.1/seo/templates/intermediaire/app/__init__.py +38 -0
  10. seo_dev_env-0.1.1/seo/templates/intermediaire/app/core/__init__.py +0 -0
  11. seo_dev_env-0.1.1/seo/templates/intermediaire/app/core/config.py +23 -0
  12. seo_dev_env-0.1.1/seo/templates/intermediaire/app/taches/__init__.py +0 -0
  13. seo_dev_env-0.1.1/seo/templates/intermediaire/app/taches/models.py +18 -0
  14. seo_dev_env-0.1.1/seo/templates/intermediaire/app/taches/routes.py +44 -0
  15. seo_dev_env-0.1.1/seo/templates/intermediaire/app/utilisateurs/__init__.py +0 -0
  16. seo_dev_env-0.1.1/seo/templates/intermediaire/app/utilisateurs/models.py +29 -0
  17. seo_dev_env-0.1.1/seo/templates/intermediaire/app/utilisateurs/routes.py +34 -0
  18. seo_dev_env-0.1.1/seo/templates/intermediaire/config.py +10 -0
  19. seo_dev_env-0.1.1/seo/templates/intermediaire/docker-compose.yml +39 -0
  20. seo_dev_env-0.1.1/seo/templates/intermediaire/run.py +17 -0
  21. seo_dev_env-0.1.1/seo/templates/pro/Dockerfile +26 -0
  22. seo_dev_env-0.1.1/seo/templates/pro/docker-compose.yml +39 -0
  23. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1/seo_dev_env.egg-info}/PKG-INFO +1 -1
  24. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/seo_dev_env.egg-info/SOURCES.txt +12 -0
  25. seo_dev_env-0.1.1/seo_dev_env.egg-info/entry_points.txt +3 -0
  26. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/setup.py +3 -2
  27. seo_dev_env-0.1.0/seo/__init__.py +0 -3
  28. seo_dev_env-0.1.0/seo/generators.py +0 -161
  29. seo_dev_env-0.1.0/seo/templates/debutant/app.py +0 -0
  30. seo_dev_env-0.1.0/seo/templates/debutant/index.html +0 -0
  31. seo_dev_env-0.1.0/seo/templates/debutant/style.css +0 -0
  32. seo_dev_env-0.1.0/seo/templates/intermediaire/run.py +0 -0
  33. seo_dev_env-0.1.0/seo/templates/pro/app/api/v1/__init__.py +0 -0
  34. seo_dev_env-0.1.0/seo/templates/pro/app/core/config.py +0 -0
  35. seo_dev_env-0.1.0/seo/templates/pro/docker-compose.yml +0 -0
  36. seo_dev_env-0.1.0/seo_dev_env.egg-info/entry_points.txt +0 -2
  37. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/LICENSE.ls +0 -0
  38. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/README.md +0 -0
  39. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/seo/templates/intermediaire/app/models.py +0 -0
  40. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/seo/templates/intermediaire/app/routes.py +0 -0
  41. {seo_dev_env-0.1.0/seo/templates/intermediaire → seo_dev_env-0.1.1/seo/templates/pro}/app/__init__.py +0 -0
  42. {seo_dev_env-0.1.0/seo/templates/pro/app → seo_dev_env-0.1.1/seo/templates/pro/app/api}/__init__.py +0 -0
  43. {seo_dev_env-0.1.0/seo/templates/pro/app/api → seo_dev_env-0.1.1/seo/templates/pro/app/api/v1}/__init__.py +0 -0
  44. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/seo/templates/pro/app/api/v1/endpoints.py +0 -0
  45. {seo_dev_env-0.1.0/seo/templates/intermediaire → seo_dev_env-0.1.1/seo/templates/pro/app/core}/config.py +0 -0
  46. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/seo/templates/pro/app/core/security.py +0 -0
  47. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/seo/templates/pro/app/db/base.py +0 -0
  48. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/seo/templates/pro/app/db/models.py +0 -0
  49. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/seo/utils.py +0 -0
  50. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/seo_dev_env.egg-info/dependency_links.txt +0 -0
  51. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/seo_dev_env.egg-info/requires.txt +0 -0
  52. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/seo_dev_env.egg-info/top_level.txt +0 -0
  53. {seo_dev_env-0.1.0 → seo_dev_env-0.1.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: seo-dev-env
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary: Générateur d'environnements de développement pour tous niveaux
5
5
  Home-page: https://github.com/https://github.com/elkast/seo-dev-env
6
6
  Author: Votre Nom
@@ -0,0 +1,3 @@
1
+ from .generators import creer_environnement, creer_projet, creer_projet_interactif, main
2
+
3
+ __all__ = ['creer_environnement', 'creer_projet', 'creer_projet_interactif', 'main']
@@ -0,0 +1,165 @@
1
+ """CLI interactif pour SEO Dev Env"""
2
+ import sys
3
+ from typing import Dict, Any
4
+
5
+
6
+ def afficher_titre():
7
+ print("\n" + "="*60)
8
+ print(" SEO Dev Env - Créateur d'architecture Flask")
9
+ print(" pour développeurs francophones")
10
+ print("="*60 + "\n")
11
+
12
+
13
+ def poser_question(question: str, options: list, defaut: int = 1) -> int:
14
+ print(f"\n{question}")
15
+ for i, option in enumerate(options, 1):
16
+ marqueur = "" if i == defaut else " "
17
+ print(f" {marqueur} {i}. {option}")
18
+ while True:
19
+ try:
20
+ choix = input(f"\nVotre choix [1-{len(options)}] (défaut: {defaut}): ").strip()
21
+ if not choix:
22
+ return defaut - 1
23
+ choix_int = int(choix)
24
+ if 1 <= choix_int <= len(options):
25
+ return choix_int - 1
26
+ else:
27
+ print(f" Veuillez choisir entre 1 et {len(options)}")
28
+ except ValueError:
29
+ print(" Veuillez entrer un nombre valide")
30
+ except KeyboardInterrupt:
31
+ print("\n\n Annulé")
32
+ sys.exit(0)
33
+
34
+
35
+ def poser_question_texte(question: str, defaut: str = "") -> str:
36
+ prompt = f"{question} (défaut: {defaut}): " if defaut else f"{question}: "
37
+ try:
38
+ reponse = input(prompt).strip()
39
+ return reponse if reponse else defaut
40
+ except KeyboardInterrupt:
41
+ print("\n\n Annulé")
42
+ sys.exit(0)
43
+
44
+
45
+ def confirmer(question: str, defaut: bool = True) -> bool:
46
+ suffixe = "[O/n]" if defaut else "[o/N]"
47
+ try:
48
+ reponse = input(f"{question} {suffixe}: ").strip().lower()
49
+ if not reponse:
50
+ return defaut
51
+ return reponse in ["o", "oui", "y", "yes"]
52
+ except KeyboardInterrupt:
53
+ print("\n\n Annulé")
54
+ sys.exit(0)
55
+
56
+
57
+ def collecter_preferences() -> Dict[str, Any]:
58
+ afficher_titre()
59
+ preferences = {}
60
+
61
+ print(" Configuration du projet")
62
+ preferences["nom_projet"] = poser_question_texte("Nom de votre projet", "mon-projet")
63
+
64
+ type_options = [
65
+ "Apprentissage (simple, pour débuter)",
66
+ "Application web (structure MVC complète)",
67
+ "API professionnelle (production-ready)",
68
+ "Startup SaaS (auth, paiement, dashboard)"
69
+ ]
70
+ type_choix = poser_question(" Quel type de projet ?", type_options)
71
+ types_mapping = {0: "apprentissage", 1: "application", 2: "api", 3: "saas"}
72
+ preferences["type_projet"] = types_mapping[type_choix]
73
+
74
+ if preferences["type_projet"] in ["application", "api", "saas"]:
75
+ db_options = [
76
+ "SQLite (simple, fichier local)",
77
+ "PostgreSQL (recommandé pour production)",
78
+ "MySQL (compatible, largement utilisé)"
79
+ ]
80
+ db_choix = poser_question(" Quelle base de données ?", db_options,
81
+ defaut=2 if preferences["type_projet"] in ["api", "saas"] else 1)
82
+ db_mapping = {0: "sqlite", 1: "postgresql", 2: "mysql"}
83
+ preferences["base_donnees"] = db_mapping[db_choix]
84
+
85
+ if preferences["base_donnees"] == "sqlite" and preferences["type_projet"] in ["api", "saas"]:
86
+ print("\n ATTENTION: SQLite non recommandé pour production.")
87
+ if not confirmer("\n Continuer avec SQLite ?", defaut=False):
88
+ print("\n Passage à PostgreSQL")
89
+ preferences["base_donnees"] = "postgresql"
90
+
91
+ auth_options = [
92
+ "Session classique (cookies Flask)",
93
+ "JWT (tokens, pour API)",
94
+ "OAuth2 (Google, GitHub, etc.)"
95
+ ]
96
+ auth_choix = poser_question(" Type d'authentification ?", auth_options,
97
+ defaut=2 if preferences["type_projet"] == "api" else 1)
98
+ auth_mapping = {0: "session", 1: "jwt", 2: "oauth"}
99
+ preferences["auth"] = auth_mapping[auth_choix]
100
+
101
+ if preferences["type_projet"] in ["api", "saas"]:
102
+ preferences["docker"] = True
103
+ print("\n Docker inclus automatiquement")
104
+ else:
105
+ preferences["docker"] = confirmer("\n Inclure Docker ?", defaut=True)
106
+ else:
107
+ preferences["base_donnees"] = "sqlite"
108
+ preferences["auth"] = "session"
109
+ preferences["docker"] = False
110
+
111
+ if preferences["type_projet"] == "saas":
112
+ preferences["stripe"] = confirmer("\n Inclure Stripe ?", defaut=True)
113
+ preferences["email"] = confirmer(" Inclure Flask-Mail ?", defaut=True)
114
+ preferences["celery"] = confirmer(" Inclure Celery ?", defaut=True)
115
+
116
+ preferences["git"] = confirmer("\n Initialiser Git ?", defaut=True)
117
+ return preferences
118
+
119
+
120
+ def afficher_resume(preferences: Dict[str, Any]):
121
+ print("\n" + "="*60)
122
+ print(" Résumé")
123
+ print("="*60)
124
+ print(f"\n Projet: {preferences['nom_projet']}")
125
+ print(f" Type: {preferences['type_projet']}")
126
+ if "base_donnees" in preferences:
127
+ print(f" Base: {preferences['base_donnees']}")
128
+ if "auth" in preferences:
129
+ print(f" Auth: {preferences['auth']}")
130
+ if preferences.get("docker"):
131
+ print(" Docker: ")
132
+ if preferences.get("stripe"):
133
+ print(" Stripe: ")
134
+ if preferences.get("email"):
135
+ print(" Email: ")
136
+ if preferences.get("celery"):
137
+ print(" Celery: ")
138
+ if preferences.get("git"):
139
+ print(" Git: ")
140
+ print("\n" + "="*60 + "\n")
141
+
142
+
143
+ def afficher_prochaines_etapes(nom_projet: str, type_projet: str, docker: bool = False):
144
+ print("\n" + "="*60)
145
+ print(" Projet créé !")
146
+ print("="*60)
147
+ print(f"\n Prochaines étapes:\n")
148
+ print(f" 1. cd {nom_projet}")
149
+ if docker:
150
+ print(" 2. docker-compose up --build")
151
+ else:
152
+ if type_projet == "apprentissage":
153
+ print(" 2. python app.py")
154
+ else:
155
+ print(" 2. python -m venv venv")
156
+ print(" 3. venv\\Scripts\\activate")
157
+ print(" 4. pip install -r requirements.txt")
158
+ print(" 5. seo db init")
159
+ print(" 6. seo user create")
160
+ print(" 7. seo run")
161
+ print("\n Commandes:")
162
+ print(" seo db init - Initialiser la base")
163
+ print(" seo user create - Créer un admin")
164
+ print(" seo run - Lancer l'app")
165
+ print("\n" + "="*60 + "\n")
@@ -0,0 +1,93 @@
1
+ """
2
+ Commandes internes pour gérer le projet Flask
3
+ """
4
+ import os
5
+ import sys
6
+ import subprocess
7
+ from pathlib import Path
8
+
9
+
10
+ def commande_db(action: str):
11
+ """Gestion de la base de données"""
12
+ if action == "init":
13
+ print(" Initialisation de la base...")
14
+ subprocess.run([sys.executable, "-m", "flask", "db", "init"])
15
+ print(" Base initialisée")
16
+ elif action == "migrate":
17
+ message = input("Message (optionnel): ").strip()
18
+ if message:
19
+ subprocess.run([sys.executable, "-m", "flask", "db", "migrate", "-m", message])
20
+ else:
21
+ subprocess.run([sys.executable, "-m", "flask", "db", "migrate"])
22
+ print(" Migration créée")
23
+ elif action == "upgrade":
24
+ subprocess.run([sys.executable, "-m", "flask", "db", "upgrade"])
25
+ print(" Migrations appliquées")
26
+ else:
27
+ print(f" Action '{action}' inconnue")
28
+
29
+
30
+ def commande_user(action: str):
31
+ """Gestion des utilisateurs"""
32
+ if action == "create":
33
+ print(" Création admin\n")
34
+ username = input("Username: ").strip()
35
+ email = input("Email: ").strip()
36
+ import getpass
37
+ password = getpass.getpass("Password: ")
38
+
39
+ try:
40
+ from app import create_app, db
41
+ from app.models import User
42
+ app = create_app()
43
+ with app.app_context():
44
+ user = User(username=username, email=email, is_admin=True)
45
+ user.set_password(password)
46
+ db.session.add(user)
47
+ db.session.commit()
48
+ print(f" Utilisateur '{username}' créé")
49
+ except ImportError as e:
50
+ print(f" Erreur: {e}")
51
+ elif action == "list":
52
+ try:
53
+ from app import create_app, db
54
+ from app.models import User
55
+ app = create_app()
56
+ with app.app_context():
57
+ users = User.query.all()
58
+ print("\n Utilisateurs:\n")
59
+ for user in users:
60
+ print(f" {user.username}")
61
+ except ImportError:
62
+ print(" Impossible de charger les utilisateurs")
63
+
64
+
65
+ def commande_run(mode: str = "dev"):
66
+ """Lance l'application"""
67
+ if mode == "dev":
68
+ print(" Mode développement...\n")
69
+ os.environ["FLASK_ENV"] = "development"
70
+ os.environ["FLASK_DEBUG"] = "1"
71
+ if Path("run.py").exists():
72
+ subprocess.run([sys.executable, "run.py"])
73
+ elif Path("app.py").exists():
74
+ subprocess.run([sys.executable, "app.py"])
75
+ else:
76
+ subprocess.run([sys.executable, "-m", "flask", "run", "--debug"])
77
+
78
+
79
+ def afficher_aide():
80
+ """Affiche l'aide"""
81
+ print("\n" + "="*60)
82
+ print(" Commandes SEO")
83
+ print("="*60 + "\n")
84
+ print(" Base de données:")
85
+ print(" seo db init - Initialiser")
86
+ print(" seo db migrate - Créer migration")
87
+ print(" seo db upgrade - Appliquer")
88
+ print("\n Utilisateurs:")
89
+ print(" seo user create - Créer admin")
90
+ print(" seo user list - Lister")
91
+ print("\n Lancement:")
92
+ print(" seo run - Mode dev")
93
+ print("\n" + "="*60 + "\n")
@@ -0,0 +1,335 @@
1
+ import os
2
+ import subprocess
3
+ import sys
4
+ import shutil
5
+ from pathlib import Path
6
+ from typing import Dict, Any
7
+ from .utils import creer_fichier, copier_dossier
8
+ from .cli import collecter_preferences, afficher_resume, afficher_prochaines_etapes
9
+
10
+ class EnvironnementGenerator:
11
+ """Classe de base pour générer des environnements"""
12
+
13
+ def __init__(self, niveau: str, type_app: str, chemin: str):
14
+ self.niveau = niveau
15
+ self.type_app = type_app
16
+ self.chemin_projet = Path(chemin).resolve()
17
+ self.packages = []
18
+ self.template_dir = Path(__file__).parent / 'templates' / niveau
19
+
20
+ def _installer_dependances(self):
21
+ """Installe les packages nécessaires"""
22
+ if self.packages:
23
+ print(f"🔧 Installation des packages: {', '.join(self.packages)}")
24
+ subprocess.run([sys.executable, '-m', 'pip', 'install'] + self.packages)
25
+
26
+ def _copier_template(self):
27
+ """Copie les fichiers du template"""
28
+ if self.template_dir.exists():
29
+ copier_dossier(self.template_dir, self.chemin_projet)
30
+ else:
31
+ print(f"⚠️ Avertissement: Template {self.niveau} non trouvé, création de base")
32
+ self._creer_structure_base()
33
+
34
+ def _creer_structure_base(self):
35
+ """Crée une structure de base si le template est manquant"""
36
+ creer_fichier(self.chemin_projet / 'app.py', "# Votre application Flask")
37
+ (self.chemin_projet / 'templates').mkdir(exist_ok=True)
38
+ creer_fichier(self.chemin_projet / 'templates/index.html', "<h1>Bienvenue</h1>")
39
+
40
+ def _post_creation(self):
41
+ """Actions supplémentaires après création"""
42
+ pass
43
+
44
+ def generer(self):
45
+ """Méthode principale pour générer l'environnement"""
46
+ self.chemin_projet.mkdir(exist_ok=True, parents=True)
47
+ print(f"🏗️ Création de l'environnement {self.niveau} ({self.type_app})...")
48
+
49
+ self._copier_template()
50
+ self._creer_structure()
51
+ self._installer_dependances()
52
+ self._post_creation()
53
+
54
+ print(f"✅ Environnement créé avec succès dans {self.chemin_projet}")
55
+ print("👉 Pour démarrer: cd " + str(self.chemin_projet))
56
+
57
+ class DebutantWebGenerator(EnvironnementGenerator):
58
+ """Générateur pour débutants - Site web simple"""
59
+
60
+ def __init__(self, chemin):
61
+ super().__init__('debutant', 'web', chemin)
62
+ self.packages = ['flask', 'python-dotenv']
63
+
64
+ def _creer_structure(self):
65
+ # Personnalisation supplémentaire
66
+ creer_fichier(
67
+ self.chemin_projet / 'README.md',
68
+ f"# Mon Premier Projet Flask\n\nCe projet a été créé avec SEO pour les débutants!"
69
+ )
70
+
71
+ class IntermediaireWebGenerator(EnvironnementGenerator):
72
+ """Générateur intermédiaire - Applications web complètes"""
73
+
74
+ def __init__(self, chemin):
75
+ super().__init__('intermediaire', 'web', chemin)
76
+ self.packages = [
77
+ 'flask',
78
+ 'flask-sqlalchemy',
79
+ 'flask-wtf',
80
+ 'flask-login',
81
+ 'flask-migrate',
82
+ 'python-dotenv'
83
+ ]
84
+
85
+ def _creer_structure(self):
86
+ # Création de la base de données
87
+ db_path = self.chemin_projet / 'app.db'
88
+ if not db_path.exists():
89
+ with open(db_path, 'w') as f:
90
+ f.write("")
91
+
92
+ # Création du fichier requirements
93
+ creer_fichier(
94
+ self.chemin_projet / 'requirements.txt',
95
+ "\n".join(self.packages)
96
+ )
97
+
98
+ class ProWebGenerator(EnvironnementGenerator):
99
+ """Générateur pro - Applications professionnelles"""
100
+
101
+ def __init__(self, chemin):
102
+ super().__init__('pro', 'web', chemin)
103
+ self.packages = [
104
+ 'flask',
105
+ 'flask-restx',
106
+ 'flask-cors',
107
+ 'flask-sqlalchemy',
108
+ 'flask-migrate',
109
+ 'flask-jwt-extended',
110
+ 'python-dotenv',
111
+ 'gunicorn',
112
+ 'psycopg2-binary'
113
+ ]
114
+
115
+ def _post_creation(self):
116
+ # Initialiser un dépôt Git
117
+ try:
118
+ subprocess.run(['git', 'init', str(self.chemin_projet)], check=True)
119
+ print("📦 Dépôt Git initialisé")
120
+ except:
121
+ print("⚠️ Git non installé, ignore l'initialisation du dépôt")
122
+
123
+ # Interface simplifiée
124
+ def creer_environnement(niveau, type_app='web', chemin='.'):
125
+ """
126
+ Crée un environnement de développement adapté
127
+
128
+ Args:
129
+ niveau: 'debutant', 'intermediaire' ou 'pro'
130
+ type_app: 'web' ou 'mobile' (défaut: 'web')
131
+ chemin: Chemin où créer le projet (défaut: dossier actuel)
132
+ """
133
+ generators = {
134
+ 'debutant': DebutantWebGenerator,
135
+ 'intermediaire': IntermediaireWebGenerator,
136
+ 'pro': ProWebGenerator
137
+ }
138
+
139
+ if niveau not in generators:
140
+ raise ValueError(f"🚫 Niveau non supporté: {niveau}")
141
+
142
+ generator = generators[niveau](chemin)
143
+ generator.generer()
144
+
145
+ # Ajout des instructions spécifiques
146
+ if niveau == 'debutant':
147
+ print("\n🚀 Pour démarrer votre application:")
148
+ print(f"cd {chemin}")
149
+ print("python app.py")
150
+ elif niveau == 'intermediaire':
151
+ print("\n🚀 Pour initialiser la base de données:")
152
+ print(f"cd {chemin}")
153
+ print("flask db init")
154
+ print("flask db migrate")
155
+ print("flask db upgrade")
156
+ print("flask run")
157
+ else:
158
+ print("\n🚀 Pour démarrer avec Docker:")
159
+ print(f"cd {chemin}")
160
+ print("docker-compose up --build")
161
+
162
+ # Alias pour une utilisation plus simple
163
+ creer_projet = creer_environnement
164
+
165
+
166
+ def main():
167
+ """Point d'entrée principal pour le CLI"""
168
+ import argparse
169
+
170
+ parser = argparse.ArgumentParser(
171
+ description='SEO Dev Env - Générateur de projets Flask pour francophones'
172
+ )
173
+
174
+ subparsers = parser.add_subparsers(dest='commande', help='Commandes disponibles')
175
+
176
+ # Commande create (mode interactif)
177
+ parser_create = subparsers.add_parser('create', help='Créer un nouveau projet (mode interactif)')
178
+ parser_create.add_argument('nom', nargs='?', help='Nom du projet (optionnel, sera demandé si non fourni)')
179
+
180
+ # Commandes db
181
+ parser_db = subparsers.add_parser('db', help='Gestion de la base de données')
182
+ parser_db.add_argument('action', choices=['init', 'migrate', 'upgrade', 'downgrade'])
183
+
184
+ # Commandes user
185
+ parser_user = subparsers.add_parser('user', help='Gestion des utilisateurs')
186
+ parser_user.add_argument('action', choices=['create', 'list'])
187
+
188
+ # Commande run
189
+ parser_run = subparsers.add_parser('run', help='Lancer l\'application')
190
+ parser_run.add_argument('mode', nargs='?', default='dev', choices=['dev', 'prod'])
191
+
192
+ # Commande help
193
+ parser_help = subparsers.add_parser('help', help='Afficher l\'aide')
194
+
195
+ args = parser.parse_args()
196
+
197
+ # Si aucune commande, afficher l'aide
198
+ if not args.commande:
199
+ from .commandes import afficher_aide
200
+ afficher_aide()
201
+ return
202
+
203
+ # Traiter les commandes
204
+ if args.commande == 'create':
205
+ creer_projet_interactif(args.nom)
206
+
207
+ elif args.commande == 'db':
208
+ from .commandes import commande_db
209
+ commande_db(args.action)
210
+
211
+ elif args.commande == 'user':
212
+ from .commandes import commande_user
213
+ commande_user(args.action)
214
+
215
+ elif args.commande == 'run':
216
+ from .commandes import commande_run
217
+ commande_run(args.mode)
218
+
219
+ elif args.commande == 'help':
220
+ from .commandes import afficher_aide
221
+ afficher_aide()
222
+
223
+
224
+ def creer_projet_interactif(nom_fourni: str = None):
225
+ """Crée un projet en mode interactif"""
226
+ # Collecter les préférences
227
+ preferences = collecter_preferences()
228
+
229
+ # Utiliser le nom fourni en argument si disponible
230
+ if nom_fourni:
231
+ preferences['nom_projet'] = nom_fourni
232
+
233
+ # Afficher le résumé
234
+ afficher_resume(preferences)
235
+
236
+ # Confirmer
237
+ from .cli import confirmer
238
+ if not confirmer("Créer le projet avec cette configuration ?"):
239
+ print("❌ Annulé")
240
+ return
241
+
242
+ # Générer le projet selon le type
243
+ generer_selon_preferences(preferences)
244
+
245
+ # Afficher les prochaines étapes
246
+ afficher_prochaines_etapes(
247
+ preferences['nom_projet'],
248
+ preferences['type_projet'],
249
+ preferences.get('docker', False)
250
+ )
251
+
252
+
253
+ def generer_selon_preferences(preferences: Dict[str, Any]):
254
+ """Génère le projet selon les préférences"""
255
+ type_projet = preferences['type_projet']
256
+ nom_projet = preferences['nom_projet']
257
+
258
+ if type_projet == 'apprentissage':
259
+ generator = ApprentissageGenerator(nom_projet, preferences)
260
+ elif type_projet == 'application':
261
+ generator = ApplicationGenerator(nom_projet, preferences)
262
+ elif type_projet == 'api':
263
+ generator = APIGenerator(nom_projet, preferences)
264
+ elif type_projet == 'saas':
265
+ generator = SaaSGenerator(nom_projet, preferences)
266
+ else:
267
+ raise ValueError(f"Type de projet inconnu: {type_projet}")
268
+
269
+ generator.generer()
270
+
271
+
272
+ class ApprentissageGenerator(EnvironnementGenerator):
273
+ """Générateur pour débutants"""
274
+ def __init__(self, nom: str, preferences: Dict[str, Any]):
275
+ super().__init__('debutant', 'web', nom)
276
+ self.preferences = preferences
277
+ self.packages = ['flask', 'python-dotenv']
278
+
279
+ def _creer_structure(self):
280
+ creer_fichier(self.chemin_projet / 'README.md',
281
+ f"# {self.preferences['nom_projet']}\n\nProjet Flask pour apprentissage")
282
+
283
+
284
+ class ApplicationGenerator(EnvironnementGenerator):
285
+ """Générateur pour applications web (architecture par feature)"""
286
+ def __init__(self, nom: str, preferences: Dict[str, Any]):
287
+ super().__init__('intermediaire', 'web', nom)
288
+ self.preferences = preferences
289
+ self.packages = [
290
+ 'flask', 'flask-sqlalchemy', 'flask-migrate',
291
+ 'flask-wtf', 'flask-login', 'python-dotenv'
292
+ ]
293
+
294
+ def _creer_structure(self):
295
+ creer_fichier(self.chemin_projet / 'requirements.txt', "\n".join(self.packages))
296
+
297
+
298
+ class APIGenerator(EnvironnementGenerator):
299
+ """Générateur pour API professionnelles"""
300
+ def __init__(self, nom: str, preferences: Dict[str, Any]):
301
+ super().__init__('pro', 'api', nom)
302
+ self.preferences = preferences
303
+ self.packages = [
304
+ 'flask', 'flask-restx', 'flask-cors', 'flask-sqlalchemy',
305
+ 'flask-migrate', 'flask-jwt-extended', 'python-dotenv', 'gunicorn'
306
+ ]
307
+ if preferences.get('base_donnees') == 'postgresql':
308
+ self.packages.append('psycopg2-binary')
309
+ elif preferences.get('base_donnees') == 'mysql':
310
+ self.packages.append('pymysql')
311
+
312
+ def _creer_structure(self):
313
+ creer_fichier(self.chemin_projet / 'requirements.txt', "\n".join(self.packages))
314
+
315
+
316
+ class SaaSGenerator(EnvironnementGenerator):
317
+ """Générateur pour startup SaaS"""
318
+ def __init__(self, nom: str, preferences: Dict[str, Any]):
319
+ super().__init__('pro', 'saas', nom)
320
+ self.preferences = preferences
321
+ self.packages = [
322
+ 'flask', 'flask-restx', 'flask-cors', 'flask-sqlalchemy',
323
+ 'flask-migrate', 'flask-jwt-extended', 'python-dotenv', 'gunicorn'
324
+ ]
325
+ if preferences.get('stripe'):
326
+ self.packages.append('stripe')
327
+ if preferences.get('email'):
328
+ self.packages.append('flask-mail')
329
+ if preferences.get('celery'):
330
+ self.packages.extend(['celery', 'redis'])
331
+ if preferences.get('base_donnees') == 'postgresql':
332
+ self.packages.append('psycopg2-binary')
333
+
334
+ def _creer_structure(self):
335
+ creer_fichier(self.chemin_projet / 'requirements.txt', "\n".join(self.packages))
@@ -0,0 +1,16 @@
1
+ from flask import Flask, render_template
2
+
3
+ app = Flask(__name__)
4
+ app.config["SECRET_KEY"] = "votre-cle-secrete-changez-moi"
5
+
6
+ @app.route("/")
7
+ def accueil():
8
+ return render_template("index.html", titre="Bienvenue")
9
+
10
+ @app.route("/a-propos")
11
+ def a_propos():
12
+ return render_template("a_propos.html", titre="À propos")
13
+
14
+ if __name__ == "__main__":
15
+ print(" Application Flask démarrée sur http://localhost:5000")
16
+ app.run(debug=True)
@@ -0,0 +1,46 @@
1
+ <!DOCTYPE html>
2
+ <html lang="fr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{ titre }} - Mon Projet Flask</title>
7
+ <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
8
+ </head>
9
+ <body>
10
+ <nav>
11
+ <div class="container">
12
+ <h1> Mon Projet Flask</h1>
13
+ <ul>
14
+ <li><a href="/">Accueil</a></li>
15
+ <li><a href="/a-propos">À propos</a></li>
16
+ </ul>
17
+ </div>
18
+ </nav>
19
+
20
+ <main class="container">
21
+ <h2>Bienvenue sur votre première application Flask !</h2>
22
+ <p>Cette application a été générée avec <strong>SEO Dev Env</strong>.</p>
23
+
24
+ <div class="card">
25
+ <h3> Prochaines étapes</h3>
26
+ <ul>
27
+ <li>Personnalisez ce template dans <code>templates/index.html</code></li>
28
+ <li>Modifiez le style dans <code>static/style.css</code></li>
29
+ <li>Ajoutez de nouvelles routes dans <code>app.py</code></li>
30
+ </ul>
31
+ </div>
32
+
33
+ <div class="card">
34
+ <h3> Ressources utiles</h3>
35
+ <ul>
36
+ <li><a href="https://flask.palletsprojects.com/" target="_blank">Documentation Flask</a></li>
37
+ <li><a href="https://jinja.palletsprojects.com/" target="_blank">Documentation Jinja2</a></li>
38
+ </ul>
39
+ </div>
40
+ </main>
41
+
42
+ <footer>
43
+ <p>Créé avec en utilisant Flask</p>
44
+ </footer>
45
+ </body>
46
+ </html>