Metadata-Version: 2.4
Name: notifyall
Version: 0.3.1
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
Project-URL: Changelog, https://github.com/votre-pseudo/notifyall/blob/main/CHANGELOG.md
Project-URL: Funding, https://github.com/sponsors/votre-pseudo
Project-URL: Buy Me a Coffee, https://buymeacoffee.com/votre-pseudo
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)
[![Buy Me a Coffee](https://img.shields.io/badge/Buy%20Me%20a%20Coffee-☕-yellow?logo=buy-me-a-coffee)](https://buymeacoffee.com/votre-pseudo)
[![GitHub Sponsors](https://img.shields.io/badge/Sponsor-%E2%9D%A4-pink?logo=github)](https://github.com/sponsors/votre-pseudo)
[![Ko-fi](https://img.shields.io/badge/Ko--fi-Support-blue?logo=ko-fi)](https://ko-fi.com/votre-pseudo)

> **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**.

---

## 📋 Table des matières

- [Pourquoi notifyall ?](#-pourquoi-notifyall-)
- [Installation](#-installation)
- [Démarrage rapide](#-démarrage-rapide)
- [Canaux supportés](#-canaux-supportés)
- [Documentation complète](#-documentation-complète)
  - [Notifier — Classe principale](#notifier--classe-principale)
  - [Envoi séquentiel vs parallèle](#envoi-séquentiel-vs-parallèle)
  - [Niveaux de notification](#niveaux-de-notification)
  - [Templates de messages](#templates-de-messages)
  - [Envoi conditionnel](#envoi-conditionnel)
  - [Envoi différé et répété](#envoi-différé-et-répété)
  - [Hooks (before / after / error)](#hooks-before--after--error)
  - [Retry automatique](#retry-automatique)
  - [Statistiques](#statistiques)
  - [Historique et export](#historique-et-export)
- [Configuration de chaque canal](#-configuration-de-chaque-canal)
- [Cas d'usage réels](#%EF%B8%8F-cas-dusage-réels)
- [Zéro dépendance externe](#-zéro-dépendance-externe)
- [Contribuer](#-contribuer)
- [Soutenir le projet](#-soutenir-le-projet)
- [Licence](#-licence)

---

## 🚀 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 !) | ✅ |
| Microsoft 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 !")
```

Les icônes sont ajoutées automatiquement :

| Niveau | Icône | Titre |
|---|---|---|
| info | ℹ️ | INFO |
| success | ✅ | SUCCESS |
| warning | ⚠️ | WARNING |
| error | ❌ | ERROR |
| critical | 🚨 | CRITICAL |

---

### 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 (non bloquant)
n.notify_scheduled("Tâche planifiée terminée", delay_seconds=30)

# Envoyer 3 fois toutes les 5 minutes (non bloquant)
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 uniquement
for entry in n.failed_notifications():
    print(entry)

# Exporter tout l'historique en JSON
n.export_history("notifications.json")

# Vider l'historique
n.clear_history()
```

---

## 🔧 Configuration de chaque canal

### Email (Gmail, Outlook, etc.)

```python
from notifyall.channels import EmailChannel

ch = EmailChannel(
    smtp_host="smtp.gmail.com",
    smtp_port=587,
    username="moi@gmail.com",
    password="app_password",
    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"])
```

> 💡 Pour Gmail, activez la validation en 2 étapes et créez un **mot de passe d'application** dans les paramètres de compte Google.

---

### 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")

# Avec Block Kit (mise en forme avancée)
ch.send_blocks([
    {"type": "header", "text": {"type": "plain_text", "text": "🚀 Alerte"}},
    {"type": "section", "text": {"type": "mrkdwn", "text": "*Déploiement* réussi ✅"}}
])
```

> 💡 Créez un Incoming Webhook sur [api.slack.com/apps](https://api.slack.com/apps).

---

### 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"])
```

> 💡 Créez un bot avec [@BotFather](https://t.me/BotFather) sur Telegram pour obtenir le token.

---

### 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")

# Embed enrichi
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"
)
```

> 💡 Créez un webhook dans les paramètres de votre serveur Discord → Intégrations.

---

### Ntfy (100% gratuit, sans compte)

```python
from notifyall.channels import NtfyChannel

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

> 💡 Installez l'app [ntfy](https://ntfy.sh) sur votre téléphone et abonnez-vous à votre topic. Aucun compte requis !

---

### Microsoft Teams

```python
from notifyall.channels import TeamsChannel

ch = TeamsChannel(webhook_url="https://outlook.office.com/webhook/...")

ch.send("Message simple", title="Alerte")

# Carte enrichie avec faits
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"
)
```

> 💡 Créez un Incoming Webhook dans les connecteurs de votre canal Teams.

---

### 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")
```

---

### WhatsApp (via Twilio)

```python
from notifyall.channels import WhatsAppChannel

ch = WhatsAppChannel(
    account_sid="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    auth_token="your_auth_token",
    from_number="whatsapp:+14155238886",
    to_number="whatsapp:+33612345678"
)
ch.send("Alerte critique !", title="Monitoring")
```

> 💡 Nécessite un compte [Twilio](https://twilio.com). Sandbox gratuit disponible pour les tests.

---

### Pushover

```python
from notifyall.channels import PushoverChannel

ch = PushoverChannel(
    app_token="azGDORePK8gMaC0QOYAMyEEuzJnyUi",
    user_key="uQiRzpo4DXghDmr9QzzfQu27cmVRsG",
    priority=PushoverChannel.PRIORITY_HIGH,
    sound="siren"
)
ch.send("Serveur en panne !", title="🚨 CRITIQUE")
```

> 💡 Créez une application sur [pushover.net](https://pushover.net) pour obtenir votre app token.

---

## 🛠️ 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
disk = psutil.disk_usage("/").percent

n.notify_if(cpu > 90,  f"CPU critique : {cpu}%")
n.notify_if(mem > 85,  f"RAM élevée : {mem}%")
n.notify_if(disk > 95, f"Disque presque plein : {disk}%")
```

---

### 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
import time
from notifyall import Notifier
from notifyall.channels import EmailChannel, TelegramChannel

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

def rapport():
    n.notify("Ventes du jour : 1 234 €\nNouveaux clients : 42\nTickets résolus : 18")

schedule.every().day.at("08:00").do(rapport)

while True:
    schedule.run_pending()
    time.sleep(60)
```

---

### Alerte de trading

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

n = Notifier(default_title="📈 Trading Bot")
n.add(TelegramChannel(bot_token="...", chat_id="..."))
n.add(DiscordChannel(webhook_url="..."))

def check_price(symbol, price, target):
    n.notify_if(
        price >= target,
        f"{symbol} a atteint {price}€ (objectif : {target}€) 🎯",
        title="Signal d'achat"
    )
```

---

## 🧪 Tests

```bash
pip install pytest
pytest tests/
```

---

## ✅ Zéro dépendance externe

`notifyall` utilise **uniquement la bibliothèque standard Python** :

| Module | Usage |
|---|---|
| `smtplib` | Envoi d'emails |
| `urllib` | Requêtes HTTP vers les APIs |
| `json` | Sérialisation des payloads |
| `threading` | Envoi parallèle non bloquant |
| `base64` | Authentification Basic (WhatsApp) |
| `time` | Retry, délais, timestamps |

---

## 🤝 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

**Idées de contributions bienvenues :**
- Nouveau canal (Pushbullet, Signal, Matrix, Gotify...)
- Tests unitaires supplémentaires
- Intégration avec `logging` standard Python
- Support async/await

---

## ☕ Soutenir le projet

`notifyall` est **100% gratuit et open source** (MIT). Si cette bibliothèque vous fait gagner du temps, un petit café est toujours apprécié ! 🙏

| Plateforme | Lien |
|---|---|
| ☕ Buy Me a Coffee | [buymeacoffee.com/votre-pseudo](https://buymeacoffee.com/votre-pseudo) |
| ❤️ GitHub Sponsors | [github.com/sponsors/votre-pseudo](https://github.com/sponsors/votre-pseudo) |
| 🍵 Ko-fi | [ko-fi.com/votre-pseudo](https://ko-fi.com/votre-pseudo) |

Votre soutien permet de :
- 🔧 Maintenir et corriger la bibliothèque
- ➕ Ajouter de nouveaux canaux
- 📖 Améliorer la documentation
- ⚡ Développer de nouvelles fonctionnalités

Merci à tous les contributeurs et donateurs ! 💙

---

## 📄 Licence

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