Metadata-Version: 2.4
Name: notifyall
Version: 0.3.0
Summary: Notifications multi-canaux : Email, Slack, Telegram, Discord, WhatsApp, Teams, Ntfy, Mattermost, Rocket.Chat, Pushover en une ligne
License-Expression: MIT
Project-URL: Homepage, https://github.com/votre-pseudo/notifyall
Project-URL: Issues, https://github.com/votre-pseudo/notifyall/issues
Keywords: notification,slack,telegram,discord,whatsapp,teams,ntfy,mattermost,rocketchat,pushover,email,alert,monitoring
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Communications
Classifier: Topic :: System :: Monitoring
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"

# notifyall 🔔

[![PyPI version](https://badge.fury.io/py/notifyall.svg)](https://pypi.org/project/notifyall/)
[![Downloads](https://static.pepy.tech/badge/notifyall)](https://pepy.tech/project/notifyall)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

> **La bibliothèque Python ultime pour les notifications multi-canaux.**
> Envoyez vers **10 canaux différents** en une seule ligne de code — zéro dépendance externe.

---

## 🚀 Pourquoi notifyall ?

Dans tout projet Python sérieux (DevOps, monitoring, automatisation, trading, e-commerce...), vous avez besoin d'envoyer des notifications. Le problème : chaque service a sa propre bibliothèque, sa propre API, sa propre syntaxe.

**notifyall résout ça en une interface unifiée.**

| Avant notifyall | Avec notifyall |
|---|---|
| `slack_sdk`, `python-telegram-bot`, `discord-webhook`... | `pip install notifyall` |
| Code différent pour chaque service | `.notify("message")` partout |
| Dépendances lourdes | Zéro dépendance externe |
| Pas de retry, pas de stats | Retry, stats, historique intégrés |

---

## ⚡ Installation

```bash
pip install notifyall
```

---

## 🏁 Démarrage rapide

```python
from notifyall import Notifier
from notifyall.channels import SlackChannel, TelegramChannel, DiscordChannel

n = Notifier(default_title="Mon Application")
n.add(SlackChannel(webhook_url="https://hooks.slack.com/services/..."))
n.add(TelegramChannel(bot_token="123456:ABC-DEF", chat_id="-100123456789"))
n.add(DiscordChannel(webhook_url="https://discord.com/api/webhooks/..."))

results = n.notify("Déploiement réussi ✅")
print(results)
# [
#   {"channel": "slack",    "status": "ok"},
#   {"channel": "telegram", "status": "ok"},
#   {"channel": "discord",  "status": "ok"},
# ]
```

---

## 📦 Canaux supportés (10 canaux)

| Canal        | Classe              | Prérequis                         | Gratuit |
|--------------|---------------------|-----------------------------------|---------|
| Email        | EmailChannel        | SMTP host/port/user/pass          | ✅      |
| Slack        | SlackChannel        | Webhook URL                       | ✅      |
| Telegram     | TelegramChannel     | Bot token + Chat ID               | ✅      |
| Discord      | DiscordChannel      | Webhook URL                       | ✅      |
| Ntfy         | NtfyChannel         | Topic (sans compte requis !)      | ✅      |
| Teams        | TeamsChannel        | Webhook URL                       | ✅      |
| Mattermost   | MattermostChannel   | Webhook URL                       | ✅      |
| Rocket.Chat  | RocketChatChannel   | Webhook URL                       | ✅      |
| WhatsApp     | WhatsAppChannel     | Compte Twilio                     | 💰      |
| Pushover     | PushoverChannel     | App token + User key              | 💰      |

---

## 📖 Documentation complète

### Notifier — Classe principale

```python
from notifyall import Notifier

n = Notifier(default_title="Mon App")
```

| Méthode | Description |
|---|---|
| `.add(channel)` | Ajoute un canal. Retourne `self` (chaînable) |
| `.remove(channel)` | Retire un canal |
| `.notify(msg, title)` | Envoie sur tous les canaux (séquentiel) |
| `.notify_parallel(msg, title)` | Envoie sur tous les canaux en parallèle |
| `.notify_one(name, msg, title)` | Envoie sur un seul canal par nom |
| `.notify_template(tpl, **kwargs)` | Envoie un message formaté |
| `.notify_if(cond, msg, title)` | Envoie uniquement si condition vraie |
| `.notify_level(level, msg)` | Envoie avec niveau (info/success/warning/error/critical) |
| `.notify_scheduled(msg, title, delay)` | Envoie après un délai (secondes) |
| `.notify_repeat(msg, title, times, interval)` | Répète l'envoi N fois |
| `.on(event, callback)` | Ajoute un hook (before/after/error) |
| `.stats()` | Retourne les statistiques d'envoi |
| `.history` | Liste toutes les notifications envoyées |
| `.failed_notifications()` | Liste les notifications en erreur |
| `.export_history(filepath)` | Exporte l'historique en JSON |
| `.clear_history()` | Vide l'historique |
| `.channel_count` | Nombre de canaux configurés |

---

### Envoi séquentiel vs parallèle

```python
# Séquentiel — attend la réponse de chaque canal avant le suivant
results = n.notify("Hello")

# Parallèle — envoie sur tous les canaux simultanément (plus rapide)
results = n.notify_parallel("Hello")
```

---

### Niveaux de notification

```python
n.notify_level("info",     "Démarrage du service")
n.notify_level("success",  "Déploiement terminé")
n.notify_level("warning",  "CPU à 80%")
n.notify_level("error",    "Base de données inaccessible")
n.notify_level("critical", "Serveur en panne !")
```

---

### Templates de messages

```python
n.notify_template(
    "🚀 Version {version} déployée sur {env} par {user}",
    version="2.1.0",
    env="production",
    user="alice"
)
```

---

### Envoi conditionnel

```python
cpu_usage = 95
n.notify_if(cpu_usage > 90, f"CPU surchargé : {cpu_usage}%", title="⚠️ Alerte")

disk_free = 500
n.notify_if(disk_free < 1000, "Disque presque plein !", title="🔴 Critique")
```

---

### Envoi différé et répété

```python
# Envoyer dans 30 secondes
n.notify_scheduled("Tâche planifiée terminée", delay_seconds=30)

# Envoyer 3 fois, toutes les 5 minutes
n.notify_repeat("Rappel : réunion dans 15 minutes", times=3, interval=300)
```

---

### Hooks (before / after / error)

```python
def avant_envoi(message, title):
    print(f"[notifyall] Envoi : {title} — {message}")

def apres_envoi(message, title, results):
    ok = sum(1 for r in results if r.get("status") == "ok")
    print(f"[notifyall] {ok}/{len(results)} canaux OK")

def en_erreur(result):
    print(f"[notifyall] Erreur sur {result['channel']} : {result['error']}")

n.on("before", avant_envoi)
n.on("after",  apres_envoi)
n.on("error",  en_erreur)
```

---

### Retry automatique

```python
from notifyall.channels import SlackChannel

ch = SlackChannel(webhook_url="...")
result = ch.send_with_retry("Message important", retries=3, delay=2.0)
# Réessaie jusqu'à 3 fois avec 2 secondes entre chaque tentative
```

---

### Statistiques

```python
n.notify("Déploiement 1")
n.notify("Déploiement 2")
n.notify("Déploiement 3")

print(n.stats())
# {
#   "total_sends": 9,
#   "success": 9,
#   "errors": 0,
#   "success_rate": "100.0%",
#   "notifications_sent": 3,
#   "channels_configured": 3
# }
```

---

### Historique et export

```python
# Voir les 5 dernières notifications
for entry in n.history[-5:]:
    print(f"[{entry['timestamp']}] {entry['title']} — {entry['message']}")

# Voir les notifications en erreur
for entry in n.failed_notifications():
    print(entry)

# Exporter en JSON
n.export_history("notifications.json")
```

---

### Configuration des canaux

#### Email (Gmail)
```python
from notifyall.channels import EmailChannel

ch = EmailChannel(
    smtp_host="smtp.gmail.com",
    smtp_port=587,
    username="moi@gmail.com",
    password="app_password",      # Mot de passe d'application Gmail
    from_addr="moi@gmail.com",
    to_addr="destinataire@email.com",
    use_tls=True
)

ch.send("Bonjour !", title="Test Email")
ch.send_html("<h1>Bonjour</h1><p>Message HTML</p>", title="Email HTML")
ch.send_to_multiple("Message groupé", ["alice@mail.com", "bob@mail.com"])
```

#### Slack
```python
from notifyall.channels import SlackChannel

ch = SlackChannel(
    webhook_url="https://hooks.slack.com/services/XXX/YYY/ZZZ",
    username="notifyall",
    icon_emoji=":bell:"
)

ch.send("Déploiement réussi", title="Prod")
ch.send_blocks([
    {"type": "header", "text": {"type": "plain_text", "text": "Alerte"}},
    {"type": "section", "text": {"type": "mrkdwn", "text": "*Déploiement* réussi ✅"}}
])
```

#### Telegram
```python
from notifyall.channels import TelegramChannel

ch = TelegramChannel(
    bot_token="123456789:ABCdefGHIjklMNOpqrSTUvwxYZ",
    chat_id="-100123456789",
    parse_mode="HTML",
    disable_preview=True
)

ch.send("Bonjour depuis notifyall !", title="Test")
ch.send_photo("https://example.com/image.png", caption="Graphique du jour")
ch.send_document("https://example.com/rapport.pdf", caption="Rapport mensuel")
ch.send_poll("Êtes-vous satisfait ?", ["Oui", "Non", "Peut-être"])
```

#### Discord
```python
from notifyall.channels import DiscordChannel

ch = DiscordChannel(
    webhook_url="https://discord.com/api/webhooks/XXX/YYY",
    username="notifyall",
    avatar_url="https://example.com/avatar.png"
)

ch.send("Message simple")
ch.send_embed(
    title="Rapport de déploiement",
    description="La version 2.0 est en ligne",
    color=0x00ff00,
    fields=[
        {"name": "Environnement", "value": "Production", "inline": True},
        {"name": "Durée", "value": "2m 34s", "inline": True}
    ],
    footer="notifyall v0.3.0",
    thumbnail_url="https://example.com/logo.png"
)
```

#### Ntfy (100% gratuit, sans compte)
```python
from notifyall.channels import NtfyChannel

ch = NtfyChannel(
    topic="mon-topic-secret",
    server="https://ntfy.sh",
    priority="high"
)
ch.send("Notification push gratuite !", title="Test Ntfy")
```

#### Microsoft Teams
```python
from notifyall.channels import TeamsChannel

ch = TeamsChannel(webhook_url="https://outlook.office.com/webhook/...")
ch.send("Message simple", title="Alerte")
ch.send_card(
    title="Rapport de déploiement",
    message="Version 2.0 déployée avec succès",
    facts=[
        {"name": "Environnement", "value": "Production"},
        {"name": "Durée", "value": "2 minutes"}
    ],
    color="00FF00"
)
```

#### Mattermost
```python
from notifyall.channels import MattermostChannel

ch = MattermostChannel(
    webhook_url="https://votre-instance.mattermost.com/hooks/XXX",
    channel="alerts",
    username="notifyall"
)
ch.send("Déploiement réussi", title="Prod")
```

#### Rocket.Chat
```python
from notifyall.channels import RocketChatChannel

ch = RocketChatChannel(
    webhook_url="https://votre-instance.rocket.chat/hooks/XXX",
    alias="notifyall",
    emoji=":bell:"
)
ch.send("Alerte système", title="Monitoring")
```

---

## 🛠️ Cas d'usage réels

### Monitoring serveur
```python
import psutil
from notifyall import Notifier
from notifyall.channels import TelegramChannel, SlackChannel

n = Notifier(default_title="🖥️ Monitoring")
n.add(TelegramChannel(bot_token="...", chat_id="..."))
n.add(SlackChannel(webhook_url="..."))

cpu = psutil.cpu_percent()
mem = psutil.virtual_memory().percent

n.notify_if(cpu > 90,  f"CPU critique : {cpu}%")
n.notify_if(mem > 85,  f"RAM élevée : {mem}%")
n.notify_level("success", "Monitoring OK")
```

### Pipeline CI/CD
```python
from notifyall import Notifier
from notifyall.channels import SlackChannel, TeamsChannel

n = Notifier()
n.add(SlackChannel(webhook_url="..."))
n.add(TeamsChannel(webhook_url="..."))

try:
    deploy()
    n.notify_template("✅ v{version} déployée sur {env} !", version="2.0", env="prod")
except Exception as e:
    n.notify_level("critical", f"Déploiement échoué : {e}")
```

### Rapport quotidien automatique
```python
import schedule, time
from notifyall import Notifier
from notifyall.channels import EmailChannel

n = Notifier(default_title="📊 Rapport quotidien")
n.add(EmailChannel(...))

def rapport():
    n.notify(f"Ventes du jour : 1234€\nNouveaux clients : 42")

schedule.every().day.at("08:00").do(rapport)
while True:
    schedule.run_pending()
    time.sleep(60)
```

---

## ✅ Zéro dépendance externe

`notifyall` utilise **uniquement la bibliothèque standard Python** :
`smtplib`, `urllib`, `json`, `threading`, `base64`, `time`

Aucune installation supplémentaire requise.

---

## 🤝 Contribuer

Les contributions sont les bienvenues !

1. Forkez le projet
2. Créez une branche (`git checkout -b feature/nouveau-canal`)
3. Commitez (`git commit -m "feat: ajout canal XYZ"`)
4. Pushez (`git push origin feature/nouveau-canal`)
5. Ouvrez une Pull Request

---

## 📄 Licence

MIT — Libre d'utilisation pour projets personnels et commerciaux.
