Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Ronde de Cadeaux

❖ Français ❖ English ❖


Ronde de Cadeaux est un outil libre pour tirer au sort des gens à qui faire des cadeaux façon Secret Santa, envoyant des mails aux participant⋅e⋅s pour leur indiquer la personne à régaler. Le tirage peut également être contrôlé par différents mécanismes de contraintes, comme par exemple empêcher une personne d'en tirer une autre ou faire en sorte qu'elle en tire une dans un groupe donné.


Table des matières

🤔 Comment qu'on s'en sert ?

📥 Installation

Cet outil est écrit en Python 3.12, assure-toi d'avoir installé une version supérieure ou égale à la 3.12. Ronde-de-cadeaux s'installe en ligne de commande avec pip ou uv.

Installation avec pip :

pip install ronde-de-cadeaux

Installation avec uv :

uv tool install ronde-de-cadeaux

🧑‍💻 Utilisation

Cet outil installe un seul exécutable, ronde. Voilà son message d'aide :

Utilisation : ronde [-h] [--version] [--test-mail] [-a AUTH] [-m MESSAGE] [--no-imap]
                    [--text-format {html,txt,auto}] [-p PEOPLE] [-s] [-o OUTPUT] [--force]
                    [--seed SEED]

Ce programme permet de générer un tirage de gens à qui offrir des cadeaux en prenant en compte un
système de contraintes complexes.

Arguments:
  -h, --help            Afficher ce message et quitter
  --version             Afficher le numéro de version et quitter
  --test-mail           Tester la configuration de mail
  -a AUTH, --auth AUTH  Fichier de configuration mail
  -m MESSAGE, --message MESSAGE
                        Fichier patron du message envoyé par mail
  --no-imap             Ne pas copier les mails dans la boîte d'envoi
  --text-format {html,txt,auto}
                        Formatage du corps du mail (par défaut `auto`, essaye de détecter)
  -p PEOPLE, --people PEOPLE
                        Fichier des personnes (YAML ou CSV, voir la documentation pour le schéma)
  -s, --show            Afficher la ronde calculée
  -o OUTPUT, --output OUTPUT
                        Fichier dans lequel exporter le tirage
  --force               Forcer l'écriture dans le fichier de sortie, même si celui-ci existe déjà
  --seed SEED           Utilise cette graine aléatoire pour le tirage

L'outil permet deux actions principales, effectuer un tirage et tester la configuration mail.

🎁 Effectuer un tirage

Pour effectuer un tirage il faut fournir un fichier d'entrée contenant les informations sur les personnes participant au tirage, à minima leurs noms (et leur mails si on envoie le tirage par mail aux participant·e·s). Ce fichier est passé avec l'option --people et est au format CSV ou YAML. La structure de ce fichier est discutée plus bas.

Ensuite il faut effectuer au moins une des actions suivantes:

  1. Envoyer un mail aux participant·e·s en utilisant les options --auth suivi du fichier de configuration mail et --message suivi message type à envoyer aux participant·e·s. Le détail de ces fichiers est discuté plus bas, ainsi que des options supplémentaires à l'action d'envoi de mail.
  2. Afficher le tirage dans la console avec l'option --show.
  3. Écrire le résultat du tirage dans un fichier avec l'option --output suivie d'un nom de fichier. Si le fichier existe déjà, une erreur survient mais il est possible de forcer le programme à écraser le fichier avec --force

Pour forcer un tirage aléatoire donnant systématiquement les mêmes résultats, il est possible de passer une graine aléatoire avec l'argument --seed. Cela permet par exemple de ne stocker en clair aucune information sur le tirage, mais d'être capable de le reproduire à l'identique dans le futur, si besoin il est.

⚙️ Tester la configuration mail

Avant d'envoyer un mail à tout le monde, on peut vouloir s'assurer que 1. l’authentification mail est correcte et que 2. le message type est correctement formaté. Pour ce faire on utilise l'option --test-mail en plus de l'option --auth vue plus haut. Cela se connecte aux serveurs mail et envoie un mail à l'adresse mail utilisée pour envoyer les mails. Si --message est passée, le message envoyé est formaté avec des valeurs de test.

📃 Format des différents fichiers d'entrée

😎 Le fichier contenant les informations sur les gens

Ce fichier peut être écrit au format YAML ou CSV. Il est passé en argument avec --people.

Format CSV

Ce type de fichier doit se terminer par l'extension .csv ou .txt, le séparateur est ;. Voilà un exemple contenu d'un tel fichier (ou voir le fichier d'exemple) :

Alice Ecila  ; alice@eci.la ; Alice la pote de Ève
Bœbélius            ;
Caroline
Ève ; ; Ève la pote d'Alice

Ici un tirage au sort sera effectué entre Alice Ecila, Ben, Bœbélius et Caroline. Chaque ligne représente une personne, commence par l'appellation de la personne et son (éventuelle) adresse mail est indiquée après un points virgules ;. D'éventuels commentaires sont insérés après le deuxième ;. Les commentaires n'ont aucune influence sur le tirage. Les espaces intermédiaires non plus et si la personne n'a pas d'adresse mail, un ; peut être inséré après son nom ou pas. Il va sans dire que chaque personne doit avoir un nom différent.

Ce fichier est la façon la plus simple de réaliser un tirage mais n'offre aucune possibilité de contraintes ni de créer des champs personnalisés pour les personnes (ex. surnom).

Le fichier donné en exemple, s'il est valide pour les options --show et --output ne le sera évidemment pas pour l'option --auth puisque seule Alice Ecila possède une adresse mail.

Le format YAML

Ce type de fichier doit se terminer par l'extension .yaml ou .yml.

Ce type de fichier permet de personnaliser les champs ainsi que de créer des contraintes de tirage via les mécanismes de listes d'autorisation (allowlist) et de listes de rejet (denylist).

Un exemple de fichier est donné en exemple.

Un fichier yaml de description consiste en deux dictionnaires (notés avec des deux-points :), people et groups permettant de définir respectivement qui participe et les groupes de gens. Le second dictionnaire est optionnel et son utilité est décrite plus bas.

# Structure de base de la configuration en YAML
people:
  ...
groups: # optionnel
  ...
Les gens

Les éléments de people sont eux aussi des dictionnaires, la clé étant l'appellation (ou identifiant) d'une personne, et les valeurs des champs décrivant la personne. Par exemple :

people:
  Robert T:
    display_name: "Robert Trebor"
    nickname: "Bobby"
    email: "robert@trev.or"

Les champs display_name et nickname décrivent respectivement le nom à afficher et le surnom de la personne. Ils sont optionnels et valent par défaut l'identifiant de la personne, ici "Robert T". Ces champs servent essentiellement à mettre en forme le message type pour l'envoi des mails. Le champ email, lui aussi optionnel désigne l'adresse mail de la personne.

Le fichier de configuration YAML suivant est similaire à celui au format CSV vu plus haut :

people:
  Alice Ecila: # Alice la pote de Ève
    email: "alice@eci.la"
  Bœbélius:
  Caroline:
  Ève: # Ève la pote d'Alice

Notons que Bœbélius, Caroline et Ève n'ont pas de champs mais sont toujours des clés de dictionnaire et donc doivent avoir des : à la fin.

Le format YAML permet d'ajouter des contraintes via les mécanismes de listes d'autorisation via le champ allowlist et de listes de rejet via le champ denylist. Dans l'exemple suivant :

people:
  A:
    allowlist:
    - B
    - C
  B:
    denylist:
    - A
  C:
    allowlist:
    - A
    - B
    denylist:
    - A
  D:
  • A ne peut tirer que B ou C
  • B ne peut pas tirer A
  • C peut tirer "A et B mais pas A" donc seulement B
  • D n'a aucune contrainte, il peut tirer tout le monde

Le cas de C n'a pas de sens pour le moment, pourquoi s'embêter à mettre une personne à la fois dans la liste d'autorisation et dans la liste de rejet ? Ce mécanisme prend tout son sens quand on ajoute le concept de groupes.

Les groupes

Le champ groups est lui aussi un dictionnaire et prend en clé un nom de groupe et en valeur une liste de personnes. Prenons par exemple deux familles, les Ecila et les Trebor. Alice E, Ève et Dorian font partie de la famille Ecila et Robert, Alice T et Fatma. Supposons que chaque famille fait déjà une ronde de cadeaux dans son coin et souhaite faire tirage de sorte qu'une personne d'une famille ne puisse pas tirer quelqu'un·e de sa propre famille pour éviter un cas où une personne doit offrir un cadeaux deux fois à la même personne. Maintenant supposons que Dorian ne connaisse pas très bien Alice T et qu'on souhaite faire en sorte qu'il ne puisse pas la tirer. Tout ceci est facilement modélisable, par exemple comme ceci :

people:

  # Famille Ecila
  Alice E:
    denylist: [Ecila]
  Ève:
    denylist: [Ecila]
  Dorian:
    denylist: [Ecila, Alice T] # Dorian ne peut tirer personne de sa famille ni `Alice T`

  # Famille Trebor
  Robert:
    denylist: [Trebor]
  Alice T:
    denylist: [Trebor]
  Fatma:
    allowlist: [Ecila] # À deux groupes, équivalent à mettre Trebor dans sa denylist

groups:
  Ecila: [Alice E, Ève, Dorian]
  Trebor: [Robert, Alice T, Fatma]

En effet ici, dans groups on définit deux groupes, les familles Trebor et Ecila, et dans les allowlist et denylist des personnes on ajoute ces contraintes.

Notons qu'en YAML les listes peuvent être définies avec la syntaxe de liste à puce et celle utilisant des crochets, voir les deux précédents exemples.

Résumé des contraintes
  • Les personnes définies dans people peuvent avoir des champs allowlist et denylist.
  • Chacun de ces champs est une liste contenant les identifiants de personnes ou de groupe.
  • Les groupes définis dans groups contiennent une liste de personnes ou de groupes .
  • Par défaut, si une personne n'a pas de allowlist, on considère qu'elle peut tirer tout le monde.
  • L'ensemble des personnes qu'une personne peut tirer est définie comme l'ensemble des gens contenus dans sa allowlist (ou voir règle précédente) moins l'ensemble des gens contenus dans sa denylist.

Voir le fichier donné en exemple pour un exemple complexe d'architecture de groupes et de personnes.

📧 Le fichier de configuration mail

Le fichier de configuration de mail est un fichier au format YAML. Il est passé avec l'argument --auth. Il est structuré comme suit:

smtp:
  hostname: ...
  port: ... # optionnel, 587 par défaut
imap: # optionnel, utilise les mêmes paramètres que smtp par défaut
  hostname: ... # optionnel, `smtp.hostname` par défaut
  port: ... # optionnel, 143 par défaut
  sent_folder: ... # optionnel "Sent" par défaut
username: ...
password: ... # optionnel, demandé si non fourni
sender_mail: ... # optionnel, `username` par défaut
sender_name: ... # optionnel, `username` par défaut

Un fichier minimal ressemble à :

smtp:
  hostname: "my_mail_server.org"
username: "my_mail@domain.ext"

Un fichier plus détaillé est donné en exemple.

Attention, ce programme se connecte au serveur mail en STARTTLS. Ce protocole n'est pas supporté par tous les serveurs.

Par défaut, lorsqu'un tirage est effectué, les personnes reçoivent un mail de la part de l'adresse expéditrice et ces mails sont copiés dans la boîte d'envoi. Il est possible de désactiver la copie en passant en argument --no-imap.

💬 Le fichier type de message

Ce fichier est obligatoirement utilisé pour l'envoi des courriels. Il est passé en argument avec --message. C'est un modèle ou patron de conception (template) dont certains champs vont être remplacés par les informations concernant cellui qui offre et cellui qui reçoit.

Ce message peut être au format texte brut ou HTML. Le format est déduit par défaut via l'extension du fichier (.txt ou .html).

Voici un exemple de fichier type au format HTML :

{gifter_name}, cette année tu feras un cadeau à…

Salut {gifter_nickname} !<br>
La personne qui t'a été attribuée lors du tirage est <b>{giftee_name}</b>.<br><br>

On se voit le 13/12 chez Camille ;) 

La première ligne définit le sujet du message, les autres le corps du message. Il peut y avoir des lignes blanches entre les deux parties, cela ne fait aucune différence.

Les remplacements par personnes seront fait comme suit, sur la base des informations des personnes :

Champ Valeur
{sender_mail} Adresse mail expéditrice
{sender_name} Nom associé à l'adresse expéditrice
{gifter_id} Identifiant de la personne qui reçoit le courriel
{gifter_name} Nom de la personne qui reçoit le courriel
{gifter_nickname} Surnom de la personne qui reçoit le message
{gifter_email} Adresse mail de la personne qui reçoit le courriel
{giftee_id} Identifiant de la personne tirée au sort
{giftee_name} Nom de la personne tirée au sort
{giftee_nickname} Surnom de la personne qui reçoit le message
{giftee_email} Adresse mail de la personne tirée au sort

En pratique, seuls les champs gifter_name, gifter_nickname, giftee_name et giftee_nickname sont utiles, mais le reste est disponible si besoin.

Si ce fichier est passé en option lors du test de l'envoi des courriels (avec --test-mail), un mail est envoyé à l'adresse d'envoi avec des valeurs de test pour les champs à remplacer.

Il est possible de forcer le format d'envoi en passant --text-format <value> en argument. <value> peut être txt, html ou auto, par défaut auto qui essaie de déduire le format de l'extension.

🥳 Exemples d'utilisation

Effectuer un tirage avec les données fournies en exemple avec la graine aléatoire jaaj42, les exporter dans un fichier tirage.txt qui existait déjà et afficher ce tirage dans la console :

$ ronde -p examples/people.yaml -o tirage.txt --force -s --seed jaaj42
Alice-Andréa-Alexia Foo → Isöbel Bar
             Isöbel Bar → Dave Foo
               Dave Foo → Henry Bar
              Henry Bar → Cärol Foo
              Cärol Foo → Eve Bar
                Eve Bar → Linda Qux
              Linda Qux → Gulliver Bar
           Gulliver Bar → Nick Qux
               Nick Qux → Flora Bar
              Flora Bar → Jack Baz
               Jack Baz → Bœbélius Foo
           Bœbélius Foo → Mark Qux
               Mark Qux → Alice-Andréa-Alexia Foo

Tester la connection au serveur mail avec un message type et en forçant le format texte brut malgré l'extension :

$ ronde --test-mail -a examples/mail.yaml -m examples/message.html --text-format=txt

(Noter que dans ce cas les balises html seraient envoyées telles quelles, ce qui serait assez disgracieux.)

🔎 FAQ

Pourquoi j'utiliserais un outil chelou en ligne de commande comme ça plutôt qu'un site tout fait qui s'occupe de tout ?

Bonne question, voilà des pistes de réflexions en vrac :

  • Tu ne donnes pas tes données personnelles ni celles de tes proches à un tiers dont tu en ignores l'usage...
  • Les sites ne gèrent pas (tous) un système de contrainte comme celui proposé qui permet de faire des tirages complexes, s'assurant par exemple que les couples ne se tirent pas entre eux, que les enfant ne puissent pas tirés d'adultes de la famille trop éloignée, tout ça.
  • C'est stylé la ligne de commande en vrai, non ?
  • Vive le logiciel libre !

C'est un peu une usine à gaz ton truc. Moi j'ai juste un groupe de potes sans contraintes particulières.

Le format CSV est parfait pour ce genre de cas ;)

Je veux faire un tirage pour ma famille de manière à ce que les adultes se tirent entre eux et les enfants entre eux, comment je fais ?

Cet outil génère un cycle hamiltonien, c'est à dire une boucle unique qui passe par toutes les personnes impliquées. Dans le cas proposé là, l'outil ne trouvera aucune solution, et affichera un message d'erreur. En effet la solution serait d'avoir deux cycles, un pour les adultes et un pour les enfants. Dans ce cas, il faudra faire deux tirages. Plus généralement, si il y a N sous-groupes qui n'interagissent pas les uns avec les autres, il faudra faire N tirages.

La possibilité de permettre à l'outil de générer le nombre minimal de cycles hamiltoniens est en cours de réflexion, mais c'est un problème difficile qui n'a peut être pas énormément de cas d'usage réels.

🤓 Comment contribuer ou aider ?

Déjà il n'y a pas besoin de savoir développer pour contribuer : tous les retours sont les bienvenus, que ce soient les problèmes ou les idées d'améliorations. Pour faire un retour, contacte-moi par mail ou mieux, si tu as un compte framagit, crée un ticket.

Si tu veux absolument développer et que tu utilises Visual Studio Code (ou mieux VSCodium), un .vscode/ existe pour simplifier le lancement des tests ou le debug. Si tu fais des merge requests, n'hésite pas à créer des tests unitaires pour t'assurer que tout fonctionne. Et il te faudra lancer tous les autres tests unitaires pour s'assurer de n'avoir rien cassé :

python -m unittest discover -s tests

Des pistes de trucs en vrac qui pourraient être chouette :

  • Résoudre le problème de la couverture minimale du graphe par des cycles hamiltoniens.
  • Traduire le projet dans plus de langues
  • Faire de la GUI

Si vraiment tu as envie de donner de la bonne THUNE pour ce projet, déjà incroyable et merci, mais je n'en n'ai pas besoin donc donne plutôt aux associations qui œuvrent pour des causes justes, au hasard la LPO 🐦, La Quadrature du Net 🥧, Amnesty International 🕯️ ou l'Association France Palestine Solidarité 🍉...


Ce projet est la continuation du projet ronde-de-cadeaux originel disponible ici.

Metadata

Release files for ronde-de-cadeaux 0.0.0.dev0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ronde-de-cadeaux 0.0.0.dev0
File Size Uploaded Provenance
ronde_de_cadeaux-0.0.0.dev0.tar.gz 41.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for ronde-de-cadeaux 0.0.0.dev0
File Interpreter ABI Platform
ronde_de_cadeaux-0.0.0.dev0-py3-none-any.whl Python 3 none any Details

Total release size: 71.9 kB

Release files / ronde_de_cadeaux-0.0.0.dev0.tar.gz

Download URL ronde_de_cadeaux-0.0.0.dev0.tar.gz
Size 41.0 kB
Tags Source
SHA-256 checksum
How to use checksums
17af33a1d44a55a0016940f4098d57c5a70266d71ddb20d3f61aab2dc21883a9
BLAKE2b-256 checksum
How to use checksums
75350bee1eb22cda832372255c96037d3d3a2e87aa2f92f53b03e8307f4a0d28
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release files / ronde_de_cadeaux-0.0.0.dev0-py3-none-any.whl

Download URL ronde_de_cadeaux-0.0.0.dev0-py3-none-any.whl
Size 31.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5501981287b0341245a2849ffc5893c53d3e22ecedeb9c3cdc9289338e96249c
BLAKE2b-256 checksum
How to use checksums
a204acf55b81521fb25b5f92057e468c03049c64fde0256ac49a343fe43ab215
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Security for ronde-de-cadeaux 0.0.0.dev0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page