# Cheatsheet Black - Guide Ultra-Détaillé pour Grands Débutants


[OK] CONCEPTS FONDAMENTAUX (EXPLICATIONS TRÈS DÉTAILLÉES)

# === QU'EST-CE QUE BLACK ? ===

# Imagine que tu écris du code Python
# Tu peux écrire de différentes manières:

# Version 1:
def hello(name,age):
    print("Hello "+name+" you are "+str(age))

# Version 2:
def hello(name, age):
    print(f"Hello {name}, you are {age}")

# Version 3:
def hello(
    name,
    age
):
    print(
        f"Hello {name}, you are {age}"
    )

# Toutes ces versions FONCTIONNENT!
# Mais elles ont des styles différents
# = BEAUCOUP de débats dans les équipes sur "le bon style"

# BLACK = Outil qui formate automatiquement ton code
# = Il choisit UN style unique pour TOUT le monde
# = Plus besoin de débattre du style!
# = "The uncompromising code formatter"

# Black s'appelle un "code formatter"
# = Programme qui reformate automatiquement ton code
# = Comme "auto-corriger" dans Word mais pour du code

# === POURQUOI BLACK EXISTE? ===

# Problème avant Black:
# 1. Chaque développeur a son propre style
# 2. Code reviews perdent du temps sur les débats de style
# 3. Difficile de lire le code des autres
# 4. Conflits git fréquents à cause du formatage différent

# Solution Black:
# 1. UN SEUL style pour tout le monde
# 2. Pas de configuration (ou presque)
# 3. Formatage automatique = gain de temps
# 4. Code cohérent dans toute l'équipe

# Philosophie de Black:
# "You get what Black gives you"
# = Pas de personnalisation extensive
# = Black décide pour toi
# = Concentration sur le CODE, pas le style


# === VOCABULAIRE BLACK (TRÈS IMPORTANT!) ===

# CODE FORMATTER (Formateur de code)
# = Programme qui reformate automatiquement ton code
# = Ne change PAS le comportement, seulement l'apparence
# = Exemple: ajouter/enlever des espaces, des sauts de ligne

# STYLE GUIDE (Guide de style)
# = Ensemble de règles pour écrire du code
# = Exemple: PEP 8 pour Python
# = Black implémente une version stricte de PEP 8

# UNCOMPROMISING (Sans compromis)
# = Black ne négocie pas
# = Tu ne peux pas personnaliser chaque détail
# = C'est volontaire: éviter les débats de style

# LINE LENGTH (Longueur de ligne)
# = Nombre maximum de caractères par ligne
# = Black par défaut: 88 caractères
# = Pourquoi 88? Compromis entre lisibilité et utilisation écran

# AST (Abstract Syntax Tree)
# = Représentation interne du code
# = Black utilise l'AST pour comprendre ton code
# = Garantit que le formatage ne change PAS le comportement

# STABLE FORMATTING (Formatage stable)
# = Si tu lances Black 2 fois sur le même fichier
# = La 2ème fois ne change RIEN
# = = Le formatage est "stable"

# MAGIC TRAILING COMMA (Virgule finale magique)
# = Virgule à la fin d'une liste/tuple
# = Indique à Black de garder chaque élément sur une ligne
# = Exemple:
my_list = [
    1,
    2,
    3,  # <- virgule magique
]


# === COMMENT ÇA MARCHE? (FLUX COMPLET) ===

# 1. Tu as un fichier Python mal formaté
#    example.py:
#    def hello(x,y,z):return x+y+z

# 2. Tu lances Black:
#    black example.py

# 3. Black analyse le code:
#    a. Lit le fichier
#    b. Parse en AST (comprend la structure)
#    c. Applique ses règles de formatage
#    d. Écrit le nouveau code formaté

# 4. Résultat dans example.py:
#    def hello(x, y, z):
#        return x + y + z

# 5. Comportement du code: INCHANGÉ
#    hello(1, 2, 3) retourne toujours 6

# IMPORTANT: Black ne touche JAMAIS à la logique!
# Il ne fait QUE reformater l'apparence


# === BLACK VS AUTRES FORMATTERS ===

# AUTOPEP8:
# - Suit strictement PEP 8
# - Beaucoup d'options de configuration
# - Moins opinionné que Black

# YAPF (Yet Another Python Formatter):
# - Créé par Google
# - Très configurable
# - Peut produire différents styles

# BLACK:
# - Presque aucune configuration
# - UN style unique
# - Plus rapide à adopter (pas de débat)
# - Très populaire dans la communauté Python

# Pourquoi choisir Black?
# - Gain de temps (pas de config)
# - Adoption massive (industrie standard)
# - Intégration facile (pre-commit hooks, CI/CD)
# - Code cohérent garantit


[OK] INSTALLATION SUPER DÉTAILLÉE

# === MÉTHODE 1: INSTALLATION GLOBALE ===

# Pourquoi globale?
# - Disponible partout sur ton système
# - Pratique pour formater rapidement n'importe quel fichier
# - Un seul Black pour tous les projets

# Installation avec pip:
pip install black

# Vérifier l'installation:
black --version
# Affiche: black, 24.1.0 (ou version actuelle)

# Mise à jour:
pip install --upgrade black


# === MÉTHODE 2: INSTALLATION PAR PROJET (RECOMMANDÉ) ===

# Pourquoi par projet?
# - Version spécifique de Black pour chaque projet
# - Évite les conflits de versions
# - Reproductibilité garantie

# Créer un environnement virtuel:
python -m venv venv
source venv/bin/activate  # Linux/macOS
venv\Scripts\activate     # Windows

# Installer Black:
pip install black

# Ajouter à requirements.txt:
echo "black==24.1.0" >> requirements.txt

# Ou avec requirements-dev.txt (recommandé):
echo "black==24.1.0" >> requirements-dev.txt


# === MÉTHODE 3: INSTALLATION AVEC POETRY ===

# Poetry = gestionnaire de dépendances moderne

# Ajouter Black comme dépendance de développement:
poetry add --group dev black

# Cela met à jour pyproject.toml automatiquement


# === MÉTHODE 4: INSTALLATION AVEC PIPX ===

# pipx = outil pour installer des CLI Python isolés

# Installer pipx d'abord:
python -m pip install pipx
python -m pipx ensurepath

# Installer Black avec pipx:
pipx install black

# Avantage:
# - Black isolé dans son propre environnement
# - Disponible globalement
# - Pas de conflits avec autres packages


# === VÉRIFICATION POST-INSTALLATION ===

# Vérifier que Black est installé:
black --version
# Affiche: black, 24.1.0 (compiled: yes)

# Voir l'aide:
black --help
# Affiche toutes les options disponibles

# Tester sur un fichier:
echo "def hello(x,y):return x+y" > test.py
black test.py
cat test.py
# Affiche:
# def hello(x, y):
#     return x + y


[OK] UTILISATION BASIQUE (LIGNE DE COMMANDE)

# === FORMATER UN SEUL FICHIER ===

# Syntaxe de base:
black fichier.py

# Exemple concret:
# Avant (fichier mal formaté):
# app.py:
def hello(name,age):print("Hello "+name)

# Commande:
black app.py

# Affiche:
# reformatted app.py
# All done! * [SHORTCAKE] *
# 1 file reformatted.

# Après (fichier formaté):
# app.py:
def hello(name, age):
    print("Hello " + name)

# Explications:
# - Black ajoute des espaces autour des opérateurs
# - Sépare l'instruction print sur une nouvelle ligne
# - Ajoute des espaces après les virgules


# === FORMATER PLUSIEURS FICHIERS ===

# Formater plusieurs fichiers spécifiques:
black file1.py file2.py file3.py

# Formater tous les fichiers dans un dossier:
black mon_projet/

# Formater récursivement (tous les sous-dossiers):
black .
# Le point "." = dossier courant + tous les sous-dossiers

# Black ignore automatiquement:
# - Les fichiers/dossiers dans .gitignore
# - Les dossiers venv/, .venv/, env/
# - Les dossiers __pycache__/, .git/


# === MODE DRY-RUN (SIMULATION) ===

# Pourquoi?
# - Voir ce que Black va changer SANS modifier les fichiers
# - Utile avant de commiter

# Commande:
black --check fichier.py

# Si le fichier NÉCESSITE du formatage:
# Affiche:
# would reformat fichier.py
# Oh no! [IMPACT] [BROKEN_HEART] [IMPACT]
# 1 file would be reformatted.
# Exit code: 1

# Si le fichier est DÉJÀ bien formaté:
# Affiche:
# All done! * [SHORTCAKE] *
# 1 file would be left unchanged.
# Exit code: 0

# Utilisation typique en CI/CD:
black --check .
# Si exit code != 0, le CI échoue (code mal formaté)


# === VOIR LES DIFFÉRENCES (DIFF) ===

# Afficher les changements que Black va faire:
black --diff fichier.py

# Exemple de sortie:
# --- fichier.py  2024-01-15 10:00:00.000000 +0000
# +++ fichier.py  2024-01-15 10:00:01.000000 +0000
# @@ -1 +1,2 @@
# -def hello(x,y):return x+y
# +def hello(x, y):
# +    return x + y

# Explications:
# - Lignes avec "-" = code avant Black
# - Lignes avec "+" = code après Black
# - Utile pour code reviews


# === COMBINER --check ET --diff ===

# Voir les différences SANS modifier:
black --check --diff fichier.py

# Affiche:
# 1. Les différences (--diff)
# 2. Message d'erreur si formatage nécessaire (--check)

# Parfait pour CI/CD:
# - Voir exactement ce qui doit être corrigé
# - Fail le build si code mal formaté


# === FORMATER AVEC UNE LONGUEUR DE LIGNE DIFFÉRENTE ===

# Par défaut Black: 88 caractères par ligne
# Pour changer:
black --line-length 120 fichier.py

# Pourquoi 88 par défaut?
# - Compromis entre lisibilité et espace écran
# - ~10% de lignes en plus comparé à 80
# - Largeur confortable pour review sur GitHub

# Quand changer?
# - Projet avec écrans larges
# - Code avec beaucoup de noms longs
# - Contraintes d'équipe spécifiques


# === FORMATER STDIN/STDOUT ===

# Lire depuis stdin, écrire vers stdout:
echo "def hello(x,y):return x+y" | black -

# Affiche le code formaté:
# def hello(x, y):
#     return x + y

# Utilisation pratique:
# - Scripts shell
# - Pipelines
# - Intégration dans d'autres outils


# === EXCLURE DES FICHIERS ===

# Exclure un pattern spécifique:
black --exclude "migrations/" .

# Exclure plusieurs patterns:
black --exclude "migrations/|tests/" .

# Utiliser une regex complexe:
black --exclude "/(\.git|\.venv|migrations|__pycache__)/" .


# === MODE QUIET (SILENCIEUX) ===

# Ne rien afficher si tout va bien:
black --quiet fichier.py

# Affiche seulement les erreurs
# Utile pour les scripts automatisés


# === MODE VERBOSE (VERBEUX) ===

# Afficher plus d'informations:
black --verbose fichier.py

# Affiche:
# - Quels fichiers sont visités
# - Quels fichiers sont ignorés
# - Statistiques détaillées

# Utilisation:
# - Debugging
# - Comprendre pourquoi un fichier est ignoré


[OK] CONFIGURATION DÉTAILLÉE

# === FICHIER pyproject.toml (RECOMMANDÉ) ===

# Pourquoi pyproject.toml?
# - Standard Python moderne (PEP 518)
# - Un seul fichier pour toute la config du projet
# - Partageable avec l'équipe via git

# Créer pyproject.toml à la racine du projet:

[tool.black]
line-length = 88
target-version = ['py311']
include = '\.pyi?$'
extend-exclude = '''
/(
  # Dossiers à exclure
  \.eggs
  | \.git
  | \.hg
  | \.mypy_cache
  | \.tox
  | \.venv
  | _build
  | buck-out
  | build
  | dist
  | migrations
)/
'''

# Explications ligne par ligne:

# [tool.black]
# = Section dédiée à Black dans pyproject.toml

# line-length = 88
# = Longueur maximale des lignes
# = Valeur par défaut: 88
# = Peut être changée (60-120 recommandé)

# target-version = ['py311']
# = Version(s) Python cible(s)
# = Black adapte le formatage selon la version
# = Peut avoir plusieurs versions: ['py38', 'py39', 'py310']

# include = '\.pyi?$'
# = Regex des fichiers à inclure
# = Par défaut: .py et .pyi (stub files)
# = Peut être étendu: '\.pyx?$' (Cython)

# extend-exclude = '''...'''
# = Patterns à exclure EN PLUS des exclusions par défaut
# = Format: regex
# = Utilise ''' pour multi-lignes


# === EXEMPLE: Configuration minimale ===

[tool.black]
line-length = 100

# C'est tout! Black utilise les autres valeurs par défaut


# === EXEMPLE: Configuration pour Django ===

[tool.black]
line-length = 88
target-version = ['py311']
extend-exclude = '''
/(
  migrations
  | \.venv
  | venv
  | build
  | dist
)/
'''

# Explications:
# - migrations/ = fichiers générés automatiquement, ne pas formater
# - venv/ = environnements virtuels, ignorés
# - build/, dist/ = dossiers de build, ignorés


# === EXEMPLE: Configuration stricte ===

[tool.black]
line-length = 80
target-version = ['py38', 'py39', 'py310', 'py311']
skip-string-normalization = false
skip-magic-trailing-comma = false

# Explications:
# - line-length = 80: plus strict (PEP 8 classique)
# - target-version multiple: support plusieurs versions Python
# - skip-string-normalization = false: normaliser les quotes
# - skip-magic-trailing-comma = false: respecter les virgules magiques


# === OPTIONS IMPORTANTES ===

# skip-string-normalization
# = Par défaut: false (Black normalise les quotes)
# = Si true: Black ne touche PAS aux quotes

# Exemple avec false (défaut):
# Avant:
name = 'John'
# Après:
name = "John"  # Black préfère les guillemets doubles

# Exemple avec true:
# Avant:
name = 'John'
# Après:
name = 'John'  # Inchangé

# Quand utiliser true?
# - Projet avec convention stricte sur les quotes simples
# - Code avec beaucoup de quotes dans les strings


# skip-magic-trailing-comma
# = Par défaut: false (Black respecte les virgules magiques)
# = Si true: Black ignore les virgules magiques

# Exemple avec false (défaut):
# Avant:
data = [
    1,
    2,
    3,  # <- virgule magique
]
# Après: INCHANGÉ (Black respecte la virgule)

# Avant (sans virgule):
data = [1, 2, 3]
# Après: INCHANGÉ (tient sur une ligne)

# Exemple avec true:
# Black ignore les virgules magiques et reformate selon ses règles


# === LIRE LA CONFIGURATION ===

# Black cherche la config dans cet ordre:
# 1. Fichier spécifié avec --config
# 2. pyproject.toml dans le dossier courant
# 3. pyproject.toml dans les dossiers parents
# 4. Valeurs par défaut de Black

# Voir la config utilisée:
black --verbose fichier.py
# Affiche: "Using configuration from /path/to/pyproject.toml"

# Ignorer toute config et utiliser les défauts:
black --config "" fichier.py


[OK] RÈGLES DE FORMATAGE DÉTAILLÉES

# === ESPACES AUTOUR DES OPÉRATEURS ===

# Black ajoute des espaces autour des opérateurs

# Avant:
x=1+2*3
result=x**2
# Après:
x = 1 + 2 * 3
result = x**2

# Règle: espace autour de =, +, -, *, /, //, %, etc.
# Exception: ** (puissance) n'a PAS d'espace


# === ESPACES APRÈS LES VIRGULES ===

# Avant:
def hello(x,y,z):
    return [x,y,z]
# Après:
def hello(x, y, z):
    return [x, y, z]

# Règle: toujours un espace après une virgule


# === PARENTHÈSES ET ESPACES ===

# Avant:
result = function( x, y )
data = [ 1, 2, 3 ]
# Après:
result = function(x, y)
data = [1, 2, 3]

# Règle: PAS d'espace après ( ou avant )


# === LONGUEUR DE LIGNE ===

# Si une ligne dépasse 88 caractères, Black la découpe

# Avant:
def calculate_total_price_with_tax_and_discount(base_price, tax_rate, discount_percentage):
    return base_price * (1 + tax_rate) * (1 - discount_percentage)

# Après:
def calculate_total_price_with_tax_and_discount(
    base_price, tax_rate, discount_percentage
):
    return base_price * (1 + tax_rate) * (1 - discount_percentage)

# Règle:
# - Black découpe les longues lignes
# - Préfère découper aux virgules ou opérateurs logiques
# - Maintient la lisibilité


# === IMPORTS ===

# Black ne réorganise PAS les imports!
# Pour ça, utilise isort en complément

# Black formate seulement l'espacement:

# Avant:
import os,sys
from pathlib import Path,PurePath
# Après:
import os, sys
from pathlib import Path, PurePath

# Pour réorganiser les imports, utilise isort:
# pip install isort
# isort --profile black fichier.py


# === STRINGS (CHAÎNES DE CARACTÈRES) ===

# Black normalise les quotes (guillemets)

# Par défaut: préfère les guillemets doubles

# Avant:
name = 'John'
message = 'Hello'
# Après:
name = "John"
message = "Hello"

# Exception: strings avec des guillemets doubles à l'intérieur

# Avant:
message = 'He said "Hello"'
# Après:
message = 'He said "Hello"'  # Garde les simples

# Pour désactiver la normalisation:
# pyproject.toml:
[tool.black]
skip-string-normalization = true


# === STRINGS MULTI-LIGNES ===

# Black respecte les strings multi-lignes

# Avant et après: INCHANGÉ
description = """
This is a long
multi-line string
"""

# Black ne touche PAS au contenu des strings!


# === LISTES, TUPLES, DICTS ===

# Si tient sur une ligne: Black garde sur une ligne

# Avant et après:
data = [1, 2, 3]
point = (10, 20)
config = {"debug": True, "port": 5000}

# Si trop long ou virgule magique: Black sépare

# Avant:
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
# Après:
data = [
    1,
    2,
    3,
    4,
    5,
    6,
    7,
    8,
    9,
    10,
    11,
    12,
    13,
    14,
    15,
]


# === VIRGULE MAGIQUE (MAGIC TRAILING COMMA) ===

# La virgule magique indique à Black de garder chaque élément sur une ligne

# SANS virgule magique:
# Avant:
data = [
    1,
    2,
    3
]
# Après:
data = [1, 2, 3]  # Black met sur une ligne

# AVEC virgule magique:
# Avant:
data = [
    1,
    2,
    3,  # <- virgule après le dernier élément
]
# Après:
data = [
    1,
    2,
    3,
]  # Black respecte le format vertical

# Utilisation:
# - Quand tu veux garder un élément par ligne
# - Facilite les diffs git (ajout/suppression)
# - Évite les conflits de merge


# === FONCTIONS ET MÉTHODES ===

# Black formate les signatures de fonctions

# Avant:
def hello(name,age,city,country):
    return f"{name}, {age}, {city}, {country}"

# Après:
def hello(name, age, city, country):
    return f"{name}, {age}, {city}, {country}"

# Si trop long:
# Avant:
def calculate_final_price_with_discounts_and_taxes(base_price, tax_rate, discount):
    return base_price * (1 + tax_rate) * (1 - discount)

# Après:
def calculate_final_price_with_discounts_and_taxes(
    base_price, tax_rate, discount
):
    return base_price * (1 + tax_rate) * (1 - discount)


# === CLASSES ===

# Black ajoute 2 lignes vides avant les classes

# Avant:
class MyClass:
    pass
class AnotherClass:
    pass

# Après:
class MyClass:
    pass


class AnotherClass:
    pass

# Règle PEP 8: 2 lignes vides entre les définitions de top-level


# === MÉTHODES DANS LES CLASSES ===

# Black ajoute 1 ligne vide entre les méthodes

# Avant:
class MyClass:
    def method1(self):
        pass
    def method2(self):
        pass

# Après:
class MyClass:
    def method1(self):
        pass

    def method2(self):
        pass


# === COMMENTAIRES ===

# Black respecte les commentaires!

# Avant et après: INCHANGÉ
# This is a comment
x = 1  # Inline comment

# Black peut déplacer les commentaires si nécessaire:

# Avant:
result = some_long_function_name(arg1, arg2, arg3)  # Comment
# Après (si ligne trop longue):
# Comment
result = some_long_function_name(
    arg1, arg2, arg3
)


# === DOCSTRINGS ===

# Black respecte les docstrings!

# Avant et après: INCHANGÉ
def hello(name):
    """
    Say hello to someone.
    
    Args:
        name: The person's name
    """
    return f"Hello {name}"


# === LIGNES VIDES ===

# Black supprime les lignes vides excessives

# Avant:
def hello():
    pass



def world():
    pass

# Après:
def hello():
    pass


def world():
    pass

# Règle: maximum 2 lignes vides consécutives


[OK] INTÉGRATION AVEC LES ÉDITEURS

# === VISUAL STUDIO CODE (VSCODE) ===

# Étape 1: Installer l'extension Python
# - Ouvre VSCode
# - Extensions (Ctrl+Shift+X)
# - Cherche "Python"
# - Installe "Python" par Microsoft

# Étape 2: Configurer Black comme formatter
# - Ouvre Settings (Ctrl+,)
# - Cherche "python formatting provider"
# - Sélectionne "black"

# Ou ajoute dans settings.json:
{
  "python.formatting.provider": "black",
  "editor.formatOnSave": true,
  "python.formatting.blackArgs": [
    "--line-length=88"
  ]
}

# Explications:
# - "python.formatting.provider": "black" = utilise Black
# - "editor.formatOnSave": true = formate automatiquement à la sauvegarde
# - "python.formatting.blackArgs" = arguments passés à Black

# Utilisation:
# - Sauvegarde (Ctrl+S) = formatage automatique
# - Ou: Ctrl+Shift+P -> "Format Document"


# === PYCHARM / INTELLIJ ===

# Méthode 1: File Watcher (automatique)

# Étape 1: Installer le plugin File Watchers
# - Settings -> Plugins
# - Cherche "File Watchers"
# - Installe

# Étape 2: Configurer File Watcher
# - Settings -> Tools -> File Watchers
# - Clique "+"
# - Ajoute un nouveau watcher:
#   Name: Black
#   File type: Python
#   Scope: Project Files
#   Program: $PyInterpreterDirectory$/black
#   Arguments: $FilePath$
#   Working directory: $ProjectFileDir$

# Méthode 2: External Tool (manuel)

# Étape 1: Configurer External Tool
# - Settings -> Tools -> External Tools
# - Clique "+"
# - Ajoute:
#   Name: Black
#   Program: black
#   Arguments: $FilePath$
#   Working directory: $ProjectFileDir$

# Étape 2: Ajouter un raccourci clavier
# - Settings -> Keymap
# - Cherche "External Tools -> Black"
# - Clique droit -> Add Keyboard Shortcut
# - Définis ton raccourci (ex: Ctrl+Alt+B)


# === SUBLIME TEXT ===

# Étape 1: Installer Package Control
# - Ctrl+Shift+P -> "Install Package Control"

# Étape 2: Installer le package Python Black
# - Ctrl+Shift+P -> "Package Control: Install Package"
# - Cherche "python-black"
# - Installe

# Étape 3: Configurer
# - Preferences -> Package Settings -> Python Black -> Settings
# - Ajoute:
{
  "black_command": "black",
  "black_line_length": 88,
  "black_fast": false,
  "black_skip_string_normalization": false,
  "black_on_save": true
}

# Utilisation:
# - Sauvegarde = formatage automatique
# - Ou: Ctrl+Shift+P -> "Black: Format Current File"


# === VIM / NEOVIM ===

# Méthode 1: Plugin vim-black

# Installer avec vim-plug:
" Dans .vimrc ou init.vim:
Plug 'psf/black', { 'branch': 'stable' }

# Configurer:
" Format on save
autocmd BufWritePre *.py execute ':Black'

" Raccourci manuel
nnoremap <F9> :Black<CR>

# Méthode 2: ALE (Asynchronous Lint Engine)

" Dans .vimrc:
Plug 'dense-analysis/ale'

let g:ale_fixers = {
\   'python': ['black'],
\}
let g:ale_fix_on_save = 1


# === EMACS ===

# Installer le package blacken:

# Ajoute à init.el:
(use-package blacken
  :ensure t
  :hook (python-mode . blacken-mode))

# Configuration:
(setq blacken-line-length 88)
(setq blacken-skip-string-normalization nil)

# Utilisation:
# - M-x blacken-buffer (formater tout le buffer)
# - Ou active blacken-mode pour format on save


[OK] PRE-COMMIT HOOKS (AUTOMATISATION)

# === QU'EST-CE QU'UN PRE-COMMIT HOOK? ===

# Pre-commit hook = script qui s'exécute AVANT chaque commit git
# = Empêche de commiter du code mal formaté
# = Garantit que tout le code committé est formaté par Black

# Workflow:
# 1. Tu fais: git commit -m "Add feature"
# 2. Pre-commit hook lance Black automatiquement
# 3. Si code mal formaté: Black le corrige + commit échoue
# 4. Tu dois re-stager les fichiers corrigés et re-commit
# 5. Si code déjà bien formaté: commit réussit


# === INSTALLER PRE-COMMIT ===

# Pre-commit = framework Python pour gérer les hooks

pip install pre-commit

# Vérifier:
pre-commit --version
# Affiche: pre-commit 3.x.x


# === CONFIGURER PRE-COMMIT POUR BLACK ===

# Créer .pre-commit-config.yaml à la racine du projet:

repos:
  - repo: https://github.com/psf/black
    rev: 24.1.0  # Utilise la dernière version
    hooks:
      - id: black
        language_version: python3.11

# Explications:
# - repos: liste des repositories de hooks
# - repo: URL du repo GitHub de Black
# - rev: version spécifique de Black (tag git)
# - hooks: liste des hooks à utiliser
# - id: black = hook de formatBlack
# - language_version: version Python à utiliser


# === INSTALLER LES HOOKS ===

# Cette commande installe le hook dans .git/hooks/

pre-commit install

# Affiche:
# pre-commit installed at .git/hooks/pre-commit

# Vérifier:
ls -la .git/hooks/
# Doit afficher: pre-commit


# === TESTER LE HOOK ===

# Tester sur tous les fichiers:
pre-commit run --all-files

# Affiche:
# black....................................................................Passed
# - hook id: black
# - duration: 0.5s

# Si fichiers mal formatés:
# black....................................................................Failed
# - hook id: black
# - files were modified by this hook


# === WORKFLOW TYPIQUE AVEC PRE-COMMIT ===

# 1. Modifier du code:
# app.py:
def hello(x,y):return x+y

# 2. Stager les fichiers:
git add app.py

# 3. Essayer de commit:
git commit -m "Add hello function"

# 4. Pre-commit hook s'exécute:
# black....................................................................Failed
# - hook id: black
# - files were modified by this hook

# 5. Black a corrigé le code automatiquement:
# app.py:
def hello(x, y):
    return x + y

# 6. Re-stager les fichiers corrigés:
git add app.py

# 7. Re-commit:
git commit -m "Add hello function"
# Affiche:
# black....................................................................Passed
# [main abc1234] Add hello function


# === CONFIGURATION AVANCÉE ===

# Ajouter des arguments à Black dans le hook:

repos:
  - repo: https://github.com/psf/black
    rev: 24.1.0
    hooks:
      - id: black
        language_version: python3.11
        args: ['--line-length=100', '--skip-string-normalization']

# Exclure certains fichiers:

repos:
  - repo: https://github.com/psf/black
    rev: 24.1.0
    hooks:
      - id: black
        exclude: ^migrations/

# Combine avec d'autres hooks:

repos:
  - repo: https://github.com/psf/black
    rev: 24.1.0
    hooks:
      - id: black

  - repo: https://github.com/pycqa/isort
    rev: 5.12.0
    hooks:
      - id: isort
        args: ['--profile', 'black']

  - repo: https://github.com/pycqa/flake8
    rev: 6.0.0
    hooks:
      - id: flake8


# === BYPASSER LE HOOK (TEMPORAIREMENT) ===

# Si tu DOIS commiter du code non formaté (rare!):
git commit --no-verify -m "Quick fix"

# ATTENTION: À utiliser avec précaution!


# === METTRE À JOUR LES HOOKS ===

# Mettre à jour vers les dernières versions:
pre-commit autoupdate

# Affiche:
# Updating https://github.com/psf/black ... 23.1.0 -> 24.1.0


[OK] INTÉGRATION CI/CD (GITHUB ACTIONS, GITLAB CI)

# === POURQUOI CI/CD? ===

# CI/CD = Continuous Integration / Continuous Deployment
# = Pipeline automatisé pour tester/déployer le code

# Problème:
# - Même avec pre-commit hooks, quelqu'un peut bypasser
# - Certains développeurs ne configurent pas les hooks
# - Code mal formaté peut entrer dans la branche main

# Solution:
# - Ajouter Black dans le pipeline CI/CD
# - Fail le build si code mal formaté
# - Garantit que TOUT le code sur main est formaté


# === GITHUB ACTIONS ===

# Créer .github/workflows/black.yml:

name: Black Code Formatter

on: [push, pull_request]

jobs:
  black:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      
      - name: Install Black
        run: pip install black
      
      - name: Run Black check
        run: black --check --diff .

# Explications:

# on: [push, pull_request]
# = Lance le workflow sur chaque push et pull request

# runs-on: ubuntu-latest
# = Utilise Ubuntu comme environnement

# actions/checkout@v3
# = Clone le repository

# actions/setup-python@v4
# = Installe Python 3.11

# pip install black
# = Installe Black

# black --check --diff .
# = Vérifie tous les fichiers Python
# = --check: fail si code mal formaté
# = --diff: affiche les différences

# Si code mal formaté:
# - Le workflow échoue (exit code 1)
# - PR ne peut pas être merged
# - Développeur doit corriger


# === GITLAB CI ===

# Créer .gitlab-ci.yml:

stages:
  - lint

black:
  stage: lint
  image: python:3.11
  before_script:
    - pip install black
  script:
    - black --check --diff .
  only:
    - merge_requests
    - main

# Explications:

# stages: - lint
# = Définit une étape "lint" dans le pipeline

# image: python:3.11
# = Utilise l'image Docker Python 3.11

# before_script
# = Commandes à exécuter avant le script principal

# script
# = Commandes principales (vérification Black)

# only
# = Lance seulement sur merge requests et main


# === TRAVIS CI ===

# Créer .travis.yml:

language: python
python:
  - "3.11"

install:
  - pip install black

script:
  - black --check --diff .

# Simple et efficace!


# === CIRCLE CI ===

# Créer .circleci/config.yml:

version: 2.1

jobs:
  black:
    docker:
      - image: cimg/python:3.11
    steps:
      - checkout
      - run:
          name: Install Black
          command: pip install black
      - run:
          name: Run Black check
          command: black --check --diff .

workflows:
  version: 2
  lint:
    jobs:
      - black


# === COMBINER AVEC D'AUTRES LINTERS ===

# GitHub Actions avec Black + isort + flake8:

name: Lint

on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      
      - name: Install dependencies
        run: |
          pip install black isort flake8
      
      - name: Run Black
        run: black --check --diff .
      
      - name: Run isort
        run: isort --check --diff .
      
      - name: Run flake8
        run: flake8 .

# Si un des linters échoue, le workflow échoue


[OK] BLACK AVEC DOCKER

# === POURQUOI BLACK DANS DOCKER? ===

# Avantages:
# - Pas besoin d'installer Black localement
# - Version isolée et reproductible
# - Fonctionne sur n'importe quel système (Linux/Mac/Windows)
# - Utile pour CI/CD


# === UTILISER L'IMAGE OFFICIELLE BLACK ===

# Black fournit une image Docker officielle

# Formater un fichier:
docker run --rm -v $(pwd):/src pyfound/black:24.1.0 /src/app.py

# Explications:
# - --rm: supprimer le conteneur après exécution
# - -v $(pwd):/src: monter le dossier courant dans /src
# - pyfound/black:24.1.0: image officielle Black
# - /src/app.py: chemin du fichier dans le conteneur

# Formater tout le projet:
docker run --rm -v $(pwd):/src pyfound/black:24.1.0 /src

# Vérifier sans modifier:
docker run --rm -v $(pwd):/src pyfound/black:24.1.0 --check /src


# === CRÉER UN ALIAS (PRATIQUE) ===

# Linux/macOS:
alias black='docker run --rm -v $(pwd):/src pyfound/black:24.1.0 /src'

# Ajoute à ~/.bashrc ou ~/.zshrc pour le rendre permanent

# Utilisation:
black app.py
# Équivalent à lancer Black localement


# === INTÉGRER DANS UN DOCKERFILE ===

# Si tu as une app Python avec Dockerfile:

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Installer Black pour développement
RUN pip install black

COPY . .

# Formater le code au build (optionnel)
RUN black --check .

CMD ["python", "app.py"]

# Avantages:
# - Garantit que le code dans l'image est bien formaté
# - Fail le build si code mal formaté


# === DOCKER-COMPOSE AVEC BLACK ===

# docker-compose.yml:

version: '3.9'

services:
  app:
    build: .
    volumes:
      - .:/app
    command: python app.py

  black:
    image: pyfound/black:24.1.0
    volumes:
      - .:/src
    command: black --check /src
    profiles:
      - lint

# Utilisation:

# Lancer l'app:
docker-compose up app

# Vérifier le formatage:
docker-compose --profile lint up black


# === PRE-COMMIT AVEC DOCKER ===

# Utiliser Black via Docker dans pre-commit:

repos:
  - repo: local
    hooks:
      - id: black
        name: black
        entry: docker run --rm -v $(pwd):/src pyfound/black:24.1.0 /src
        language: system
        types: [python]

# Avantages:
# - Pas besoin d'installer Black localement
# - Version Black cohérente pour toute l'équipe


[OK] BLACK AVEC JUPYTER NOTEBOOKS

# === POURQUOI FORMATER LES NOTEBOOKS? ===

# Problème:
# - Jupyter notebooks (.ipynb) contiennent du code Python
# - Code souvent mal formaté
# - Difficile à review dans les PRs

# Solution:
# - Black peut formater les notebooks!
# - Version spéciale: black[jupyter]


# === INSTALLER BLACK AVEC SUPPORT JUPYTER ===

pip install black[jupyter]

# Ou avec requirements.txt:
echo "black[jupyter]==24.1.0" >> requirements.txt
pip install -r requirements.txt


# === FORMATER UN NOTEBOOK ===

# Formater un notebook:
black mon_notebook.ipynb

# Affiche:
# reformatted mon_notebook.ipynb
# All done! * [SHORTCAKE] *
# 1 file reformatted.

# Black formate SEULEMENT les cellules de code
# Les cellules Markdown restent INCHANGÉES


# === VÉRIFIER SANS MODIFIER ===

black --check mon_notebook.ipynb

# Si mal formaté:
# would reformat mon_notebook.ipynb
# Oh no! [IMPACT] [BROKEN_HEART] [IMPACT]

# Si bien formaté:
# All done! * [SHORTCAKE] *
# 1 file left unchanged.


# === FORMATER TOUS LES NOTEBOOKS ===

black *.ipynb
# Ou:
black notebooks/


# === EXEMPLE: AVANT/APRÈS ===

# Avant (cellule de code dans notebook.ipynb):
def hello(x,y,z):return x+y+z
data=[1,2,3,4,5]

# Après Black:
def hello(x, y, z):
    return x + y + z

data = [1, 2, 3, 4, 5]


# === INTÉGRER AVEC JUPYTERLAB ===

# Extension jupyterlab-code-formatter:

# Installer:
pip install jupyterlab-code-formatter black[jupyter]
jupyter labextension install @ryantam626/jupyterlab_code_formatter

# Redémarrer JupyterLab

# Utilisation:
# - Dans une cellule, clique droit
# - "Format Cell" ou "Format Notebook"
# - Ou raccourci: Ctrl+Shift+B


# === PRE-COMMIT AVEC NOTEBOOKS ===

# Ajouter à .pre-commit-config.yaml:

repos:
  - repo: https://github.com/psf/black
    rev: 24.1.0
    hooks:
      - id: black-jupyter

# Installer:
pre-commit install

# Maintenant Black formatera les notebooks automatiquement avant commit!


# === CI/CD AVEC NOTEBOOKS ===

# GitHub Actions:

name: Lint Notebooks

on: [push, pull_request]

jobs:
  black:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      
      - name: Install Black with Jupyter
        run: pip install black[jupyter]
      
      - name: Check notebooks
        run: black --check *.ipynb


# === LIMITATIONS ===

# Black pour notebooks:
# - Formate les cellules de code Python
# - NE formate PAS: Markdown, HTML, JavaScript
# - NE réorganise PAS les cellules
# - Respecte les outputs des cellules


[OK] MIGRATION D'UN PROJET EXISTANT

# === STRATÉGIE DE MIGRATION ===

# Problème:
# - Tu as un gros projet existant
# - Pas formaté avec Black
# - Beaucoup de fichiers à modifier

# Stratégie 1: Big Bang (TOUT EN UNE FOIS)
# Avantages:
# - Rapide
# - Code uniformément formaté immédiatement
# Inconvénients:
# - Gros commit difficile à review
# - Conflits avec les branches en cours
# - Historique git pollué

# Stratégie 2: Incremental (PROGRESSIF)
# Avantages:
# - Moins perturbant
# - Facilite les reviews
# Inconvénients:
# - Plus long
# - Code mixte (formaté/non formaté) temporairement


# === MÉTHODE 1: BIG BANG (RECOMMANDÉ POUR PETITS PROJETS) ===

# Étape 1: Créer une branche dédiée
git checkout -b format-with-black

# Étape 2: Installer Black
pip install black

# Étape 3: Créer pyproject.toml
cat > pyproject.toml << 'EOF'
[tool.black]
line-length = 88
target-version = ['py311']
EOF

# Étape 4: Formater TOUT le projet
black .

# Affiche:
# reformatted app.py
# reformatted models.py
# reformatted views.py
# ...
# All done! * [SHORTCAKE] *
# 47 files reformatted, 3 files left unchanged.

# Étape 5: Vérifier les changements
git diff
# Regarde les modifications

# Étape 6: Commiter
git add .
git commit -m "Format all code with Black"

# Étape 7: Créer une PR
git push origin format-with-black
# Crée une Pull Request sur GitHub/GitLab

# Étape 8: Review + Merge
# IMPORTANT: Merge RAPIDEMENT pour éviter les conflits!

# Étape 9: Annoncer à l'équipe
# "[ATTENTION] Main branch formaté avec Black"
# "Rebaser vos branches en cours!"

# Étape 10: Les autres développeurs rebaser leurs branches
git checkout ma-feature-branch
git rebase main
# Résoudre les conflits de formatage
black .
git add .
git rebase --continue


# === MÉTHODE 2: INCREMENTAL (RECOMMANDÉ POUR GROS PROJETS) ===

# Étape 1: Formater les nouveaux fichiers seulement

# Créer pyproject.toml:
[tool.black]
line-length = 88

# Installer pre-commit:
pip install pre-commit

# Créer .pre-commit-config.yaml:
repos:
  - repo: https://github.com/psf/black
    rev: 24.1.0
    hooks:
      - id: black

# Installer les hooks:
pre-commit install

# Maintenant: TOUT nouveau code sera formaté automatiquement
# Ancien code: reste non formaté (pour l'instant)

# Étape 2: Formater module par module

# Semaine 1: formater le module "auth"
black auth/
git commit -m "Format auth module with Black"

# Semaine 2: formater le module "api"
black api/
git commit -m "Format api module with Black"

# Etc.

# Étape 3: Après quelques semaines/mois
# Tout le code finit par être formaté!


# === GÉRER LES CONFLITS GIT ===

# Problème:
# - Branch A: code non formaté
# - Branch B (main): code formaté avec Black
# - Merge A -> B: CONFLITS!

# Solution 1: Formater la branch A avant merge
git checkout branch-a
black .
git add .
git commit -m "Format with Black before merge"
git checkout main
git merge branch-a
# Moins de conflits!

# Solution 2: Utiliser git merge-base
# Trouver l'ancêtre commun:
git merge-base main branch-a
# abc123

# Formater depuis l'ancêtre:
git diff abc123..HEAD --name-only | xargs black
git add .
git commit -m "Format changed files"


# === IGNORER LES COMMITS DE FORMATAGE DANS GIT BLAME ===

# Problème:
# - Après le gros commit Black
# - git blame affiche ce commit partout
# - Difficile de trouver l'auteur original!

# Solution: .git-blame-ignore-revs

# Étape 1: Noter le hash du commit de formatage
git log --oneline
# abc1234 Format all code with Black
# def5678 Add feature X

# Étape 2: Créer .git-blame-ignore-revs
cat > .git-blame-ignore-revs << 'EOF'
# Commit de formatage Black
abc1234
EOF

# Étape 3: Configurer git
git config blame.ignoreRevsFile .git-blame-ignore-revs

# Étape 4: Commiter le fichier
git add .git-blame-ignore-revs
git commit -m "Add git-blame-ignore-revs"

# Maintenant git blame ignore ce commit!
git blame fichier.py
# Affiche les vrais auteurs, pas le commit Black


# === COMMUNIQUER AVEC L'ÉQUIPE ===

# Avant la migration:
# 1. Annonce sur Slack/Teams
# "[RAPIDE] On va adopter Black pour formater le code!"

# 2. Documentation
# README.md:
## Code Style

This project uses [Black](https://github.com/psf/black) for code formatting.

### Setup
```bash
pip install black
pre-commit install
```

### Usage
Format all files:
```bash
black .
```

# 3. Meeting d'équipe
# - Expliquer pourquoi Black
# - Montrer comment configurer les éditeurs
# - Expliquer le workflow

# Pendant la migration:
# - Prévenir avant le merge du gros commit
# - Aider les collègues à rebaser leurs branches

# Après la migration:
# - Vérifier que tout le monde a configuré pre-commit
# - Ajouter Black dans le CI/CD


[OK] TROUBLESHOOTING (RÉSOLUTION DE PROBLÈMES)

# === PROBLÈME: "Black modifie mon code et ça casse tout!" ===

# IMPOSSIBLE!
# Black ne change JAMAIS le comportement du code
# Il utilise l'AST (Abstract Syntax Tree) pour garantir ça

# Si ton code se casse après Black:
# 1. Tu avais un bug avant (masqué par hasard)
# 2. Tu as modifié autre chose en même temps

# Vérifier:
# Avant Black:
python -m py_compile fichier.py
# Si erreur: le code était déjà cassé!

# Après Black:
python -m py_compile fichier.py
# Si erreur: idem


# === PROBLÈME: "Black met mes imports sur une seule ligne!" ===

# Black ne touche PAS aux imports!
# Il formate seulement l'espacement

# Avant et après (INCHANGÉ):
from module import a, b, c

# Pour réorganiser les imports, utilise isort:
pip install isort
isort --profile black fichier.py

# Combiné:
isort --profile black fichier.py && black fichier.py


# === PROBLÈME: "Black ignore mes fichiers!" ===

# Causes possibles:

# 1. Fichiers dans .gitignore
# Solution: Black respecte .gitignore par défaut
# Override:
black --force-exclude fichier.py

# 2. Fichiers dans extend-exclude (pyproject.toml)
# Solution: Enlève-les de extend-exclude

# 3. Fichiers sans extension .py
# Solution: Utilise --include
black --include '\.pyx?$' .

# 4. Syntaxe Python invalide
# Solution: Corrige les erreurs de syntaxe
python -m py_compile fichier.py


# === PROBLÈME: "Black est trop lent!" ===

# Causes:
# - Gros projet avec beaucoup de fichiers
# - Vieille version de Black

# Solutions:

# 1. Mettre à jour Black
pip install --upgrade black

# 2. Utiliser le mode multiprocessing
black --workers 4 .
# Utilise 4 processus en parallèle

# 3. Formater seulement les fichiers modifiés
git diff --name-only | grep '\.py$' | xargs black

# 4. Utiliser le cache
# Black a un cache par défaut dans ~/.cache/black/
# Vérifier:
ls -la ~/.cache/black/


# === PROBLÈME: "Black et flake8 se contredisent!" ===

# Exemple:
# Black formate:
def hello(
    x,
):
    pass

# flake8 dit: "E203 whitespace before ':'"

# Solution: Configurer flake8 pour être compatible

# Créer .flake8 ou setup.cfg:
[flake8]
max-line-length = 88
extend-ignore = E203, W503
exclude = .git,__pycache__,venv,.venv

# Explications:
# - max-line-length = 88: même que Black
# - extend-ignore = E203, W503: ignore les règles incompatibles
#   E203: whitespace before ':'
#   W503: line break before binary operator


# === PROBLÈME: "Black met mes strings trop longues sur plusieurs lignes" ===

# Black NE découpe PAS les strings automatiquement!

# Avant et après (INCHANGÉ):
message = "This is a very very very very very very very very long string that exceeds 88 characters"

# Si tu veux découper, fais-le manuellement:
message = (
    "This is a very very very very "
    "very very very very long string"
)

# Ou utilise des f-strings multi-lignes:
message = f"""
This is a very long
multi-line message
"""


# === PROBLÈME: "Black et mypy se contredisent!" ===

# mypy = type checker pour Python
# Rarement de conflit avec Black

# Si conflit, configurer mypy:

# mypy.ini ou pyproject.toml:
[mypy]
python_version = 3.11
warn_return_any = True
warn_unused_configs = True


# === PROBLÈME: "Black change mes doctests!" ===

# Doctests = exemples de code dans les docstrings

# Exemple:
def hello(x):
    """
    >>> hello(5)
    10
    """
    return x * 2

# Black peut reformater le code dans le doctest!

# Solution: Désactiver Black dans le docstring
def hello(x):
    """
    # fmt: off
    >>> hello(5)
    10
    # fmt: on
    """
    return x * 2


# === PROBLÈME: "Comment exclure une partie du code?" ===

# Utilise les commentaires spéciaux de Black

# Exclure une ligne:
# fmt: off
result = some_function(arg1,arg2,arg3)
# fmt: on

# Exclure une région:
# fmt: off
data = [1,2,3,4,5]
result = calculate(data)
more_code(result)
# fmt: on

# ATTENTION: à utiliser avec parcimonie!
# Seulement si vraiment nécessaire


# === PROBLÈME: "Black dans Docker ne trouve pas mes fichiers" ===

# Vérifie le volume mount:
docker run --rm -v $(pwd):/src pyfound/black /src

# Vérifie les permissions:
ls -la
# Si les fichiers sont owned by root: problème!

# Solution:
docker run --rm --user $(id -u):$(id -g) -v $(pwd):/src pyfound/black /src


[OK] BONNES PRATIQUES

# === QUAND ADOPTER BLACK? ===

# [OK] Au début d'un nouveau projet
# - Pas de code existant à migrer
# - Tout le monde commence avec Black

# [OK] Lors d'un refactoring majeur
# - Code déjà bouleversé
# - Bon moment pour uniformiser le style

# [OK] Quand l'équipe perd du temps sur le style
# - Code reviews interminables
# - Débats sur les espaces/virgules

# [X] Juste avant un release
# - Trop risqué
# - Conflits avec les hotfixes

# [X] Quand l'équipe est opposée
# - Attendre le consensus
# - Expliquer les bénéfices


# === CONFIGURATION MINIMALE RECOMMANDÉE ===

# pyproject.toml:
[tool.black]
line-length = 88
target-version = ['py311']

# .pre-commit-config.yaml:
repos:
  - repo: https://github.com/psf/black
    rev: 24.1.0
    hooks:
      - id: black

# .github/workflows/black.yml:
name: Black
on: [push, pull_request]
jobs:
  black:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - run: pip install black
      - run: black --check --diff .

# C'EST TOUT!
# Pas besoin de plus pour 99% des projets


# === COMBINER AVEC D'AUTRES OUTILS ===

# Stack recommandée:
# 1. Black: formatage
# 2. isort: organisation des imports
# 3. flake8: linting (erreurs logiques)
# 4. mypy: type checking

# Ordre d'exécution:
isort --profile black .
black .
flake8 .
mypy .

# pyproject.toml complet:
[tool.black]
line-length = 88

[tool.isort]
profile = "black"

[tool.mypy]
python_version = "3.11"
warn_return_any = true

# .pre-commit-config.yaml complet:
repos:
  - repo: https://github.com/pycqa/isort
    rev: 5.12.0
    hooks:
      - id: isort
        args: ['--profile', 'black']

  - repo: https://github.com/psf/black
    rev: 24.1.0
    hooks:
      - id: black

  - repo: https://github.com/pycqa/flake8
    rev: 6.0.0
    hooks:
      - id: flake8
        args: ['--max-line-length=88', '--extend-ignore=E203,W503']


# === RÈGLES D'ÉQUIPE ===

# 1. TOUJOURS utiliser Black avant de commit
# - Configurer l'éditeur (format on save)
# - Installer pre-commit hooks

# 2. NE JAMAIS bypasser Black
# - Pas de --no-verify (sauf urgence)
# - Pas de # fmt: off (sauf vraiment nécessaire)

# 3. Un seul commit de formatage par PR
# - Séparer les changements de code des changements de format
# - Facilite les reviews

# 4. Documenter les exceptions
# - Si tu dois désactiver Black: commenter POURQUOI
# Exemple:
# fmt: off  # Black casse l'alignement visuel nécessaire ici
matrix = [
    [1, 2,  3],
    [4, 5,  6],
    [7, 8, 90]
]
# fmt: on


# === ÉDUQUER L'ÉQUIPE ===

# 1. Session de démo
# - Montrer Black en action
# - Expliquer les bénéfices

# 2. Documentation interne
# - Guide setup pour nouveaux devs
# - FAQ sur Black

# 3. Code review guidelines
# - Ne PLUS commenter sur le style
# - Si style mal formaté: "Passe Black svp"

# 4. Célébrer les gains
# - "Code reviews 50% plus rapides!"
# - "Zéro débat sur le style ce mois-ci!"


# === MÉTRIQUES DE SUCCÈS ===

# Avant Black:
# - 30% du temps de code review = débats de style
# - Conflits git fréquents (formatage)
# - Code inconsistant

# Après Black:
# - 0% du temps sur le style
# - Moins de conflits git
# - Code uniformément formaté


[OK] CAS D'USAGE AVANCÉS

# === BLACK AVEC CYTHON ===

# Cython = Python avec types statiques (fichiers .pyx)

# Black supporte Cython partiellement

# Configuration:
[tool.black]
include = '\.pyx?$'

# Limitations:
# - Black formate la syntaxe Python
# - Peut casser les annotations Cython spéciales

# Exemple:
# Avant:
cdef int add(int x,int y):
    return x+y

# Après Black:
cdef int add(int x, int y):
    return x + y


# === BLACK AVEC MYPY STRICT ===

# mypy = type checker

# Configuration compatible:

# pyproject.toml:
[tool.black]
line-length = 88

[tool.mypy]
python_version = "3.11"
strict = true

# Black et mypy sont généralement compatibles
# Aucune config spéciale nécessaire


# === BLACK AVEC DJANGO ===

# Django = framework web Python

# Black fonctionne parfaitement avec Django!

# Configuration recommandée:

# pyproject.toml:
[tool.black]
line-length = 88
extend-exclude = '''
/(
  migrations
)/
'''

# Explications:
# - migrations/ = fichiers générés automatiquement
# - Ne PAS formater les migrations!

# Formater tout sauf migrations:
black --extend-exclude migrations/ .


# === BLACK AVEC FLASK ===

# Flask = micro-framework web

# Configuration standard:

[tool.black]
line-length = 88

# Black avec blueprints, app factory, etc:
# Aucune config spéciale nécessaire!


# === BLACK AVEC FASTAPI ===

# FastAPI = framework web moderne

# Configuration:
[tool.black]
line-length = 88

# Black formate bien les type hints de FastAPI:

# Avant:
@app.post("/items/")
async def create_item(item:Item,db:Session=Depends(get_db)):
    return {"item":item}

# Après:
@app.post("/items/")
async def create_item(item: Item, db: Session = Depends(get_db)):
    return {"item": item}


# === BLACK AVEC POETRY ===

# Poetry = gestionnaire de dépendances

# Installer Black:
poetry add --group dev black

# Configuration dans pyproject.toml:
[tool.poetry]
name = "my-project"
version = "0.1.0"

[tool.poetry.dependencies]
python = "^3.11"

[tool.poetry.group.dev.dependencies]
black = "^24.1.0"

[tool.black]
line-length = 88

# Formater avec Poetry:
poetry run black .


# === BLACK AVEC PYTEST ===

# pytest = framework de test

# Black formate les tests comme du code normal!

# Avant:
def test_hello():
    result=hello("John",25)
    assert result=="Hello John, 25"

# Après:
def test_hello():
    result = hello("John", 25)
    assert result == "Hello John, 25"

# Aucune configuration spéciale


# === BLACK AVEC SPHINX ===

# Sphinx = générateur de documentation

# Black formate le code dans les docstrings:

# Avant:
def hello(x):
    """
    Example:
        >>> hello(5)
        10
        >>> hello(10)
        20
    """
    return x * 2

# Après: INCHANGÉ (Black respecte les docstrings)

# Pour formater les exemples de code dans la doc:
# Utilise blacken-docs:
pip install blacken-docs
blacken-docs docs/*.rst


# === BLACK EN MODE LIBRARY ===

# Utiliser Black comme library Python (pas CLI)

from black import format_str, FileMode

# Code non formaté:
code = "def hello(x,y):return x+y"

# Formater:
formatted = format_str(code, mode=FileMode())

print(formatted)
# Affiche:
# def hello(x, y):
#     return x + y

# Options:
mode = FileMode(
    line_length=100,
    string_normalization=False,
)
formatted = format_str(code, mode=mode)

# Cas d'usage:
# - Outils de génération de code
# - Plugins pour autres éditeurs
# - Systèmes de formatage personnalisés


[OK] ALTERNATIVES ET COMPARAISONS

# === BLACK VS AUTOPEP8 ===

# AUTOPEP8:
# - Suit strictement PEP 8
# - Très configurable
# - Change seulement le strict nécessaire

# BLACK:
# - Opinionné (un seul style)
# - Peu configurable
# - Change tout pour uniformiser

# Exemple:

# Code original:
x = 1+2

# autopep8:
x = 1 + 2  # Ajoute des espaces

# black:
x = 1 + 2  # Idem

# Code original:
def hello(name,age):
  return f"{name}, {age}"

# autopep8:
def hello(name, age):
  return f"{name}, {age}"  # Fixe seulement les espaces

# black:
def hello(name, age):
    return f"{name}, {age}"  # Fixe espaces ET indentation

# Quand choisir autopep8?
# - Tu veux un changement minimal
# - Tu veux beaucoup de contrôle

# Quand choisir Black?
# - Tu veux zéro configuration
# - Tu veux un style uniforme


# === BLACK VS YAPF ===

# YAPF (Yet Another Python Formatter):
# - Créé par Google
# - Très configurable (comme clang-format)
# - Plusieurs styles prédéfinis (Google, PEP8, etc)

# BLACK:
# - Un seul style
# - Configuration minimale

# Exemple de config YAPF:
[yapf]
based_on_style = google
column_limit = 88
split_before_logical_operator = true

# Équivalent Black:
[tool.black]
line-length = 88
# C'EST TOUT!

# Quand choisir YAPF?
# - Tu veux un contrôle fin du style
# - Tu as des contraintes spécifiques

# Quand choisir Black?
# - Tu veux la simplicité
# - Tu veux l'adoption rapide


# === BLACK VS RUFF FORMAT ===

# RUFF:
# - Linter ET formatter ultra-rapide (Rust)
# - Compatible Black (même style!)
# - 10-100x plus rapide que Black

# Installation:
pip install ruff

# Formater avec Ruff:
ruff format .

# Avantages Ruff:
# - Beaucoup plus rapide
# - Combine linter + formatter
# - Compatible Black (migration facile)

# Inconvénients Ruff:
# - Plus récent (moins mature)
# - Moins d'adoption (pour l'instant)

# Quand choisir Black?
# - Stabilité et maturité
# - Adoption massive (industrie)

# Quand choisir Ruff?
# - Vitesse critique (gros projets)
# - Veut combiner linter + formatter


[OK] RESSOURCES ET LIENS

# Documentation officielle:
# https://black.readthedocs.io/

# Repository GitHub:
# https://github.com/psf/black

# Playground en ligne:
# https://black.vercel.app/
# (Teste Black dans ton navigateur!)

# PEP 8 (Style Guide Python):
# https://peps.python.org/pep-0008/

# Articles et tutoriels:
# - "Why Black?" par le créateur: https://github.com/psf/black#the-black-code-style
# - Real Python tutorial: https://realpython.com/python-code-quality/#formatters

# Intégrations:
# - VSCode: https://code.visualstudio.com/docs/python/editing#_formatting
# - PyCharm: https://black.readthedocs.io/en/stable/integrations/editors.html#pycharm-intellij-idea
# - pre-commit: https://pre-commit.com/

# Outils complémentaires:
# - isort (imports): https://pycqa.github.io/isort/
# - flake8 (linter): https://flake8.pycqa.org/
# - mypy (type checker): https://mypy.readthedocs.io/


[OK] RÉSUMÉ POUR DÉBUTANTS

# Tu veux formater ton code Python automatiquement?
# 1. Installe Black: pip install black
# 2. Formate ton code: black .
# 3. C'EST TOUT!

# Tu veux automatiser?
# 1. Installe pre-commit: pip install pre-commit
# 2. Crée .pre-commit-config.yaml
# 3. pre-commit install
# 4. Maintenant Black s'exécute avant chaque commit!

# Tu veux configurer ton éditeur?
# - VSCode: Installe extension Python + configure Black
# - PyCharm: Configure External Tool
# - Vim: Installe plugin vim-black

# Tu veux intégrer à CI/CD?
# - Crée .github/workflows/black.yml
# - Black vérifie le code à chaque push
# - Fail si code mal formaté

# Questions fréquentes:

# Q: Black va-t-il casser mon code?
# R: NON! Black garantit que le comportement reste identique

# Q: Puis-je personnaliser le style?
# R: Très peu. C'est volontaire (pas de débats)

# Q: Quelle longueur de ligne?
# R: 88 par défaut (recommandé)

# Q: Black ou autopep8?
# R: Black = simple et opinionné, autopep8 = configurable

# Q: Black avec Django/Flask/FastAPI?
# R: Oui! Aucun problème

# Q: Black formate les notebooks?
# R: Oui! Installe black[jupyter]

# Tu es prêt! [RAPIDE]
```