Aller au contenu

Pièces Jointes

Lorsque vous passez attach= à Apprise.notify(), Apprise normalise chaque entrée en un objet AppriseAttachment (reposant en interne sur des implémentations de AttachBase). Les plugins qui activent cette prise en charge (en définissant attachment_support = True) reçoivent une liste d’objets pièces jointes via l’argument attach de send().

Du point de vue de l’auteur d’un plugin, une pièce jointe est une petite API uniforme qui vous permet de :

  • valider sa disponibilité (if not attachment: ...) ;
  • lire son contenu (attachment.path, attachment.open(), attachment.chunk()) ;
  • récupérer ses métadonnées (attachment.name, attachment.mimetype, len(attachment)) ;
  • la convertir en base64 (attachment.base64()), pour les API qui exigent une charge utile inline ;
  • préserver la confidentialité dans les logs (attachment.url(privacy=True)).

Lorsqu’un plugin déclare la prise en charge des pièces jointes :

class NotifyFooBar(NotifyBase):
# Declare awareness to the Apprise library that this service supports
# attachments
attachment_support = True
def send(self, body, title="", notify_type=NotifyType.INFO, attach=None, **kwargs):
# Add 'attach' into your send() call as it will be populated when one
# or more attachments exist.
if attach:
for a in attach:
# ...
pass

attach vaut soit :

  • None ou une liste vide lorsqu’aucune pièce jointe n’a été fournie ;
  • une liste d’objets AttachBase (par exemple : AttachFile, AttachHTTP, AttachMemory).

Raccourci pratique :

  • if not a: signifie que la pièce jointe n’est pas exploitable pour le moment ;
  • a.path déclenche un téléchargement ou une validation si nécessaire ;
  • len(a) renvoie la taille de la pièce jointe en octets, lorsqu’elle est connue.

Apprise prend en charge plusieurs sources de pièces jointes. Elles sont toutes normalisées vers la même surface d’API.

AttachFile — les fichiers locaux référencent des chemins côté serveur. L’usage le plus simple consiste à passer directement une chaîne de chemin : Apprise la convertit en URL file:// en interne :

# Single path — Apprise wraps it in AttachFile automatically
apobj.notify(body="See log", attach="/var/log/syslog")
# Multiple paths
apobj.notify(
body="Build artifacts",
attach=["/var/log/syslog", "/tmp/report.pdf"],
)

Constructeur direct — utilisez AttachFile lorsque vous devez surcharger le nom de fichier ou le type MIME présenté au service distant, sans renommer le fichier sur le disque :

from apprise.attachment import AttachFile
# Override the filename and MIME type the service sees
a = AttachFile(
"/var/log/app.log",
name="2026-03-20-app.log", # presented name, not a rename
mimetype="text/plain",
)
apobj.notify(body="Nightly log", attach=a)

Comportements Clés :

  • Le contenu est validé sur place : il n’est ni copié ni déplacé.
  • name= et mimetype= surchargent ce que le plugin envoie en amont ; le fichier sur disque reste inchangé.
  • Les limites de taille sont appliquées via max_file_size (1 Go par défaut).
  • attachment.path renvoie le chemin absolu du fichier.
  • attachment.open() renvoie un handle lisible et constitue la bonne façon de diffuser le contenu dans les plugins.

La gestion des pièces jointes est gouvernée par des règles d’emplacement du contenu :

ValeurDescription
LOCALAutorise les fichiers locaux, les pièces jointes en mémoire et le contenu hébergé.
HOSTEDDestiné aux services hébergés. Les fichiers locaux et pièces jointes mémoire sont rejetés.
INACCESSIBLELes pièces jointes sont entièrement désactivées. Tous les téléchargements échouent et les objets valent False.

Paramètres d’URL Partagés par les Types de Pièces Jointes

Section intitulée « Paramètres d’URL Partagés par les Types de Pièces Jointes »
ValeurDescription
mimeLes URL de pièces jointes prennent en charge un petit ensemble de paramètres de requête communs.
Force le type MIME de la pièce jointe en contournant la détection.
nameForce le nom de fichier présenté au plugin. Cela ne renomme pas le fichier local ; cela modifie seulement les métadonnées (attachment.name) et ce que le plugin peut envoyer en amont.

Vérifiez toujours que les pièces jointes sont disponibles avant de les utiliser :

for attachment in attach:
if not attachment:
self.logger.error(
"Could not access attachment %s.",
attachment.url(privacy=True),
)
return False

Une pièce jointe peut échouer parce qu’elle est absente, dépasse les limites de taille, est inaccessible depuis l’emplacement d’exécution courant, ou n’a pas pu être téléchargée.

Préférez attachment.open() pour les API d’Upload

Section intitulée « Préférez attachment.open() pour les API d’Upload »

De nombreux services exigent des uploads multipart. Utilisez attachment.open() pour obtenir un objet de type fichier : cela fonctionne correctement pour tous les types de pièces jointes, y compris AttachMemory, qui n’a aucun chemin sur disque :

filename = attachment.name
mimetype = attachment.mimetype
fh = attachment.open()
try:
files = {"file": (filename, fh, mimetype)}
r = requests.post(url, files=files, ...)
finally:
fh.close()

Ou via la forme avec gestionnaire de contexte :

with attachment as f:
files = {"file": (attachment.name, f, attachment.mimetype)}
r = requests.post(url, files=files, ...)

Tous les types de pièces jointes prennent en charge l’export Base64. Certaines API exigent des pièces jointes encodées en base64. Utilisez attachment.base64() :

encoded = attachment.base64() # returns a str by default
payload["base64_attachments"].append(encoded)
  • base64() renvoie une chaîne ;
  • base64(encoding=None) renvoie des octets bruts.

Si la pièce jointe ne peut pas être lue, base64() lève une exception Apprise. Interceptez-la et échouez proprement.

Cela est fréquemment utilisé par les API qui ne prennent pas en charge les uploads multipart.

Si vous devez éviter de charger un fichier entier en mémoire, utilisez attachment.chunk() :

for chunk in attachment.chunk(size=5 * 1024 * 1024):
# upload / write chunk
...

Les plugins n’ont généralement pas besoin de supprimer manuellement les fichiers temporaires téléchargés. Les objets pièces jointes gèrent eux-mêmes leur nettoyage via invalidate() et leurs destructeurs.

Si vous conservez des objets pièces jointes au-delà de send(), il vous revient de bien comprendre leur cycle de vie. En règle générale, traitez-les comme des objets éphémères.

  • Les limites de taille sont appliquées par AttachBase.max_file_size. Si votre service impose une limite plus basse, faites-la respecter dans votre plugin avec len(attachment) et échouez tôt.
  • La prise en charge des pièces jointes est activée explicitement par plugin via attachment_support = True. Si votre service n’accepte pas les fichiers, laissez cette option désactivée.
  • Utilisez attachment.url(privacy=True) dans les logs. Cela garantit que les secrets embarqués sont masqués.

Les plugins devraient valider tôt la taille et le nombre des pièces jointes, et gérer proprement les pièces jointes inaccessibles.

Le projet principal contient des modèles courants que vous pouvez reprendre.

  • envoi de pièces jointes sous forme de fichiers (multipart) avec sélection basée sur le MIME ;
  • conversion de pièces jointes en base64 pour les API JSON ;
  • itération sur les pièces jointes et remontée des échecs partiels.

Consultez les plugins Telegram et Signal API pour des implémentations réelles de ces approches.

Questions ou commentaires ?

Documentation

Vous avez repéré une faute de frappe ou une erreur ? Signalez-la ou proposez une correction .

Problèmes Techniques

Vous rencontrez un problème avec le code ? Ouvrez un ticket sur GitHub :

Conçu avec amour depuis le Canada